Skip to content

Commit c12b5f9

Browse files
authored
feat: provide launch and startServer functions as single source of truth for creating new browser/server instance within monorepo (microsoft#26375)
* feat(scripts-pupeteer): provide launch function as single source of truth for creating new browser instance * chore: bump puppeteer to v17 * refactor(scripts): make startServer generic and used everywhere
1 parent bd18313 commit c12b5f9

17 files changed

+319
-229
lines changed

apps/ssr-tests-v9/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"devDependencies": {
2626
"@fluentui/eslint-plugin": "*",
2727
"@fluentui/scripts-tasks": "*",
28-
"@fluentui/scripts-storybook": "*"
28+
"@fluentui/scripts-storybook": "*",
29+
"@fluentui/scripts-puppeteer": "*"
2930
}
3031
}

apps/ssr-tests-v9/src/test.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ async function test(): Promise<void> {
1515
const startTime = process.hrtime();
1616
console.log('Starting a browser...');
1717

18+
const htmlPath = path.resolve(__dirname, '..', 'dist', 'index.html');
19+
20+
if (!fs.existsSync(htmlPath)) {
21+
throw new Error('"dist/index.html" does not exist, please run "yarn build" first');
22+
}
23+
1824
let browser: Browser | undefined;
1925

2026
try {
2127
browser = await launchBrowser();
2228
console.log('Using', await browser.version());
2329

24-
const htmlPath = path.resolve(__dirname, '..', 'dist', 'index.html');
25-
26-
if (!fs.existsSync(htmlPath)) {
27-
throw new Error('"dist/index.html" does not exist, please run "yarn build" first');
28-
}
29-
3030
const url = `file://${htmlPath}`;
3131
console.log(`Using "${url}"`);
3232

+1-23
Original file line numberDiff line numberDiff line change
@@ -1,23 +1 @@
1-
import { Browser, launch } from 'puppeteer';
2-
3-
export async function launchBrowser(): Promise<Browser> {
4-
let browser;
5-
let attempt = 1;
6-
7-
while (!browser) {
8-
try {
9-
browser = await launch();
10-
} catch (err) {
11-
if (attempt === 5) {
12-
console.error(`Failed to launch a browser after 5 attempts...`);
13-
throw err;
14-
}
15-
16-
console.warn('A browser failed to start, retrying...');
17-
console.warn(err);
18-
attempt++;
19-
}
20-
}
21-
22-
return browser;
23-
}
1+
export { launch as launchBrowser } from '@fluentui/scripts-puppeteer';

apps/ssr-tests-v9/src/utils/visitPage.test.ts

-34
This file was deleted.

apps/ssr-tests-v9/src/utils/visitPage.ts

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,11 @@
1-
import type { Browser, Page } from 'puppeteer';
1+
import type { Browser } from 'puppeteer';
2+
import { visitUrl } from '@fluentui/scripts-puppeteer';
23
import { PROVIDER_ID } from './constants';
34

45
class RenderError extends Error {
56
public name = 'RangeError';
67
}
78

8-
export async function visitUrl(page: Page, url: string) {
9-
let attempt = 1;
10-
11-
while (attempt <= 5) {
12-
try {
13-
await page.goto(url, { timeout: 10 * 1000 /* 10 seconds */ });
14-
break;
15-
} catch (err) {
16-
if (attempt === 5) {
17-
console.error(`Failed to navigate to a page after 5 attempts...`);
18-
throw err;
19-
}
20-
21-
console.warn('A browser failed to navigate to a page, retrying...');
22-
console.warn(err);
23-
24-
attempt++;
25-
}
26-
}
27-
}
28-
299
export async function visitPage(browser: Browser, url: string) {
3010
const page = await browser.newPage();
3111
await page.setRequestInterception(true);

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@
291291
"pretty-bytes": "5.6.0",
292292
"progress": "2.0.3",
293293
"prompts": "2.4.2",
294-
"puppeteer": "14.4.0",
294+
"puppeteer": "17.1.3",
295295
"raw-loader": "4.0.2",
296296
"react": "17.0.2",
297297
"react-app-polyfill": "2.0.0",

scripts/gulp/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@fluentui/scripts-utils": "*",
1616
"@fluentui/scripts-prettier": "*",
1717
"@fluentui/scripts-puppeteer": "*",
18-
"@fluentui/scripts-babel": "*"
18+
"@fluentui/scripts-babel": "*",
19+
"@fluentui/scripts-projects-test": "*"
1920
}
2021
}

scripts/gulp/src/tasks/browserAdapters.ts

+7-26
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { spawn, spawnSync } from 'child_process';
2-
import CDP from 'chrome-remote-interface';
3-
import puppeteer from 'puppeteer';
42
import * as net from 'net';
53

6-
import { safeLaunchOptions } from '@fluentui/scripts-puppeteer';
4+
import { launch } from '@fluentui/scripts-puppeteer';
5+
import CDP from 'chrome-remote-interface';
76

87
export type Page = {
98
executeJavaScript: <R>(code: string) => Promise<R>;
@@ -17,39 +16,24 @@ export type Browser = {
1716
};
1817

1918
export async function createChrome(): Promise<Browser> {
20-
const options = safeLaunchOptions();
21-
let browser: puppeteer.Browser | undefined;
22-
let attempt = 1;
23-
while (!browser) {
24-
try {
25-
browser = await puppeteer.launch(options);
26-
} catch (err) {
27-
if (attempt === 5) {
28-
console.error(`Puppeteer failed to launch after 5 attempts`);
29-
throw err;
30-
}
31-
console.warn('Puppeteer failed to launch (will retry):');
32-
console.warn(err);
33-
attempt++;
34-
}
35-
}
19+
const browser = await launch();
3620

3721
console.log(`Chromium version: ${await browser.version()}`);
3822

3923
return {
4024
openPage: async url => {
41-
const page = await (browser as puppeteer.Browser).newPage();
25+
const page = await browser.newPage();
4226

4327
await page.goto(url);
4428

4529
return {
4630
executeJavaScript: async code => {
4731
return page.evaluate(code);
4832
},
49-
close: async () => page.close(),
33+
close: () => page.close(),
5034
};
5135
},
52-
close: async () => (browser as puppeteer.Browser).close(),
36+
close: () => browser.close(),
5337
};
5438
}
5539

@@ -137,9 +121,6 @@ export async function createElectron(electronPath: string): Promise<Browser> {
137121
},
138122
};
139123
},
140-
141-
// FIXME: this async is not necessary
142-
// eslint-disable-next-line @typescript-eslint/no-empty-function
143-
close: async () => {},
124+
close: () => Promise.resolve(),
144125
};
145126
}

