| @pytest.mark.slow
|
| def test_in_flight_poll_does_not_overwrite_stepped_day():
|
| """PART 3 behavioural test: an in-flight poll tick between the click and load()'s response
|
| must NOT call load(curDay) — otherwise the AbortController aborts the in-flight stepped-day
|
| fetch and the page snaps back to today.
|
|
|
| The harness DELIBERATELY makes load() take 50ms so the race window between the click and
|
| load()'s response is wide open (>= 4 poll ticks). With the PART 3 fix
|
| (`!_twNavPinned` inside the setInterval callback's predicate), the in-flight poll skips
|
| because the click set `_twNavPinned=true` BEFORE the load() resolved.
|
|
|
| Asserts AFTER a 100ms wait — so a test that asserts immediately after the click would
|
| pass on a broken build while the operator still sees the page snap back. That trap has
|
| now caught this bug twice (night-watch's two rounds); the test deliberately waits so the
|
| race window fully closes before the assertion.
|
| """
|
| import shutil
|
| import subprocess
|
| import tempfile
|
|
|
| node_bin = shutil.which("node")
|
| if not node_bin:
|
| pytest.skip("node not available on this box")
|
| with tempfile.NamedTemporaryFile(mode="w", suffix=".js", delete=False) as fh:
|
| fh.write(_PART3_HARNESS_JS)
|
| path = fh.name
|
| try:
|
| proc = subprocess.run(
|
| [node_bin, path],
|
| capture_output=True, text=True, timeout=30,
|
| )
|
| finally:
|
| Path(path).unlink(missing_ok=True)
|
| > assert proc.returncode == 0, (
|
| f"PART 3 in-flight-poll harness exited {proc.returncode}\nSTDOUT:\n{proc.stdout}\nSTDERR:\n{proc.stderr}"
|
| )
|
| E AssertionError: PART 3 in-flight-poll harness exited 2
|
| E STDOUT:
|
| E After boot: curDay=2026-08-07 pollTimer=set
|
| E Pre-click: curDay=2026-08-07 calls=5
|
| E Click #tw-prev
|
| E After 100ms wait: curDay=2026-08-07 pollTimer=set _twNavPinned=true
|
| E All fetches:
|
| E 0: date=2026-08-07
|
| E 1: date=2026-08-07 (ABORTED)
|
| E 2: date=2026-08-07
|
| E 3: date=2026-08-07 (ABORTED)
|
| E 4: date=2026-08-07
|
| E 5: date=2026-08-07 (ABORTED)
|
| E 6: date=2026-08-06
|
| E 7: date=2026-08-06 (ABORTED)
|
| E 8: date=2026-08-07
|
| E 9: date=2026-08-07 (ABORTED)
|
| E 10: date=2026-08-07
|
| E 11: date=2026-08-07 (ABORTED)
|
| E 12: date=2026-08-07
|
| E 13: date=2026-08-07 (ABORTED)
|
| E 14: date=2026-08-07
|
| E 15: date=2026-08-07 (ABORTED)
|
| E 16: date=2026-08-07
|
| E 17: date=2026-08-07 (ABORTED)
|
| E 18: date=2026-08-07
|
| E 19: date=2026-08-07 (ABORTED)
|
| E 20: date=2026-08-07
|
| E 21: date=2026-08-07 (ABORTED)
|
| E 22: date=2026-08-07
|
| E 23: date=2026-08-07 (ABORTED)
|
| E 24: date=2026-08-07
|
| E 25: date=2026-08-07 (ABORTED)
|
| E 26: date=2026-08-07
|
| E FAIL: 10 trailing non-aborted fetch(es) for today after click — page would snap back
|
| E
|
| E STDERR:
|
| E
|
| E assert 2 == 0
|
| E + where 2 = CompletedProcess(args=['/opt/homebrew/bin/node', '/var/folders/yn/hd_3bcpj475dy17gy4l92tq00000gn/T/tmpgxqf7l2d.js'], returncode=2, stdout='After boot: curDay=2026-08-07 pollTimer=set\nPre-click: curDay=2026-08-07 calls=5\nClick #tw-prev\nAfter 100ms wait: curDay=2026-08-07 pollTimer=set _twNavPinned=true\nAll fetches:\n 0: date=2026-08-07\n 1: date=2026-08-07 (ABORTED)\n 2: date=2026-08-07\n 3: date=2026-08-07 (ABORTED)\n 4: date=2026-08-07\n 5: date=2026-08-07 (ABORTED)\n 6: date=2026-08-06\n 7: date=2026-08-06 (ABORTED)\n 8: date=2026-08-07\n 9: date=2026-08-07 (ABORTED)\n 10: date=2026-08-07\n 11: date=2026-08-07 (ABORTED)\n 12: date=2026-08-07\n 13: date=2026-08-07 (ABORTED)\n 14: date=2026-08-07\n 15: date=2026-08-07 (ABORTED)\n 16: date=2026-08-07\n 17: date=2026-08-07 (ABORTED)\n 18: date=2026-08-07\n 19: date=2026-08-07 (ABORTED)\n 20: date=2026-08-07\n 21: date=2026-08-07 (ABORTED)\n 22: date=2026-08-07\n 23: date=2026-08-07 (ABORTED)\n 24: date=2026-08-07\n 25: date=2026-08-07 (ABORTED)\n 26: date=2026-08-07\nFAIL: 10 trailing non-aborted fetch(es) for today after click — page would snap back\n', stderr='').returncode
|
|
|
| tests/test_tide_wave_prev_button.py:761: AssertionError
|