Files
python-tdd/src/functional_tests/test_jasmine.py
Disco DeDisco ad0041db74
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed
FT flake mitigations triggered by pipelines #302/#303 — three independent fixes consolidated in one commit; test_admin_tarot._login_to_admin now waits on "Site administration" body substring before returning, same shape as 054b0aa's test_admin.py fix — the helper used to click submit + return immediately, letting the three TarotAdminTest tests race their subsequent browser.get(/admin/epic/tarotcard/) against the in-flight POST → 302 → admin home navigation so on a slow CI runner the new GET cancelled the unfinished POST, the session cookie was never set, the browser landed back on /admin/login/?next=…, and the downstream assertion saw the login-page body ('Earthman Deck' not found in 'Django administration\nEmail:\nPassword:' in #303, plus a NoSuchElementException for "The Schiz" on test_admin_earthman_card_detail's link-text click) — wait_for w. assertIn retries til the post-login page actually renders so the rest of the helper's callers start from a settled state ; test_jasmine swaps wait_for(check_results)wait_for_slow(check_results, timeout=60) — the spec suite has grown well past the 10s MAX_WAIT the default wait_for decorator affords + under CI contention (parallel Selenium workers competing for CPU on the same droplet) Jasmine's .jasmine-overall-result was still reporting "Running..." at 10s when the assertion fired w. (no detail) failure list (#303); check_results body is unchanged — "Running..." doesn't match the 0 failures regex so it falls into the failure branch + raises AssertionError, which wait_for_slow naturally retries til the result settles or 60s elapses ; base._make_browser wraps webdriver.Firefox(options=options) in try/except WebDriverException w. one sleep+retry when "geckodriver" appears in the error message — covers the spawn race under --parallel where multiple workers hit the same binary mid-permission-set + one of them gets 'geckodriver' executable may have wrong permissions (1 test in #302 + 1 test in #303, different test classes each time, confirming infra not test-logic); narrow filter on "geckodriver" so a genuine install fault still fails fast — both attempts would surface the same error in <1s ; deferred option filed to memory (project_ci_remove_pip_install_deferred.md) — dropping the pip install -r requirements.dev.txt line from each FT step would save ~5 min/pipeline (CI image drifted from requirements.dev.txt since a21e6aa so the install actually downloads 30+ packages every step instead of the intended "already satisfied" no-op verify) but loses the dep-drift safety net; declined for now, revisit when wall-clock pain > safety value — TDD
Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 12:53:49 -04:00

31 lines
1.5 KiB
Python

import re
from selenium.webdriver.common.by import By
from .base import FunctionalTest
class JasmineTest(FunctionalTest):
def test_jasmine_specs_pass(self):
self.browser.get(self.live_server_url + "/static/tests/SpecRunner.html")
def check_results():
result = self.browser.find_element(By.CSS_SELECTOR, ".jasmine-overall-result")
# Word-boundary anchor — Jasmine 6 reports as "N specs, X failures".
# Plain `"0 failures" in text` matches "10 failures", "20 failures",
# etc., letting up to 99 failed specs slip past as green.
if not re.search(r"(?<!\d)0 failures\b", result.text):
failures = self.browser.find_elements(
By.CSS_SELECTOR, ".jasmine-failed .jasmine-description"
)
detail = "\n".join(f.text for f in failures) if failures else "(no detail)"
self.fail(f"{result.text}\nFailing specs:\n{detail}")
# wait_for_slow w. 60s ceiling — the spec suite has grown well past the
# 10s MAX_WAIT the default wait_for affords. Under CI contention
# (parallel Selenium workers competing for CPU) Jasmine's still
# reporting "Running..." at 10s; pipeline #303 caught this. The
# check_results body keeps raising AssertionError ("Running..." doesn't
# match the 0-failures regex) so wait_for_slow naturally retries til
# the result settles or the timeout fires.
self.wait_for_slow(check_results, timeout=60)