Update Puppeteer to version 20

This commit makes the following required changes:

- Replace custom cache trimming logic in favor of the (per our request)
  newly added `trimCache` method in Puppeteer. Not only does this greatly
  simplify our code and prevents having to import Puppeteer internals,
  it's also necessary because Puppeteer 20 removed the `BrowserFetcher`
  API in favor of the new separate `@puppeteer/browsers` package.
- Start browsers in series instead of in parallel. Parallel browser
  starts broke since Puppetter 19.1.0 and it turns out that it has never
  been supported officially, so it worked more-or-less by accident.
  Starting browsers in series is the supported way, is almost equally
  fast and ensures that we avoid any race conditions during startup.
  Finally, it also allows us to remove the `browserPromise` state on our
  session objects.

Fixes #15865.
This commit is contained in:
Tim van der Meij 2023-05-29 14:46:31 +02:00
parent 7f6f33da3c
commit ca620e4cc9
No known key found for this signature in database
GPG Key ID: 8C3FD2925A5F2762
3 changed files with 765 additions and 83 deletions

790
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,7 @@
"postcss": "^8.4.23", "postcss": "^8.4.23",
"postcss-dir-pseudo-class": "^7.0.2", "postcss-dir-pseudo-class": "^7.0.2",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"puppeteer": "^19.0.0", "puppeteer": "^20.4.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"streamqueue": "^1.1.2", "streamqueue": "^1.1.2",
"stylelint": "^15.6.2", "stylelint": "^15.6.2",

View File

@ -315,7 +315,7 @@ function startRefTest(masterMode, showRefImages) {
} }
} }
function setup() { async function setup() {
if (fs.existsSync(refsTmpDir)) { if (fs.existsSync(refsTmpDir)) {
console.error("tmp/ exists -- unable to proceed with testing"); console.error("tmp/ exists -- unable to proceed with testing");
process.exit(1); process.exit(1);
@ -334,7 +334,7 @@ function startRefTest(masterMode, showRefImages) {
onAllSessionsClosed = finalize; onAllSessionsClosed = finalize;
const startUrl = `http://${host}:${server.port}/test/test_slave.html`; const startUrl = `http://${host}:${server.port}/test/test_slave.html`;
startBrowsers(function (session) { await startBrowsers(function (session) {
session.masterMode = masterMode; session.masterMode = masterMode;
session.taskResults = {}; session.taskResults = {};
session.tasks = {}; session.tasks = {};
@ -795,39 +795,35 @@ function makeTestUrl(startUrl) {
}; };
} }
function startUnitTest(testUrl, name) { async function startUnitTest(testUrl, name) {
onAllSessionsClosed = onAllSessionsClosedAfterTests(name); onAllSessionsClosed = onAllSessionsClosedAfterTests(name);
startServer(); startServer();
server.hooks.POST.push(unitTestPostHandler); server.hooks.POST.push(unitTestPostHandler);
const startUrl = `http://${host}:${server.port}${testUrl}`; const startUrl = `http://${host}:${server.port}${testUrl}`;
startBrowsers(function (session) { await startBrowsers(function (session) {
session.numRuns = 0; session.numRuns = 0;
session.numErrors = 0; session.numErrors = 0;
}, makeTestUrl(startUrl)); }, makeTestUrl(startUrl));
} }
function startIntegrationTest() { async function startIntegrationTest() {
onAllSessionsClosed = onAllSessionsClosedAfterTests("integration"); onAllSessionsClosed = onAllSessionsClosedAfterTests("integration");
startServer(); startServer();
const { runTests } = require("./integration-boot.js"); const { runTests } = require("./integration-boot.js");
startBrowsers(function (session) { await startBrowsers(function (session) {
session.numRuns = 0; session.numRuns = 0;
session.numErrors = 0; session.numErrors = 0;
}); });
global.integrationBaseUrl = `http://${host}:${server.port}/build/generic/web/viewer.html`; global.integrationBaseUrl = `http://${host}:${server.port}/build/generic/web/viewer.html`;
global.integrationSessions = sessions; global.integrationSessions = sessions;
Promise.all(sessions.map(session => session.browserPromise)).then( const results = { runs: 0, failures: 0 };
async () => { await runTests(results);
const results = { runs: 0, failures: 0 }; sessions[0].numRuns = results.runs;
await runTests(results); sessions[0].numErrors = results.failures;
sessions[0].numRuns = results.runs; await Promise.all(sessions.map(session => closeSession(session.name)));
sessions[0].numErrors = results.failures;
await Promise.all(sessions.map(session => closeSession(session.name)));
}
);
} }
function unitTestPostHandler(req, res) { function unitTestPostHandler(req, res) {
@ -896,27 +892,6 @@ function unitTestPostHandler(req, res) {
} }
async function startBrowser(browserName, startUrl = "") { async function startBrowser(browserName, startUrl = "") {
const revisions =
require("puppeteer-core/lib/cjs/puppeteer/revisions.js").PUPPETEER_REVISIONS;
const wantedRevision =
browserName === "chrome" ? revisions.chromium : revisions.firefox;
// Remove other revisions than the one we want to use. Updating Puppeteer can
// cause a new revision to be used, and not removing older revisions causes
// the disk to fill up.
const browserFetcher = puppeteer.createBrowserFetcher({
product: browserName,
});
const localRevisions = await browserFetcher.localRevisions();
if (localRevisions.length > 1) {
for (const localRevision of localRevisions) {
if (localRevision !== wantedRevision) {
console.log(`Removing old ${browserName} revision ${localRevision}...`);
await browserFetcher.remove(localRevision);
}
}
}
const options = { const options = {
product: browserName, product: browserName,
headless: false, headless: false,
@ -974,7 +949,12 @@ async function startBrowser(browserName, startUrl = "") {
return browser; return browser;
} }
function startBrowsers(initSessionCallback, makeStartUrl = null) { async function startBrowsers(initSessionCallback, makeStartUrl = null) {
// Remove old browser revisions from Puppeteer's cache. Updating Puppeteer can
// cause new browser revisions to be downloaded, so trimming the cache will
// prevent the disk from filling up over time.
await puppeteer.default.trimCache();
const browserNames = options.noChrome ? ["firefox"] : ["firefox", "chrome"]; const browserNames = options.noChrome ? ["firefox"] : ["firefox", "chrome"];
sessions = []; sessions = [];
@ -995,7 +975,7 @@ function startBrowsers(initSessionCallback, makeStartUrl = null) {
sessions.push(session); sessions.push(session);
const startUrl = makeStartUrl ? makeStartUrl(browserName) : ""; const startUrl = makeStartUrl ? makeStartUrl(browserName) : "";
session.browserPromise = startBrowser(browserName, startUrl) await startBrowser(browserName, startUrl)
.then(function (browser) { .then(function (browser) {
session.browser = browser; session.browser = browser;
initSessionCallback?.(session); initSessionCallback?.(session);