scripts/gulp/src/tasks/serve.ts

+18-35
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,27 @@
1-
import express from 'express';
1+
import type { Server } from 'http';
22

3+
import { closeServer, startServer } from '@fluentui/scripts-projects-test';
34
import historyApiFallback from 'connect-history-api-fallback';
4-
import { Server } from 'http';
5-
import { colors, log } from 'gulp-util';
5+
import type { Express } from 'express';
66

7-
type Express = ReturnType<typeof express>;
8-
9-
export const serve = (
7+
export const serve = async (
108
directoryPath: string,
119
host: string,
1210
port: number,
13-
configureMiddleware: (express: Express) => Express = app => app,
11+
configureMiddleware = (app: Express) => app,
1412
): Promise<Server> => {
15-
return new Promise((resolve, reject) => {
16-
try {
17-
const server = configureMiddleware(
18-
express().use(
19-
historyApiFallback({
20-
verbose: false,
21-
}),
22-
),
23-
)
24-
.use(express.static(directoryPath))
25-
.listen(port, host, () => {
26-
log(colors.yellow(`Server running at http://${host}:${port}`));
27-
resolve(server);
28-
});
29-
} catch (err) {
30-
reject(err);
31-
}
32-
});
33-
};
13+
const middleware = (app: Express) => {
14+
return configureMiddleware(
15+
app.use(
16+
historyApiFallback({
17+
verbose: false,
18+
}),
19+
),
20+
);
21+
};
3422

35-
export const forceClose = (server: Server): Promise<void> => {
36-
if (!server) {
37-
return Promise.resolve();
38-
}
39-
40-
return new Promise((resolve, reject) => {
41-
server.keepAliveTimeout = 1000;
42-
server.close(err => (err ? reject(err) : resolve()));
43-
});
23+
const { server } = await startServer({ root: directoryPath, host, port }, middleware);
24+
return server;
4425
};
26+
27+
export const forceClose = closeServer;

scripts/projects-test/src/index.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export * from './createReactApp';
2-
export * from './packPackages';
3-
export * from './performBrowserTest';
4-
export * from './utils';
1+
export { prepareCreateReactApp } from './createReactApp';
2+
export { addResolutionPathsForProjectPackages, packProjectPackages } from './packPackages';
3+
export { performBrowserTest, startServer, closeServer } from './performBrowserTest';
4+
export { createTempDir, generateFiles, log, prepareTempDirs, shEcho, workspaceRoot } from './utils';
5+
export type { TempPaths } from './utils';

0 commit comments

Comments
 (0)