Skip to content

Commit 85fea6d

Browse files
authored
Merge pull request #4 from lingodotdev/feat/e2e
feat: add e2e tests
2 parents 629dcc6 + f0fd562 commit 85fea6d

File tree

19 files changed

+1939
-137
lines changed

19 files changed

+1939
-137
lines changed

cmp/.github/workflows/ci.yml

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
name: CI
22

33
on:
4+
push:
5+
branches: [main]
46
pull_request:
5-
branches: [main, dev]
7+
branches: [main]
68

79
jobs:
810
lint:
@@ -42,3 +44,34 @@ jobs:
4244
run: pnpm build
4345
- name: Test
4446
run: pnpm test
47+
48+
playwright-e2e:
49+
timeout-minutes: 60
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v5.0.1
53+
# pnpm version is taken from package.json
54+
- name: Install pnpm
55+
uses: pnpm/action-setup@v4
56+
- name: Use Node.js 20
57+
uses: actions/setup-node@v6.0.0
58+
with:
59+
node-version: 20
60+
cache: "pnpm"
61+
- name: Install dependencies
62+
run: pnpm install
63+
- name: Install Playwright Browsers
64+
working-directory: ./compiler
65+
run: pnpm exec playwright install --with-deps
66+
- name: Prepare tests
67+
working-directory: ./compiler
68+
run: pnpm run test:prepare
69+
- name: Run tests
70+
working-directory: ./compiler
71+
run: pnpm run test:e2e
72+
- uses: actions/upload-artifact@v4
73+
if: ${{ !cancelled() }}
74+
with:
75+
name: playwright-report
76+
path: playwright-report/
77+
retention-days: 30

cmp/compiler/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
# Playwright
3+
node_modules/
4+
/test-results/
5+
/playwright-report/
6+
/blob-report/
7+
/playwright/.cache/
8+
/playwright/.auth/
9+
10+
# Translation server logs
11+
translation-server.log

cmp/compiler/package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,14 @@
117117
"clean": "rm -rf build",
118118
"test": "vitest --run",
119119
"test:watch": "vitest -w",
120-
"test:prepare": "tsx tests/helpers/prepare-fixtures.ts",
120+
"test:prepare": "pnpm build && tsx tests/helpers/prepare-fixtures.ts",
121121
"test:e2e": "playwright test",
122122
"test:e2e:next": "playwright test --grep next",
123123
"test:e2e:vite": "playwright test --grep vite",
124124
"test:e2e:shared": "playwright test tests/e2e/shared",
125125
"test:e2e:dev": "playwright test --ui",
126126
"test:e2e:debug": "playwright test --debug",
127-
"test:e2e:report": "playwright show-report",
128-
"playwright:install": "playwright install chromium"
127+
"test:e2e:report": "playwright show-report"
129128
},
130129
"keywords": [],
131130
"author": "",
@@ -140,7 +139,7 @@
140139
"@types/react": "^18.3.26",
141140
"@types/react-dom": "^19.2.3",
142141
"@types/ws": "^8.18.1",
143-
"next": "^16.0.3",
142+
"next": "^16.1.0",
144143
"tsdown": "^0.16.5",
145144
"tsx": "^4.19.2",
146145
"typescript": "^5.9.3",
@@ -172,8 +171,8 @@
172171
},
173172
"peerDependencies": {
174173
"next": "^15.0.0 || ^16.0.4",
175-
"react": "^18.0.0 || ^19.0.0",
176-
"react-dom": "^18.0.0 || ^19.0.0"
174+
"react": "^19.0.0",
175+
"react-dom": " ^19.0.0"
177176
},
178177
"peerDependenciesMeta": {
179178
"next": {

cmp/compiler/playwright.config.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { defineConfig, devices } from "@playwright/test";
2+
3+
/**
4+
* Read environment variables from file.
5+
* https://github.com/motdotla/dotenv
6+
*/
7+
// import dotenv from 'dotenv';
8+
// import path from 'path';
9+
// dotenv.config({ path: path.resolve(__dirname, '.env') });
10+
11+
/**
12+
* See https://playwright.dev/docs/test-configuration.
13+
*/
14+
export default defineConfig({
15+
testDir: "./tests",
16+
fullyParallel: false,
17+
/* Fail the build on CI if you accidentally left test.only in the source code. */
18+
forbidOnly: !!process.env.CI,
19+
/* Retry on CI only */
20+
retries: process.env.CI ? 2 : 0,
21+
/* Run tests sequentially with a single worker */
22+
workers: 1,
23+
/* Timeout for each test (includes beforeAll/afterAll hooks) */
24+
timeout: 180000, // 3 minutes - accounts for packing compiler, installing deps, starting servers
25+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
26+
reporter: "html",
27+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
28+
use: {
29+
/* Base URL to use in actions like `await page.goto('')`. */
30+
// baseURL: 'http://localhost:3000',
31+
32+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
33+
trace: "on-first-retry",
34+
/* Action timeout (individual page actions like click, fill, etc) */
35+
actionTimeout: 30000, // 30 seconds for individual actions
36+
},
37+
38+
/* Configure projects for major browsers */
39+
projects: [
40+
{
41+
name: "chromium",
42+
use: { ...devices["Desktop Chrome"] },
43+
},
44+
],
45+
});

cmp/compiler/src/react/shared/LingoProvider.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,7 @@ function LingoProvider__Dev({
468468
pendingCount: pendingHashesRef.current.size,
469469
position: devWidget?.position || "bottom-left",
470470
} satisfies LingoDevState;
471-
// Set WebSocket URL for widget to connect to translation server
472471
window.__LINGO_DEV_WS_URL__ = serverUrl;
473-
// Trigger widget update
474472
window.__LINGO_DEV_UPDATE__?.();
475473
}
476474
}, [isLoading, locale, sourceLocale, devWidget]);

