fix(ci): preserve portable fixtures and complete confirmation tab coverage

This commit is contained in:
cesnimda
2026-10-20 20:05:01 +02:00
parent 6db62095c6
commit bba52af4b8
4 changed files with 21 additions and 3 deletions
@@ -0,0 +1,9 @@
# Browser fixture portability and confirmation focus contracts
Run832 at main `d1fcd2308755dfc112a2bd6a736dd763bbc895f9` completed its331-case browser suite:314 passed,16 failed, one flaky Rules draft case. Deployment was skipped. The Playwright runtime-corruption signature did not recur in this completed run. These outcomes do not establish production readiness or resolve the existing intermittent Rules observation.
Eleven failures came from `seed-operation.py` calling Python3.12's `Path.is_junction` on the Debian runner's Python3.11.2 PosixPath. This was independently reproduced by running the unchanged helper in an isolated, network-disabled `node:20-bookworm` container on the runner host; host Python3.12.3 passed. Junction checks now execute only on Windows, where the existing Python3.12 guard is preserved. Absolute/direct-temp-root, symlink, hardlink, exact owner/schema and insert-only SQL protections remain unchanged. All29 self-checks pass both on local Windows and in that same Python3.11 container after the correction. No existing application data or production container is mounted into the test container.
Five failures were stale keyboard expectations after the verified shared confirmation scroll-body accessibility correction. The focusable named body now belongs in the native tab cycle. The tests explicitly verify Cancel → reverse Tab to named body → reverse Tab to Confirm → forward Tab to body → forward Tab to Cancel, followed by the original cancellation/focus/draft/action proofs. No focus assertion, axe rule, timeout or application behavior is relaxed. All five affected native cases pass with zero skips/flaky/retries,20October18:03:21–18:04:21UTC.
The bounded repair changes only the offline fixture and those two browser test consumers. Full release CI and deployed identity still require a new successful run. Production readiness remains NO-GO independently of the owner's authorization to publish main. The Qwen3.5 adapter preparation is separately tested; model activation and P5-13 qualification remain separate.
+3 -3
View File
@@ -69,11 +69,11 @@ def seed_operation(payload: object) -> str:
except OSError as error:
raise SeedDenied("The isolated dataRoot must already exist") from error
if (root != requested or root.parent != temporary or not root.is_dir()
or requested.is_symlink() or requested.is_junction()
or requested.is_symlink() or (sys.platform == "win32" and requested.is_junction())
or not re.fullmatch(r"jobtracker-e2e-[A-Za-z0-9][A-Za-z0-9_-]*", root.name)):
raise SeedDenied("Only an unlinked jobtracker-e2e-* direct child of system temp is allowed")
database = root / "jobtracker.db"
if (not database.is_file() or database.is_symlink() or database.is_junction()
if (not database.is_file() or database.is_symlink() or (sys.platform == "win32" and database.is_junction())
or database.resolve(strict=True) != database or database.stat().st_nlink != 1):
raise SeedDenied("The unlinked existing direct jobtracker.db file is required")
# EF's SQLite Guid converter writes uppercase canonical text.
@@ -110,7 +110,7 @@ def temporary_fixture():
yield root
finally:
assert root.parent == Path(tempfile.gettempdir()).resolve()
assert root.name.startswith("jobtracker-e2e-operation-selftest-") and not root.is_symlink() and not root.is_junction()
assert root.name.startswith("jobtracker-e2e-operation-selftest-") and not root.is_symlink() and not (sys.platform == "win32" and root.is_junction())
def self_test() -> dict:
@@ -171,8 +171,13 @@ for (const [mode, language, width] of [["light", "en", 1440], ["dark", "nb", 144
await expect(cancel).toBeFocused();
await expect(confirm).toHaveAccessibleDescription(t.attachmentsDeleteConfirm.replace("{name}", "Reviewed æøå.txt"));
await cancel.press("Shift+Tab");
const messageRegion = confirm.getByRole("region", { name: t.attachmentsDeleteTitle, exact: true });
await expect(messageRegion).toBeFocused();
await messageRegion.press("Shift+Tab");
await expect(confirm.getByRole("button", { name: t.attachmentsDelete, exact: true })).toBeFocused();
await page.keyboard.press("Tab");
await expect(messageRegion).toBeFocused();
await page.keyboard.press("Tab");
await expect(cancel).toBeFocused();
await scan(page, info, "confirm", true);
await capture(page, info, `confirm-${suffix}`);
@@ -366,7 +366,11 @@ test('[P7-05 Discovery] keyboard native create and alert updates persist; delete
const cancel = dialog.getByRole('button', { name: t.cancel, exact: true });
await expect(cancel).toBeFocused();
await page.keyboard.press('Shift+Tab');
const messageRegion = dialog.getByRole('region', { name: await dialog.getByRole('heading').innerText(), exact: true });
await expect(messageRegion).toBeFocused();
await messageRegion.press('Shift+Tab');
await expect(dialog.getByRole('button', { name: t.adminUsersDelete, exact: true })).toBeFocused();
await page.keyboard.press('Tab'); await expect(messageRegion).toBeFocused();
await page.keyboard.press('Tab'); await expect(cancel).toBeFocused();
await page.keyboard.press('Enter');
await expect(dialog).toHaveCount(0); await expect(deleteButton).toBeFocused();