Skip to content

Commit 3467d20

Browse files
committed
feat: add playwright
1 parent d1f63ea commit 3467d20

File tree

9 files changed

+323
-7
lines changed

9 files changed

+323
-7
lines changed

.eslintrc.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ module.exports = {
2323
files: ['**/*.test.ts', '**/*.test.tsx'],
2424
extends: ['plugin:vitest/recommended', 'plugin:testing-library/react'],
2525
},
26+
{
27+
files: ['e2e/**/*.spec.ts'],
28+
extends: ['plugin:playwright/recommended'],
29+
},
2630
],
2731
ignorePatterns: ['node_modules/', '.next/', 'public/', 'components/ui'],
2832
}

.github/workflows/playwright.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
branches: [ main, master ]
5+
pull_request:
6+
branches: [ main, master ]
7+
jobs:
8+
test:
9+
timeout-minutes: 60
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: lts/*
16+
- name: Install dependencies
17+
run: npm install -g pnpm && pnpm install
18+
- name: Install Playwright Browsers
19+
run: pnpm exec playwright install --with-deps
20+
- name: Run Playwright tests
21+
run: pnpm exec playwright test
22+
- uses: actions/upload-artifact@v4
23+
if: always()
24+
with:
25+
name: playwright-report
26+
path: playwright-report/
27+
retention-days: 30

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ next-env.d.ts
3838

3939
# IDE
4040
.idea
41+
42+
/e2e-results/
43+
/playwright-report/
44+
/blob-report/
45+
/playwright/.cache/

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ This is a [Next.js](https://nextjs.org/) 14 Boilerplate project base on [`create
2424
- [next-international](https://github.com/QuiiBz/next-international) seems better, but not compatible with Not found page
2525
- Maybe the best choice is official Example: [app-dir-i18n-routing](https://github.com/vercel/next.js/tree/canary/examples/app-dir-i18n-routing)
2626
- Docker
27-
- Playwright: Write end-to-end tests like a pro or cypress -TBD
27+
- Playwright: Write end-to-end tests like a pro or cypress
28+
- Github actions/CI
2829

2930
## TODO
3031

e2e/app.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
test('should navigate to the dashboard page', async ({ page }) => {
4+
// Start from the index page (the baseURL is set via the webServer in the playwright.config.ts)
5+
await page.goto('/')
6+
// Find an element with the text 'About' and click on it
7+
await page.click('text=dashboard')
8+
// The new URL should be "/about" (baseURL is used there)
9+
await expect(page).toHaveURL('/dashboard')
10+
// The new page should contain an h1 with "About"
11+
await expect(page.locator('h2')).toContainText('Dashboard')
12+
})
13+
14+
test('app journey', async ({ page }) => {
15+
await page.goto('/')
16+
const footerText = page.locator('footer p')
17+
await expect(footerText).toBeVisible()
18+
19+
const navLinks = page.locator('nav a')
20+
const expectedLinksText = ['Loading', 'dashboard', 'todo demos', 'GitHub']
21+
22+
for (let i = 0; i < expectedLinksText.length; i++) {
23+
const linkText = await navLinks.nth(i).textContent()
24+
expect(linkText).toContain(expectedLinksText[i])
25+
}
26+
27+
await navLinks.nth(0).click()
28+
await expect(page).toHaveURL('/loading-and-streaming')
29+
30+
await expect(
31+
page.getByRole('heading', { name: 'Show loading UI and streaming' }),
32+
).toBeVisible()
33+
34+
await navLinks.nth(2).click()
35+
await expect(page).toHaveURL('/todo')
36+
await expect(
37+
page.getByRole('heading', { name: 'Todo demo with RCC' }),
38+
).toBeVisible()
39+
// todo test submit
40+
})

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
"build": "next build",
77
"build-analyze": "cross-env ANALYZE=true pnpm run build",
88
"check-types": "tsc --noEmit --pretty",
9-
"coverage": "vitest run --coverage",
109
"dev": "next dev | pino-pretty",
1110
"dev:turbo": "next dev --turbo | pino-pretty",
1211
"preinstall": "npx only-allow pnpm",
1312
"lint": "next lint",
1413
"lint-fix": "next lint --fix && pnpm run prettier:fix",
1514
"prepare": "husky",
1615
"prettier:fix": "prettier '**/*.{js,jsx,ts,tsx,json,md}' --write",
17-
"preview": "next build && cp -r dist/static dist/standalone/dist/static && cp -r public dist/standalone/public && node dist/standalone/server.js",
18-
"start": "next start",
16+
"start": "next build && cp -r dist/static dist/standalone/dist/static && cp -r public dist/standalone/public && node dist/standalone/server.js",
1917
"test": "vitest run",
18+
"test:coverage": "vitest run --coverage",
2019
"test:e2e": "playwright test",
2120
"test:watch": "vitest"
2221
},
@@ -56,6 +55,7 @@
5655
"@commitlint/config-conventional": "^19.1.0",
5756
"@commitlint/types": "^19.0.3",
5857
"@next/bundle-analyzer": "^14.2.2",
58+
"@playwright/test": "^1.43.1",
5959
"@testing-library/jest-dom": "^6.4.2",
6060
"@testing-library/react": "^15.0.2",
6161
"@testing-library/user-event": "^14.5.2",
@@ -69,6 +69,7 @@
6969
"eslint": "^8",
7070
"eslint-config-next": "^14.2.2",
7171
"eslint-config-prettier": "^9.1.0",
72+
"eslint-plugin-playwright": "^1.6.0",
7273
"eslint-plugin-prettier": "^5.1.3",
7374
"eslint-plugin-simple-import-sort": "^12.1.0",
7475
"eslint-plugin-tailwindcss": "^3.15.1",

