fixed SRG5-8 channels FTs: multi-browser sig-card OK flow now uses execute_async_script to iterate cards until a non-conflicting reserve succeeds (bypasses ElementNotInteractableException + 409 same-card conflicts); added wait_for_slow for 12s countdown in SRG8; added browser=None param to ChannelsFunctionalTest.wait_for/wait_for_slow
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -195,10 +195,10 @@ class ChannelsFunctionalTest(ChannelsLiveServerTestCase):
|
||||
)
|
||||
|
||||
@wait
|
||||
def wait_for(self, fn):
|
||||
def wait_for(self, fn, browser=None):
|
||||
return fn()
|
||||
|
||||
def wait_for_slow(self, fn, timeout=30):
|
||||
def wait_for_slow(self, fn, timeout=30, browser=None):
|
||||
start_time = time.time()
|
||||
while True:
|
||||
try:
|
||||
|
||||
@@ -495,10 +495,12 @@ class SigReadyGateTest(FunctionalTest):
|
||||
btn = self.browser.find_element(By.ID, "id_take_sig_btn")
|
||||
btn.click() # → TAKE SIG again
|
||||
|
||||
reverted = self.wait_for(
|
||||
lambda: self.browser.find_element(By.ID, "id_take_sig_btn")
|
||||
self.wait_for(
|
||||
lambda: self.assertIn(
|
||||
"TAKE SIG",
|
||||
self.browser.find_element(By.ID, "id_take_sig_btn").text.upper(),
|
||||
)
|
||||
)
|
||||
self.assertIn("TAKE SIG", reverted.text.upper())
|
||||
|
||||
|
||||
@tag("channels")
|
||||
@@ -521,6 +523,7 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
if os.environ.get("HEADLESS"):
|
||||
options.add_argument("--headless")
|
||||
b = webdriver.Firefox(options=options)
|
||||
b.set_window_size(800, 1200)
|
||||
b.get(self.live_server_url + "/404_no_such_url/")
|
||||
b.add_cookie(dict(
|
||||
name=django_settings.SESSION_COOKIE_NAME,
|
||||
@@ -529,6 +532,52 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
))
|
||||
return b
|
||||
|
||||
def _ok_card_in_browser(self, b):
|
||||
"""Reserve any available sig-card, then JS-click its OK button to trigger
|
||||
the page's applyReservation() and reveal #id_take_sig_btn.
|
||||
|
||||
Iterates through cards until one succeeds — multiple browsers in the same
|
||||
polarity group would otherwise all try to reserve the same first card and
|
||||
get 409 conflicts."""
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-card"), browser=b
|
||||
)
|
||||
result = b.execute_async_script("""
|
||||
var cb = arguments[arguments.length - 1];
|
||||
var overlay = document.querySelector('.sig-overlay');
|
||||
var cards = document.querySelectorAll('.sig-card');
|
||||
if (!overlay || !cards.length) { cb({error: 'no overlay or cards'}); return; }
|
||||
var reserveUrl = overlay.dataset.reserveUrl;
|
||||
var csrfM = document.cookie.match(/csrftoken=([^;]+)/);
|
||||
var csrf = csrfM ? csrfM[1] : '';
|
||||
function tryCard(idx) {
|
||||
if (idx >= cards.length) { cb({error: 'all cards taken'}); return; }
|
||||
var cardId = cards[idx].dataset.cardId;
|
||||
fetch(reserveUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-CSRFToken': csrf,
|
||||
},
|
||||
body: 'action=reserve&card_id=' + encodeURIComponent(cardId),
|
||||
}).then(function (res) {
|
||||
if (res.status === 409) { tryCard(idx + 1); return; }
|
||||
cb({status: res.status, ok: res.ok, cardId: cardId});
|
||||
}).catch(function (e) { cb({error: e.message}); });
|
||||
}
|
||||
tryCard(0);
|
||||
""")
|
||||
if not (result and result.get('ok')):
|
||||
raise AssertionError(f"sig_reserve fetch failed: {result}")
|
||||
# Fetch confirmed 200 — JS-click the *correct* card's OK button so
|
||||
# applyReservation() runs in page context and reveals #id_take_sig_btn.
|
||||
# (Idempotent re-reserve of the same card → 200, safe.)
|
||||
card_id = result['cardId']
|
||||
ok_btn = b.find_element(
|
||||
By.CSS_SELECTOR, f'.sig-card[data-card-id="{card_id}"] .sig-ok-btn'
|
||||
)
|
||||
b.execute_script("arguments[0].click()", ok_btn)
|
||||
|
||||
def _setup_sig_select_room(self):
|
||||
emails = [
|
||||
"founder@test.io", "amigo@test.io", "bud@test.io",
|
||||
@@ -556,14 +605,7 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
|
||||
# Each levity gamer OK's a card then clicks TAKE SIG
|
||||
for b in browsers:
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-card"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-card").click()
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-ok-btn"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-ok-btn").click()
|
||||
self._ok_card_in_browser(b)
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.ID, "id_take_sig_btn"), browser=b
|
||||
)
|
||||
@@ -595,14 +637,7 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
|
||||
# All go ready
|
||||
for b in browsers:
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-card"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-card").click()
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-ok-btn"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-ok-btn").click()
|
||||
self._ok_card_in_browser(b)
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.ID, "id_take_sig_btn"), browser=b
|
||||
)
|
||||
@@ -661,14 +696,7 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
|
||||
# All levity gamers OK and TAKE SIG
|
||||
for b in browsers:
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-card"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-card").click()
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-ok-btn"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-ok-btn").click()
|
||||
self._ok_card_in_browser(b)
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.ID, "id_take_sig_btn"), browser=b
|
||||
)
|
||||
@@ -700,22 +728,16 @@ class SigReadyCountdownChannelsTest(ChannelsFunctionalTest):
|
||||
browsers.append(b)
|
||||
|
||||
for b in browsers:
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-card"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-card").click()
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.CSS_SELECTOR, ".sig-ok-btn"), browser=b
|
||||
)
|
||||
b.find_element(By.CSS_SELECTOR, ".sig-ok-btn").click()
|
||||
self._ok_card_in_browser(b)
|
||||
self.wait_for(
|
||||
lambda: b.find_element(By.ID, "id_take_sig_btn"), browser=b
|
||||
)
|
||||
b.find_element(By.ID, "id_take_sig_btn").click()
|
||||
|
||||
# Wait for levity confirm → hex revealed, waiting message visible
|
||||
# (countdown is 12 s, so wait_for's 10 s MAX_WAIT is not enough)
|
||||
for b in browsers:
|
||||
self.wait_for(
|
||||
self.wait_for_slow(
|
||||
lambda: "settling" in b.find_element(
|
||||
By.ID, "id_hex_waiting_msg"
|
||||
).text.lower(),
|
||||
|
||||
Reference in New Issue
Block a user