cmp/compiler/src/react/shared/LocaleSwitcher.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export function LocaleSwitcher({
8787
...style,
8888
}}
8989
aria-label="Select language"
90+
data-testid="lingo-locale-switcher"
9091
>
9192
{locales.map((loc) => (
9293
<option key={loc.code} value={loc.code}>

cmp/compiler/tests/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Playwright artifacts
2+
playwright-report/
3+
test-results/
4+
5+
# Prepared fixtures (with node_modules)
6+
fixtures/

cmp/compiler/tests/QUICK_START.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# E2E Tests - Quick Start
2+
3+
## First Time Setup (5 minutes)
4+
5+
```bash
6+
# 1. Install dependencies
7+
pnpm install
8+
9+
# 2. Install Playwright browsers
10+
pnpm playwright:install
11+
12+
# 3. Prepare test fixtures (takes 2-3 minutes)
13+
pnpm test:prepare
14+
```
15+
16+
## Running Tests
17+
18+
```bash
19+
# Run all tests
20+
pnpm test:e2e
21+
22+
# Run in interactive UI mode (recommended for development)
23+
pnpm test:e2e:dev
24+
25+
# Run only shared tests
26+
pnpm test:e2e:shared
27+
28+
# Debug a specific test
29+
pnpm test:e2e:debug
30+
```
31+
32+
## How It Works
33+
34+
### Fast Test Execution Strategy
35+
36+
Instead of installing dependencies on every test run, we use a two-stage approach:
37+
38+
```
39+
┌─────────────────────────────────────────────────────────────┐
40+
│ Stage 1: Preparation (ONE TIME - run pnpm test:prepare) │
41+
├─────────────────────────────────────────────────────────────┤
42+
│ │
43+
│ demo/next16/ ──────┐ │
44+
│ ├──> tests/fixtures/next/ │
45+
│ + pnpm install ────┘ (with node_modules) │
46+
│ │
47+
│ demo/vite/ ──────┐ │
48+
│ ├──> tests/fixtures/vite/ │
49+
│ + pnpm install ────┘ (with node_modules) │
50+
│ │
51+
└─────────────────────────────────────────────────────────────┘
52+
53+
┌─────────────────────────────────────────────────────────────┐
54+
│ Stage 2: Test Execution (FAST - every test run) │
55+
├─────────────────────────────────────────────────────────────┤
56+
│ │
57+
│ tests/fixtures/next/ ──> /tmp/lingo-test-next-xyz/ │
58+
│ (copy with node_modules) (isolated test environment) │
59+
│ │
60+
│ ✅ No dependency installation needed │
61+
│ ✅ Each test gets clean copy │
62+
│ ✅ Fast execution (~seconds per test) │
63+
│ │
64+
└─────────────────────────────────────────────────────────────┘
65+
```
66+
67+
### Why This Approach?
68+
69+
**Without preparation:**
70+
71+
- ❌ Install deps on every test: ~2-3 min per test
72+
- ❌ Total test time: ~10-15 minutes for 5 tests
73+
74+
**With preparation:**
75+
76+
- ✅ Prepare once: ~2-3 minutes (one time)
77+
- ✅ Each test: ~10-30 seconds
78+
- ✅ Total test time: ~2-5 minutes for 5 tests
79+
80+
**10x faster test execution!**
81+
82+
## When to Re-run `pnpm test:prepare`
83+
84+
- When demo app `package.json` changes
85+
- When you update demo app dependencies
86+
- After pulling major changes to demo apps
87+
- If fixtures get corrupted
88+
89+
## Directory Structure
90+
91+
```
92+
tests/
93+
├── fixtures/ # ← Prepared fixtures (gitignored)
94+
│ ├── next/ # ← Next.js with node_modules
95+
│ └── vite/ # ← Vite with node_modules
96+
├── e2e/
97+
│ └── shared/
98+
│ └── development.test.ts
99+
└── helpers/
100+
├── prepare-fixtures.ts # ← Prepares fixtures
101+
└── setup-fixture.ts # ← Copies fixtures to temp dir
102+
```
103+
104+
## Example Test Flow
105+
106+
```typescript
107+
import { setupFixture } from "../../helpers/setup-fixture";
108+
109+
test("my test", async ({ page }) => {
110+
// 1. Copy prepared fixture to temp dir (fast - already has node_modules)
111+
const fixture = await setupFixture({ framework: "next" });
112+
113+
// 2. Start dev server (dependencies already installed)
114+
const devServer = await fixture.startDev();
115+
116+
try {
117+
// 3. Run your test
118+
await page.goto(`http://localhost:${devServer.port}`);
119+
// ... test assertions ...
120+
} finally {
121+
// 4. Cleanup
122+
devServer.stop();
123+
await fixture.clean();
124+
}
125+
});
126+
```
127+
128+
## CI/CD Integration
129+
130+
In CI, run both stages:
131+
132+
```yaml
133+
- name: Prepare fixtures
134+
run: pnpm test:prepare
135+
136+
- name: Run E2E tests
137+
run: pnpm test:e2e
138+
```
139+
140+
You could also cache the `tests/fixtures/` directory to speed up CI runs.

0 commit comments

Comments
 (0)