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/cloudflare-workers/interactive.spec.ts

170lines · modecode

1import { test, expect } from "@playwright/test";
2
3const BASE = "http://localhost:4176";
4
5test.describe("App Router interactive behavior on Cloudflare Workers", () => {
6 test("counter increments on multiple clicks", async ({ page }) => {
7 await page.goto(`${BASE}/`);
8 await expect(page.locator("h1")).toHaveText(
9 "vinext on Cloudflare Workers",
10 );
11
12 // Wait for hydration by polling counter clicks
13 await expect(async () => {
14 await page.click('[data-testid="increment"]');
15 const text = await page.locator('[data-testid="count"]').textContent();
16 expect(text).not.toBe("Count: 0");
17 }).toPass({ timeout: 10_000 });
18
19 // Click more
20 await page.click('[data-testid="increment"]');
21 await page.click('[data-testid="increment"]');
22
23 // Count should be at least 3 (may be higher if polling clicked extra)
24 const text = await page.locator('[data-testid="count"]').textContent();
25 const count = parseInt(text!.replace("Count: ", ""), 10);
26 expect(count).toBeGreaterThanOrEqual(3);
27 });
28
29 test("clicking link to About navigates correctly", async ({ page }) => {
30 await page.goto(`${BASE}/`);
31 await expect(page.locator("h1")).toHaveText(
32 "vinext on Cloudflare Workers",
33 );
34
35 // Click About link
36 await page.click('a[href="/about"]');
37 await expect(page.locator("h1")).toHaveText("About");
38 await expect(page.locator("p:first-of-type")).toContainText(
39 "vinext app deployed on Cloudflare Workers",
40 );
41 expect(page.url()).toBe(`${BASE}/about`);
42 });
43
44 test("clicking back link returns to home", async ({ page }) => {
45 await page.goto(`${BASE}/about`);
46 await expect(page.locator("h1")).toHaveText("About");
47
48 // Click back link
49 await page.click('a[href="/"]');
50 await expect(page.locator("h1")).toHaveText(
51 "vinext on Cloudflare Workers",
52 );
53 expect(page.url()).toBe(`${BASE}/`);
54 });
55
56 test("browser back button works after navigation", async ({ page }) => {
57 await page.goto(`${BASE}/`);
58 await expect(page.locator("h1")).toHaveText(
59 "vinext on Cloudflare Workers",
60 );
61
62 // Navigate to about
63 await page.click('a[href="/about"]');
64 await expect(page.locator("h1")).toHaveText("About");
65
66 // Browser back
67 await page.goBack();
68 await expect(page.locator("h1")).toHaveText(
69 "vinext on Cloudflare Workers",
70 );
71 expect(page.url()).toBe(`${BASE}/`);
72
73 // Browser forward
74 await page.goForward();
75 await expect(page.locator("h1")).toHaveText("About");
76 expect(page.url()).toBe(`${BASE}/about`);
77 });
78
79 test("server component timestamp changes on each request", async ({
80 page,
81 }) => {
82 await page.goto(`${BASE}/`);
83 const ts1 = await page
84 .locator('[data-testid="timestamp"]')
85 .textContent();
86
87 await page.waitForTimeout(100);
88 await page.goto(`${BASE}/`);
89 const ts2 = await page
90 .locator('[data-testid="timestamp"]')
91 .textContent();
92
93 // Each request should produce a different timestamp (server rendering)
94 expect(ts1).not.toBe(ts2);
95 });
96
97 test("counter state resets on full page navigation", async ({ page }) => {
98 await page.goto(`${BASE}/`);
99 await expect(page.locator("h1")).toHaveText(
100 "vinext on Cloudflare Workers",
101 );
102
103 // Wait for hydration and increment counter
104 await expect(async () => {
105 await page.click('[data-testid="increment"]');
106 const text = await page.locator('[data-testid="count"]').textContent();
107 expect(text).not.toBe("Count: 0");
108 }).toPass({ timeout: 10_000 });
109
110 // Full page reload
111 await page.goto(`${BASE}/`);
112
113 // Counter should be back to 0
114 await expect(page.locator('[data-testid="count"]')).toHaveText("Count: 0");
115 });
116});
117
118test.describe("App Router dynamic routes on Cloudflare Workers", () => {
119 test("renders blog post with dynamic slug", async ({ page }) => {
120 await page.goto(`${BASE}/blog/hello-world`);
121 await expect(page.locator('[data-testid="blog-title"]')).toHaveText(
122 "Blog: hello-world",
123 );
124 await expect(page.locator('[data-testid="blog-slug"]')).toHaveText(
125 "Slug: hello-world",
126 );
127 });
128
129 test("different slugs render different content", async ({ page }) => {
130 await page.goto(`${BASE}/blog/first-post`);
131 await expect(page.locator('[data-testid="blog-title"]')).toHaveText(
132 "Blog: first-post",
133 );
134
135 await page.goto(`${BASE}/blog/second-post`);
136 await expect(page.locator('[data-testid="blog-title"]')).toHaveText(
137 "Blog: second-post",
138 );
139 });
140
141 test("blog page has back link to home", async ({ page }) => {
142 await page.goto(`${BASE}/blog/test`);
143 await expect(page.locator('[data-testid="blog-title"]')).toHaveText(
144 "Blog: test",
145 );
146
147 await page.click('a[href="/"]');
148 await expect(page.locator("h1")).toHaveText(
149 "vinext on Cloudflare Workers",
150 );
151 });
152});
153
154test.describe("App Router API routes on Workers — extended", () => {
155 test("API returns Cloudflare Workers runtime", async ({ request }) => {
156 const response = await request.get(`${BASE}/api/hello`);
157 const body = await response.json();
158 expect(body.runtime).toContain("Cloudflare-Workers");
159 });
160
161 test("API response is valid JSON with correct headers", async ({
162 request,
163 }) => {
164 const response = await request.get(`${BASE}/api/hello`);
165 expect(response.status()).toBe(200);
166 expect(response.headers()["content-type"]).toContain("application/json");
167 const body = await response.json();
168 expect(body.message).toBeTruthy();
169 });
170});