Skip to content

Commit 5914d25

Browse files
yanghuidongclaude
andcommitted
test(solid-query): add e2e tests for head() async loader fix
Adds comprehensive playwright tests verifying the head() re-execution fix: - Verifies page title updates correctly on back navigation after login - Tests fallback title when loader returns null - Tests logout flow with correct title updates - Verifies race condition handling with rapid navigation Also fixes package.json start script to use 'pnpm dlx' instead of deprecated 'pnpx' command for compatibility with modern pnpm versions. All tests passing, confirming non-blocking head() re-execution works correctly after async loaders complete. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
1 parent cf623b9 commit 5914d25

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

e2e/solid-start/basic-solid-query/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dev:e2e": "vite dev",
99
"build": "vite build && tsc --noEmit",
1010
"preview": "vite preview",
11-
"start": "pnpx srvx --prod -s ../client dist/server/server.js",
11+
"start": "pnpm dlx srvx --prod -s ../client dist/server/server.js",
1212
"test:e2e": "rm -rf port*.txt; playwright test --project=chromium"
1313
},
1414
"dependencies": {
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
test.describe('head() function with async loaders and back navigation', () => {
4+
test.beforeEach(async ({ page }) => {
5+
// Clear auth state before each test
6+
await page.goto('/')
7+
await page.evaluate(() => localStorage.clear())
8+
})
9+
10+
test('page title updates correctly when navigating back after login', async ({
11+
page,
12+
}) => {
13+
// Step 1: Visit article while unauthenticated
14+
await page.goto('/test-head/article/123')
15+
16+
// Should show "Article Not Found" content and title
17+
await expect(page.getByTestId('article-not-found')).toBeVisible()
18+
await expect(page).toHaveTitle('Article Not Found')
19+
20+
// Step 2: Click login link
21+
await page.getByTestId('go-to-login-link').click()
22+
23+
// Should be on login page
24+
await expect(page.getByTestId('login-page')).toBeVisible()
25+
await expect(page).toHaveTitle('Login')
26+
27+
// Step 3: Simulate login
28+
await page.getByTestId('login-button').click()
29+
30+
// Should be redirected to dashboard
31+
await expect(page.getByTestId('dashboard')).toBeVisible()
32+
await expect(page).toHaveTitle('Dashboard')
33+
34+
// Step 4: Navigate back with browser back button
35+
// This is the critical test - the bug was that the title wouldn't update
36+
await page.goBack()
37+
38+
// Wait for the article content to load (proves loader ran)
39+
await expect(page.getByTestId('article-content')).toBeVisible()
40+
await expect(page.getByTestId('article-title')).toContainText(
41+
'Article 123 Title',
42+
)
43+
44+
// Critical assertion: page title should update to the actual article title
45+
// With the bug, this would remain "Article Not Found"
46+
// With the fix, head() re-executes after async loaders complete
47+
await expect(page).toHaveTitle('Article 123 Title')
48+
})
49+
50+
test('page title shows correct fallback when loader returns null', async ({
51+
page,
52+
}) => {
53+
// Visit article while unauthenticated
54+
await page.goto('/test-head/article/456')
55+
56+
// Should show fallback content and title
57+
await expect(page.getByTestId('article-not-found')).toBeVisible()
58+
await expect(page).toHaveTitle('Article Not Found')
59+
})
60+
61+
test('logout flow works correctly', async ({ page }) => {
62+
// Set up authenticated state
63+
await page.goto('/fake-login')
64+
await page.getByTestId('login-button').click()
65+
66+
// Navigate to article
67+
await page.goto('/test-head/article/789')
68+
await expect(page.getByTestId('article-content')).toBeVisible()
69+
await expect(page).toHaveTitle('Article 789 Title')
70+
71+
// Click logout button
72+
await page.getByTestId('logout-button').click()
73+
74+
// Page should reload and show not found state
75+
await expect(page.getByTestId('article-not-found')).toBeVisible()
76+
await expect(page).toHaveTitle('Article Not Found')
77+
})
78+
79+
test('rapid navigation does not cause stale head() execution', async ({
80+
page,
81+
}) => {
82+
// Set up authenticated state
83+
await page.goto('/fake-login')
84+
await page.getByTestId('login-button').click()
85+
86+
// Navigate to first article
87+
await page.goto('/test-head/article/111')
88+
await expect(page).toHaveTitle('Article 111 Title')
89+
90+
// Rapidly navigate to second article
91+
await page.goto('/test-head/article/222')
92+
await expect(page).toHaveTitle('Article 222 Title')
93+
94+
// Title should match the current route, not the previous one
95+
const title = await page.title()
96+
expect(title).toBe('Article 222 Title')
97+
expect(title).not.toBe('Article 111 Title')
98+
})
99+
})

0 commit comments

Comments
 (0)