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

fix: deflake E2E tests (refresh.spec.ts, themes_management.spec.ts) (#2752)

## Summary - **refresh.spec.ts**: Fix race condition where the "refresh app" test would fail because the iframe body was empty after refresh. Added explicit waits for the iframe body to have content both before removing it and after clicking refresh, preventing the `toMatchAriaSnapshot` from matching against an empty `<body></body>`. - **themes_management.spec.ts**: Fix strict mode violations where `getByLabel('Description (optional)')` resolved to 2 elements (one on the Manual tab, one on the AI tab). Replaced ambiguous label selectors with specific element ID selectors (`#manual-description`, `#manual-prompt`, `#ai-description`). Also scoped edit dialog selectors to the dialog role to avoid similar ambiguity. ## Verification Both spec files were verified with `--repeat-each=10` (0 retries) after fixes: - `refresh.spec.ts`: 40/40 passed (was 34/40 before fix) - `themes_management.spec.ts`: 50/50 passed (was 49/50 before fix) ## Flaky test scan results Scanned 2 CI runs on main + 11 PRs by wwwillchen/wwwillchen-bot. Most previously flaky tests (setup_flow, setup, select_component, debugging_logs, switch_versions, etc.) appear to have been fixed in prior commits. Only refresh.spec.ts and themes_management.spec.ts were still reproducing locally. ## Test plan - [x] `refresh.spec.ts` passes 10x repeat-each with 0 retries - [x] `themes_management.spec.ts` passes 10x repeat-each with 0 retries - [x] Formatting, linting, and type checks pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2752" 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>
上级 67072434
...@@ -5,10 +5,16 @@ testSkipIfWindows("refresh app", async ({ po }) => { ...@@ -5,10 +5,16 @@ 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
await po.previewPanel.expectPreviewIframeIsVisible();
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.
await po.previewPanel await iframe
.getPreviewIframeElement()
.contentFrame() .contentFrame()
.locator("body") .locator("body")
.evaluate((body) => { .evaluate((body) => {
...@@ -16,6 +22,12 @@ testSkipIfWindows("refresh app", async ({ po }) => { ...@@ -16,6 +22,12 @@ testSkipIfWindows("refresh app", async ({ po }) => {
}); });
await po.previewPanel.clickPreviewRefresh(); await po.previewPanel.clickPreviewRefresh();
// Wait for the iframe to reload with content after refresh
await expect(iframe.contentFrame().locator("body")).not.toBeEmpty({
timeout: Timeout.LONG,
});
await po.previewPanel.snapshotPreview(); await po.previewPanel.snapshotPreview();
}); });
......
...@@ -28,11 +28,9 @@ test("themes management - CRUD operations", async ({ po }) => { ...@@ -28,11 +28,9 @@ test("themes management - CRUD operations", async ({ po }) => {
// Fill in manual configuration form // Fill in manual configuration form
await po.page.locator("#manual-name").fill("My Test Theme"); await po.page.locator("#manual-name").fill("My Test Theme");
await po.page.locator("#manual-description").fill("A test theme description");
await po.page await po.page
.getByLabel("Description (optional)") .locator("#manual-prompt")
.fill("A test theme description");
await po.page
.getByLabel("Theme Prompt")
.fill("Use blue colors and modern styling"); .fill("Use blue colors and modern styling");
// Save the theme // Save the theme
...@@ -60,10 +58,14 @@ test("themes management - CRUD operations", async ({ po }) => { ...@@ -60,10 +58,14 @@ test("themes management - CRUD operations", async ({ po }) => {
.getByLabel("Theme Name") .getByLabel("Theme Name")
.fill("Updated Theme"); .fill("Updated Theme");
await po.page await po.page
.getByRole("dialog")
.getByLabel("Description (optional)") .getByLabel("Description (optional)")
.fill("Updated description"); .fill("Updated description");
await po.page.getByLabel("Theme Prompt").clear(); await po.page.getByRole("dialog").getByLabel("Theme Prompt").clear();
await po.page.getByLabel("Theme Prompt").fill("Updated prompt content"); await po.page
.getByRole("dialog")
.getByLabel("Theme Prompt")
.fill("Updated prompt content");
// Save changes // Save changes
await po.page.getByRole("button", { name: "Save" }).click(); await po.page.getByRole("button", { name: "Save" }).click();
...@@ -126,11 +128,9 @@ test("themes management - create theme from chat input", async ({ po }) => { ...@@ -126,11 +128,9 @@ test("themes management - create theme from chat input", async ({ po }) => {
// Fill in manual configuration form // Fill in manual configuration form
await po.page.locator("#manual-name").fill("Chat Input Theme"); await po.page.locator("#manual-name").fill("Chat Input Theme");
await po.page.locator("#manual-description").fill("Created from chat input");
await po.page await po.page
.getByLabel("Description (optional)") .locator("#manual-prompt")
.fill("Created from chat input");
await po.page
.getByLabel("Theme Prompt")
.fill("Use dark mode with purple accents"); .fill("Use dark mode with purple accents");
// Save the theme // Save the theme
...@@ -240,9 +240,7 @@ test("themes management - AI generator flow", async ({ po }) => { ...@@ -240,9 +240,7 @@ test("themes management - AI generator flow", async ({ po }) => {
// Fill in theme details // Fill in theme details
await po.page.locator("#ai-name").fill("AI Generated Theme"); await po.page.locator("#ai-name").fill("AI Generated Theme");
await po.page await po.page.locator("#ai-description").fill("Created via AI generator");
.getByLabel("Description (optional)")
.fill("Created via AI generator");
// Upload an image // Upload an image
const fileChooserPromise = po.page.waitForEvent("filechooser"); const fileChooserPromise = po.page.waitForEvent("filechooser");
...@@ -310,9 +308,7 @@ test("themes management - AI generator from website URL", async ({ po }) => { ...@@ -310,9 +308,7 @@ test("themes management - AI generator from website URL", async ({ po }) => {
// Fill in theme details // Fill in theme details
await po.page.locator("#ai-name").fill("Website Theme"); await po.page.locator("#ai-name").fill("Website Theme");
await po.page await po.page.locator("#ai-description").fill("Generated from website");
.getByLabel("Description (optional)")
.fill("Generated from website");
// Enter a website URL // Enter a website URL
await urlInput.fill("https://example.com"); await urlInput.fill("https://example.com");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论