Skip to content

Commit bcafb59

Browse files
committed
feat: e2e tests
1 parent 21605f6 commit bcafb59

File tree

9 files changed

+232
-317
lines changed

9 files changed

+232
-317
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
branches: [main]
5+
pull_request:
6+
branches: [main]
7+
jobs:
8+
test:
9+
timeout-minutes: 60
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v5.0.1
13+
# pnpm version is taken from package.json
14+
- name: Install pnpm
15+
uses: pnpm/action-setup@v4
16+
- name: Use Node.js 20
17+
uses: actions/setup-node@v6.0.0
18+
with:
19+
node-version: 20
20+
cache: "pnpm"
21+
- name: Install dependencies
22+
run: pnpm install
23+
- name: Install Playwright Browsers
24+
working-directory: ./compiler
25+
run: pnpm exec playwright install --with-deps
26+
- name: Prepare tests
27+
working-directory: ./compiler
28+
run: pnpm run test:prepare
29+
- name: Run tests
30+
working-directory: ./compiler
31+
run: pnpm run test:e2e
32+
- uses: actions/upload-artifact@v4
33+
if: ${{ !cancelled() }}
34+
with:
35+
name: playwright-report
36+
path: playwright-report/
37+
retention-days: 30

cmp/compiler/.github/workflows/playwright.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

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}>
Lines changed: 75 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import { expect, Page, test } from "@playwright/test";
1+
import { expect, test } from "@playwright/test";
22
import {
33
DevServer,
44
findTranslationServerPort,
55
setupFixture,
66
type TestFixture,
77
} from "../../helpers/setup-fixture";
8-
import { switchLocale } from "../../helpers/locale-switcher";
8+
import {
9+
getCurrentLocale,
10+
switchLocale,
11+
} from "../../helpers/locale-switcher"; /**
12+
* Development Mode Tests
13+
* These tests verify that the translation system works correctly in development mode
14+
*/
915

