Skip to content

Commit e7acfb9

Browse files
committed
test: migrate E2E tests to puppeteer instead of protractor
1 parent 4f446a1 commit e7acfb9

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

tests/e2e/tests/build/jit-prod.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { getGlobalVariable } from '../../utils/env';
22
import { ng } from '../../utils/process';
33
import { updateJsonFile } from '../../utils/project';
4+
import { runE2eTest } from '../../utils/puppeteer';
45

56
export default async function () {
67
// Make prod use JIT.
@@ -18,5 +19,5 @@ export default async function () {
1819
});
1920

2021
// Test it works
21-
await ng('e2e', '--configuration=production');
22+
await runE2eTest({ configuration: 'production' });
2223
}

tests/e2e/utils/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ ts_project(
1515
"//:node_modules/@types/semver",
1616
"//:node_modules/fast-glob",
1717
"//:node_modules/protractor",
18+
"//:node_modules/puppeteer",
1819
"//:node_modules/semver",
1920
"//:node_modules/verdaccio",
2021
"//:node_modules/verdaccio-auth-memory",

tests/e2e/utils/puppeteer.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { type Page, launch } from 'puppeteer';
2+
import { execAndWaitForOutputToMatch, killAllProcesses } from './process';
3+
4+
export interface E2eTestOptions {
5+
project?: string;
6+
configuration?: string;
7+
baseUrl?: string;
8+
checkFn?: (page: Page) => Promise<void>;
9+
}
10+
11+
export async function runE2eTest(options: E2eTestOptions = {}) {
12+
let url = options.baseUrl;
13+
let hasStartedServer = false;
14+
15+
try {
16+
if (!url) {
17+
// Start serving
18+
const match = /open your browser on (http:\/\/localhost:\d+\/)/;
19+
const serveArgs = ['serve', '--port=0'];
20+
if (options.project) {
21+
serveArgs.push(options.project);
22+
}
23+
if (options.configuration) {
24+
serveArgs.push(`--configuration=${options.configuration}`);
25+
}
26+
27+
const { stdout } = await execAndWaitForOutputToMatch('ng', serveArgs, match);
28+
url = stdout.match(match)?.[1];
29+
if (!url) {
30+
throw new Error('Could not find serving URL');
31+
}
32+
hasStartedServer = true;
33+
}
34+
35+
const browser = await launch({ executablePath: process.env['CHROME_BIN'], headless: true });
36+
try {
37+
const page = await browser.newPage();
38+
39+
// Capture errors
40+
const errors: string[] = [];
41+
page.on('console', (msg) => {
42+
if (msg.type() === 'error') {
43+
errors.push(msg.text());
44+
}
45+
});
46+
page.on('pageerror', (err) => {
47+
errors.push(err.toString());
48+
});
49+
50+
await page.goto(url);
51+
52+
if (options.checkFn) {
53+
await options.checkFn(page);
54+
} else {
55+
// Default check: verify app-root exists
56+
await page.waitForSelector('app-root');
57+
}
58+
59+
if (errors.length > 0) {
60+
throw new Error(`Browser console errors detected:\n${errors.join('\n')}`);
61+
}
62+
} finally {
63+
await browser.close();
64+
}
65+
} finally {
66+
if (hasStartedServer) {
67+
await killAllProcesses();
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)