playwright.config.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
import path from 'path'
3+
4+
/**
5+
* Read environment variables from file.
6+
* https://github.com/motdotla/dotenv
7+
*/
8+
// require('dotenv').config();
9+
10+
// Use process.env.PORT by default and fallback to port 3000
11+
const PORT = process.env.PORT || 3000
12+
13+
// Set webServer.url and use.baseURL with the location of the WebServer respecting the correct set port
14+
const baseURL = `http://localhost:${PORT}`
15+
16+
/**
17+
* See https://playwright.dev/docs/test-configuration.
18+
*/
19+
export default defineConfig({
20+
// Timeout per test
21+
timeout: 30 * 1000,
22+
// Test directory
23+
testDir: path.join(__dirname, 'e2e'),
24+
/* Run tests in files in parallel */
25+
fullyParallel: true,
26+
/* Fail the build on CI if you accidentally left test.only in the source code. */
27+
forbidOnly: !!process.env.CI,
28+
/* Retry on CI only */
29+
retries: process.env.CI ? 2 : 0,
30+
/* Opt out of parallel tests on CI. */
31+
workers: process.env.CI ? 1 : undefined,
32+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
33+
reporter: process.env.CI ? 'github' : 'html',
34+
// Artifacts folder where screenshots, videos, and traces are stored.
35+
outputDir: 'e2e-results/',
36+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
37+
38+
// Run your local dev server before starting the tests:
39+
// https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests
40+
webServer: {
41+
command: process.env.CI ? 'pnpm run start' : 'pnpm run dev:turbo',
42+
url: baseURL,
43+
timeout: 2 * 60 * 1000,
44+
reuseExistingServer: !process.env.CI,
45+
},
46+
use: {
47+
// Use baseURL so to make navigations relative.
48+
// More information: https://playwright.dev/docs/api/class-testoptions#test-options-base-url
49+
baseURL,
50+
51+
// Retry a test if its failing with enabled tracing. This allows you to analyze the DOM, console logs, network traffic etc.
52+
// More information: https://playwright.dev/docs/trace-viewer
53+
trace: 'retry-with-trace',
54+
55+
// All available context options: https://playwright.dev/docs/api/class-browser#browser-new-context
56+
// contextOptions: {
57+
// ignoreHTTPSErrors: true,
58+
// },
59+
},
60+
61+
/* Configure projects for major browsers */
62+
projects: [
63+
{
64+
name: 'chromium',
65+
use: { ...devices['Desktop Chrome'] },
66+
},
67+
68+
// {
69+
// name: 'firefox',
70+
// use: { ...devices['Desktop Firefox'] },
71+
// },
72+
//
73+
// {
74+
// name: 'webkit',
75+
// use: { ...devices['Desktop Safari'] },
76+
// },
77+
78+
/* Test against mobile viewports. */
79+
// {
80+
// name: 'Mobile Chrome',
81+
// use: { ...devices['Pixel 5'] },
82+
// },
83+
// {
84+
// name: 'Mobile Safari',
85+
// use: { ...devices['iPhone 12'] },
86+
// },
87+
88+
/* Test against branded browsers. */
89+
// {
90+
// name: 'Microsoft Edge',
91+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
92+
// },
93+
// {
94+
// name: 'Google Chrome',
95+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
96+
// },
97+
],
98+
99+
/* Run your local dev server before starting the tests */
100+
// webServer: {
101+
// command: 'npm run start',
102+
// url: 'http://127.0.0.1:3000',
103+
// reuseExistingServer: !process.env.CI,
104+
// },
105+
})

0 commit comments

Comments
 (0)