1016
/**
1117
* Development Mode Tests
@@ -15,33 +21,28 @@ import { switchLocale } from "../../helpers/locale-switcher";
1521
test.describe.serial("Development Mode", () => {
1622
test.describe.serial("Next.js", () => {
1723
let fixture: TestFixture;
18-
let page: Page;
1924
let devServer: DevServer;
2025

21-
test.beforeAll(async ({ browser }, testInfo) => {
26+
test.beforeAll(async ({}, testInfo) => {
2227
fixture = await setupFixture({ framework: "next" });
23-
const context = await browser.newContext();
24-
page = await context.newPage();
2528
devServer = await fixture.startDev();
26-
testInfo.setTimeout(180000);
2729
});
2830

2931
test.afterAll(async () => {
30-
// Stop dev server first, then clean up
32+
// Stop dev server, then clean up
3133
if (devServer) {
3234
await devServer.stop();
3335
// Give Windows time to release file handles
3436
await new Promise((resolve) => setTimeout(resolve, 1000));
3537
}
36-
await page?.close();
3738
await fixture?.clean();
3839
});
3940

40-
test("should start translation server on dev", async () => {
41-
// Wait for server to be ready
42-
await devServer.waitForReady();
41+
test.beforeEach(async ({ page }) => {
42+
await page.goto(`http://localhost:${devServer.port}`);
43+
});
4344

44-
// Check translation server is running
45+
test("should start translation server on dev", async ({}) => {
4546
const translationPort = await findTranslationServerPort();
4647
expect(translationPort).toBeGreaterThanOrEqual(60000);
4748
expect(translationPort).not.toBeNull();
@@ -55,15 +56,15 @@ test.describe.serial("Development Mode", () => {
5556
}
5657
});
5758

58-
test("should generate translations on demand in dev", async () => {
59+
test("should generate translations on demand in dev", async ({ page }) => {
5960
// Navigate to app
6061
await page.goto(`http://localhost:${devServer.port}`);
6162

6263
// Wait for page to load
63-
await page.waitForSelector("h1", { timeout: 30000 });
64-
const heading = await page.textContent("h1");
64+
const initialHeading = page.getByRole("heading", { level: 1 });
65+
await expect(initialHeading).toBeVisible();
66+
const heading = await initialHeading.textContent();
6567
expect(heading).toBeTruthy();
66-
console.log("Initial heading:", heading);
6768

6869
// Monitor translation requests
6970
const translationRequests: string[] = [];
@@ -75,14 +76,12 @@ test.describe.serial("Development Mode", () => {
7576
}
7677
});
7778

78-
// Use the locale switching utility
7979
console.log("Switching to German locale...");
8080
await switchLocale(page, "de");
8181

82-
// Wait a bit for translations to potentially load
83-
await page.waitForTimeout(2000);
84-
85-
const germanHeading = await page.textContent("h1");
82+
const germanHeading = await page
83+
.getByRole("heading", { level: 1 })
84+
.textContent();
8685
console.log("German heading:", germanHeading);
8786
expect(germanHeading).toBeTruthy();
8887

@@ -91,63 +90,46 @@ test.describe.serial("Development Mode", () => {
9190
console.log("✅ Translation changed the heading");
9291
} else {
9392
console.log(
94-
"⚠️ Heading unchanged (pseudo-translation may not modify all text)",
93+
"⚠️ Heading unchanged (pseudo-translation may not modify all text)",
9594
);
9695
}
9796

98-
await switchLocale(page, "en");
9997
// Verify translation request was made (optional check)
10098
console.log("Translation requests:", translationRequests);
99+
expect(translationRequests).toHaveLength(1);
101100
});
102101

103-
test("should handle hot reload with text changes", async () => {
102+
test("should handle hot reload with text changes", async ({ page }) => {
104103
await page.goto(`http://localhost:${devServer.port}`);
105104

106-
// Wait for initial render
107-
await page.waitForSelector("h1", { timeout: 30000 });
108-
const initialText = await page.textContent("h1");
105+
const initialHeading = page.getByRole("heading", { level: 1 });
106+
await expect(initialHeading).toBeVisible();
107+
const initialText = await initialHeading.textContent();
109108
expect(initialText).toBeTruthy();
110109

111-
// Modify the component
112-
const pagePath = "app/page.tsx";
113-
await fixture.updateFile(pagePath, (content) => {
110+
// Modify the component (cleanup is automatic via fixture.updateFile)
111+
await fixture.updateFile("app/page.tsx", (content) => {
114112
// Add a new text element
115113
return content.replace(
116114
"</main>",
117115
'<p data-testid="hot-reload-test">Hot reload works!</p></main>',
118116
);
119117
});
120118

121-
// Wait for hot reload
122-
await page.waitForSelector('[data-testid="hot-reload-test"]', {
123-
timeout: 15000,
124-
});
125-
const newElement = await page.textContent(
126-
'[data-testid="hot-reload-test"]',
127-
);
119+
const newElement = await page
120+
.getByTestId("hot-reload-test")
121+
.textContent();
128122
expect(newElement).toBe("Hot reload works!");
129-
130-
// Restore original content
131-
await fixture.updateFile(pagePath, (content) => {
132-
return content.replace(
133-
'<p data-testid="hot-reload-test">Hot reload works!</p>',
134-
"",
135-
);
136-
});
137123
});
138124
});
139125

140126
test.describe.serial("Vite", () => {
141127
let fixture: TestFixture;
142-
let page: Page;
143128
let devServer: DevServer;
144129

145-
test.beforeAll(async ({ browser }, testInfo) => {
130+
test.beforeAll(async ({}) => {
146131
fixture = await setupFixture({ framework: "vite" });
147-
const context = await browser.newContext();
148-
page = await context.newPage();
149132
devServer = await fixture.startDev();
150-
testInfo.setTimeout(180000); // 3 minutes timeout for packing and installing deps
151133
});
152134

153135
test.afterAll(async () => {
@@ -156,85 +138,66 @@ test.describe.serial("Development Mode", () => {
156138
// Give Windows time to release file handles
157139
await new Promise((resolve) => setTimeout(resolve, 1000));
158140
}
159-
await page?.close();
160141
await fixture?.clean();
161142
});
162143

163-
test("should start vite dev server and render page", async () => {
164-
// Wait for server to be ready
165-
await devServer.waitForReady();
144+
test.beforeEach(async ({ page }) => {
145+
await page.goto(`http://localhost:${devServer.port}`);
146+
});
166147

148+
test("should start vite dev server and render page", async ({ page }) => {
167149
// Navigate to app
168-
await page.goto(`http://localhost:${devServer.port}`);
169-
await page.waitForSelector("h1", { timeout: 30000 });
150+
const initialHeading = page.getByRole("heading", { level: 1 });
151+
await expect(initialHeading).toBeVisible();
170152

171-
const heading = await page.textContent("h1");
172-
console.log("Vite - Initial heading:", heading);
173-
expect(heading).toBeTruthy();
153+
const heading = await initialHeading.textContent();
174154
expect(heading).toContain("Welcome");
175155
});
176156

177-
test("should switch locales and verify translation system", async () => {
178-
const devServer = await fixture.startDev();
179-
180-
try {
181-
// Navigate to homepage
182-
await page.goto(`http://localhost:${devServer.port}`);
183-
await page.waitForSelector("h1", { timeout: 30000 });
184-
185-
const initialHeading = await page.textContent("h1");
186-
console.log("Vite - Initial heading:", initialHeading);
187-
expect(initialHeading).toBeTruthy();
188-
189-
// Check that LocaleSwitcher is present
190-
const select = page.locator('select[aria-label="Select language"]');
191-
await expect(select).toBeVisible();
192-
193-
// Switch to Spanish
194-
console.log("Vite - Switching to Spanish...");
195-
await switchLocale(page, "es");
196-
await page.waitForTimeout(2000);
197-
198-
const spanishHeading = await page.textContent("h1");
199-
console.log("Vite - Spanish heading:", spanishHeading);
200-
expect(spanishHeading).toBeTruthy();
201-
202-
if (spanishHeading !== initialHeading) {
203-
console.log("✅ Translation system changed the text");
204-
} else {
205-
console.log("⚠️ Text unchanged (pseudo-translation varies)");
206-
}
207-
await switchLocale(page, "en");
208-
} finally {
209-
await devServer.stop();
157+
test.only("should switch locales and verify translation system", async ({
158+
page,
159+
}) => {
160+
const initialHeading = page.getByRole("heading", { level: 1 });
161+
console.log("Vite - Initial heading:", initialHeading);
162+
await expect(initialHeading).toBeVisible();
163+
const initialHeadingText = await initialHeading.textContent();
164+
165+
// Switch to Spanish
166+
console.log("Vite - Switching to Spanish...");
167+
await switchLocale(page, "es");
168+
169+
const spanishHeading = page.getByRole("heading", { level: 1 });
170+
console.log("Vite - Spanish heading:", spanishHeading);
171+
await expect(spanishHeading).toBeVisible();
172+
const spanishHeadingText = await spanishHeading.textContent();
173+
174+
if (spanishHeadingText !== initialHeadingText) {
175+
console.log("✅ Translation system changed the text");
176+
} else {
177+
console.log("⚠️ Text unchanged");
210178
}
211179
});
212180

213-
test("should navigate between pages and persist locale", async () => {
214-
const devServer = await fixture.startDev();
215-
216-
// Navigate to homepage
217-
await page.goto(`http://localhost:${devServer.port}`);
218-
await page.waitForSelector("h1", { timeout: 30000 });
181+
test("should navigate between pages and persist locale", async ({
182+
page,
183+
}) => {
184+
const initialHeading = page.getByRole("heading", { level: 1 });
185+
await expect(initialHeading).toBeVisible();
186+
const newLocale = "fr";
219187

220188
// Switch to French
221-
console.log("Vite - Switching to French...");
222-
await switchLocale(page, "fr");
223-
await page.waitForTimeout(1000);
189+
console.log(`Vite - Switching to ${newLocale}...`);
190+
await switchLocale(page, newLocale);
224191

225192
// Navigate to about page
226-
await page.click('a[href="/about"]');
227-
await page.waitForSelector("h1", { timeout: 10000 });
228-
229-
const aboutHeading = await page.textContent("h1");
230-
console.log("Vite - About page heading:", aboutHeading);
231-
expect(aboutHeading).toBeTruthy();
193+
await page.getByTestId("about-link").click();
194+
const aboutHeading = page.getByRole("heading", { level: 1 });
195+
await expect(aboutHeading).toBeVisible();
232196

233197
// Verify locale persisted
234-
const select = page.locator('select[aria-label="Select language"]');
235-
const currentLocale = await select.inputValue();
236-
expect(currentLocale).toBe("fr");
237-
console.log("✅ Locale persisted across navigation");
198+
const currentLocale = await getCurrentLocale(page);
199+
expect(currentLocale).toBe(newLocale);
200+
console.log(`✅ Locale persisted across navigation to ${newLocale}`);
238201
});
239202
});
240203
});

0 commit comments

Comments
 (0)