From 28418598e522b4500db276d1008142fbb36fa73e Mon Sep 17 00:00:00 2001 From: Tim van der Meij Date: Sat, 10 Feb 2024 18:21:34 +0100 Subject: [PATCH] Update `puppeteer` to version 22.0.0 This is a major version bump that requires two changes on our side: - The new headless mode is now the default, so we can remove our transformation code (see https://github.com/puppeteer/puppeteer/pull/11815). - The `page.waitForTimeout` API is removed. Sadly we still used it in the integration tests (but fortunately much less than before we worked on fixing intermittent failures), so until we remove the final occurrences we provide an implementation ourselves (see https://github.com/puppeteer/puppeteer/pull/11780). The full changelog can be found here: https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-core-v22.0.0 --- package-lock.json | 38 +++++++++------------ package.json | 2 +- test/integration/annotation_spec.mjs | 17 +++++----- test/integration/freetext_editor_spec.mjs | 9 ++--- test/integration/scripting_spec.mjs | 41 ++++++++++++----------- test/integration/test_utils.mjs | 21 ++++++++++-- test/test.mjs | 4 +-- 7 files changed, 72 insertions(+), 60 deletions(-) diff --git a/package-lock.json b/package-lock.json index 12de0c4ae..35908f182 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "postcss-discard-comments": "^6.0.1", "postcss-nesting": "^12.0.2", "prettier": "^3.2.5", - "puppeteer": "^21.11.0", + "puppeteer": "^22.0.0", "rimraf": "^3.0.2", "streamqueue": "^1.1.2", "stylelint": "^16.2.1", @@ -2633,9 +2633,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", - "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.0.0.tgz", + "integrity": "sha512-3PS82/5+tnpEaUWonjAFFvlf35QHF15xqyGd34GBa5oP5EPVfFXRsbSxIGYf1M+vZlqBZ3oxT1kRg9OYhtt8ng==", "dev": true, "dependencies": { "debug": "4.3.4", @@ -2650,7 +2650,7 @@ "browsers": "lib/cjs/main-cli.js" }, "engines": { - "node": ">=16.3.0" + "node": ">=18" } }, "node_modules/@puppeteer/browsers/node_modules/debug": { @@ -13371,7 +13371,6 @@ }, "node_modules/npm/node_modules/lodash._baseindexof": { "version": "3.1.0", - "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -13387,19 +13386,16 @@ }, "node_modules/npm/node_modules/lodash._bindcallback": { "version": "3.0.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._cacheindexof": { "version": "3.0.2", - "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._createcache": { "version": "3.1.2", - "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -13414,7 +13410,6 @@ }, "node_modules/npm/node_modules/lodash._getnative": { "version": "3.9.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -13432,7 +13427,6 @@ }, "node_modules/npm/node_modules/lodash.restparam": { "version": "3.6.1", - "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -17006,30 +17000,30 @@ } }, "node_modules/puppeteer": { - "version": "21.11.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.11.0.tgz", - "integrity": "sha512-9jTHuYe22TD3sNxy0nEIzC7ZrlRnDgeX3xPkbS7PnbdwYjl2o/z/YuCrRBwezdKpbTDTJ4VqIggzNyeRcKq3cg==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.0.0.tgz", + "integrity": "sha512-zYVnjwJngnSB4dbkWp7DHFSIc3nqHvZzrdHyo9+ugV1nq1Lm8obOMcmCFaGfR3PJs0EmYNz+/skBeO45yvASCQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@puppeteer/browsers": "1.9.1", + "@puppeteer/browsers": "2.0.0", "cosmiconfig": "9.0.0", - "puppeteer-core": "21.11.0" + "puppeteer-core": "22.0.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "node_modules/puppeteer-core": { - "version": "21.11.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", - "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.0.0.tgz", + "integrity": "sha512-S3s91rLde0A86PWVeNY82h+P0fdS7CTiNWAicCVH/bIspRP4nS2PnO5j+VTFqCah0ZJizGzpVPAmxVYbLxTc9w==", "dev": true, "dependencies": { - "@puppeteer/browsers": "1.9.1", + "@puppeteer/browsers": "2.0.0", "chromium-bidi": "0.5.8", "cross-fetch": "4.0.0", "debug": "4.3.4", @@ -17037,7 +17031,7 @@ "ws": "8.16.0" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "node_modules/puppeteer-core/node_modules/debug": { diff --git a/package.json b/package.json index 35e6afcce..ef68adcc7 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "postcss-discard-comments": "^6.0.1", "postcss-nesting": "^12.0.2", "prettier": "^3.2.5", - "puppeteer": "^21.11.0", + "puppeteer": "^22.0.0", "rimraf": "^3.0.2", "streamqueue": "^1.1.2", "stylelint": "^16.2.1", diff --git a/test/integration/annotation_spec.mjs b/test/integration/annotation_spec.mjs index 7c35b1e6e..4b5ad229c 100644 --- a/test/integration/annotation_spec.mjs +++ b/test/integration/annotation_spec.mjs @@ -18,6 +18,7 @@ import { getQuerySelector, getSelector, loadAndWait, + waitForTimeout, } from "./test_utils.mjs"; describe("Annotation highlight", () => { @@ -140,7 +141,7 @@ describe("Checkbox annotation", () => { ); for (const selector of selectors) { await page.click(selector); - page.waitForTimeout(10); + await waitForTimeout(10); } for (const selector of selectors) { await page.waitForFunction( @@ -199,7 +200,7 @@ describe("Text widget", () => { pages.map(async ([browserName, page]) => { await page.type(getSelector("22R"), "a"); await page.keyboard.press("Tab"); - await page.waitForTimeout(10); + await waitForTimeout(10); const text = await page.$eval(getSelector("22R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("aHello World"); @@ -485,12 +486,12 @@ describe("ResetForm action", () => { `document.querySelector("[data-annotation-id='25R']").hidden === false` ); await page.click("#editorFreeText"); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.waitForFunction( `document.querySelector("[data-annotation-id='25R']").hidden === true` ); await page.click("#editorFreeText"); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.waitForFunction( `document.querySelector("[data-annotation-id='25R']").hidden === false` ); @@ -553,7 +554,7 @@ describe("ResetForm action", () => { expect(hidden).withContext(`In ${browserName}`).toEqual(true); await page.focus("[data-annotation-id='20R']"); await page.keyboard.press("Enter"); - await page.waitForTimeout(10); + await waitForTimeout(10); hidden = await page.$eval( "[data-annotation-id='21R']", el => el.hidden @@ -561,7 +562,7 @@ describe("ResetForm action", () => { expect(hidden).withContext(`In ${browserName}`).toEqual(false); await page.keyboard.press("Enter"); - await page.waitForTimeout(10); + await waitForTimeout(10); hidden = await page.$eval( "[data-annotation-id='21R']", el => el.hidden @@ -569,7 +570,7 @@ describe("ResetForm action", () => { expect(hidden).withContext(`In ${browserName}`).toEqual(true); await page.keyboard.press("Enter"); - await page.waitForTimeout(10); + await waitForTimeout(10); hidden = await page.$eval( "[data-annotation-id='21R']", el => el.hidden @@ -577,7 +578,7 @@ describe("ResetForm action", () => { expect(hidden).withContext(`In ${browserName}`).toEqual(false); await page.keyboard.press("Escape"); - await page.waitForTimeout(10); + await waitForTimeout(10); hidden = await page.$eval( "[data-annotation-id='21R']", el => el.hidden diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 499d32011..f3cff4cea 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -43,6 +43,7 @@ import { waitForSelectedEditor, waitForSerialized, waitForStorageEntries, + waitForTimeout, waitForUnselectedEditor, } from "./test_utils.mjs"; import { PNG } from "pngjs"; @@ -52,7 +53,7 @@ const copyPaste = async page => { await kbCopy(page); await promise; - await page.waitForTimeout(10); + await waitForTimeout(10); promise = waitForEvent(page, "paste"); await kbPaste(page); @@ -1137,7 +1138,7 @@ describe("FreeText Editor", () => { await kbUndo(page); // Nothing should happen, it's why we can't wait for something // specific! - await page.waitForTimeout(200); + await waitForTimeout(200); // We check that the editor hasn't been removed. editorIds = await getEditors(page, "freeText"); @@ -1343,7 +1344,7 @@ describe("FreeText Editor", () => { // Enter in editing mode. await switchToFreeText(page); - await page.waitForTimeout(200); + await waitForTimeout(200); // Disable editing mode. await page.click("#editorFreeText"); @@ -2373,7 +2374,7 @@ describe("FreeText Editor", () => { // The editor must be moved in the DOM and potentially the focus // will be lost, hence there's a callback will get back the focus. - await page.waitForTimeout(200); + await waitForTimeout(200); const focused = await page.evaluate(sel => { const editor = document.querySelector(sel); diff --git a/test/integration/scripting_spec.mjs b/test/integration/scripting_spec.mjs index daa572920..5f29be1ef 100644 --- a/test/integration/scripting_spec.mjs +++ b/test/integration/scripting_spec.mjs @@ -27,6 +27,7 @@ import { loadAndWait, scrollIntoView, waitForEntryInStorage, + waitForTimeout, } from "./test_utils.mjs"; describe("Interaction", () => { @@ -1711,7 +1712,7 @@ describe("Interaction", () => { await clearInput(page, getSelector("27R")); await page.type(getSelector("27R"), exportValue); await page.click("[data-annotation-id='28R']"); - await page.waitForTimeout(10); + await waitForTimeout(10); value = await page.$eval(getSelector("24R"), el => el.value); expect(value).withContext(`In ${browserName}`).toEqual(exportValue); @@ -1758,7 +1759,7 @@ describe("Interaction", () => { await page.waitForFunction( `${getQuerySelector("30R")}.value !== "abc"` ); - await page.waitForTimeout(100); + await waitForTimeout(100); const focusedId = await page.evaluate(_ => window.document.activeElement.getAttribute("data-element-id") @@ -1854,7 +1855,7 @@ describe("Interaction", () => { expect(text).withContext(`In ${browserName}`).toEqual("00000000123"); await page.click(getSelector("26R")); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("25R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("00000000123"); @@ -1888,13 +1889,13 @@ describe("Interaction", () => { expect(text).withContext(`In ${browserName}`).toEqual("5,25"); await page.click(getSelector("22R")); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("22R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("5,25"); await page.click(getSelector("31R")); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("31R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("5.25"); @@ -1925,7 +1926,7 @@ describe("Interaction", () => { expect(text).withContext(`In ${browserName}`).toEqual(""); await page.select(getSelector("6R"), "Yes"); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("44R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("Yes"); @@ -1933,7 +1934,7 @@ describe("Interaction", () => { await clearInput(page, getSelector("44R")); await page.select(getSelector("6R"), "No"); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("44R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("No"); @@ -1990,14 +1991,14 @@ describe("Interaction", () => { await page.type(getSelector("26R"), "abcde", { delay: 10 }); await page.click(getSelector("23R")); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.click(getSelector("26R")); await kbSelectAll(page); await page.keyboard.press("Backspace"); await page.click(getSelector("23R")); - await page.waitForTimeout(10); + await waitForTimeout(10); text = await page.$eval(getSelector("26R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual(""); @@ -2093,7 +2094,7 @@ describe("Interaction", () => { expect(visibility).withContext(`In ${browserName}`).toEqual("hidden"); await page.click(getSelector("11R")); - await page.waitForTimeout(10); + await waitForTimeout(10); visibility = await page.$eval( getSelector("7R"), @@ -2139,28 +2140,28 @@ describe("Interaction", () => { ); expect(readonly).withContext(`In ${browserName}`).toEqual(true); await page.click(getSelector("334R")); - await page.waitForTimeout(10); + await waitForTimeout(10); readonly = await page.$eval(getSelector("353R"), el => el.disabled); expect(readonly).withContext(`In ${browserName}`).toEqual(true); await page.click(getSelector("351R")); - await page.waitForTimeout(10); + await waitForTimeout(10); readonly = await page.$eval(getSelector("353R"), el => el.disabled); expect(readonly).withContext(`In ${browserName}`).toEqual(true); await page.click(getSelector("352R")); - await page.waitForTimeout(10); + await waitForTimeout(10); readonly = await page.$eval(getSelector("353R"), el => el.disabled); expect(readonly).withContext(`In ${browserName}`).toEqual(false); await page.click(getSelector("353R")); - await page.waitForTimeout(10); + await waitForTimeout(10); let checked = await page.$eval(getSelector("353R"), el => el.checked); expect(checked).withContext(`In ${browserName}`).toEqual(true); await page.click(getSelector("334R")); - await page.waitForTimeout(10); + await waitForTimeout(10); readonly = await page.$eval(getSelector("353R"), el => el.disabled); expect(readonly).withContext(`In ${browserName}`).toEqual(true); @@ -2199,16 +2200,16 @@ describe("Interaction", () => { await page.click(getSelector("55R")); await page.type(getSelector("55R"), "Hello", { delay: 10 }); await page.click(getSelector("56R")); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.click(getSelector("55R")); await page.type(getSelector("55R"), " World", { delay: 10 }); - await page.waitForTimeout(10); + await waitForTimeout(10); await otherPages[i].bringToFront(); - await otherPages[i].waitForTimeout(100); + await waitForTimeout(100); await page.bringToFront(); - await page.waitForTimeout(100); + await waitForTimeout(100); const text = await page.$eval(getSelector("55R"), el => el.value); expect(text).withContext(`In ${browserName}`).toEqual("Hello World"); @@ -2243,7 +2244,7 @@ describe("Interaction", () => { ); await page.click(getSelector("25R")); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.click(getSelector("26R")); await page.waitForFunction( diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 4705a2f49..037b547a1 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -85,11 +85,27 @@ function closePages(pages) { ); } +function waitForTimeout(milliseconds) { + /** + * Wait for the given number of milliseconds. + * + * Note that waiting for an arbitrary time in tests is discouraged because it + * can easily cause intermittent failures, which is why this functionality is + * no longer provided by Puppeteer 22+ and we have to implement it ourselves + * for the remaining callers in the integration tests. We should avoid + * creating new usages of this function; instead please refer to the better + * alternatives at https://github.com/puppeteer/puppeteer/pull/11780. + */ + return new Promise(resolve => { + setTimeout(resolve, milliseconds); + }); +} + async function clearInput(page, selector) { await page.click(selector); await kbSelectAll(page); await page.keyboard.press("Backspace"); - await page.waitForTimeout(10); + await waitForTimeout(10); } function getSelector(id) { @@ -276,7 +292,7 @@ async function serializeBitmapDimensions(page) { async function dragAndDropAnnotation(page, startX, startY, tX, tY) { await page.mouse.move(startX, startY); await page.mouse.down(); - await page.waitForTimeout(10); + await waitForTimeout(10); await page.mouse.move(startX + tX, startY + tY); await page.mouse.up(); await page.waitForSelector("#viewer:not(.noUserSelect)"); @@ -487,5 +503,6 @@ export { waitForSerialized, waitForStorageEntries, waitForTextLayer, + waitForTimeout, waitForUnselectedEditor, }; diff --git a/test/test.mjs b/test/test.mjs index 26405e6fc..8928546d4 100644 --- a/test/test.mjs +++ b/test/test.mjs @@ -892,9 +892,7 @@ async function startBrowser({ browserName, headless, startUrl }) { const options = { product: browserName, protocol: "cdp", - // Note that using `headless: true` gives a deprecation warning; see - // https://github.com/puppeteer/puppeteer#default-runtime-settings. - headless: headless === true ? "new" : false, + headless, defaultViewport: null, ignoreDefaultArgs: ["--disable-extensions"], // The timeout for individual protocol (CDP) calls should always be lower