From d56fd38ab2fbcd370079ed7280629adf244cee80 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Fri, 6 Mar 2026 23:32:28 -0500 Subject: [PATCH] fix(codechef): replace blind sleeps and fix practice fallback detection Problem: Submit used fixed `wait_for_timeout` delays throughout, and the practice fallback check only matched one dialog variant, causing "contest not available for submission" to be silently swallowed as success. Solution: Replace the initial 2s page-load sleep with `wait_for_selector('[aria-haspopup="listbox"]')`, drop unnecessary sleeps around the Ace editor click and submit button, and wait for the result dialog with `wait_for_selector` instead of a fixed 3s sleep. Extend the fallback check to also match "not available for submission". --- scrapers/codechef.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/scrapers/codechef.py b/scrapers/codechef.py index 7767b72..0427d5d 100644 --- a/scrapers/codechef.py +++ b/scrapers/codechef.py @@ -178,16 +178,15 @@ def _submit_headless_codechef( needs_relogin = True return try: - page.wait_for_timeout(2000) + page.wait_for_selector('[aria-haspopup="listbox"]', timeout=10000) page.locator('[aria-haspopup="listbox"]').click() page.wait_for_selector('[role="option"]', timeout=5000) page.locator(f'[role="option"][data-value="{language_id}"]').click() - page.wait_for_timeout(2000) + page.wait_for_timeout(250) page.locator(".ace_editor").click() page.keyboard.press("Control+a") - page.wait_for_timeout(200) page.evaluate( """(code) => { const textarea = document.querySelector('.ace_text-input'); @@ -199,20 +198,25 @@ def _submit_headless_codechef( }""", source_code, ) - page.wait_for_timeout(1000) + page.wait_for_timeout(125) page.evaluate( "() => document.getElementById('submit_btn').scrollIntoView({block:'center'})" ) - page.wait_for_timeout(200) page.locator("#submit_btn").dispatch_event("click") - page.wait_for_timeout(3000) + try: + page.wait_for_selector('[role="dialog"], .swal2-popup', timeout=5000) + except Exception: + pass dialog_text = page.evaluate("""() => { const d = document.querySelector('[role="dialog"], .swal2-popup'); return d ? d.textContent.trim() : null; }""") - if dialog_text and "not available for accepting solutions" in dialog_text: + if dialog_text and ( + "not available for accepting solutions" in dialog_text + or "not available for submission" in dialog_text + ): submit_error = "PRACTICE_FALLBACK" elif dialog_text: submit_error = dialog_text