Repository navigation
shapeOf: keep fixed ids that contain a useId fragment (#107) - #117
Conversation
|
@greptileai review |
|
Stack: merge 116 first. This branch includes its commits. |
|
@greptile review |
[Medium impact] Refines how element IDs are classified and URL navigation works. The PR appears safe to merge, with a non-blocking fix needed for explicit empty query and hash overrides. Findings
Fix with agent prompt### Issue 1
src/browser/steps.ts:180-181
`resolveUrl` restores the base query or hash even when the target explicitly clears it. With base `https://host/app?filter=active#old`, target `/login?` gets `filter=active` again, and `/login#` gets `old` again. Specs trying to clear a filter or anchor therefore keep the old value.
Check whether the target contains each delimiter rather than whether `resolved.search` or `resolved.hash` is nonempty. Add tests for explicit empty overrides.
```suggestion
if (!relative.split('#')[0].includes('?')) resolved.search = parsed.search;
if (!relative.includes('#')) resolved.hash = parsed.hash;
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
|
| if (!resolved.search) resolved.search = parsed.search; | ||
| if (!resolved.hash) resolved.hash = parsed.hash; |
There was a problem hiding this comment.
Empty URL overrides are ignored
resolveUrl restores the base query or hash even when the target explicitly clears it. With base https://host/app?filter=active#old, target /login? gets filter=active again, and /login# gets old again. Specs trying to clear a filter or anchor therefore keep the old value.
Check whether the target contains each delimiter rather than whether resolved.search or resolved.hash is nonempty. Add tests for explicit empty overrides.
| if (!resolved.search) resolved.search = parsed.search; | |
| if (!resolved.hash) resolved.hash = parsed.hash; | |
| if (!relative.split('#')[0].includes('?')) resolved.search = parsed.search; | |
| if (!relative.includes('#')) resolved.hash = parsed.hash; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/browser/steps.ts
Line: 180-181
Comment:
**Empty URL overrides are ignored**
`resolveUrl` restores the base query or hash even when the target explicitly clears it. With base `https://host/app?filter=active#old`, target `/login?` gets `filter=active` again, and `/login#` gets `old` again. Specs trying to clear a filter or anchor therefore keep the old value.
Check whether the target contains each delimiter rather than whether `resolved.search` or `resolved.hash` is nonempty. Add tests for explicit empty overrides.
```suggestion
if (!relative.split('#')[0].includes('?')) resolved.search = parsed.search;
if (!relative.includes('#')) resolved.hash = parsed.hash;
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in bbc0183: an empty query or hash in the target clears that part of the base url.
… and hash Co-authored-by: Gabe <gpavanello@thefork.com>
Co-authored-by: Gabe <gpavanello@thefork.com>
…hash Co-authored-by: Gabe <gpavanello@thefork.com>
New lock files are version 3. plain ignores a version 2 file, so those locators are never replayed. A version 1 file still replays locators. Co-authored-by: Gabe <gpavanello@thefork.com>
1cce966 to
e5550b7
Compare
|
@greptileai review |
Step 2/3 of quality/108-goto-query. Previous: quality/108-goto-query. Next: quality/109-long-context-note.
Part of #107
Intent
A fixed id that only contains a
useIdfragment stays in the shape hash. A no-judge replay of swapped buttons isinconclusive.%%{init: {'theme': 'neutral'}}%% flowchart TD id["aria-controls value"] --> token["whole useId token?"] token -->|yes| drop["drop the attribute from the hash"] token -->|no| keep["keep tab_r_1_panel in the hash"] keep --> swap["ids swap on reload"] swap --> miss["shapes differ"] miss --> stop["no-judge click is inconclusive"]Drift
The issue text says the whole attribute value. This branch uses token bounds, so
aria-labelledby=":r1: :r2:"still matches. That is the brief’s rule.Decisions
LOCK_VERSIONgoes from 2 to 3. New lock files are version 3. plain ignores a version 2 file. A version 1 file still replays locators. Door: one-way. Old version 2 locks re-record once.GENERATED_IDkeeps the old loose match, so the id strategy still skipstab_r_1_panel. Door: two-way.inconclusivein no-judge. Door: two-way.Evidence
Before: both buttons hash to
71ca4835…aaa683,equal true. Lock replay click statuspasswith(replayed).After: hashes differ,
equal false.menu:r1:listandmenu:r2:listdiffer too. The twomake it failtests pass.npm run verify: 580 pass, 0 fail.Locator benchmark on this branch: 144/144 locators, wrong hits 0, including
use-id-regenerated.mainwas not re-run.The reload assertion in
record-locator.test.tsnow uses the next real id (_r_6n_to_r_6o_,:r2:,«r4»,base-ui-_r_6o_,radix-:r3:,headlessui-menu-button-2).`${id}x`is no longer auseIdtoken.Review round 1
Before: a version 2 lock replayed the click as
passwith(replayed). Fail-first: 1 fail.After: that lock makes the click
inconclusive. The detail matchesno recorded locator. No step is marked(replayed). New files are version 3.npm run verify: 584 pass, 0 fail. Heade5550b7. The branch was rebased onto main after #115 merged, so verify ran on the commits before the rebase.Reading map
src/browser/record-locator.test.ts,src/browser/lock.test.ts.LOCK_VERSIONis 3.Stack
Step 2/3 of quality/108-goto-query. Previous: quality/108-goto-query. Next: quality/109-long-context-note.