Skip to content

Commit d9ff643

Browse files
committed
Add failing test
1 parent 9db424f commit d9ff643

File tree

12 files changed

+509
-0
lines changed

12 files changed

+509
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-hash
5+
dist-ssr
6+
*.local
7+
8+
/test-results/
9+
/playwright-report/
10+
/blob-report/
11+
/playwright/.cache/
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vite App</title>
7+
</head>
8+
<body>
9+
<div id="app"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "tanstack-router-e2e-react-basic-auth",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite --port 3000",
7+
"dev:e2e": "vite",
8+
"build": "vite build && tsc --noEmit",
9+
"serve": "vite preview",
10+
"start": "vite",
11+
"test:e2e": "playwright test --project=chromium"
12+
},
13+
"dependencies": {
14+
"@tanstack/react-router": "workspace:^",
15+
"@tanstack/react-router-devtools": "workspace:^",
16+
"react": "^19.0.0",
17+
"react-dom": "^19.0.0",
18+
"redaxios": "^0.5.1",
19+
"postcss": "^8.5.1",
20+
"autoprefixer": "^10.4.20",
21+
"tailwindcss": "^3.4.17"
22+
},
23+
"devDependencies": {
24+
"@playwright/test": "^1.50.1",
25+
"@tanstack/router-e2e-utils": "workspace:^",
26+
"@types/react": "^19.0.8",
27+
"@types/react-dom": "^19.0.3",
28+
"@vitejs/plugin-react": "^4.3.4",
29+
"vite": "^6.1.0"
30+
}
31+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
import { derivePort } from '@tanstack/router-e2e-utils'
3+
import packageJson from './package.json' with { type: 'json' }
4+
5+
const PORT = derivePort(packageJson.name)
6+
const baseURL = `http://localhost:${PORT}`
7+
/**
8+
* See https://playwright.dev/docs/test-configuration.
9+
*/
10+
export default defineConfig({
11+
testDir: './tests',
12+
workers: 1,
13+
14+
reporter: [['line']],
15+
16+
use: {
17+
/* Base URL to use in actions like `await page.goto('/')`. */
18+
baseURL,
19+
},
20+
21+
webServer: {
22+
command: `VITE_SERVER_PORT=${PORT} pnpm build && VITE_SERVER_PORT=${PORT} pnpm serve --port ${PORT}`,
23+
url: baseURL,
24+
reuseExistingServer: !process.env.CI,
25+
stdout: 'pipe',
26+
},
27+
28+
projects: [
29+
{
30+
name: 'chromium',
31+
use: { ...devices['Desktop Chrome'] },
32+
},
33+
],
34+
})
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useMemo, useState } from 'react'
2+
3+
export type AuthUser = {
4+
id: string
5+
name: string
6+
}
7+
8+
export type AuthState =
9+
| {
10+
type: 'authenticated'
11+
user: AuthUser
12+
}
13+
| {
14+
type: 'unauthenticated'
15+
hasLoggedIn: boolean
16+
}
17+
18+
export type AuthHandle = {
19+
login: (userId: string) => Promise<void>
20+
logout: () => Promise<void>
21+
}
22+
23+
export const initialAuthState: AuthState = {
24+
type: 'unauthenticated',
25+
hasLoggedIn: false,
26+
}
27+
28+
export const initialAuthHandle: AuthHandle = {
29+
login: () => Promise.resolve(),
30+
logout: () => Promise.resolve(),
31+
}
32+
33+
export function useAuth(): readonly [AuthState, AuthHandle] {
34+
const [authState, setAuthState] = useState<AuthState>({
35+
type: 'unauthenticated',
36+
hasLoggedIn: false,
37+
})
38+
39+
const login = async (userId: string) =>
40+
new Promise<void>((resolve) => {
41+
// Delay the login with a setTimeout to simulate a network request,
42+
// and make sure any actions in response are not batched as part of
43+
// a React request handler.
44+
setTimeout(() => {
45+
setAuthState({
46+
type: 'authenticated',
47+
user: {
48+
id: userId,
49+
name: `User #${userId}`,
50+
},
51+
})
52+
resolve()
53+
}, 500)
54+
})
55+
56+
const logout = async () =>
57+
new Promise<void>((resolve) => {
58+
setTimeout(() => {
59+
setAuthState((currentState) => ({
60+
type: 'unauthenticated',
61+
hasLoggedIn:
62+
currentState.type === 'authenticated' || currentState.hasLoggedIn,
63+
}))
64+
resolve()
65+
})
66+
})
67+
68+
const authHandle = useMemo<AuthHandle>(
69+
() => ({
70+
login,
71+
logout,
72+
}),
73+
[login, logout],
74+
)
75+
76+
return [authState, authHandle]
77+
}

0 commit comments

Comments
 (0)