Skip to content

Instantly share code, notes, and snippets.

@J-Swift
Last active August 4, 2025 23:23
Show Gist options
  • Save J-Swift/fdcb395a62e186fdebb8f0989f4620d3 to your computer and use it in GitHub Desktop.
Save J-Swift/fdcb395a62e186fdebb8f0989f4620d3 to your computer and use it in GitHub Desktop.
Selenium driver automation to automate chase offer redemptions
// vibe coded alternative to run in dev console
(async function resilientAutoClick() {
const pollInterval = 100;
const shortPause = 250;
function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}
// Poll until you find the selector—never times out
function waitForSelectorInfinite(selector) {
return new Promise(resolve => {
(function tick() {
const el = document.querySelector(selector);
if (el) return resolve(el);
setTimeout(tick, pollInterval);
})();
});
}
// Same idea for shadow-root lookups
function waitForShadowSelectorInfinite(hostSel, innerSel) {
return new Promise(resolve => {
(function tick() {
for (const host of document.querySelectorAll(hostSel)) {
if (host.shadowRoot) {
const inside = host.shadowRoot.querySelector(innerSel);
if (inside) return resolve(inside);
}
}
setTimeout(tick, pollInterval);
})();
});
}
while (true) {
try {
// 1) wait for & click the add button
const addBtn = await waitForSelectorInfinite('mds-icon[type="ico_add_circle"]');
addBtn.click();
// 2) wait for & click the back button inside shadow DOM
const backBtn = await waitForShadowSelectorInfinite('mds-navigation-bar', '#back-button');
// 3) mimic your small implicit wait
await sleep(shortPause);
backBtn.click();
// optional: small pause before next iteration so you don't hammer
await sleep(shortPause);
} catch (err) {
console.error('Iteration error:', err);
// keep going—this catch is just in case something unexpected happens
}
}
})();
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
timeout_secs = 3
selector_add_btn = 'mds-icon[type="ico_add_circle"]'
selector_back_btn_shadow_root = 'mds-navigation-bar'
selector_back_btn_el = '#back-button'
options = webdriver.ChromeOptions()
options.debugger_address = "127.0.0.1:9222"
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(timeout_secs)
actions = ActionChains(driver)
wait = WebDriverWait(driver, timeout_secs)
while True:
element = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector_add_btn)))
actions.move_to_element(element).click().perform()
shadow_host = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector_back_btn_shadow_root)))
element = driver.execute_script("return arguments[0].shadowRoot.querySelector('{}')".format(selector_back_btn_el), shadow_host)
actions.move_to_element(element).click().perform()
@J-Swift
Copy link
Author

J-Swift commented Sep 8, 2024

Start browser with

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=./data-dir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment