phase: 128_sync_label_mobile
Everything verified and 100% green. The earlier rejection was a report-format issue, not a test failure — all work is in the working tree. Final report: **Phase 128 final pass — verified (all 3 tasks complete; no code defects found)** - Verified: `#sync-label` parts markup, `setSyncLabel` writer, part builders (A4 untruncated title/aria-live), flex-row CSS + mobile media query — all match design 1:1. - `uv run pytest --cov=app --cov-report=term`: 3024 passed; TOTAL coverage **99%** (>90% gate). - `uv run pytest tests/e2e/test_sync_label_mobile.py -v --no-cov`: 4 passed (119s, isolated). - `uv run ruff check .`: clean; `uv run pyright`: 0 errors. - Criteria: (1) mobile 390×844 label in-viewport, count visible in import+summaries — ✅ E2E; (2) desktop strings/cap/title unchanged — ✅ E2E+unit; (3) E2E isolated green — ✅; (4) full suite green — ✅. - Docs: README.md fixed 5 pre-existing gaps (PDF phase-126 section + `pdf` token, hidden-folders toggle ph.105, document dates ph.106, private git-source masked tokens ph.121, doc-draft Discard ph.115); AGENTS.md verified consistent — no changes. - Notable: double-`-q` (addopts `-q` + CLI `-q`) suppresses pytest's summary line — standard `-qq` behavior, not a bug; exit codes confirm green. - Next pending phase: `129_sync_chunk_progress`.
This commit is contained in:
@@ -71,12 +71,13 @@ Test → observable mapping (Playwright Mapping Rule):
|
||||
summaries_total == 3`` (the keep-final-counts convention).
|
||||
2. ``test_sync_button_names_the_summary_phase`` (UI — the slow leg):
|
||||
a fresh admin page on ``/sources.html`` clicks **Sync sources**;
|
||||
the page's OWN 2 s poll renders ``#sync-label`` matching
|
||||
``Summarizing folders… [folder] (n/3)`` (the asserted text is the
|
||||
RENDERED DOM label, with the button ``title`` riding the same
|
||||
untruncated value — A4); on settle the button reads the terminal
|
||||
``Synced HH:MM`` (the phase-32 contract) and ``#sync-result``
|
||||
carries the counts line.
|
||||
the page's OWN 2 s poll renders ``#sync-label`` as the D2 PARTS
|
||||
(phase 128: the main part ``Summarizing folders… [folder]`` + the
|
||||
pinned count part ``(n/3)`` — the asserted text is the RENDERED
|
||||
DOM parts, with the button ``title`` riding the full untruncated
|
||||
string, main + " " + count — A4); on settle the button reads the
|
||||
terminal ``Synced HH:MM`` (the phase-32 contract) and
|
||||
``#sync-result`` carries the counts line.
|
||||
3. ``test_missing_folder_summaries_read_as_pending_and_self_heal``
|
||||
(tree — the fast mock leg): after a successful sync (every
|
||||
candidate stores its canned line) NO marker is anywhere; DELETE
|
||||
@@ -727,13 +728,15 @@ def test_sync_button_names_the_summary_phase(
|
||||
) -> None:
|
||||
"""A fresh admin page on ``/sources.html`` clicks **Sync sources**;
|
||||
the page's OWN 2 s poll renders ``#sync-label`` as
|
||||
``Summarizing folders… [source/folder] (n/3)`` (asserted on the
|
||||
RENDERED text — the label is built by the page JS — with the
|
||||
button ``title`` carrying the same untruncated value, A4); on
|
||||
settle the button shows the terminal ``Synced HH:MM`` (the
|
||||
phase-32 contract) and ``#sync-result`` carries the counts line.
|
||||
The prelude/import labels stay the phase-64 shape (the endpoint
|
||||
test pins those phases; the UI pins the new summaries label)."""
|
||||
``Summarizing folders… [source/folder]`` + the pinned ``(n/3)``
|
||||
count span (phase 128: the label is PARTS — the folder part is
|
||||
optional — the phase's first poll may precede the first hook — and
|
||||
the button ``title`` carries the full untruncated string, main +
|
||||
" " + count, A4); on settle the button shows the terminal
|
||||
``Synced HH:MM`` (the phase-32 contract) and ``#sync-result``
|
||||
carries the counts line. The prelude/import labels stay the
|
||||
phase-64 shape (the endpoint test pins those phases; the UI pins
|
||||
the new summaries label)."""
|
||||
page.set_default_timeout(30_000)
|
||||
_register_source(app_url, str(syncsum_dir))
|
||||
login(page, app_url) # lands on /sources.html (the button's home)
|
||||
@@ -764,22 +767,30 @@ def test_sync_button_names_the_summary_phase(
|
||||
expect(page.locator("#sync-error-banner")).to_be_hidden()
|
||||
|
||||
# UI layer (D2): the page's own 2 s poll names the summaries phase
|
||||
# — the RENDERED label matches the D2 shape (the folder part is
|
||||
# optional — the phase's first poll may precede the first hook)
|
||||
# with the (n/3) counts, and the button ``title`` carries the same
|
||||
# untruncated value (A4). ``wait_for_function`` checks BOTH in ONE
|
||||
# in-browser evaluation: a poll tick updates label + title together
|
||||
# in a single JS task, so the atomic check can never straddle one
|
||||
# (the JS regex is the D2 shape, unit-pinned in
|
||||
# tests/unit/test_frontend_sync_upload.py).
|
||||
# — the RENDERED label matches the D2 PARTS shape (phase 128:
|
||||
# the MAIN part carries "Summarizing folders… [folder]" — the
|
||||
# folder part is optional, the phase's first poll may precede the
|
||||
# first hook — and the pinned COUNT part carries the (n/3)
|
||||
# counts), and the button ``title`` carries the full untruncated
|
||||
# string (main + " " + count, A4). ``wait_for_function`` checks
|
||||
# BOTH in ONE in-browser evaluation: a poll tick updates the parts
|
||||
# + the title together in a single JS task, so the atomic check
|
||||
# can never straddle one (the JS regexes are the D2 shapes,
|
||||
# unit-pinned in tests/unit/test_frontend_sync_upload.py).
|
||||
page.wait_for_function(
|
||||
"""() => {
|
||||
const label = document.querySelector('#sync-label');
|
||||
const btn = document.querySelector('#sync-btn');
|
||||
if (!label || !btn) return false;
|
||||
const text = label.textContent;
|
||||
const re = /^Summarizing folders…(?: \\S+)? \\(\\d+\\/3\\)$/;
|
||||
return re.test(text) && btn.getAttribute('title') === text;
|
||||
const main = label.querySelector('.sync-label-main');
|
||||
const count = label.querySelector('.sync-label-count');
|
||||
if (!main || !count || count.hidden) return false;
|
||||
const reMain = /^Summarizing folders…(?: \\S+)?$/;
|
||||
const reCount = /^\\(\\d+\\/3\\)$/;
|
||||
return reMain.test(main.textContent)
|
||||
&& reCount.test(count.textContent)
|
||||
&& btn.getAttribute('title')
|
||||
=== main.textContent + ' ' + count.textContent;
|
||||
}""",
|
||||
timeout=SETTLE_TIMEOUT_MS,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user