Three staging-gate failures. Two of them are one real bug, and it is not about autosuggest.
The dropdown reopened on top of the results
After a search, the results-page bar still holds the term in its input. On every render the query was >= 2 characters, so the suggestion list opened again — on top of the very results the search had just produced.
Playwright reported it while trying to click the first result:
Both school detail page renders name and performance data and school hero map opens fullscreen on mobile failed on it. Neither test is about autosuggest — they just try to click a search result, which a reader could no longer do either.
Suggestions now answer typing, not the mere presence of a value. hasTyped gates the hook, is set on change, and is cleared when a search is submitted or a suggestion is chosen. A pre-filled input makes no request and shows no list.
The third failure was my test, not the product
An unphased place page renders one table per phase, and an all-through school legitimately appears in both. So the page's school links were never one alphabetical run:
The assertion collected them all together and only ever passed because no town it picked happened to hold an all-through school. When the data gave Abbots Langley one, it failed on correct behaviour. It now checks each table separately — and passes against the exact data that broke it.
Guards
jest: a pre-filled input neither fetches nor opens a listbox. Verified by reverting the gate — it is the only test that fails.
E2E: submit a search, then require the first result to be clickable. That is the reader-facing version of the same bug.
I could not run the E2E guard against a live unfixed build: the school_autosuggest flag was on during the failing CI run and is off on staging now. The CI log is the demonstration instead.
Worth knowing separately
That flag flapping means the E2E gate is currently non-deterministic — twelve journeys skipped in that run because flags evaluated false, and which ones skip depends on whether Unleash happens to be reachable when the gate runs. A green gate with a dozen skips is not the same as a green gate. Fixing the Unleash connection resolves it; until then the gate is weaker than it looks.
Three staging-gate failures. Two of them are one real bug, and it is not about autosuggest.
## The dropdown reopened on top of the results
After a search, the results-page bar still holds the term in its input. On every render the query was >= 2 characters, so the suggestion list opened again — on top of the very results the search had just produced.
Playwright reported it while trying to click the first result:
```
<li role="option" id="school-suggest-bar-option-4"> ... intercepts pointer events
```
Both `school detail page renders name and performance data` and `school hero map opens fullscreen on mobile` failed on it. **Neither test is about autosuggest** — they just try to click a search result, which a reader could no longer do either.
Suggestions now answer *typing*, not the mere presence of a value. `hasTyped` gates the hook, is set on change, and is cleared when a search is submitted or a suggestion is chosen. A pre-filled input makes no request and shows no list.
## The third failure was my test, not the product
An unphased place page renders **one table per phase**, and an all-through school legitimately appears in both. So the page's school links were never one alphabetical run:
```
table 1 (primary): Abbots Langley, Bedmond, Breakspeare, Divine Saviour, Tanners Wood
table 2 (secondary): Breakspeare School
```
The assertion collected them all together and only ever passed because no town it picked happened to hold an all-through school. When the data gave Abbots Langley one, it failed on correct behaviour. It now checks each table separately — and **passes against the exact data that broke it**.
## Guards
- **jest:** a pre-filled input neither fetches nor opens a listbox. Verified by reverting the gate — it is the only test that fails.
- **E2E:** submit a search, then require the first result to be clickable. That is the reader-facing version of the same bug.
I could not run the E2E guard against a live unfixed build: the `school_autosuggest` flag was **on** during the failing CI run and is **off** on staging now. The CI log is the demonstration instead.
## Worth knowing separately
That flag flapping means **the E2E gate is currently non-deterministic** — twelve journeys skipped in that run because flags evaluated false, and which ones skip depends on whether Unleash happens to be reachable when the gate runs. A green gate with a dozen skips is not the same as a green gate. Fixing the Unleash connection resolves it; until then the gate is weaker than it looks.
Verification: backend 158, frontend 289, `tsc` clean, `next build` green, 100 E2E collected.
Three staging-gate failures, two of them one real bug.
After a search, the results-page bar still holds the term in its input,
so on every render the query was >= 2 characters and the suggestion list
opened again — on top of the very results the search had just produced.
Playwright reported it as "<li role=option ...> intercepts pointer
events" while trying to click the first result; a reader would simply
have found their first result unclickable. Both the school-detail and
hero-map journeys failed on it, and neither is about autosuggest.
Suggestions now answer typing, not the mere presence of a value:
`hasTyped` gates the hook, is set on change, and is cleared when a
search is submitted or a suggestion is chosen. A pre-filled input makes
no request and shows no list.
Third failure was my test, not the product. An unphased place page
renders one table per phase, and an all-through school legitimately
appears in both — so the page's school links were never one alphabetical
run. The assertion collected them all together and only passed because
no town it picked had held an all-through school. When the data gave
Abbots Langley one, Breakspeare School appeared in the primary table and
again in the secondary, and the test failed on correct behaviour. It now
checks each table separately, and passes against the data that broke it.
Guards: a jest test that a pre-filled input neither fetches nor opens
(verified by reverting — it is the only one that fails), and an E2E
journey that submits a search and then requires the first result to be
clickable, which is the reader-facing version of the same thing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
This PR fixes a real bug where the FilterBar's autosuggest dropdown could reopen over search results (since the results-page input arrives pre-filled, making the old length-based suggestEnabled check true on every render). The fix gates suggestions behind a hasTyped flag set only on genuine input events and cleared on submit/selection, and is backed by solid new unit and e2e coverage; the accompanying fix to the flaky alphabetical-order e2e test (checking per-table instead of per-page, to account for all-through schools appearing in two phase tables) is also correct and well-reasoned.
🟡 Minor
e2e/tests/journeys.spec.ts: The new per-table ordering check uses the generic page.locator('table'), which will match any table on the place page, not just phase/school tables. If the page ever gains an unrelated table (e.g. a stats or comparison widget) containing a[href^="/school/"]-style links or just noise, this could produce spurious failures or silently skip real school tables; scoping to a more specific selector (e.g. a school-table class/data-testid) would be more robust.
## 🤖 AI Code Review (Claude Code)
This PR fixes a real bug where the FilterBar's autosuggest dropdown could reopen over search results (since the results-page input arrives pre-filled, making the old length-based `suggestEnabled` check true on every render). The fix gates suggestions behind a `hasTyped` flag set only on genuine input events and cleared on submit/selection, and is backed by solid new unit and e2e coverage; the accompanying fix to the flaky alphabetical-order e2e test (checking per-table instead of per-page, to account for all-through schools appearing in two phase tables) is also correct and well-reasoned.
### 🟡 Minor
- **e2e/tests/journeys.spec.ts**: The new per-table ordering check uses the generic `page.locator('table')`, which will match any table on the place page, not just phase/school tables. If the page ever gains an unrelated table (e.g. a stats or comparison widget) containing `a[href^="/school/"]`-style links or just noise, this could produce spurious failures or silently skip real school tables; scoping to a more specific selector (e.g. a school-table class/data-testid) would be more robust.
tudor
merged commit a3c09d9b67 into main2026-08-26 21:07:55 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Three staging-gate failures. Two of them are one real bug, and it is not about autosuggest.
The dropdown reopened on top of the results
After a search, the results-page bar still holds the term in its input. On every render the query was >= 2 characters, so the suggestion list opened again — on top of the very results the search had just produced.
Playwright reported it while trying to click the first result:
Both
school detail page renders name and performance dataandschool hero map opens fullscreen on mobilefailed on it. Neither test is about autosuggest — they just try to click a search result, which a reader could no longer do either.Suggestions now answer typing, not the mere presence of a value.
hasTypedgates the hook, is set on change, and is cleared when a search is submitted or a suggestion is chosen. A pre-filled input makes no request and shows no list.The third failure was my test, not the product
An unphased place page renders one table per phase, and an all-through school legitimately appears in both. So the page's school links were never one alphabetical run:
The assertion collected them all together and only ever passed because no town it picked happened to hold an all-through school. When the data gave Abbots Langley one, it failed on correct behaviour. It now checks each table separately — and passes against the exact data that broke it.
Guards
I could not run the E2E guard against a live unfixed build: the
school_autosuggestflag was on during the failing CI run and is off on staging now. The CI log is the demonstration instead.Worth knowing separately
That flag flapping means the E2E gate is currently non-deterministic — twelve journeys skipped in that run because flags evaluated false, and which ones skip depends on whether Unleash happens to be reachable when the gate runs. A green gate with a dozen skips is not the same as a green gate. Fixing the Unleash connection resolves it; until then the gate is weaker than it looks.
Verification: backend 158, frontend 289,
tscclean,next buildgreen, 100 E2E collected.🤖 AI Code Review (Claude Code)
This PR fixes a real bug where the FilterBar's autosuggest dropdown could reopen over search results (since the results-page input arrives pre-filled, making the old length-based
suggestEnabledcheck true on every render). The fix gates suggestions behind ahasTypedflag set only on genuine input events and cleared on submit/selection, and is backed by solid new unit and e2e coverage; the accompanying fix to the flaky alphabetical-order e2e test (checking per-table instead of per-page, to account for all-through schools appearing in two phase tables) is also correct and well-reasoned.🟡 Minor
page.locator('table'), which will match any table on the place page, not just phase/school tables. If the page ever gains an unrelated table (e.g. a stats or comparison widget) containinga[href^="/school/"]-style links or just noise, this could produce spurious failures or silently skip real school tables; scoping to a more specific selector (e.g. a school-table class/data-testid) would be more robust.