cloudflare/vinext

Public

mirrored from https://github.com/cloudflare/vinextAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.0.9

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tests/e2e/app-router/error-interactive.spec.ts

111lines · modecode

1import { test, expect } from "@playwright/test";
2
3const BASE = "http://localhost:4174";
4
5async function disableViteErrorOverlay(page: import("@playwright/test").Page) {
6 // Vite's dev error overlay can appear during tests (even for expected errors)
7 // and intercept pointer events, causing flaky click failures.
8 await page
9 .addStyleTag({
10 content:
11 "vite-error-overlay{display:none !important; pointer-events:none !important;}",
12 })
13 .catch(() => {
14 // best effort
15 });
16}
17
18/**
19 * Trigger an error by clicking the button, using polling to handle hydration timing.
20 */
21async function triggerError(page: import("@playwright/test").Page) {
22 await disableViteErrorOverlay(page);
23
24 await expect(page.locator('[data-testid="trigger-error"]')).toBeVisible({
25 timeout: 10_000,
26 });
27
28 await expect(async () => {
29 await page
30 .locator('[data-testid="trigger-error"]')
31 .click({ noWaitAfter: true });
32 await expect(page.locator("#error-boundary")).toBeVisible({
33 timeout: 10_000,
34 });
35 }).toPass({ timeout: 20_000 });
36}
37
38test.describe("Error boundary interactive behavior", () => {
39 test("clicking Try Again resets the error boundary", async ({ page }) => {
40 await page.goto(`${BASE}/error-test`);
41 await expect(page.locator('[data-testid="error-content"]')).toBeVisible();
42
43 // Trigger error (polls until button is interactive)
44 await triggerError(page);
45 await expect(page.locator("#error-boundary p")).toContainText(
46 "Test error from client component",
47 );
48
49 // Click "Try again" — should reset the error boundary and re-render the page
50 await page.click("#error-boundary button");
51
52 await disableViteErrorOverlay(page);
53
54 await expect(page.locator("#error-boundary")).not.toBeVisible({
55 timeout: 10_000,
56 });
57
58 // The page content should re-appear (component remounts with shouldThrow=false)
59 await expect(page.locator('[data-testid="error-content"]')).toBeVisible({
60 timeout: 10_000,
61 });
62 await expect(page.locator('[data-testid="trigger-error"]')).toBeVisible();
63 });
64
65 test("can trigger error again after reset", async ({ page }) => {
66 await page.goto(`${BASE}/error-test`);
67 await expect(page.locator('[data-testid="error-content"]')).toBeVisible();
68
69 // First error cycle
70 await triggerError(page);
71
72 // Reset
73 await page.click("#error-boundary button");
74 await expect(page.locator('[data-testid="trigger-error"]')).toBeVisible({
75 timeout: 10_000,
76 });
77
78 // Second error cycle — should work the same
79 await triggerError(page);
80 await expect(page.locator("#error-boundary p")).toContainText(
81 "Test error from client component",
82 );
83 });
84
85 test("error boundary catches error without crashing the page", async ({
86 page,
87 }) => {
88 await page.goto(`${BASE}/error-test`);
89 await expect(page.locator('[data-testid="error-content"]')).toBeVisible();
90
91 // Trigger the error
92 await triggerError(page);
93
94 // The page should still be functional (not a white screen)
95 // Root layout should still be present
96 await expect(page.locator("html")).toBeVisible();
97 await expect(page.locator("body")).toBeVisible();
98 });
99
100 test("navigating away from error page works", async ({ page }) => {
101 await page.goto(`${BASE}/error-test`);
102 await expect(page.locator('[data-testid="error-content"]')).toBeVisible();
103
104 // Trigger error
105 await triggerError(page);
106
107 // Navigate to home
108 await page.goto(`${BASE}/`);
109 await expect(page.locator("h1")).toHaveText("Welcome to App Router");
110 });
111});
112