Unverified 提交 786ea5c3 authored 作者: wwwillchen-bot's avatar wwwillchen-bot 提交者: GitHub

fix: deflake E2E tests (refresh.spec.ts) (#2759)

## Summary - Fixed flaky `refresh app` test in `refresh.spec.ts` by adding pre-refresh snapshot verification and post-refresh content wait - The test was failing ~20% of the time because the iframe body would remain empty after clicking refresh - Added `snapshotPreview()` before body removal to ensure initial content is loaded - Added `not.toHaveText("")` wait after refresh to ensure content reloads before snapshotting ## Flaky test analysis Scanned 1 main branch CI run (with available artifacts) + 9 PR comments from wwwillchen/wwwillchen-bot. Top flaky spec files by occurrence: | Spec File | Occurrences | Status | |:---|:---:|:---| | setup_flow.spec.ts | 13 | Already fixed (PR #2740) | | debugging_logs.spec.ts | 6 | Stable (passed 50/50) | | select_component.spec.ts | 6 | Stable (passed 60/60) | | setup.spec.ts | 5 | Stable (passed 10/10) | | switch_versions.spec.ts | 5 | Stable (passed 20/20) | | **refresh.spec.ts** | **5** | **Fixed in this PR** | | toggle_screen_sizes.spec.ts | 4 | Stable (passed 30/30) | | undo.spec.ts | 3 | Stable (passed 30/30) | ## Verification - `refresh.spec.ts` passed 40/40 runs with `--repeat-each=10` after the fix (was 38/40 before) ## Test plan - [x] Verify `refresh.spec.ts` passes consistently with `--repeat-each=10` - [x] No application code changes (test-only fix) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2759" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: 's avatarclaude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
上级 ca08abdd
...@@ -5,12 +5,9 @@ testSkipIfWindows("refresh app", async ({ po }) => { ...@@ -5,12 +5,9 @@ testSkipIfWindows("refresh app", async ({ po }) => {
await po.setUp({ autoApprove: true }); await po.setUp({ autoApprove: true });
await po.sendPrompt("hi"); await po.sendPrompt("hi");
// Wait for the preview iframe to have content before removing body // Verify the preview content loads before we test refresh
await po.previewPanel.expectPreviewIframeIsVisible(); await po.previewPanel.snapshotPreview();
const iframe = po.previewPanel.getPreviewIframeElement(); const iframe = po.previewPanel.getPreviewIframeElement();
await expect(iframe.contentFrame().locator("body")).not.toBeEmpty({
timeout: Timeout.LONG,
});
// Drop the document.body inside the contentFrame to make // Drop the document.body inside the contentFrame to make
// sure refresh works. // sure refresh works.
...@@ -23,10 +20,11 @@ testSkipIfWindows("refresh app", async ({ po }) => { ...@@ -23,10 +20,11 @@ testSkipIfWindows("refresh app", async ({ po }) => {
await po.previewPanel.clickPreviewRefresh(); await po.previewPanel.clickPreviewRefresh();
// Wait for the iframe to reload with content after refresh // Wait for the iframe to reload and have content after refresh.
await expect(iframe.contentFrame().locator("body")).not.toBeEmpty({ // Use a short poll to ensure body has meaningful content before snapshotting.
timeout: Timeout.LONG, await expect(
}); po.previewPanel.getPreviewIframeElement().contentFrame().locator("body"),
).not.toHaveText("", { timeout: Timeout.LONG });
await po.previewPanel.snapshotPreview(); await po.previewPanel.snapshotPreview();
}); });
......
- region "Notifications (F8)":
- list
- region "Notifications alt+T"
- heading "Welcome to Your Blank App" [level=1]
- paragraph: Start building your amazing project here!
- link "Made with Dyad":
- /url: https://www.dyad.sh/
\ No newline at end of file
...@@ -82,6 +82,7 @@ The stashed changes will be automatically merged back after the rebase completes ...@@ -82,6 +82,7 @@ The stashed changes will be automatically merged back after the rebase completes
- If both sides of a conflict have valid imports/hooks, keep both and remove any duplicate constant redefinitions - If both sides of a conflict have valid imports/hooks, keep both and remove any duplicate constant redefinitions
- When rebasing documentation/table conflicts (e.g., workflow README tables), prefer keeping **both** additions from HEAD and upstream - merge new rows/content from both branches rather than choosing one side - When rebasing documentation/table conflicts (e.g., workflow README tables), prefer keeping **both** additions from HEAD and upstream - merge new rows/content from both branches rather than choosing one side
- **Complementary additions**: When both sides added new sections at the end of a file (e.g., both added different documentation tips), keep both sections rather than choosing one — they're not truly conflicting, just different additions - **Complementary additions**: When both sides added new sections at the end of a file (e.g., both added different documentation tips), keep both sections rather than choosing one — they're not truly conflicting, just different additions
- **Preserve variable declarations used in common code**: When one side of a conflict declares a variable (e.g., `const iframe = po.previewPanel.getPreviewIframeElement()`) that is referenced in non-conflicting code between or after conflict markers, keep the declaration even when adopting the other side's verification approach — the variable is needed regardless of which style you choose
- **React component wrapper conflicts**: When rebasing UI changes that conflict on wrapper div classes (e.g., `flex items-start space-x-2` vs `flex items-end gap-1`), keep the newer styling from the incoming commit but preserve any functional components (like dialogs or modals) that exist in HEAD but not in the incoming change - **React component wrapper conflicts**: When rebasing UI changes that conflict on wrapper div classes (e.g., `flex items-start space-x-2` vs `flex items-end gap-1`), keep the newer styling from the incoming commit but preserve any functional components (like dialogs or modals) that exist in HEAD but not in the incoming change
- **Refactoring conflicts**: When incoming commits refactor code (e.g., extracting inline logic into helper functions), and HEAD has new features in the same area, integrate HEAD's features into the new structure. Example: if incoming code moves streaming logic to `runSingleStreamPass()` and HEAD adds mid-turn compaction to the inline code, add compaction support to the new function rather than keeping the old inline version - **Refactoring conflicts**: When incoming commits refactor code (e.g., extracting inline logic into helper functions), and HEAD has new features in the same area, integrate HEAD's features into the new structure. Example: if incoming code moves streaming logic to `runSingleStreamPass()` and HEAD adds mid-turn compaction to the inline code, add compaction support to the new function rather than keeping the old inline version
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
The pre-commit hook runs `tsgo` (via `npm run ts`), which is stricter than `tsc --noEmit`. For example, passing a `number` to a function typed `(str: string | null | undefined)` may pass `tsc` but fail `tsgo` with `TS2345: Argument of type 'number' is not assignable to parameter of type 'string'`. Always wrap with `String()` when converting numbers to string parameters. The pre-commit hook runs `tsgo` (via `npm run ts`), which is stricter than `tsc --noEmit`. For example, passing a `number` to a function typed `(str: string | null | undefined)` may pass `tsc` but fail `tsgo` with `TS2345: Argument of type 'number' is not assignable to parameter of type 'string'`. Always wrap with `String()` when converting numbers to string parameters.
## tsgo installation requirement
`tsgo` is a Go binary, **not** an npm package — running `npx tsgo` fails with `npm error 404 Not Found - GET https://registry.npmjs.org/tsgo` because it is not in the npm registry. It is installed by the project's `npm install` step via a local package. If node_modules is missing or `npm install` fails (e.g., because the environment runs Node.js < 24, which the project requires), skip the `npm run ts` check and note that CI will verify types instead.
## ES2020 target limitations ## ES2020 target limitations
The project's `tsconfig.app.json` targets ES2020 with `lib: ["ES2020"]`. Methods introduced in ES2021+ (like `String.prototype.replaceAll`) are not available on the `string` type. If code uses `replaceAll`, it needs an `as any` cast to avoid `TS2550: Property 'replaceAll' does not exist on type 'string'`. Do not remove these casts without updating the tsconfig target. The project's `tsconfig.app.json` targets ES2020 with `lib: ["ES2020"]`. Methods introduced in ES2021+ (like `String.prototype.replaceAll`) are not available on the `string` type. If code uses `replaceAll`, it needs an `as any` cast to avoid `TS2550: Property 'replaceAll' does not exist on type 'string'`. Do not remove these casts without updating the tsconfig target.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论