|
| 1 | +# W-23127988 — E2E flake: LWC LSP hover lightning-accordion |
| 2 | + |
| 3 | +## Context |
| 4 | + |
| 5 | +- retryRate 67%. Flake, not product defect (run 27976286397: retry 0 fail, retry 1 pass). |
| 6 | +- `waitForLwcLspReady` (`lwcUtils.ts:222`) gates only on index-status UI item, not `doHover` readiness. |
| 7 | +- HTML hover step in `lwcLspHover.headless.spec.ts` (step "hover over lightning-accordion tag and verify the LWC LSP hover card appears", currently ~lines 57-76) does single `hover()` + one-shot `expect(.monaco-hover).toBeVisible({timeout:15_000})`. |
| 8 | +- Cold-LSP: hover provider not ready when index item shows; single hover that misses never re-triggers → `.monaco-hover` never visible → fail. |
| 9 | +- Fix per WI: poll inside `toPass` — re-hover + assert. |
| 10 | +- Reference steps by their `test.step` title, not line numbers (file is 117 lines and grows; line-number-only refs go stale). |
| 11 | + |
| 12 | +## Phases |
| 13 | + |
| 14 | +### Phase 1 — gate HTML hover on availability via toPass re-hover |
| 15 | + |
| 16 | +- File: `packages/salesforcedx-vscode-lwc/test/playwright/specs/lwcLspHover.headless.spec.ts` |
| 17 | +- Target: the HTML hover-verify `test.step` ("hover over lightning-accordion tag…"); wrap only the `hover()` + `.monaco-hover` assert (not the `goToLineCol` / `waitFor` setup) in `expect(async () => {...}).toPass({ timeout })`. |
| 18 | +- Each attempt: `tagToken.hover()`, then assert `.monaco-hover` w/ `View in Component Library` visible. |
| 19 | +- **Open question — must re-trigger fire on every attempt?** Hypothesis: if the pointer is already over the token, Monaco may not recompute the hover, so a missed first attempt never repaints. NOT verified — no Monaco source in `node_modules`, no repo precedent for mouse-move-away. Do NOT bake the move-away into the code as an asserted fact. |
| 20 | + - Implementation: keep each `toPass` attempt self-contained so a stale/absent hover is re-driven. Before each `hover()`, dismiss any open hover (e.g. `page.keyboard.press('Escape')`) and/or move the pointer off the token (`page.mouse.move` to editor body coords) so the next `hover()` is a genuine pointer transition. This is defensive: harmless if Monaco re-fires anyway, necessary if it suppresses same-token re-hover. |
| 21 | + - The move-away/Escape mechanism must be **confirmed in the local verification step** (below) — observe `.monaco-hover` actually disappear then reappear across attempts — before relying on it. If local run shows a bare re-`hover()` already repaints, drop the move-away to keep the step minimal. |
| 22 | +- Drop inner 15_000 → short per-attempt assert timeout; outer `toPass` timeout ~45_000. |
| 23 | +- Precedent: `lwcRename.headless.spec.ts:80-82,106-108` (toPass poll on flaky debounced UI); `lwcCustomComponentsIndex.headless.spec.ts:45`. (Precedent covers the toPass-around-flaky-assert pattern, NOT the hover re-trigger specifics.) |
| 24 | +- Commit: `test(lwc): poll lightning-accordion hover in toPass for cold-LSP - W-23127988` |
| 25 | + |
| 26 | +### Phase 2 (optional, same commit if cheap) — apply same poll to JS hover |
| 27 | + |
| 28 | +- Same file, JS hover-verify `test.step` ("hover over LightningElement…", desktop-only, 20_000 one-shot). Same cold-LSP race on `LightningElement` hover. |
| 29 | +- Wrap the `hover()` + `.monaco-hover` assert in `toPass` for consistency (same re-trigger handling as Phase 1); reduces future flake. |
| 30 | +- Fold into Phase 1 commit (one logical change: hover-readiness polling). |
| 31 | + |
| 32 | +## Skills to apply |
| 33 | + |
| 34 | +- playwright-e2e (toPass for async UI; avoid one-shot asserts on LSP-dependent UI) |
| 35 | +- concise (plan + any comments) |
| 36 | + |
| 37 | +## Verification |
| 38 | + |
| 39 | +- e2e-covered: the spec itself is the test — green run on branch confirms fix. Run `npm run test:web -w salesforcedx-vscode-lwc -- --retries 0` (and/or `test:desktop`); the `lwcPlaywrightE2E` CI workflow runs this on ubuntu (where flake observed). Ideally repeated runs to confirm retryRate drop. |
| 40 | +- Not e2e-covered: |
| 41 | + - `npm run compile` / typecheck spec file (no `let`, ternary, etc. per eslint). |
| 42 | + - eslint clean on changed spec. |
| 43 | + - **Confirm the re-trigger mechanism before PR** — local run (or PWDEBUG/headed) with `--retries 0` (`npm run test:web -w salesforcedx-vscode-lwc -- --retries 0`, so flake is observed not masked) on the HTML hover step: watch the DOM and verify across at least two `toPass` attempts that `.monaco-hover` actually disappears and reappears. This proves the loop re-drives a missed hover. If a bare re-`hover()` already repaints, drop the Escape/move-away. If even the move-away does not re-fire, escalate: the toPass loop is then ineffective and Phase 1 needs a different trigger (e.g. dispatch synthetic `mousemove`, or re-focus the token via `goToLineCol`). |
| 44 | + - **Status:** as committed, the Escape + editor-body `mouse.move` is retained defensively — the local confirm-and-trim step above was not performed, so the move-away is kept (harmless if Monaco re-fires anyway). Trim only after the local DOM observation confirms a bare re-`hover()` repaints. |
0 commit comments