test(e2e): restore a green e2e suite on main — fixture rot + assertions updated for merged UI changes - #487
Conversation
…arch-project#442 merge PR opensearch-project#454 (b964e48) redesigned MatcherResultsPanel's llm-judge rows: no fabricated "score 0%" headline, dimension chips in the header, a "Why it failed" / "How to fix it" pair, a per-fact checklist, and the verbatim reasoning rendered exactly once. PR opensearch-project#442 (1f0951d) merged a day later and its conflict resolution for components/MatcherResultsPanel.tsx took the pre-opensearch-project#454 file wholesale (plus opensearch-project#442's own `notReached` rows), silently reverting the redesign on main — the panel dropped to the old description/error/reasoning dump (error and reasoning duplicated again, "score 0%" back), opensearch-project#454's unit suite was replaced by opensearch-project#442's five not-reached tests, and lib/matchers/judgeReasoningParse.ts was left orphaned with no importer. tests/e2e/judge-tab-whyfix.spec.ts has been red on main since. This restores the opensearch-project#454 panel verbatim and layers opensearch-project#442's not-reached behaviour on top: `notReached` entries are excluded from the passed/failed counts and get their own "N not reached" tally, render with the muted MinusCircle + "not reached" label, and always go through the plain MatcherRow (never the judge WHY/FIX row, even when method is llm-judge). Tests: the opensearch-project#454 unit suite is restored and opensearch-project#442's five not-reached cases are appended (plus one asserting an llm-judge not-reached marker takes the plain row). tests/e2e/judge-tab-whyfix.spec.ts is unchanged and passes again. Signed-off-by: goyamegh <goyamegh@amazon.com>
…ensearch-project#460 PR opensearch-project#460 (7773915) replaced the run-name <h2> in RunInspectorPage and the plain <span> in the EvalRunsPage row with InlineRenameField for standalone evaluation-run docs (legacy benchmark-embedded runs, which have no rename endpoint, still get the <h2>). Two specs asserted the old markup and have been red on main since: - benchmark-run-row-link.spec.ts: `h2:has-text(RUN_NAME)` -> the `run-inspector-rename-text` testid. The run under test IS a standalone doc (deliberately unresolvable agentKey so it fails before linkCompletedRunToBenchmark appends it to benchmark.runs[]), so the rename field is the correct "the inspector rendered THIS run" signal. The not-found and URL assertions are untouched; the fixture agent is intentionally nonexistent and stays that way. - evalruns-no-left-status-icon.spec.ts: `svg` count 0 in the name cell -> `svg:not(.lucide-pencil)` count 0. The cell now legitimately hosts the rename pencil; the guard against the redundant CheckCircle2/XCircle/Clock status icon (opensearch-project#430) is preserved because any other svg still fails the assertion. Signed-off-by: goyamegh <goyamegh@amazon.com>
…search-project#447 PR opensearch-project#447 (4f3ce80) replaced the benchmark page's split test-case panel with a fixed two-tab layout (Cases | Runs); the "No test cases in this version" / "N test case(s)" copy the spec looked for no longer exists anywhere in the app, so the rendered-panel test has been red on main since. The API-sanity test (both testCaseIds levels populated) was already passing and is unchanged. The UI test now lands on the benchmark's default route, asserts the Cases tab badge shows the 1 linked case, and asserts exactly one `role=option` row exists in the "Benchmark cases" listbox carrying the linked case's name — the same regression signal (a dropped version-level link renders an empty case list) against the current surface. Signed-off-by: goyamegh <goyamegh@amazon.com>
… tagline Two independent staleness bugs made 'should display dashboard or first-run experience' fail (and the e2e-gate red) on a fresh file-storage server like CI's: - PR opensearch-project#399 (46a32fa) added a third Overview state: `ready-to-run` (definitions exist, nothing has run) renders <ReadyToRun/> — neither `dashboard-title` nor `first-run-experience`. Under fullyParallel other suites seed test cases/benchmarks, so CI's server is almost always in this state when the dashboard spec runs. The branch detection also raced: the loading skeleton renders `dashboard-page` + `dashboard-title` too, so the spec could see the skeleton, decide "dashboard mode", and then watch the title vanish. The spec now waits for a SETTLED marker (stats bar | ready-to-run | first-run) before branching and asserts the ready-to-run copy in the third branch. - The dashboard-mode tagline assertion ("Surface failing runs and regressions to improve your agent fast") never matched: PR opensearch-project#259 (3ef6ad5) changed the product copy to "See where each agent is failing or regressing, and improve them fast" but updated the spec to a different string. Corrected to the shipped copy. Based on the earlier unmerged repair in fork branch goyamegh/gate-repair (d30f159), rebased onto current main. Signed-off-by: goyamegh <goyamegh@amazon.com>
… arbitrary data 'should navigate to test case runs page on card click' (flaky in CI, 1 failure per main run) clicked "the first [class*=card] containing 'runs'" on whatever data other parallel suites happened to leave in storage. The first match can be a non-navigable wrapper Card, or a sibling suite can delete the row between the click and the assertion (the CI snapshot shows another spec's `e2e-legacy-*` seed as the only row). The whole file was also vacuously green with zero data. Every test now seeds its own uniquely-named test case via the storage API, isolates it with the page's search box (`search-test-cases`), clicks exactly that row, and deletes the seed by id in afterEach. The two literal `expect(true)` tests (Latest badge, metrics) now assert the seeded empty state or the run-populated state. Based on the earlier unmerged repair in fork branch goyamegh/gate-repair (6656295), rebased onto current main. Signed-off-by: goyamegh <goyamegh@amazon.com>
…e hovering 'the collapsed Evaluations icon and the expanded Evaluations link share the nav-evals3 testid' was flaky in CI: after clicking "Collapse sidebar" it hovered the zone immediately, while the zone was still animating 180px -> 64px (200ms). Playwright's hover() targets the element's CURRENT center, which for a mid-transition zone lands outside the settled 64px rail; once the zone finishes shrinking under the stationary cursor Chromium synthesizes mouseleave, and the flyout collapses again 250ms later — exactly the 178px -> 80px -> 64px sequence in the CI call log. Wait for the settled rail width first (as the first test in this file already does), then hover well inside the rail. Product behaviour is unchanged. Signed-off-by: goyamegh <goyamegh@amazon.com>
GET /api/skills/discover returns user-scope skills (~/.claude/skills) with a ~/ display path, but resolveSkillPath() resolved every non-absolute path against cwd — so selecting any user-scope skill in the Skills page failed validation with 'Directory does not exist: <cwd>/~/.claude/skills/<name>' and left Run Evaluation disabled. tests/e2e/skills.spec.ts picks the FIRST discovered skill, so on any machine with user-scope skills the two validation tests fail hard (3/3 retries) — CI's runner has none, which is the only reason the suite looked green there. resolveSkillPath() now expands `~` and `~/` to the home directory; a ~-prefixed relative dir name (e.g. ~backup/) is deliberately not expanded. Covered by two new route-level unit tests (mocked homedir) and an integration regression test that seeds a uniquely-named skill in the real home dir, validates it via the ~/ path, and removes exactly that directory (red against the unfixed server, verified). Originally drafted on fork branch goyamegh/gate-repair (47966ac); re-applied on top of opensearch-project#463's 501 folder-picker hardening. Signed-off-by: goyamegh <goyamegh@amazon.com>
…collision with the status badge)
'should show stats (passed, failed, total)' (evaluation-runs.spec.ts) and
'should show pass/fail/total statistics' (evaluation-runner.spec.ts) open
the NEWEST evaluation run and assert `text=Passed` / `text=Failed` /
`text=Total`. Playwright's `text=` selector is case-insensitive and
substring-matching, so whenever the newest run happens to be a FAILED run
(e.g. benchmark-run-row-link.spec.ts's deliberately-unresolvable-agent
run landing first under fullyParallel) `text=Failed` resolves to BOTH the
stats label and the lowercase `failed` status badge in the header and
strict mode fails the assertion 3/3 retries. Order-dependent, so it
passes or fails depending on which suite ran last — exactly the kind of
flake that makes the gate untrustworthy.
Use `getByText(..., { exact: true })`, which only matches the stats
labels. Assertions are otherwise unchanged (same three labels, same
timeout).
Signed-off-by: goyamegh <goyamegh@amazon.com>
…one mid-animation frame 'panel anchors directly beneath the trigger and click-outside closes it' flaked (12.35px > 12px cap) under the full parallel suite: PopoverContent animates in (zoom-in-95 about the panel center, components/ui/popover.tsx), and a single boundingBox() sample right after toBeVisible() can land mid-transition while the top edge is still offset. Poll the gap until it settles under the cap, then assert the sign. Same geometry contract (0 <= gap <= 12), no product change. Signed-off-by: goyamegh <goyamegh@amazon.com>
…ons, two product fixes Signed-off-by: goyamegh <goyamegh@amazon.com>
…ew (no vacuous branches) Adversarial review of this branch flagged two spec changes as weaker than the bugs they claim to guard: - benchmark-version-link-panel.spec.ts: the new Cases-tab assertion reads BenchmarkRunsPage2's `benchmarkTestCases`, which is derived from the TOP-LEVEL `benchmark.testCaseIds` — so it cannot see the original bug (top-level populated, `versions[current].testCaseIds` empty). Added a second UI test against the version-aware page that still exists and is still reachable (components/BenchmarkRunsPage.tsx at /benchmarks/:id/runs, the Overview's "Run a benchmark" CTA target): it reads the CURRENT VERSION's array via getVersionTestCases and renders the exact "No test cases in this version" / "1 test case" copy the original spec asserted. Both the Cases-tab test and the API-sanity test are kept. - test-case-runs.spec.ts "Run Cards": the seeded case had no runs, so every run-card test fell through to an "empty state renders" branch and the navigation test asserted `body` visible — coverage theater. Each run-card test now seeds two report docs (PASSED newest, FAILED older) for its own case and asserts the real contract with no fallbacks: both status labels render (exact text), exactly one "Latest" badge and it sits on the PASSED card, one "Score" per card with the seeded 90% / 20% means, and clicking the PASSED card lands on /runs/<reportId>. Reports are deleted by id. Also hardened openSeededTestCase(): the search box filters client-side over the loaded pages (100 newest), and a zero-match filter replaces the list — and its "Load More" button — with the no-results state, so a sibling suite bulk-seeding 90 cases between our seed and navigation (benchmark-cases- scroll) pushed the row off page 1 and the helper timed out. It now clears the filter, pages "Load More" (bounded) until the row is loaded, and re-applies the filter. Signed-off-by: goyamegh <goyamegh@amazon.com>
discover builds the user-scope display path as '~' + absDir.slice(home.length), so on Windows the separator after `~` is a backslash. resolveSkillPath() now treats `~`, `~/` and `~\` as home-relative (regex /^~(?:$|[\\/])/); a `~`-prefixed relative NAME (e.g. `~backup/skill`) is still left alone. Unit test added for the backslash form. Signed-off-by: goyamegh <goyamegh@amazon.com>
…earch-project#469/opensearch-project#470 CI on main HEAD (ac025b0) shows 7 failed: the original 5 plus these two, both introduced by the PRs that merged after this branch was cut and both reproducible locally 3/3. - comparison-benchmark-free.spec.ts "run row shows every metric inline and an Open-run link": opensearch-project#469 made the run NAME a link to the same report path as the "Open run" icon (owner ask: say what is being compared), so `a[href="/evaluations/runs/<id>"]` now resolves to 2 elements → strict mode. Target the icon by its existing `open-run-<id>` testid and assert its href, and additionally assert the new `run-name-link-<id>` carries the same href (the spec now covers opensearch-project#469's change instead of tripping on it). - comparison-hover-prompt-preview.spec.ts "focusing the case row link (keyboard) also opens the preview" (opensearch-project#470): Radix Tooltip closes on ANY scroll of a trigger ancestor. In the default 1280x720 viewport the case table is the last content in the page's overflow-y-auto container and the link's bottom edge sits 3px past the container's, so focus() auto-scrolls those 3px to reveal the focused element and the tooltip that opened on focus closes ~30ms later (instrumented: tooltip.open → scroll(scrollTop=3) → data-state="closed"). Pre-scrolling can't fix it — scrolling past the scoreboard sentinel condenses the band, the content shrinks to fit, and scrollTop snaps back to 0. The test now uses a 1000px-tall viewport so the table fits without scrolling; the assertion (focus opens the preview with the RUN's prompt, not today's edited content) is unchanged. Signed-off-by: goyamegh <goyamegh@amazon.com>
… comparison spec repairs Signed-off-by: goyamegh <goyamegh@amazon.com>
Signed-off-by: goyamegh <goyamegh@amazon.com>
… left stale ids → PENDING rows) run-inspector-no-autoselect.spec.ts and run-report-insights.spec.ts flaked identically in three consecutive full-suite runs (tests opensearch-project#370/opensearch-project#376, pass on retry) and reproduce deterministically with `retry-judgement.spec.ts` in front of them on 2 workers. Root cause (from the failing page's network log): the seeded benchmark (stamp …714341) referenced report ids from a DIFFERENT stamp (…712829), whose GET returned 404 "Run not found" — so every row rendered PENDING / "waiting for traces" and the detail never appeared. Under fullyParallel a worker can leave a file and come back to it later; Playwright re-runs the file's beforeAll, but module-level state persists in that worker. These specs keep `const reportIds: string[] = []` and only ever push() into it, so the second beforeAll appended a fresh set behind the first set — and `results[tcId] = reportIds[i]` (i in 0..N-1) picked the FIRST set, already deleted by the first afterAll. `testCaseIds` is reassigned (`let … =`), so it was fresh, which is why the benchmark/test cases carried the new stamp while the reports didn't. Fix: `reportIds.length = 0` at the top of beforeAll in the five specs that share this exact shape (also run-report-lazy-load, run-report-redesign, lazy-report-loading, which were latent). Test-only; no product change. Signed-off-by: goyamegh <goyamegh@amazon.com>
Signed-off-by: goyamegh <goyamegh@amazon.com>
Verification proofBefore — After — full suite on this branch, CI-equivalent setup ( (10 skipped are the suites that self-skip without a real OpenSearch / test-endpoints server — unchanged from CI.) Product-fix tests (red → green):
Ordering-flake root cause (deterministic repro): |
PR Reviewer Guide 🔍(Review updated until commit e00d2d6)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to e00d2d6 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 0079810
Suggestions up to commit cb24525
|
…pensearch-project#460 (link-check was red on main) The link-check CI job fails on main HEAD for two CHANGELOG entries that still link source files later deleted: components/RunSummaryPanel.tsx (removed by opensearch-project#443) and components/comparison/MetricComparisonPanel.tsx (removed by opensearch-project#460). Kept as plain code text with a pointer to the removing PR, per the repo's "renamed/moved a file? repoint every markdown reference" rule in AGENTS.md. Signed-off-by: goyamegh <goyamegh@amazon.com>
|
Persistent review updated to latest commit 0079810 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #487 +/- ##
==========================================
+ Coverage 70.09% 70.16% +0.06%
==========================================
Files 413 413
Lines 34033 34117 +84
Branches 10128 10166 +38
==========================================
+ Hits 23857 23937 +80
+ Misses 7915 7906 -9
- Partials 2261 2274 +13
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
CI on this PR head ( 0 failed, 0 flaky → |
…t-text stats assertions so the specs compose opensearch-project#468 (run lifecycle actions) fixed the same strict-mode collision in tests/e2e/evaluation-runner.spec.ts and tests/e2e/evaluation-runs.spec.ts (`text=Failed` also matching the lowercase status badge) with byte-identical assertions but a different explanatory comment. Both PRs are cut from origin/main, so the two comment blocks conflict when composed. Pre-align with Signed-off-by: goyamegh <goyamegh@amazon.com> opensearch-project#468 by using its wording verbatim; the assertions are unchanged.
|
Persistent review updated to latest commit e00d2d6 |
Why
The
e2e-testsCI job has been red onmainitself — latest main run: 5 failed / 3 flaky; on current HEAD (ac025b03d) 7 failed / 5 flaky — so every open PR inherits the same failures regardless of what it touches, ande2e-gatecan't be trusted as a merge gate.Each failing spec was reproduced locally against a fresh file-storage server (exactly CI's setup:
CI=1, noOPENSEARCH_*), root-caused, and repaired on the right seam. No test was deleted or skipped; no assertion was loosened without the reason in the commit. Two of the failures turned out to be real product regressions.Per-spec root cause
judge-tab-whyfixMatcherResultsPanel.tsxwholesale, silently reverting #454's Why/Fix judge-row redesign onmain(duplicated reasoning + fabricated "score 0%" were back; #454's unit suite replaced;judgeReasoningParse.tsorphaned). Restored the #454 panel and layered #442'snotReachedrows on top. Unit suite = #454 + #442 + 1 new case.skills(2 tests)GET /api/skills/discoverlists~/.claude/skills/*with a~/…path, butresolveSkillPath()resolved it against cwd → "Directory does not exist" and Run Evaluation stayed disabled.~,~/,~\now expand to home (~backup/deliberately not). Unit + integration tests (red against the unfixed server).benchmark-run-row-link(2)<h2>withInlineRenameField→ assertrun-inspector-rename-text. Fixture's nonexistent agent is intentional (deterministic "failed before linking" shape) and unchanged.evalruns-no-left-status-icon<svg>in the name cell →svg:not(.lucide-pencil)count 0 (the #430 status-icon guard still bites).benchmark-version-link-panel/benchmarks/:id/runs— the only surface readingversions[current].testCaseIds, where the original bug rendered.dashboardready-to-runOverview state (what CI's shared server is almost always in); the loading skeleton also rendersdashboard-title(branch-detection race); the tagline string never matched the copy #259 shipped. Waits for a settled marker, handles all three states.test-case-runsexpect(true)/ empty-state fallbacks.sidebar-hover-flyoutmouseleave(178→80→64px in the CI call log). Waits for the settled width first.evaluation-runs/evaluation-runnerstatstext=Failedalso matched the lowercasefailedstatus badge when the newest run was a failed one →getByText(…, { exact: true }).comparison-search-popover-anchorboundingBox()during the zoom-in animation (12.35px > 12px) → polls until settled.comparison-benchmark-freeopen-run-<id>testid and assert both hrefs.run-inspector-no-autoselect/run-report-insights(+3 latent siblings)const reportIds = []only ever grew; when a worker re-entered the file underfullyParallel,beforeAllre-ran but the array kept the previous invocation's (already-deleted) ids → seeded benchmark pointed at 404 reports → rows renderedPENDING. Reset inbeforeAll.comparison-hover-prompt-previewfocus()auto-scrolled 3px and Radix Tooltip dismisses on any ancestor scroll (instrumented:tooltip.open→scroll(scrollTop=3)→data-state="closed"). Runs in a 1000px viewport.Verification
Full suite, CI-equivalent (
CI=1, 2 workers, fresh file-storage server, noOPENSEARCH_*), two consecutive runs on the final tree:Both runs:
CI=1 AH_PORT=<port> PLAYWRIGHT_SKIP_WEBSERVER=1 npx playwright test --workers=2againstnode server/dist/index.json fresh file storage, same as.github/workflows/ci.yml.Unit:
MatcherResultsPanel.test.ts36/36,skills.test.ts26/26; integrationskills.integration.test.ts10/10 (the new~/case is red against the unfixed server). Unit suite otherwise untouched.Review
codex_review(adversarial, different model family) findings and disposition:test-case-runsrun-card tests accepted the empty state vacuously; navigation test assertedbodyvisibleLateston the newest, per-card scores, and the/runs/<id>navigationbenchmark-version-link-panelCases-tab assertion reads top-leveltestCaseIds, so it can't see the version-level regressionresolveSkillPathonly handled~/, not the Windows~\form discover would emitMatcherResultsPanelrestore +notReachedlayeringNote:
npm audit --audit-level=highreports 15 high on this branch — identical onorigin/main(no dependency changes here;package-lock.jsonuntouched).