Skip to content

Commit aecb193

Browse files
committed
test: add playwright e2e suite for files-inspector and streaming-chat
Covers the browser-level paths the existing in-process vitest suites can't reach — DOM render, RPC results landing in the UI, client-side route navigation, live token streaming over WS, and shared-state-backed history clearing. Suite spins up the real CLI dev servers via Playwright webServer; files-inspector's cwd is pinned to a fixture dir through a new DEVFRAME_E2E_CWD env so list-files assertions stay deterministic. Wires test:e2e into the root scripts and adds an e2e job alongside unit-test in ci.yml (renamed to CI).
1 parent 97bc45b commit aecb193

13 files changed

Lines changed: 208 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Unit Test
1+
name: CI
22

33
on:
44
push:
@@ -13,6 +13,31 @@ jobs:
1313
unit-test:
1414
uses: sxzz/workflows/.github/workflows/unit-test.yml@main
1515

16+
e2e:
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 15
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: pnpm/action-setup@v4
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: 22
25+
cache: pnpm
26+
- run: pnpm install --frozen-lockfile
27+
- name: Cache Playwright browsers
28+
uses: actions/cache@v4
29+
with:
30+
path: ~/.cache/ms-playwright
31+
key: playwright-${{ hashFiles('pnpm-lock.yaml') }}
32+
- run: pnpm exec playwright install --with-deps chromium
33+
- run: pnpm test:e2e
34+
- if: failure()
35+
uses: actions/upload-artifact@v4
36+
with:
37+
name: playwright-report
38+
path: playwright-report/
39+
retention-days: 7
40+
1641
# coverage:
1742
# uses: sxzz/workflows/.github/workflows/coverage.yml@main
1843
# needs: unit-test

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ temp
1515
**/.vitepress/cache
1616
**/.vitepress/dist
1717
packages/devframe/skills
18+
test-results
19+
playwright-report
20+
playwright/.cache
21+
blob-report

examples/files-inspector/src/devframe.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import process from 'node:process'
12
import { fileURLToPath } from 'node:url'
23
import { defineRpcFunction } from 'devframe'
34
import { defineDevframe } from 'devframe/types'
@@ -18,19 +19,21 @@ export default defineDevframe({
1819
},
1920
spa: { loader: 'none' },
2021
async setup(ctx) {
22+
const targetCwd = process.env.DEVFRAME_E2E_CWD || ctx.cwd
23+
2124
ctx.rpc.register(defineRpcFunction({
2225
name: 'devframe-files-inspector:get-cwd',
2326
type: 'static',
2427
jsonSerializable: true,
25-
handler: () => ({ cwd: ctx.cwd }),
28+
handler: () => ({ cwd: targetCwd }),
2629
}))
2730

2831
ctx.rpc.register(defineRpcFunction({
2932
name: 'devframe-files-inspector:list-files',
3033
type: 'query',
3134
jsonSerializable: true,
3235
handler: async () => {
33-
const files = await glob(['*'], { cwd: ctx.cwd, onlyFiles: true, dot: false })
36+
const files = await glob(['*'], { cwd: targetCwd, onlyFiles: true, dot: false })
3437
return files.map(f => f.replace(/\\/g, '/')).sort()
3538
},
3639
snapshot: true,

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
"docs:serve": "pnpm -C docs run docs:serve",
2222
"lint": "eslint --cache",
2323
"test": "turbo run build && vitest",
24+
"test:e2e": "turbo run build && playwright test",
25+
"test:e2e:ui": "turbo run build && playwright test --ui",
2426
"release": "bumpp -r",
2527
"typecheck": "tsc -b",
2628
"postinstall": "npx simple-git-hooks && skills-npm"
@@ -29,6 +31,7 @@
2931
"@antfu/eslint-config": "catalog:devtools",
3032
"@antfu/ni": "catalog:build",
3133
"@antfu/utils": "catalog:inlined",
34+
"@playwright/test": "catalog:testing",
3235
"@types/node": "catalog:types",
3336
"@types/ws": "catalog:types",
3437
"bumpp": "catalog:devtools",

playwright.config.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import process from 'node:process'
2+
import { fileURLToPath } from 'node:url'
3+
import { defineConfig, devices } from '@playwright/test'
4+
5+
const fixtureCwd = fileURLToPath(new URL('./tests/e2e/fixtures', import.meta.url))
6+
7+
export default defineConfig({
8+
testDir: './tests/e2e',
9+
fullyParallel: true,
10+
forbidOnly: !!process.env.CI,
11+
retries: process.env.CI ? 2 : 0,
12+
reporter: process.env.CI ? [['github'], ['html']] : 'list',
13+
use: {
14+
trace: 'on-first-retry',
15+
},
16+
projects: [
17+
{
18+
name: 'chromium',
19+
use: { ...devices['Desktop Chrome'] },
20+
},
21+
],
22+
webServer: [
23+
{
24+
command: 'node bin.mjs',
25+
cwd: 'examples/files-inspector',
26+
env: { DEVFRAME_E2E_CWD: fixtureCwd },
27+
url: 'http://localhost:9876/__devframe-files-inspector/',
28+
timeout: 60_000,
29+
reuseExistingServer: !process.env.CI,
30+
stdout: 'pipe',
31+
stderr: 'pipe',
32+
},
33+
{
34+
command: 'node bin.mjs',
35+
cwd: 'examples/streaming-chat',
36+
url: 'http://localhost:9897/__devframe-streaming-chat/',
37+
timeout: 60_000,
38+
reuseExistingServer: !process.env.CI,
39+
stdout: 'pipe',
40+
stderr: 'pipe',
41+
},
42+
],
43+
})

pnpm-lock.yaml

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ catalogs:
7272
human-id: ^4.1.3
7373
ua-parser-modern: ^0.1.1
7474
testing:
75+
'@playwright/test': ^1.50.0
7576
tsnapi: ^0.3.3
7677
vitest: ^4.1.6
7778
types:

tests/e2e/files-inspector.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
const BASE = 'http://localhost:9876/__devframe-files-inspector/'
4+
5+
test.describe('files-inspector', () => {
6+
test.beforeEach(async ({ page }) => {
7+
await page.goto(BASE)
8+
await expect(page.locator('h1')).toHaveText('Files Inspector')
9+
})
10+
11+
test('lists fixture files on home', async ({ page }) => {
12+
await expect(page.locator('section h2')).toContainText('Files')
13+
await expect(page.locator('section h2 small')).toHaveText('(3)')
14+
await expect(page.locator('section ul li')).toHaveText([
15+
'README.md',
16+
'package.json',
17+
'sample.txt',
18+
])
19+
})
20+
21+
test('navigates to about and shows cwd', async ({ page }) => {
22+
await page.click('a:has-text("About")')
23+
await expect(page.locator('section h2')).toHaveText('About')
24+
25+
const cwdValue = page.locator('dt:has-text("Server cwd") + dd code')
26+
await expect(cwdValue).toContainText(/fixtures$/)
27+
})
28+
})

tests/e2e/fixtures/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# fixture

tests/e2e/fixtures/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "name": "fixture" }

0 commit comments

Comments
 (0)