diff options
Diffstat (limited to 'remote/test/puppeteer')
262 files changed, 10797 insertions, 8221 deletions
diff --git a/remote/test/puppeteer/.eslintrc.js b/remote/test/puppeteer/.eslintrc.js index 250aa0c169..6bd3e4538d 100644 --- a/remote/test/puppeteer/.eslintrc.js +++ b/remote/test/puppeteer/.eslintrc.js @@ -150,7 +150,7 @@ module.exports = { // Enforces consistent file extension 'rulesdir/extensions': 'error', // Enforces license headers on files - 'rulesdir/check-license': 'warn', + 'rulesdir/check-license': 'error', }, overrides: [ { @@ -172,8 +172,6 @@ module.exports = { curly: ['error', 'all'], // Brackets keep code readable and `return` intentions clear. 'arrow-body-style': ['error', 'always'], - // Error if comments do not adhere to `tsdoc`. - 'tsdoc/syntax': 'error', // Keeps array types simple only when they are simple for readability. '@typescript-eslint/array-type': ['error', {default: 'array-simple'}], 'no-unused-vars': 'off', @@ -277,5 +275,14 @@ module.exports = { }, ], }, + + { + // Applies to only published packages + files: ['packages/**/*.ts'], + rules: { + // Error if comments do not adhere to `tsdoc`. + 'tsdoc/syntax': 'error', + }, + }, ], }; diff --git a/remote/test/puppeteer/.npmrc b/remote/test/puppeteer/.npmrc index 94a06c2180..1f6bc691f6 100644 --- a/remote/test/puppeteer/.npmrc +++ b/remote/test/puppeteer/.npmrc @@ -1 +1,2 @@ access=public +install-strategy=nested diff --git a/remote/test/puppeteer/.release-please-manifest.json b/remote/test/puppeteer/.release-please-manifest.json index 1237fb11dd..a3ccb1a4ae 100644 --- a/remote/test/puppeteer/.release-please-manifest.json +++ b/remote/test/puppeteer/.release-please-manifest.json @@ -1,7 +1,7 @@ { - "packages/puppeteer": "21.10.0", - "packages/puppeteer-core": "21.10.0", + "packages/puppeteer": "22.4.0", + "packages/puppeteer-core": "22.4.0", "packages/testserver": "0.6.0", - "packages/ng-schematics": "0.5.6", - "packages/browsers": "1.9.1" + "packages/ng-schematics": "0.6.0", + "packages/browsers": "2.1.0" } diff --git a/remote/test/puppeteer/README.md b/remote/test/puppeteer/README.md index 74a15c6eb9..288a5b623c 100644 --- a/remote/test/puppeteer/README.md +++ b/remote/test/puppeteer/README.md @@ -181,7 +181,7 @@ import puppeteer from 'puppeteer'; **1. Uses Headless mode** By default Puppeteer launches Chrome in -[old Headless mode](https://developer.chrome.com/articles/new-headless/). +[the Headless mode](https://developer.chrome.com/articles/new-headless/). ```ts const browser = await puppeteer.launch(); @@ -189,12 +189,16 @@ const browser = await puppeteer.launch(); const browser = await puppeteer.launch({headless: true}); ``` -[Chrome 112 launched a new Headless mode](https://developer.chrome.com/articles/new-headless/) that might cause some differences in behavior compared to the old Headless implementation. -In the future Puppeteer will start defaulting to new implementation. -We recommend you try it out before the switch: +Before v22, Puppeteer launched the [old Headless mode](https://developer.chrome.com/articles/new-headless/) by default. +The old headless mode is now known as +[`chrome-headless-shell`](https://developer.chrome.com/blog/chrome-headless-shell) +and ships as a separate binary. `chrome-headless-shell` does not match the +behavior of the regular Chrome completely but it is currently more performant +for automation tasks where the complete Chrome feature set is not needed. If the performance +is more important for your use case, switch to `chrome-headless-shell` as following: ```ts -const browser = await puppeteer.launch({headless: 'new'}); +const browser = await puppeteer.launch({headless: 'shell'}); ``` To launch a "headful" version of Chrome, set the diff --git a/remote/test/puppeteer/examples/README.md b/remote/test/puppeteer/examples/README.md index f20c2e7162..92e83eb39c 100644 --- a/remote/test/puppeteer/examples/README.md +++ b/remote/test/puppeteer/examples/README.md @@ -36,8 +36,4 @@ Other useful tools, articles, and projects that use Puppeteer. - [puppeteer-loadtest](https://github.com/svenkatreddy/puppeteer-loadtest) - commandline interface for performing load test on puppeteer scripts. - [cucumber-puppeteer-example](https://github.com/mlampedx/cucumber-puppeteer-example) - Example repository demonstrating how to use Puppeeteer and Cucumber for integration testing. -## Services - -- [Checkly](https://checklyhq.com) - Monitoring SaaS that uses Puppeteer to check availability and correctness of web pages and apps. -- [Doppio](https://doppio.sh) - SaaS API to create screenshots or PDFs from HTML/CSS/JS -- [Doczilla](https://www.doczilla.app) - SaaS API empowering the generation of screenshots or PDFs directly from HTML/CSS/JS code. +Also, see the [community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer) for more examples. diff --git a/remote/test/puppeteer/examples/cross-browser.js b/remote/test/puppeteer/examples/cross-browser.js index 0f972a0b70..037dba2482 100644 --- a/remote/test/puppeteer/examples/cross-browser.js +++ b/remote/test/puppeteer/examples/cross-browser.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ const puppeteer = require('puppeteer'); /** diff --git a/remote/test/puppeteer/moz.yaml b/remote/test/puppeteer/moz.yaml index 5f732140c9..35363b67dc 100644 --- a/remote/test/puppeteer/moz.yaml +++ b/remote/test/puppeteer/moz.yaml @@ -5,6 +5,6 @@ origin: description: Headless Chrome Node API license: Apache-2.0 name: puppeteer - release: puppeteer-v21.10.0 + release: puppeteer-v22.4.0 url: ../puppeteer schema: 1 diff --git a/remote/test/puppeteer/package-lock.json b/remote/test/puppeteer/package-lock.json index 76878ce829..b1fb3b0189 100644 --- a/remote/test/puppeteer/package-lock.json +++ b/remote/test/puppeteer/package-lock.json @@ -19,34 +19,34 @@ "@actions/core": "1.10.1", "@types/mocha": "10.0.6", "@types/node": "20.8.4", - "@types/semver": "7.5.6", + "@types/semver": "7.5.8", "@types/sinon": "17.0.3", - "@typescript-eslint/eslint-plugin": "6.19.1", - "@typescript-eslint/parser": "6.19.1", - "esbuild": "0.20.0", - "eslint": "8.56.0", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", + "esbuild": "0.20.1", + "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "2.29.1", - "eslint-plugin-mocha": "10.2.0", + "eslint-plugin-mocha": "10.3.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-rulesdir": "0.2.2", "eslint-plugin-tsdoc": "0.2.17", - "eslint-plugin-unused-imports": "3.0.0", + "eslint-plugin-unused-imports": "3.1.0", "execa": "8.0.1", "expect": "29.7.0", "gts": "5.2.0", "hereby": "1.8.9", "license-checker": "25.0.1", - "mocha": "10.2.0", - "npm-run-all": "4.1.5", - "prettier": "3.2.4", - "semver": "7.5.4", + "mocha": "10.3.0", + "npm-run-all2": "6.1.2", + "prettier": "3.2.5", + "semver": "7.6.0", "sinon": "17.0.1", "source-map-support": "0.5.21", "spdx-satisfies": "5.0.1", - "tsd": "0.30.4", - "tsx": "4.7.0", + "tsd": "0.30.7", + "tsx": "4.7.1", "typescript": "5.3.3", "wireit": "0.14.4" } @@ -247,374 +247,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz", - "integrity": "sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.0.tgz", - "integrity": "sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz", - "integrity": "sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.0.tgz", - "integrity": "sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz", - "integrity": "sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz", - "integrity": "sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz", - "integrity": "sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz", - "integrity": "sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz", - "integrity": "sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz", - "integrity": "sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz", - "integrity": "sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz", - "integrity": "sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz", - "integrity": "sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz", - "integrity": "sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz", - "integrity": "sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz", - "integrity": "sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz", - "integrity": "sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz", - "integrity": "sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz", - "integrity": "sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz", - "integrity": "sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz", - "integrity": "sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz", - "integrity": "sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz", - "integrity": "sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -684,15 +316,6 @@ "node": "*" } }, - "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@fastify/busboy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", @@ -897,9 +520,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -920,29 +543,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@ljharb/through": { - "version": "2.3.12", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", - "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/@microsoft/api-documenter": { - "version": "7.23.20", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.20.tgz", - "integrity": "sha512-61V6sukyYZ5jQEdyvDFzInaIRTd0wgT2ECKPanr2ba0fc+Mien+KIr5shz9EAqJMZz0GifTnw9HmJqsfR688xA==", + "version": "7.23.35", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.35.tgz", + "integrity": "sha512-zSHTX0abumOsfA3GsWJADFtiqxgwcoSCGSO+84e4s/SWotAqlUwXMYVJk6/huJFKSL+LG46gvcn7r8bsOd3K2Q==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2", - "@rushstack/ts-command-line": "4.17.1", - "colors": "~1.2.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.0", "js-yaml": "~3.13.1", "resolve": "~1.22.1" }, @@ -950,6 +561,60 @@ "api-documenter": "bin/api-documenter" } }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.0.tgz", + "integrity": "sha512-0sIHWOFGLFb6tC1zk2R0aM79ic3CF0XGzVBvhf6ytMyjDwt03DVb1qe5/5NQ0FGcvB5YyQ2WVfGsnxG6SANvHA==", + "dev": true, + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/@microsoft/api-documenter/node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -963,20 +628,27 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@microsoft/api-documenter/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/@microsoft/api-extractor": { - "version": "7.39.4", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.39.4.tgz", - "integrity": "sha512-6YvfkpbEqRQ0UPdVBc+lOiq7VlXi9kw8U3w+RcXCFDVc/UljlXU5l9fHEyuBAW1GGO2opUe+yf9OscWhoHANhg==", + "version": "7.42.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.42.2.tgz", + "integrity": "sha512-HYiOQDO4WR+Pj4XQZZE5qK5R6e3MF6Ut5s+Hi2IkeI6MiCXkdmRugQH6ppc9YzTUiydRqZ+jshZD7UWNGSA8bg==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.64.2", - "@rushstack/rig-package": "0.5.1", - "@rushstack/ts-command-line": "4.17.1", - "colors": "~1.2.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.0", "lodash": "~4.17.15", + "minimatch": "~3.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", @@ -987,14 +659,111 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.7", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.7.tgz", - "integrity": "sha512-4gCGGEQGHmbQmarnDcEWS2cjj0LtNuD3D6rh3ZcAyAYTkceAugAk2eyQHGdTcGX8w3qMjWCTU1TPb8xHnMM+Kg==", + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.0.tgz", + "integrity": "sha512-0sIHWOFGLFb6tC1zk2R0aM79ic3CF0XGzVBvhf6ytMyjDwt03DVb1qe5/5NQ0FGcvB5YyQ2WVfGsnxG6SANvHA==", + "dev": true, + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line/node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@microsoft/tsdoc": { @@ -1063,268 +832,6 @@ "node": ">= 8" } }, - "node_modules/@npmcli/agent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", - "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", - "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", - "dev": true, - "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", - "dev": true, - "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/installed-package-contents/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", - "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", - "dev": true, - "dependencies": { - "@npmcli/git": "^5.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/package-json/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/@npmcli/package-json/node_modules/normalize-package-data": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", - "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", - "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", - "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", - "dev": true, - "dependencies": { - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", - "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", - "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^10.0.0", - "which": "^4.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1351,12 +858,12 @@ "link": true }, "node_modules/@prettier/sync": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.0.tgz", - "integrity": "sha512-1a6veNypZYkSbU33anha4Pdna9Jz3HXUc0aru7sgN7HuyJHPIVNdCTfjhm1S+mG9yXmWuAO+a6I+Cznp9Ogt3A==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.5.1.tgz", + "integrity": "sha512-tpF+A1e4ynO2U4fTH21Sjgm9EYENmqg4zmJCMLrmLVfzIzuDc1cKGXyxrxbFgcH8qQRfowyDCZFAUukwhiZlsw==", "dev": true, "dependencies": { - "make-synchronized": "^0.2.5" + "make-synchronized": "^0.2.8" }, "funding": { "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" @@ -1398,12 +905,11 @@ "link": true }, "node_modules/@rushstack/node-core-library": { - "version": "3.64.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.64.2.tgz", - "integrity": "sha512-n1S2VYEklONiwKpUyBq/Fym6yAsfsCXrqFabuOMcCuj4C+zW+HyaspSHXJCKqkMxfjviwe/c9+DUqvRWIvSN9Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", "dev": true, "dependencies": { - "colors": "~1.2.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", @@ -1420,98 +926,29 @@ } } }, - "node_modules/@rushstack/rig-package": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", - "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", - "dev": true, - "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" - } - }, - "node_modules/@rushstack/ts-command-line": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", - "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", - "dev": true, - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" - } - }, - "node_modules/@sigstore/bundle": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", - "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/core": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", - "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", - "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.0" + "lru-cache": "^6.0.0" }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", - "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", - "dev": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.2.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=10" } }, - "node_modules/@sigstore/verify": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", - "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "node_modules/@rushstack/rig-package": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" } }, "node_modules/@sinclair/typebox": { @@ -1565,13 +1002,13 @@ "dev": true }, "node_modules/@swc/core": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz", - "integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.2.tgz", + "integrity": "sha512-vWgY07R/eqj1/a0vsRKLI9o9klGZfpLNOVEnrv4nrccxBgYPjcf22IWwAoaBJ+wpA7Q4fVjCUM8lP0m01dpxcg==", "dev": true, "hasInstallScript": true, "dependencies": { - "@swc/counter": "^0.1.1", + "@swc/counter": "^0.1.2", "@swc/types": "^0.1.5" }, "engines": { @@ -1582,16 +1019,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.107", - "@swc/core-darwin-x64": "1.3.107", - "@swc/core-linux-arm-gnueabihf": "1.3.107", - "@swc/core-linux-arm64-gnu": "1.3.107", - "@swc/core-linux-arm64-musl": "1.3.107", - "@swc/core-linux-x64-gnu": "1.3.107", - "@swc/core-linux-x64-musl": "1.3.107", - "@swc/core-win32-arm64-msvc": "1.3.107", - "@swc/core-win32-ia32-msvc": "1.3.107", - "@swc/core-win32-x64-msvc": "1.3.107" + "@swc/core-darwin-arm64": "1.4.2", + "@swc/core-darwin-x64": "1.4.2", + "@swc/core-linux-arm-gnueabihf": "1.4.2", + "@swc/core-linux-arm64-gnu": "1.4.2", + "@swc/core-linux-arm64-musl": "1.4.2", + "@swc/core-linux-x64-gnu": "1.4.2", + "@swc/core-linux-x64-musl": "1.4.2", + "@swc/core-win32-arm64-msvc": "1.4.2", + "@swc/core-win32-ia32-msvc": "1.4.2", + "@swc/core-win32-x64-msvc": "1.4.2" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -1602,10 +1039,10 @@ } } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.107.tgz", - "integrity": "sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==", + "node_modules/@swc/core/node_modules/@swc/core-darwin-arm64": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.2.tgz", + "integrity": "sha512-1uSdAn1MRK5C1m/TvLZ2RDvr0zLvochgrZ2xL+lRzugLlCTlSA+Q4TWtrZaOz+vnnFVliCpw7c7qu0JouhgQIw==", "cpu": [ "arm64" ], @@ -1618,10 +1055,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.107.tgz", - "integrity": "sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==", + "node_modules/@swc/core/node_modules/@swc/core-darwin-x64": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.2.tgz", + "integrity": "sha512-TYD28+dCQKeuxxcy7gLJUCFLqrwDZnHtC2z7cdeGfZpbI2mbfppfTf2wUPzqZk3gEC96zHd4Yr37V3Tvzar+lQ==", "cpu": [ "x64" ], @@ -1634,10 +1071,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.107.tgz", - "integrity": "sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.2.tgz", + "integrity": "sha512-Eyqipf7ZPGj0vplKHo8JUOoU1un2sg5PjJMpEesX0k+6HKE2T8pdyeyXODN0YTFqzndSa/J43EEPXm+rHAsLFQ==", "cpu": [ "arm" ], @@ -1650,10 +1087,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.107.tgz", - "integrity": "sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.2.tgz", + "integrity": "sha512-wZn02DH8VYPv3FC0ub4my52Rttsus/rFw+UUfzdb3tHMHXB66LqN+rR0ssIOZrH6K+VLN6qpTw9VizjyoH0BxA==", "cpu": [ "arm64" ], @@ -1666,10 +1103,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.107.tgz", - "integrity": "sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==", + "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.2.tgz", + "integrity": "sha512-3G0D5z9hUj9bXNcwmA1eGiFTwe5rWkuL3DsoviTj73TKLpk7u64ND0XjEfO0huVv4vVu9H1jodrKb7nvln/dlw==", "cpu": [ "arm64" ], @@ -1682,10 +1119,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.107.tgz", - "integrity": "sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==", + "node_modules/@swc/core/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.2.tgz", + "integrity": "sha512-LFxn9U8cjmYHw3jrdPNqPAkBGglKE3tCZ8rA7hYyp0BFxuo7L2ZcEnPm4RFpmSCCsExFH+LEJWuMGgWERoktvg==", "cpu": [ "x64" ], @@ -1698,10 +1135,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.107.tgz", - "integrity": "sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==", + "node_modules/@swc/core/node_modules/@swc/core-linux-x64-musl": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.2.tgz", + "integrity": "sha512-dp0fAmreeVVYTUcb4u9njTPrYzKnbIH0EhH2qvC9GOYNNREUu2GezSIDgonjOXkHiTCvopG4xU7y56XtXj4VrQ==", "cpu": [ "x64" ], @@ -1714,10 +1151,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.107.tgz", - "integrity": "sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.2.tgz", + "integrity": "sha512-HlVIiLMQkzthAdqMslQhDkoXJ5+AOLUSTV6fm6shFKZKqc/9cJvr4S8UveNERL9zUficA36yM3bbfo36McwnvQ==", "cpu": [ "arm64" ], @@ -1730,10 +1167,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.107.tgz", - "integrity": "sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.2.tgz", + "integrity": "sha512-WCF8faPGjCl4oIgugkp+kL9nl3nUATlzKXCEGFowMEmVVCFM0GsqlmGdPp1pjZoWc9tpYanoXQDnp5IvlDSLhA==", "cpu": [ "ia32" ], @@ -1746,10 +1183,10 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.107", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.107.tgz", - "integrity": "sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==", + "node_modules/@swc/core/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.2.tgz", + "integrity": "sha512-oV71rwiSpA5xre2C5570BhCsg1HF97SNLsZ/12xv7zayGzqr3yvFALFJN8tHKpqUdCB4FGPjoP3JFdV3i+1wUw==", "cpu": [ "x64" ], @@ -1763,9 +1200,9 @@ } }, "node_modules/@swc/counter": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", - "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, "node_modules/@swc/types": { @@ -1788,28 +1225,6 @@ "node": ">=14.17" } }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", - "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", - "dev": true, - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/@types/argparse": { "version": "1.0.38", "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", @@ -1958,9 +1373,9 @@ } }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/sinon": { @@ -2064,16 +1479,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", - "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", + "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/type-utils": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/type-utils": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2089,8 +1504,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2098,17 +1513,46 @@ } } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", - "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", - "debug": "^4.3.4" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", + "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2118,7 +1562,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2126,14 +1570,20 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", - "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2141,18 +1591,67 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", - "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", + "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2162,7 +1661,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2170,10 +1669,27 @@ } } }, - "node_modules/@typescript-eslint/types": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", - "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2183,14 +1699,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", - "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2211,18 +1727,35 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", - "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", "semver": "^7.5.4" }, "engines": { @@ -2233,16 +1766,91 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", - "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2303,19 +1911,6 @@ "node": ">= 14" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2438,13 +2033,9 @@ } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-back": { "version": "4.0.2", @@ -2456,13 +2047,16 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2505,17 +2099,36 @@ "node": ">=8" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "node_modules/array.prototype.filter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", + "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", + "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2561,17 +2174,18 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", "is-shared-array-buffer": "^1.0.2" }, "engines": { @@ -2613,10 +2227,13 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -2625,15 +2242,48 @@ } }, "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz", + "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.1.5.tgz", + "integrity": "sha512-5t0nlecX+N2uJqdxe9d18A98cp2u9BETelbjKpiVgQqzzmVNFYWEAjQHqS+2Khgto1vcwhik9cXucaj5ve2WWA==", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-os": "^2.0.0", + "bare-path": "^2.0.0", + "streamx": "^2.13.0" + } + }, + "node_modules/bare-os": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.0.tgz", + "integrity": "sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz", + "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==", + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2740,15 +2390,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, "node_modules/c8": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", @@ -2815,47 +2456,20 @@ "node": ">=12" } }, - "node_modules/cacache": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", - "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2953,27 +2567,6 @@ "node": ">= 6" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-bidi": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.6.tgz", - "integrity": "sha512-ber8smgoAs4EqSUHRb0I8fpx371ZmvsdQav8HRM9oO4fk5Ox16vQiNYXlsZkRj4FfvVL2dCef+zBFQixp+79CA==", - "dependencies": { - "mitt": "3.0.1", - "urlpattern-polyfill": "10.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2989,15 +2582,6 @@ "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3063,15 +2647,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/colors": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/command-line-usage": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", @@ -3171,7 +2746,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -3201,9 +2777,9 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", - "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "engines": { "node": ">= 14" } @@ -3295,17 +2871,20 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-lazy-prop": { @@ -3348,9 +2927,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1232444", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", - "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==" + "version": "0.0.1249869", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1249869.tgz", + "integrity": "sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg==" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -3463,12 +3042,6 @@ "node": ">=6" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3478,50 +3051,52 @@ } }, "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", + "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.7", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.2", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", + "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "hasown": "^2.0.1", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", + "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.0", + "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.8", "string.prototype.trimend": "^1.0.7", "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", + "typed-array-buffer": "^1.0.1", "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -3530,15 +3105,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -3571,9 +3173,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", - "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", "dev": true, "hasInstallScript": true, "bin": { @@ -3583,35 +3185,403 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.0", - "@esbuild/android-arm": "0.20.0", - "@esbuild/android-arm64": "0.20.0", - "@esbuild/android-x64": "0.20.0", - "@esbuild/darwin-arm64": "0.20.0", - "@esbuild/darwin-x64": "0.20.0", - "@esbuild/freebsd-arm64": "0.20.0", - "@esbuild/freebsd-x64": "0.20.0", - "@esbuild/linux-arm": "0.20.0", - "@esbuild/linux-arm64": "0.20.0", - "@esbuild/linux-ia32": "0.20.0", - "@esbuild/linux-loong64": "0.20.0", - "@esbuild/linux-mips64el": "0.20.0", - "@esbuild/linux-ppc64": "0.20.0", - "@esbuild/linux-riscv64": "0.20.0", - "@esbuild/linux-s390x": "0.20.0", - "@esbuild/linux-x64": "0.20.0", - "@esbuild/netbsd-x64": "0.20.0", - "@esbuild/openbsd-x64": "0.20.0", - "@esbuild/sunos-x64": "0.20.0", - "@esbuild/win32-arm64": "0.20.0", - "@esbuild/win32-ia32": "0.20.0", - "@esbuild/win32-x64": "0.20.0" + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -3648,16 +3618,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -3944,9 +3914,9 @@ } }, "node_modules/eslint-plugin-mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.2.0.tgz", - "integrity": "sha512-ZhdxzSZnd1P9LqDPF0DBcFLpRIGdh1zkF2JHnQklKQOvrQtT73kdP5K9V2mzvbLR+cCAO9OI48NXK/Ax9/ciCQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.3.0.tgz", + "integrity": "sha512-IWzbg2K6B1Q7h37Ih4zMyW+nhmw1JvUlHlbCUUUu6PfOOAUGCB0gxmvv7/U+TQQ6e8yHUv+q7KMdIIum4bx+PA==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -4084,9 +4054,9 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", - "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", + "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", "dev": true, "dependencies": { "eslint-rule-composer": "^0.3.0" @@ -4095,8 +4065,8 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0", - "eslint": "^8.0.0" + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -4174,6 +4144,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4304,12 +4283,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -4423,9 +4396,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -4536,9 +4509,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.0.tgz", + "integrity": "sha512-noqGuLw158+DuD9UPRKHpJ2hGxpFyDlYYrfM0mWt4XhT4n0lwzTLh70Tkdyy4kyTmyTT9Bv7bWAJqw7cgkEXDg==", "dev": true }, "node_modules/for-each": { @@ -4579,18 +4552,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4654,16 +4615,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4681,13 +4646,14 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -4709,51 +4675,49 @@ } }, "node_modules/get-uri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", - "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.0", + "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "fs-extra": "^11.2.0" }, "engines": { "node": ">= 14" } }, "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14.14" } }, - "node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "node_modules/get-uri/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "universalify": "^2.0.0" }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 10.0.0" } }, "node_modules/glob-parent": { @@ -5358,21 +5322,21 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -5394,12 +5358,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5409,9 +5373,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -5466,16 +5430,10 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -5485,9 +5443,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -5537,26 +5495,14 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" } }, - "node_modules/ignore-walk": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", - "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", - "dev": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -5657,12 +5603,12 @@ } }, "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", + "es-errors": "^1.3.0", "hasown": "^2.0.0", "side-channel": "^1.0.4" }, @@ -5670,10 +5616,17 @@ "node": ">= 0.4" } }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/irregular-plurals": { "version": "3.5.0", @@ -5685,14 +5638,16 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5831,16 +5786,10 @@ "node": ">=8" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" @@ -5907,12 +5856,15 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5961,12 +5913,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -6045,9 +5997,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -6177,10 +6129,10 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, "node_modules/json-buffer": { "version": "3.0.1", @@ -6188,12 +6140,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -6226,26 +6172,17 @@ "node_modules/jsonc-parser": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", @@ -6409,21 +6346,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6481,7 +6403,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6489,17 +6410,6 @@ "node": ">=10" } }, - "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -6515,32 +6425,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", - "dev": true, - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/make-synchronized": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.7.tgz", - "integrity": "sha512-tbTJaNgmKV3E6yYxEN5djObcMt0j1WB2ltn8JteZYczrdFkGMor3KAraPGUf4NJsf5u+FvJbgbGGL35N3J6VVw==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/make-synchronized/-/make-synchronized-0.2.8.tgz", + "integrity": "sha512-jtXnKYCxjmGaXiZhXbDbGPbh4YyTvIIbOgcQjtAboc4RSm9k3nyhTFvFQB0cfs7QFKuZXKe2D2RvOkv1c+vpxg==", "dev": true, "funding": { "url": "https://github.com/fisker/make-synchronized?sponsor=1" @@ -6710,154 +6598,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -6875,15 +6615,10 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", + "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", "dependencies": { "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", @@ -6892,13 +6627,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -6913,51 +6647,26 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -6988,14 +6697,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7007,17 +6708,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7039,15 +6729,6 @@ "ncp": "bin/ncp" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -7056,16 +6737,10 @@ "node": ">= 0.4.0" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/nise": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.7.tgz", - "integrity": "sha512-wWtNUhkT7k58uvWTB/Gy26eA/EJKtPZFVAhEilN5UYVmmGRYOURbejRUyKm0Uu9XVEW7K5nBOZfR8VMB4QR2RQ==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", @@ -7094,78 +6769,6 @@ } } }, - "node_modules/node-gyp": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", - "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", - "dev": true, - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -7202,318 +6805,90 @@ "node": ">=0.10.0" } }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", - "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true }, - "node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", - "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "node_modules/npm-run-all2": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", + "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", "dev": true, "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/npm-packlist": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", - "dev": true, - "dependencies": { - "ignore-walk": "^6.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", - "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", - "dev": true, - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", - "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" }, "bin": { "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">= 4" + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" } }, - "node_modules/npm-run-all/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm-run-all/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/npm-run-all/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "node": ">=12" }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/npm-run-all/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/npm-run-all/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm-run-all/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/npm-run-all2/node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": "*" - } - }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node": ">=0.10" } }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-run-all/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/npm-run-all2/node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-run-path": { @@ -7597,15 +6972,16 @@ } }, "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", + "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" + "array.prototype.filter": "^1.0.3", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.0.0" } }, "node_modules/object.values": { @@ -7760,21 +7136,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -7803,12 +7164,11 @@ } }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -7826,19 +7186,6 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/parse-ms": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", @@ -7869,6 +7216,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -7903,9 +7251,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "engines": { "node": "14 || >=16.14" } @@ -7947,27 +7295,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/pixelmatch": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", @@ -8025,6 +7352,15 @@ "node": ">=14.19.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8035,9 +7371,9 @@ } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8102,15 +7438,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -8119,25 +7446,6 @@ "node": ">=0.4.0" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -8156,14 +7464,14 @@ "dev": true }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", @@ -8303,37 +7611,6 @@ "npm-normalize-package-bin": "^1.0.0" } }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/read-package-json/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -8403,20 +7680,6 @@ "semver": "bin/semver" } }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/read-pkg-up": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", @@ -8564,45 +7827,6 @@ "node": ">=8" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -8663,14 +7887,15 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -8938,13 +8163,13 @@ ] }, "node_modules/safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" }, "engines": { @@ -8961,10 +8186,9 @@ "devOptional": true }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8984,14 +8208,15 @@ } }, "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", "dev": true, "dependencies": { - "define-data-property": "^1.1.1", + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", + "get-intrinsic": "^1.2.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.1" }, @@ -9000,14 +8225,15 @@ } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9042,14 +8268,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9066,23 +8296,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sigstore": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", - "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", - "dev": true, - "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.2.1", - "@sigstore/tuf": "^2.3.0", - "@sigstore/verify": "^0.1.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/sinon": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", @@ -9102,9 +8315,9 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -9138,15 +8351,15 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", + "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -9163,11 +8376,6 @@ "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9209,9 +8417,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -9225,9 +8433,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/spdx-ranges": { @@ -9248,22 +8456,9 @@ } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -9287,12 +8482,15 @@ } }, "node_modules/streamx": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", - "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", "dependencies": { "fast-fifo": "^1.1.0", "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { @@ -9339,23 +8537,6 @@ "node": ">=8" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz", - "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -9559,31 +8740,17 @@ "node": ">=6" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", "dependencies": { - "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" } }, "node_modules/tar-stream": { @@ -9596,51 +8763,6 @@ "streamx": "^2.15.0" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -9755,12 +8877,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -9791,9 +8913,9 @@ } }, "node_modules/tsd": { - "version": "0.30.4", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.4.tgz", - "integrity": "sha512-ncC4SwAeUk0OTcXt5h8l0/gOLHJSp9ogosvOADT6QYzrl0ITm398B3wkz8YESqefIsEEwvYAU8bvo7/rcN/M0Q==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.7.tgz", + "integrity": "sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==", "dev": true, "dependencies": { "@tsd/typescript": "~5.3.3", @@ -9833,9 +8955,9 @@ } }, "node_modules/tsx": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", - "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", "dev": true, "dependencies": { "esbuild": "~0.19.10", @@ -10257,20 +9379,6 @@ "@esbuild/win32-x64": "0.19.12" } }, - "node_modules/tuf-js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", - "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", - "dev": true, - "dependencies": { - "@tufjs/models": "2.0.0", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -10314,29 +9422,30 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -10346,16 +9455,17 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -10365,14 +9475,20 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", + "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10425,9 +9541,9 @@ } }, "node_modules/undici": { - "version": "5.28.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", - "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -10442,34 +9558,11 @@ "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", "devOptional": true }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, "engines": { "node": ">= 4.0.0" } @@ -10531,18 +9624,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", @@ -10605,16 +9686,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -10748,8 +9829,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "16.2.0", @@ -10769,9 +9849,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "engines": { "node": ">=10" } @@ -10871,14 +9951,15 @@ }, "packages/browsers": { "name": "@puppeteer/browsers", - "version": "1.9.1", + "version": "2.1.0", "license": "Apache-2.0", "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", "yargs": "17.7.2" }, @@ -10893,7 +9974,7 @@ "@types/yargs": "17.0.32" }, "engines": { - "node": ">=16.3.0" + "node": ">=18" } }, "packages/browsers/node_modules/cliui": { @@ -10933,26 +10014,27 @@ }, "packages/ng-schematics": { "name": "@puppeteer/ng-schematics", - "version": "0.5.6", + "version": "0.6.0", "license": "Apache-2.0", "dependencies": { - "@angular-devkit/architect": "^0.1701.1", - "@angular-devkit/core": "^17.0.7", - "@angular-devkit/schematics": "^17.0.7" + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2" }, "devDependencies": { - "@angular/cli": "^17.0.7", - "@schematics/angular": "^17.0.7" + "@angular/cli": "17.2.2", + "@schematics/angular": "17.2.2" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/ng-schematics/node_modules/@angular-devkit/architect": { - "version": "0.1700.6", - "license": "MIT", + "version": "0.1702.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1702.2.tgz", + "integrity": "sha512-qBvif8/NquFUqVQgs4U+8wXh/rQZv+YlYwg6eDZly1bIaTd/k9spko/seTtNT1OpK/Be+GLo5IbiQ7i2SON3iQ==", "dependencies": { - "@angular-devkit/core": "17.0.6", + "@angular-devkit/core": "17.2.2", "rxjs": "7.8.1" }, "engines": { @@ -10962,13 +10044,14 @@ } }, "packages/ng-schematics/node_modules/@angular-devkit/core": { - "version": "17.0.6", - "license": "MIT", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.2.2.tgz", + "integrity": "sha512-bKMi6bBkEeN4a3qTxCykhrAvE0ESHhKO38Qh1bN/8QSyvKVAEyVAVls5W9IN5GKRHvXgEn9aw+DSzRnPpy9nyw==", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", "rxjs": "7.8.1", "source-map": "0.7.4" }, @@ -10986,13 +10069,25 @@ } } }, + "packages/ng-schematics/node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "packages/ng-schematics/node_modules/@angular-devkit/schematics": { - "version": "17.0.6", - "license": "MIT", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.2.2.tgz", + "integrity": "sha512-t6dBhHvto9BEIo+Kew0+YyIS3TV1SEd4MActUk+zF4NNQyJ8wRUHL+8glUKB6ZWPyCTYSinJ+QKn/3yytELTHg==", "dependencies": { - "@angular-devkit/core": "17.0.6", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.5", + "@angular-devkit/core": "17.2.2", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.7", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -11002,27 +10097,39 @@ "yarn": ">= 1.13.0" } }, + "packages/ng-schematics/node_modules/@angular-devkit/schematics/node_modules/magic-string": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, "packages/ng-schematics/node_modules/@angular/cli": { - "version": "17.0.6", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.2.2.tgz", + "integrity": "sha512-cGGOnOTjU1bHBAU+5LMR1vfjUSmIY204pUcRAHu6xq1Qp8jm0Wf1lYOG1KrzpDezKa8d0WZe6FIVlxsCZRRYSw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1700.6", - "@angular-devkit/core": "17.0.6", - "@angular-devkit/schematics": "17.0.6", - "@schematics/angular": "17.0.6", + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2", + "@schematics/angular": "17.2.2", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", - "inquirer": "9.2.11", - "jsonc-parser": "3.2.0", + "inquirer": "9.2.14", + "jsonc-parser": "3.2.1", "npm-package-arg": "11.0.1", "npm-pick-manifest": "9.0.0", "open": "8.4.2", "ora": "5.4.1", - "pacote": "17.0.4", + "pacote": "17.0.6", "resolve": "1.22.8", - "semver": "7.5.4", + "semver": "7.6.0", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -11035,47 +10142,49 @@ "yarn": ">= 1.13.0" } }, - "packages/ng-schematics/node_modules/@schematics/angular": { - "version": "17.0.6", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer": { + "version": "9.2.14", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.14.tgz", + "integrity": "sha512-4ByIMt677Iz5AvjyKrDpzaepIyMewNvDcvwpVVRZNmy9dLakVoVgdCHZXbK1SlVJra1db0JZ6XkJyHsanpdrdQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.0.6", - "@angular-devkit/schematics": "17.0.6", - "jsonc-parser": "3.2.0" + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=18" } }, - "packages/ng-schematics/node_modules/ajv": { - "version": "8.12.0", - "license": "MIT", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/@ljharb/through": { + "version": "2.3.12", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", + "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "call-bind": "^1.0.5" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "packages/ng-schematics/node_modules/ansi-colors": { - "version": "4.1.3", - "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "packages/ng-schematics/node_modules/chalk": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/chalk": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -11083,73 +10192,382 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "packages/ng-schematics/node_modules/cli-width": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/cli-width": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "license": "ISC", "engines": { "node": ">= 12" } }, - "packages/ng-schematics/node_modules/cliui": { - "version": "8.0.1", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, "engines": { - "node": ">=12" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/escape-string-regexp": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/validate-npm-package-name": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, - "license": "MIT", + "dependencies": { + "builtins": "^5.0.0" + }, "engines": { - "node": ">=12" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-package-arg/node_modules/validate-npm-package-name/node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest/node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/git/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" } }, - "packages/ng-schematics/node_modules/figures": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents/node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/installed-package-contents/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/promise-spawn/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, - "license": "MIT", "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "packages/ng-schematics/node_modules/hosted-git-info": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/hosted-git-info": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -11157,78 +10575,885 @@ "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/inquirer": { - "version": "9.2.11", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/@npmcli/package-json/node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dev": true, - "license": "MIT", "dependencies": { - "@ljharb/through": "^2.3.9", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=14.18.0" + "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/is-unicode-supported": { - "version": "1.3.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "dev": true, - "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, "engines": { - "node": ">=12" + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/node-gyp/node_modules/nopt/node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/@npmcli/run-script/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/ng-schematics/node_modules/json-parse-even-better-errors": { - "version": "3.0.1", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map/node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, - "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/p-map/node_modules/aggregate-error/node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/cacache/node_modules/unique-filename/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "packages/ng-schematics/node_modules/jsonc-parser": { - "version": "3.2.0", - "license": "MIT" + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "packages/ng-schematics/node_modules/lru-cache": { - "version": "10.1.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-packlist/node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, - "license": "ISC", "engines": { "node": "14 || >=16.14" } }, - "packages/ng-schematics/node_modules/mute-stream": { - "version": "1.0.0", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, - "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "packages/ng-schematics/node_modules/normalize-package-data": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream/node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/npm-registry-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/promise-retry/node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", "is-core-module": "^2.8.1", @@ -11239,77 +11464,704 @@ "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/npm-normalize-package-bin": { + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/normalize-package-data/node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/read-package-json/node_modules/npm-normalize-package-bin": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/pacote": { - "version": "17.0.4", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", "dev": true, - "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/bundle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", + "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/protobuf-specs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" + "ssri": "^10.0.0" }, - "bin": { - "pacote": "lib/bin.js" + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, - "packages/ng-schematics/node_modules/picomatch": { - "version": "3.0.1", - "license": "MIT", + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/sign/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", + "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0", + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/@tufjs/models/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/tuf/node_modules/tuf-js/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/sigstore/node_modules/@sigstore/verify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", + "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, "engines": { "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/ng-schematics/node_modules/@angular/cli/node_modules/pacote/node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/ng-schematics/node_modules/@schematics/angular": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.2.2.tgz", + "integrity": "sha512-Q3VAQ/S4gj8D1JPWgWG4enDdDZUu8mUXWVRG1rOi4sHgOF5zgPieQFp3LXqMUgOncmzbXrctkbO6NKc4N2FAag==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "packages/ng-schematics/node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "packages/ng-schematics/node_modules/read-package-json": { - "version": "7.0.0", + "packages/ng-schematics/node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "packages/ng-schematics/node_modules/cliui": { + "version": "8.0.1", "dev": true, "license": "ISC", "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=12" } }, - "packages/ng-schematics/node_modules/run-async": { - "version": "3.0.0", + "packages/ng-schematics/node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "packages/ng-schematics/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, "packages/ng-schematics/node_modules/rxjs": { "version": "7.8.1", "license": "Apache-2.0", @@ -11328,19 +12180,6 @@ "version": "2.6.2", "license": "0BSD" }, - "packages/ng-schematics/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "packages/ng-schematics/node_modules/yargs": { "version": "17.7.2", "dev": true, @@ -11367,13 +12206,13 @@ } }, "packages/puppeteer": { - "version": "21.10.0", + "version": "22.4.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", + "@puppeteer/browsers": "2.1.0", "cosmiconfig": "9.0.0", - "puppeteer-core": "21.10.0" + "puppeteer-core": "22.4.0" }, "bin": { "puppeteer": "lib/esm/puppeteer/node/cli.js" @@ -11382,18 +12221,18 @@ "@types/node": "18.17.15" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/puppeteer-core": { - "version": "21.10.0", + "version": "22.4.0", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", - "chromium-bidi": "0.5.6", + "@puppeteer/browsers": "2.1.0", + "chromium-bidi": "0.5.12", "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1232444", + "devtools-protocol": "0.0.1249869", "ws": "8.16.0" }, "devDependencies": { @@ -11405,7 +12244,7 @@ "rxjs": "7.8.1" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" } }, "packages/puppeteer-core/node_modules/@types/node": { @@ -11413,6 +12252,18 @@ "dev": true, "license": "MIT" }, + "packages/puppeteer-core/node_modules/chromium-bidi": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.12.tgz", + "integrity": "sha512-sZMgEBWKbupD0Q7lyFu8AWkrE+rs5ycE12jFkGwIgD/VS8lDPtelPlXM7LYaq4zrkZ/O2L3f4afHUHL0ICdKog==", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "packages/puppeteer-core/node_modules/rxjs": { "version": "7.8.1", "dev": true, @@ -11487,7 +12338,7 @@ "name": "@puppeteer-test/test", "version": "latest", "dependencies": { - "diff": "5.1.0", + "diff": "5.2.0", "jpeg-js": "0.4.4", "pixelmatch": "5.3.0", "pngjs": "7.0.0" @@ -11503,26 +12354,46 @@ "version": "latest", "dependencies": { "glob": "10.3.10", - "mocha": "10.2.0" + "mocha": "10.3.0" } }, "test/node_modules/diff": { - "version": "5.1.0", + "version": "5.2.0", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "test/node_modules/glob": { + "version": "10.3.10", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/docgen": { "name": "@puppeteer/docgen", "version": "0.1.0", "license": "Apache-2.0", "devDependencies": { - "@microsoft/api-documenter": "7.23.20", - "@microsoft/api-extractor": "7.39.4", - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-documenter": "7.23.35", + "@microsoft/api-extractor": "7.42.2", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" } }, "tools/doctest": { @@ -11533,7 +12404,7 @@ "doctest": "bin/doctest.js" }, "devDependencies": { - "@swc/core": "1.3.107", + "@swc/core": "1.4.2", "@types/doctrine": "0.0.9", "@types/source-map-support": "0.5.10", "@types/yargs": "17.0.32", @@ -11559,6 +12430,27 @@ "node": ">=12" } }, + "tools/doctest/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/doctest/node_modules/source-map": { "version": "0.7.4", "dev": true, @@ -11597,7 +12489,8 @@ "version": "0.1.0", "license": "Apache-2.0", "devDependencies": { - "@prettier/sync": "0.5.0" + "@prettier/sync": "0.5.1", + "@typescript-eslint/utils": "7.1.0" } }, "tools/mocha-runner": { @@ -11628,6 +12521,27 @@ "node": ">=12" } }, + "tools/mocha-runner/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "tools/mocha-runner/node_modules/yargs": { "version": "17.7.2", "dev": true, diff --git a/remote/test/puppeteer/package.json b/remote/test/puppeteer/package.json index 612f5ac369..0ffdceedf7 100644 --- a/remote/test/puppeteer/package.json +++ b/remote/test/puppeteer/package.json @@ -32,7 +32,7 @@ "test:chrome:bidi-local": "wireit", "test:chrome:headful": "wireit", "test:chrome:headless": "wireit", - "test:chrome:new-headless": "wireit", + "test:chrome:shell": "wireit", "test:firefox": "wireit", "test:firefox:bidi": "wireit", "test:firefox:bidi:headful": "wireit", @@ -50,7 +50,8 @@ "./packages/puppeteer:build", "./packages/testserver:build", "./test:build", - "./test/installation:build" + "./test/installation:build", + "build:tools" ] }, "build:tools": { @@ -83,7 +84,7 @@ "test:chrome:bidi", "test:chrome:headful", "test:chrome:headless", - "test:chrome:new-headless" + "test:chrome:shell" ] }, "test:chrome:bidi": { @@ -98,8 +99,8 @@ "test:chrome:headless": { "command": "npm test -- --test-suite chrome-headless" }, - "test:chrome:new-headless": { - "command": "npm test -- --test-suite chrome-new-headless" + "test:chrome:shell": { + "command": "npm test -- --test-suite chrome-headless-shell" }, "test:firefox:bidi": { "command": "npm test -- --test-suite firefox-bidi" @@ -139,34 +140,34 @@ "@actions/core": "1.10.1", "@types/mocha": "10.0.6", "@types/node": "20.8.4", - "@types/semver": "7.5.6", + "@types/semver": "7.5.8", "@types/sinon": "17.0.3", - "@typescript-eslint/eslint-plugin": "6.19.1", - "@typescript-eslint/parser": "6.19.1", - "esbuild": "0.20.0", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", + "esbuild": "0.20.1", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", "eslint-plugin-import": "2.29.1", - "eslint-plugin-mocha": "10.2.0", + "eslint-plugin-mocha": "10.3.0", "eslint-plugin-prettier": "5.1.3", "eslint-plugin-rulesdir": "0.2.2", "eslint-plugin-tsdoc": "0.2.17", - "eslint-plugin-unused-imports": "3.0.0", - "eslint": "8.56.0", + "eslint-plugin-unused-imports": "3.1.0", + "eslint": "8.57.0", "execa": "8.0.1", "expect": "29.7.0", "gts": "5.2.0", "hereby": "1.8.9", "license-checker": "25.0.1", - "mocha": "10.2.0", - "npm-run-all": "4.1.5", - "prettier": "3.2.4", - "semver": "7.5.4", + "mocha": "10.3.0", + "npm-run-all2": "6.1.2", + "prettier": "3.2.5", + "semver": "7.6.0", "sinon": "17.0.1", "source-map-support": "0.5.21", "spdx-satisfies": "5.0.1", - "tsd": "0.30.4", - "tsx": "4.7.0", + "tsd": "0.30.7", + "tsx": "4.7.1", "typescript": "5.3.3", "wireit": "0.14.4" }, diff --git a/remote/test/puppeteer/packages/browsers/CHANGELOG.md b/remote/test/puppeteer/packages/browsers/CHANGELOG.md index abfb45bb6d..a2798068e9 100644 --- a/remote/test/puppeteer/packages/browsers/CHANGELOG.md +++ b/remote/test/puppeteer/packages/browsers/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## [2.1.0](https://github.com/puppeteer/puppeteer/compare/browsers-v2.0.1...browsers-v2.1.0) (2024-02-21) + + +### Features + +* allow comparing browser versions ([#11954](https://github.com/puppeteer/puppeteer/issues/11954)) ([bf71b34](https://github.com/puppeteer/puppeteer/commit/bf71b34fca73ed14eeb23616682799ff545fc371)) +* support local aliases when launching a browser ([#11947](https://github.com/puppeteer/puppeteer/issues/11947)) ([561e4cd](https://github.com/puppeteer/puppeteer/commit/561e4cd6ee79b19ac43f2c2fceaa1fce51052c02)) + + +### Bug Fixes + +* check if executable exists ([#11946](https://github.com/puppeteer/puppeteer/issues/11946)) ([e95a308](https://github.com/puppeteer/puppeteer/commit/e95a308c33021a80c9eb27a4ac02c607af60ff99)) +* implement a fallback to download URLs provided by dashboard ([#11951](https://github.com/puppeteer/puppeteer/issues/11951)) ([73c1f9b](https://github.com/puppeteer/puppeteer/commit/73c1f9bbf3c862decded533401e3bd26a18f8194)) + +## [2.0.1](https://github.com/puppeteer/puppeteer/compare/browsers-v2.0.0...browsers-v2.0.1) (2024-02-17) + + +### Bug Fixes + +* Chrome for Testing downloads have a new URL ([#11923](https://github.com/puppeteer/puppeteer/issues/11923)) ([f00a94a](https://github.com/puppeteer/puppeteer/commit/f00a94a809d38ee1c2c8cfc8597c66db9f3d243d)) + +## [2.0.0](https://github.com/puppeteer/puppeteer/compare/browsers-v1.9.1...browsers-v2.0.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) + ## [1.9.1](https://github.com/puppeteer/puppeteer/compare/browsers-v1.9.0...browsers-v1.9.1) (2024-01-04) diff --git a/remote/test/puppeteer/packages/browsers/package.json b/remote/test/puppeteer/packages/browsers/package.json index 45de79abb8..0f2afa74de 100644 --- a/remote/test/puppeteer/packages/browsers/package.json +++ b/remote/test/puppeteer/packages/browsers/package.json @@ -1,12 +1,12 @@ { "name": "@puppeteer/browsers", - "version": "1.9.1", + "version": "2.1.0", "description": "Download and launch browsers", "scripts": { "build:docs": "wireit", "build": "wireit", "build:test": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "test": "wireit" }, "type": "commonjs", @@ -87,7 +87,7 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "engines": { - "node": ">=16.3.0" + "node": ">=18" }, "files": [ "lib", @@ -98,10 +98,11 @@ "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", + "proxy-agent": "6.4.0", + "tar-fs": "3.0.5", "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "yargs": "17.7.2", + "semver": "7.6.0" }, "devDependencies": { "@types/debug": "4.1.12", diff --git a/remote/test/puppeteer/packages/browsers/src/CLI.ts b/remote/test/puppeteer/packages/browsers/src/CLI.ts index 255f5545b4..281f22c9f5 100644 --- a/remote/test/puppeteer/packages/browsers/src/CLI.ts +++ b/remote/test/puppeteer/packages/browsers/src/CLI.ts @@ -173,6 +173,18 @@ export class CLI { 'Install the latest available build for the Chrome browser.' ); yargs.example( + '$0 install chrome@stable', + 'Install the latest available build for the Chrome browser from the stable channel.' + ); + yargs.example( + '$0 install chrome@beta', + 'Install the latest available build for the Chrome browser from the beta channel.' + ); + yargs.example( + '$0 install chrome@dev', + 'Install the latest available build for the Chrome browser from the dev channel.' + ); + yargs.example( '$0 install chrome@canary', 'Install the latest available build for the Chrome Canary browser.' ); @@ -238,6 +250,7 @@ export class CLI { } args.browser.buildId = pinnedVersion; } + const originalBuildId = args.browser.buildId; args.browser.buildId = await resolveBuildId( args.browser.name, args.platform, @@ -253,6 +266,10 @@ export class CLI { args.browser.buildId ), baseUrl: args.baseUrl, + buildIdAlias: + originalBuildId !== args.browser.buildId + ? originalBuildId + : undefined, }); console.log( `${args.browser.name}@${ diff --git a/remote/test/puppeteer/packages/browsers/src/Cache.ts b/remote/test/puppeteer/packages/browsers/src/Cache.ts index 13b465835a..e6b574d9dd 100644 --- a/remote/test/puppeteer/packages/browsers/src/Cache.ts +++ b/remote/test/puppeteer/packages/browsers/src/Cache.ts @@ -8,13 +8,18 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; +import debug from 'debug'; + import { Browser, type BrowserPlatform, executablePathByBrowser, + getVersionComparator, } from './browser-data/browser-data.js'; import {detectBrowserPlatform} from './detectPlatform.js'; +const debugCache = debug('puppeteer:browsers:cache'); + /** * @public */ @@ -57,6 +62,14 @@ export class InstalledBrowser { this.buildId ); } + + readMetadata(): Metadata { + return this.#cache.readMetadata(this.browser); + } + + writeMetadata(metadata: Metadata): void { + this.#cache.writeMetadata(this.browser, metadata); + } } /** @@ -80,6 +93,11 @@ export interface ComputeExecutablePathOptions { buildId: string; } +export interface Metadata { + // Maps an alias (canary/latest/dev/etc.) to a buildId. + aliases: Record<string, string>; +} + /** * The cache used by Puppeteer relies on the following structure: * @@ -112,6 +130,39 @@ export class Cache { return path.join(this.#rootDir, browser); } + metadataFile(browser: Browser): string { + return path.join(this.browserRoot(browser), '.metadata'); + } + + readMetadata(browser: Browser): Metadata { + const metatadaPath = this.metadataFile(browser); + if (!fs.existsSync(metatadaPath)) { + return {aliases: {}}; + } + // TODO: add type-safe parsing. + const data = JSON.parse(fs.readFileSync(metatadaPath, 'utf8')); + if (typeof data !== 'object') { + throw new Error('.metadata is not an object'); + } + return data; + } + + writeMetadata(browser: Browser, metadata: Metadata): void { + const metatadaPath = this.metadataFile(browser); + fs.mkdirSync(path.dirname(metatadaPath), {recursive: true}); + fs.writeFileSync(metatadaPath, JSON.stringify(metadata, null, 2)); + } + + resolveAlias(browser: Browser, alias: string): string | undefined { + const metadata = this.readMetadata(browser); + if (alias === 'latest') { + return Object.values(metadata.aliases || {}) + .sort(getVersionComparator(browser)) + .at(-1); + } + return metadata.aliases[alias]; + } + installationDir( browser: Browser, platform: BrowserPlatform, @@ -134,6 +185,12 @@ export class Cache { platform: BrowserPlatform, buildId: string ): void { + const metadata = this.readMetadata(browser); + for (const alias of Object.keys(metadata.aliases)) { + if (metadata.aliases[alias] === buildId) { + delete metadata.aliases[alias]; + } + } fs.rmSync(this.installationDir(browser, platform, buildId), { force: true, recursive: true, @@ -180,6 +237,12 @@ export class Cache { `Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})` ); } + try { + options.buildId = + this.resolveAlias(options.browser, options.buildId) ?? options.buildId; + } catch { + debugCache('could not read .metadata file for the browser'); + } const installationDir = this.installationDir( options.browser, options.platform, diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts index 67bb4990b2..3e78030aa7 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/browser-data.ts @@ -43,6 +43,14 @@ export const executablePathByBrowser = { [Browser.FIREFOX]: firefox.relativeExecutablePath, }; +export const versionComparators = { + [Browser.CHROMEDRIVER]: chromedriver.compareVersions, + [Browser.CHROMEHEADLESSSHELL]: chromeHeadlessShell.compareVersions, + [Browser.CHROME]: chrome.compareVersions, + [Browser.CHROMIUM]: chromium.compareVersions, + [Browser.FIREFOX]: firefox.compareVersions, +}; + export {Browser, BrowserPlatform, ChromeReleaseChannel}; /** @@ -185,3 +193,15 @@ export function resolveSystemExecutablePath( return chrome.resolveSystemExecutablePath(platform, channel); } } + +/** + * Returns a version comparator for the given browser that can be used to sort + * browser versions. + * + * @public + */ +export function getVersionComparator( + browser: Browser +): (a: string, b: string) => number { + return versionComparators[browser]; +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts index b1c6178de8..f5f65cdbd4 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome-headless-shell.ts @@ -25,7 +25,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -66,4 +66,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts index c6329255c3..c7975163fc 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chrome.ts @@ -6,6 +6,8 @@ import path from 'path'; +import semver from 'semver'; + import {getJSON} from '../httpUtil.js'; import {BrowserPlatform, ChromeReleaseChannel} from './types.js'; @@ -28,7 +30,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -193,3 +195,19 @@ export function resolveSystemExecutablePath( `Unable to detect browser executable path for '${channel}' on ${platform}.` ); } + +export function compareVersions(a: string, b: string): number { + if (!semver.valid(a)) { + throw new Error(`Version ${a} is not a valid semver version`); + } + if (!semver.valid(b)) { + throw new Error(`Version ${b} is not a valid semver version`); + } + if (semver.gt(a, b)) { + return 1; + } else if (semver.lt(a, b)) { + return -1; + } else { + return 0; + } +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts index 290598d0d7..2f1242b249 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chromedriver.ts @@ -25,7 +25,7 @@ function folder(platform: BrowserPlatform): string { export function resolveDownloadUrl( platform: BrowserPlatform, buildId: string, - baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing' + baseUrl = 'https://storage.googleapis.com/chrome-for-testing-public' ): string { return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`; } @@ -53,4 +53,4 @@ export function relativeExecutablePath( } } -export {resolveBuildId} from './chrome.js'; +export {resolveBuildId, compareVersions} from './chrome.js'; diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts index 09cfc987a8..820e76d018 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/chromium.ts @@ -86,3 +86,7 @@ export async function resolveBuildId( ) ); } + +export function compareVersions(a: string, b: string): number { + return Number(a) - Number(b); +} diff --git a/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts b/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts index ccc30fa1b5..87e3804c8f 100644 --- a/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts +++ b/remote/test/puppeteer/packages/browsers/src/browser-data/firefox.ts @@ -235,10 +235,6 @@ function defaultProfilePreferences( // Disable the GFX sanity window 'media.sanity-test.disabled': true, - // Prevent various error message on the console - // jest-puppeteer asserts that no error message is emitted by the console - 'network.cookie.cookieBehavior': 0, - // Disable experimental feature that is only available in Nightly 'network.cookie.sameSite.laxByDefault': false, @@ -328,3 +324,8 @@ async function writePreferences(options: ProfileOptions): Promise<void> { await fs.promises.copyFile(prefsPath, prefsBackupPath); } } + +export function compareVersions(a: string, b: string): number { + // TODO: this is a not very reliable check. + return parseInt(a.replace('.', ''), 16) - parseInt(b.replace('.', ''), 16); +} diff --git a/remote/test/puppeteer/packages/browsers/src/install.ts b/remote/test/puppeteer/packages/browsers/src/install.ts index 375c75babc..e78b2c3461 100644 --- a/remote/test/puppeteer/packages/browsers/src/install.ts +++ b/remote/test/puppeteer/packages/browsers/src/install.ts @@ -11,15 +11,15 @@ import os from 'os'; import path from 'path'; import { - type Browser, - type BrowserPlatform, + Browser, + BrowserPlatform, downloadUrls, } from './browser-data/browser-data.js'; import {Cache, InstalledBrowser} from './Cache.js'; import {debug} from './debug.js'; import {detectBrowserPlatform} from './detectPlatform.js'; import {unpackArchive} from './fileUtil.js'; -import {downloadFile, headHttpRequest} from './httpUtil.js'; +import {downloadFile, getJSON, headHttpRequest} from './httpUtil.js'; const debugInstall = debug('puppeteer:browsers:install'); @@ -63,6 +63,13 @@ export interface InstallOptions { */ buildId: string; /** + * An alias for the provided `buildId`. It will be used to maintain local + * metadata to support aliases in the `launch` command. + * + * @example 'canary' + */ + buildIdAlias?: string; + /** * Provides information about the progress of the download. */ downloadProgressCallback?: ( @@ -74,7 +81,7 @@ export interface InstallOptions { * * @defaultValue Either * - * - https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing or + * - https://storage.googleapis.com/chrome-for-testing-public or * - https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central * */ @@ -115,6 +122,68 @@ export async function install( options.buildId, options.baseUrl ); + try { + return await installUrl(url, options); + } catch (err) { + debugInstall(`Error downloading from ${url}.`); + switch (options.browser) { + case Browser.CHROME: + case Browser.CHROMEDRIVER: + case Browser.CHROMEHEADLESSSHELL: { + debugInstall( + `Trying to find download URL via https://googlechromelabs.github.io/chrome-for-testing.` + ); + interface Version { + downloads: Record<string, Array<{platform: string; url: string}>>; + } + const version = (await getJSON( + new URL( + `https://googlechromelabs.github.io/chrome-for-testing/${options.buildId}.json` + ) + )) as Version; + let platform = ''; + switch (options.platform) { + case BrowserPlatform.LINUX: + platform = 'linux64'; + break; + case BrowserPlatform.MAC_ARM: + platform = 'mac-arm64'; + break; + case BrowserPlatform.MAC: + platform = 'mac-x64'; + break; + case BrowserPlatform.WIN32: + platform = 'win32'; + break; + case BrowserPlatform.WIN64: + platform = 'win64'; + break; + } + const url = version.downloads[options.browser]?.find(link => { + return link['platform'] === platform; + })?.url; + if (url) { + debugInstall(`Falling back to downloading from ${url}.`); + return await installUrl(new URL(url), options); + } + throw err; + } + default: + throw err; + } + } +} + +async function installUrl( + url: URL, + options: InstallOptions +): Promise<InstalledBrowser | string> { + options.platform ??= detectBrowserPlatform(); + if (!options.platform) { + throw new Error( + `Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})` + ); + } const fileName = url.toString().split('/').pop(); assert(fileName, `A malformed download URL was found: ${url}.`); const cache = new Cache(options.cacheDir); @@ -140,15 +209,22 @@ export async function install( options.platform, options.buildId ); - if (existsSync(outputPath)) { - return new InstalledBrowser( - cache, - options.browser, - options.buildId, - options.platform - ); - } + try { + if (existsSync(outputPath)) { + const installedBrowser = new InstalledBrowser( + cache, + options.browser, + options.buildId, + options.platform + ); + if (!existsSync(installedBrowser.executablePath)) { + throw new Error( + `The browser folder (${outputPath}) exists but the executable (${installedBrowser.executablePath}) is missing` + ); + } + return installedBrowser; + } debugInstall(`Downloading binary from ${url}`); try { debugTime('download'); @@ -164,17 +240,23 @@ export async function install( } finally { debugTimeEnd('extract'); } + const installedBrowser = new InstalledBrowser( + cache, + options.browser, + options.buildId, + options.platform + ); + if (options.buildIdAlias) { + const metadata = installedBrowser.readMetadata(); + metadata.aliases[options.buildIdAlias] = options.buildId; + installedBrowser.writeMetadata(metadata); + } + return installedBrowser; } finally { if (existsSync(archivePath)) { await unlink(archivePath); } } - return new InstalledBrowser( - cache, - options.browser, - options.buildId, - options.platform - ); } /** diff --git a/remote/test/puppeteer/packages/browsers/src/main.ts b/remote/test/puppeteer/packages/browsers/src/main.ts index df93de530d..c03c0c0090 100644 --- a/remote/test/puppeteer/packages/browsers/src/main.ts +++ b/remote/test/puppeteer/packages/browsers/src/main.ts @@ -37,6 +37,7 @@ export { BrowserPlatform, ChromeReleaseChannel, createProfile, + getVersionComparator, } from './browser-data/browser-data.js'; export {CLI, makeProgressCallback} from './CLI.js'; export {Cache, InstalledBrowser} from './Cache.js'; diff --git a/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts new file mode 100644 index 0000000000..e8a3fb9619 --- /dev/null +++ b/remote/test/puppeteer/packages/browsers/test/src/Cache.spec.ts @@ -0,0 +1,72 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'assert'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; + +import {Browser, Cache} from '../../lib/cjs/main.js'; + +describe('Cache', () => { + let tmpDir = '/tmp/puppeteer-browsers-test'; + let cache: Cache; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'puppeteer-browsers-test')); + cache = new Cache(tmpDir); + }); + + afterEach(() => { + cache.clear(); + }); + + it('return empty metadata if .metadata file does not exist', async function () { + assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), { + aliases: {}, + }); + }); + + it('throw an error if .metadata is malformed', async function () { + // @ts-expect-error wrong type on purpose; + cache.writeMetadata(Browser.CHROME, 'metadata'); + assert.throws(() => { + return cache.readMetadata(Browser.CHROME); + }, new Error(`.metadata is not an object`)); + }); + + it('writes and reads .metadata', async function () { + cache.writeMetadata(Browser.CHROME, { + aliases: { + canary: '123.0.0.0', + }, + }); + assert.deepStrictEqual(cache.readMetadata(Browser.CHROME), { + aliases: { + canary: '123.0.0.0', + }, + }); + + assert.deepStrictEqual( + cache.resolveAlias(Browser.CHROME, 'canary'), + '123.0.0.0' + ); + }); + + it('resolves latest', async function () { + cache.writeMetadata(Browser.CHROME, { + aliases: { + canary: '115.0.5789', + stable: '114.0.5789', + }, + }); + + assert.deepStrictEqual( + cache.resolveAlias(Browser.CHROME, 'latest'), + '115.0.5789' + ); + }); +}); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts index 65008b5edb..2a9f03e2cc 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome-headless-shell/chrome-headless-shell-data.spec.ts @@ -18,23 +18,23 @@ describe('chrome-headless-shell', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/linux64/chrome-headless-shell-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/linux64/chrome-headless-shell-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-x64/chrome-headless-shell-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/mac-x64/chrome-headless-shell-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/mac-arm64/chrome-headless-shell-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/mac-arm64/chrome-headless-shell-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win32/chrome-headless-shell-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/win32/chrome-headless-shell-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '118.0.5950.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5950.0/win64/chrome-headless-shell-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/118.0.5950.0/win64/chrome-headless-shell-win64.zip' ); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts index 510afa8454..4d5bc980b1 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome/chrome-data.spec.ts @@ -16,29 +16,30 @@ import { relativeExecutablePath, resolveSystemExecutablePath, resolveBuildId, + compareVersions, } from '../../../lib/cjs/browser-data/chrome.js'; describe('Chrome', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/linux64/chrome-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/linux64/chrome-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/mac-x64/chrome-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-x64/chrome-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/win32/chrome-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win32/chrome-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '113.0.5672.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/113.0.5672.0/win64/chrome-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win64/chrome-win64.zip' ); }); @@ -116,4 +117,10 @@ describe('Chrome', () => { it('should resolve build prefix', async () => { assert.strictEqual(await resolveBuildId('115.0.5790'), '115.0.5790.170'); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('115.0.5790', '115.0.5789') >= 1); + assert.ok(compareVersions('115.0.5789', '115.0.5790') <= -1); + assert.ok(compareVersions('115.0.5790', '115.0.5790') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts index 8103ff3612..f669d1c57c 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chrome/install.spec.ts @@ -17,6 +17,7 @@ import { Browser, BrowserPlatform, Cache, + computeExecutablePath, } from '../../../lib/cjs/main.js'; import {getServerUrl, setupTestServer} from '../utils.js'; import {testChromeBuildId} from '../versions.js'; @@ -63,6 +64,42 @@ describe('Chrome install', () => { ); }); + it('can detect missing executables', async function () { + this.timeout(60000); + const expectedOutputPath = path.join( + tmpDir, + 'chrome', + `${BrowserPlatform.LINUX}-${testChromeBuildId}` + ); + fs.mkdirSync(expectedOutputPath, {recursive: true}); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); + async function installThatThrows(): Promise<Error | undefined> { + try { + await install({ + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + }); + return undefined; + } catch (err) { + return err as Error; + } + } + assert.strictEqual( + (await installThatThrows())?.message, + `The browser folder (${expectedOutputPath}) exists but the executable (${computeExecutablePath( + { + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + } + )}) is missing` + ); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); + }); + it('should download a buildId that is a zip archive', async function () { this.timeout(60000); const expectedOutputPath = path.join( @@ -100,30 +137,21 @@ describe('Chrome install', () => { ); }); - it('throws on invalid URL', async function () { + it('falls back to the chrome-for-testing dashboard URLs if URL is not available', async function () { const expectedOutputPath = path.join( tmpDir, 'chrome', `${BrowserPlatform.LINUX}-${testChromeBuildId}` ); assert.strictEqual(fs.existsSync(expectedOutputPath), false); - - async function installThatThrows(): Promise<unknown> { - try { - await install({ - cacheDir: tmpDir, - browser: Browser.CHROME, - platform: BrowserPlatform.LINUX, - buildId: testChromeBuildId, - baseUrl: 'https://127.0.0.1', - }); - return undefined; - } catch (err) { - return err; - } - } - assert.ok(await installThatThrows()); - assert.strictEqual(fs.existsSync(expectedOutputPath), false); + await install({ + cacheDir: tmpDir, + browser: Browser.CHROME, + platform: BrowserPlatform.LINUX, + buildId: testChromeBuildId, + baseUrl: 'https://127.0.0.1', + }); + assert.strictEqual(fs.existsSync(expectedOutputPath), true); }); describe('with proxy', () => { @@ -198,7 +226,7 @@ describe('Chrome install', () => { true ); assert.deepStrictEqual(proxiedRequestUrls, [ - getServerUrl() + '/113.0.5672.0/linux64/chrome-linux64.zip', + getServerUrl() + `/${testChromeBuildId}/linux64/chrome-linux64.zip`, ]); assert.deepStrictEqual(proxiedRequestHosts, [ getServerUrl().replace('http://', ''), @@ -223,7 +251,7 @@ describe('Chrome install', () => { assert.strictEqual(browser.path, expectedOutputPath); assert.ok(fs.existsSync(expectedOutputPath)); assert.deepStrictEqual(proxiedRequestUrls, [ - getServerUrl() + '/113.0.5672.0/linux64/chrome-linux64.zip', + getServerUrl() + `/${testChromeBuildId}/linux64/chrome-linux64.zip`, ]); assert.deepStrictEqual(proxiedRequestHosts, [ getServerUrl().replace('http://', ''), diff --git a/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts index 62522d88f4..8a9d07f667 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chromedriver/chromedriver-data.spec.ts @@ -18,23 +18,23 @@ describe('ChromeDriver', () => { it('should resolve download URLs', () => { assert.strictEqual( resolveDownloadUrl(BrowserPlatform.LINUX, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/linux64/chromedriver-linux64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/linux64/chromedriver-linux64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/mac-x64/chromedriver-mac-x64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/mac-x64/chromedriver-mac-x64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.MAC_ARM, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/mac-arm64/chromedriver-mac-arm64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/mac-arm64/chromedriver-mac-arm64.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN32, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/win32/chromedriver-win32.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/win32/chromedriver-win32.zip' ); assert.strictEqual( resolveDownloadUrl(BrowserPlatform.WIN64, '115.0.5763.0'), - 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5763.0/win64/chromedriver-win64.zip' + 'https://storage.googleapis.com/chrome-for-testing-public/115.0.5763.0/win64/chromedriver-win64.zip' ); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts index 601efccc47..ecb7946c99 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/chromium/chromium-data.spec.ts @@ -11,6 +11,7 @@ import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { resolveDownloadUrl, relativeExecutablePath, + compareVersions, } from '../../../lib/cjs/browser-data/chromium.js'; describe('Chromium', () => { @@ -59,4 +60,10 @@ describe('Chromium', () => { path.join('chrome-win', 'chrome.exe') ); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('12372323', '12372322') >= 1); + assert.ok(compareVersions('12372322', '12372323') <= -1); + assert.ok(compareVersions('12372323', '12372323') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts index d0bb056090..b5dd2db0b3 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/firefox/firefox-data.spec.ts @@ -11,6 +11,7 @@ import path from 'path'; import {BrowserPlatform} from '../../../lib/cjs/browser-data/browser-data.js'; import { + compareVersions, createProfile, relativeExecutablePath, resolveDownloadUrl, @@ -94,4 +95,10 @@ describe('Firefox', () => { assert.ok(text.includes(`user_pref("test", 1);`)); // custom preference. }); }); + + it('should compare versions', async () => { + assert.ok(compareVersions('111.0a1', '110.0a1') >= 1); + assert.ok(compareVersions('110.0a1', '111.0a1') <= -1); + assert.ok(compareVersions('111.0a1', '111.0a1') === 0); + }); }); diff --git a/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts b/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts index 1bada43729..29bc76d1b2 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/firefox/install.spec.ts @@ -49,6 +49,32 @@ describe('Firefox install', () => { assert.ok(fs.existsSync(expectedOutputPath)); }); + it('throws on invalid URL', async function () { + const expectedOutputPath = path.join( + tmpDir, + 'chrome', + `${BrowserPlatform.LINUX}-${testFirefoxBuildId}` + ); + assert.strictEqual(fs.existsSync(expectedOutputPath), false); + + async function installThatThrows(): Promise<unknown> { + try { + await install({ + cacheDir: tmpDir, + browser: Browser.FIREFOX, + platform: BrowserPlatform.LINUX, + buildId: testFirefoxBuildId, + baseUrl: 'https://127.0.0.1', + }); + return undefined; + } catch (err) { + return err; + } + } + assert.ok(await installThatThrows()); + assert.strictEqual(fs.existsSync(expectedOutputPath), false); + }); + // install relies on the `hdiutil` utility on MacOS. // The utility is not available on other platforms. (os.platform() === 'darwin' ? it : it.skip)( diff --git a/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts b/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts index 245a0048b2..f3ee678d4e 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/mocha-utils.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import debug from 'debug'; export const mochaHooks = { diff --git a/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json b/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json index 03eae4a458..097d55c06e 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json +++ b/remote/test/puppeteer/packages/browsers/test/src/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", - "outDir": "../build", + "outDir": "../build" }, - "references": [{"path": "../../tsconfig.json"}], + "references": [{"path": "../../tsconfig.json"}] } diff --git a/remote/test/puppeteer/packages/browsers/test/src/versions.ts b/remote/test/puppeteer/packages/browsers/test/src/versions.ts index 3e13b8fc61..83f26ca41a 100644 --- a/remote/test/puppeteer/packages/browsers/test/src/versions.ts +++ b/remote/test/puppeteer/packages/browsers/test/src/versions.ts @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const testChromeBuildId = '113.0.5672.0'; +export const testChromeBuildId = '121.0.6167.85'; export const testChromiumBuildId = '1083080'; -export const testFirefoxBuildId = '123.0a1'; -export const testChromeDriverBuildId = '115.0.5763.0'; -export const testChromeHeadlessShellBuildId = '118.0.5950.0'; +export const testFirefoxBuildId = '125.0a1'; +export const testChromeDriverBuildId = '121.0.6167.85'; +export const testChromeHeadlessShellBuildId = '121.0.6167.85'; diff --git a/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs b/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs index 9fb704baf5..4129428986 100644 --- a/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs +++ b/remote/test/puppeteer/packages/browsers/tools/updateVersions.mjs @@ -5,12 +5,15 @@ */ import fs from 'node:fs/promises'; +import path from 'path'; +import url from 'url'; import actions from '@actions/core'; import {testFirefoxBuildId} from '../test/build/versions.js'; -const filePath = './test/src/versions.ts'; +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const filePath = path.join(__dirname, '../test/src/versions.ts'); const getVersion = async () => { // https://stackoverflow.com/a/1732454/96656 diff --git a/remote/test/puppeteer/packages/browsers/tsconfig.json b/remote/test/puppeteer/packages/browsers/tsconfig.json index b662532a01..a219f8b704 100644 --- a/remote/test/puppeteer/packages/browsers/tsconfig.json +++ b/remote/test/puppeteer/packages/browsers/tsconfig.json @@ -3,6 +3,6 @@ "files": [], "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md b/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md index a483c4f2fb..fbe3408b45 100644 --- a/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md +++ b/remote/test/puppeteer/packages/ng-schematics/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.6.0](https://github.com/puppeteer/puppeteer/compare/ng-schematics-v0.5.6...ng-schematics-v0.6.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) + ## [0.5.6](https://github.com/puppeteer/puppeteer/compare/ng-schematics-v0.5.5...ng-schematics-v0.5.6) (2024-01-16) diff --git a/remote/test/puppeteer/packages/ng-schematics/package.json b/remote/test/puppeteer/packages/ng-schematics/package.json index 29db1dcdc9..6d88d23926 100644 --- a/remote/test/puppeteer/packages/ng-schematics/package.json +++ b/remote/test/puppeteer/packages/ng-schematics/package.json @@ -1,10 +1,10 @@ { "name": "@puppeteer/ng-schematics", - "version": "0.5.6", + "version": "0.6.0", "description": "Puppeteer Angular schematics", "scripts": { "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "dev:test": "npm run test --watch", "dev": "npm run build --watch", "unit": "wireit" @@ -48,16 +48,16 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "dependencies": { - "@angular-devkit/architect": "^0.1701.1", - "@angular-devkit/core": "^17.0.7", - "@angular-devkit/schematics": "^17.0.7" + "@angular-devkit/architect": "0.1702.2", + "@angular-devkit/core": "17.2.2", + "@angular-devkit/schematics": "17.2.2" }, "devDependencies": { - "@schematics/angular": "^17.0.7", - "@angular/cli": "^17.0.7" + "@schematics/angular": "17.2.2", + "@angular/cli": "17.2.2" }, "files": [ "lib", diff --git a/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts b/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts index 82a1e8e7da..e8caab83c9 100644 --- a/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts +++ b/remote/test/puppeteer/packages/ng-schematics/src/builders/puppeteer/index.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {spawn} from 'child_process'; import {normalize, join} from 'path'; diff --git a/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template b/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template index 2136f99a3a..1e291839fe 100644 --- a/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template +++ b/remote/test/puppeteer/packages/ng-schematics/src/schematics/ng-add/files/common/e2e/tests/utils.ts.template @@ -10,15 +10,11 @@ let page: puppeteer.Page; export function setupBrowserHooks(path = ''): void { <% if(testRunner == 'jasmine' || testRunner == 'jest') { %> beforeAll(async () => { - browser = await puppeteer.launch({ - headless: 'new' - }); + browser = await puppeteer.launch(); }); <% } %><% if(testRunner == 'mocha' || testRunner == 'node') { %> before(async () => { - browser = await puppeteer.launch({ - headless: 'new' - }); + browser = await puppeteer.launch(); }); <% } %> diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts index e4ec03ed54..9390e6fd74 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/config.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts index 8ae211cd59..2d80c613f9 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/e2e.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts index d912c5dc3d..56f82ef926 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/ng-add.test.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {describe, it} from 'node:test'; import expect from 'expect'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts b/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts index 503cbd5cec..ea74d8e21f 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts +++ b/remote/test/puppeteer/packages/ng-schematics/test/src/utils.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import https from 'https'; import {before, after} from 'node:test'; import {join} from 'path'; diff --git a/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json b/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json index 3d45f9cc54..8d9f78e0f6 100644 --- a/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json +++ b/remote/test/puppeteer/packages/ng-schematics/test/tsconfig.json @@ -3,8 +3,8 @@ "compilerOptions": { "rootDir": "src/", "outDir": "build/", - "types": ["node"], + "types": ["node"] }, "include": ["src/**/*"], - "references": [{"path": "../tsconfig.json"}], + "references": [{"path": "../tsconfig.json"}] } diff --git a/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json b/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json new file mode 100644 index 0000000000..f5b91f4af6 --- /dev/null +++ b/remote/test/puppeteer/packages/ng-schematics/test/tsdoc.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + + "extends": ["@microsoft/api-extractor/extends/tsdoc-base.json"], + "tagDefinitions": [ + { + "tagName": "@license", + "syntaxKind": "modifier", + "allowMultiple": false + } + ], + "supportForTags": { + "@license": true + } +} diff --git a/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs b/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs index 985200881e..1c6e346a6a 100644 --- a/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs +++ b/remote/test/puppeteer/packages/ng-schematics/tools/projects.mjs @@ -13,8 +13,14 @@ import {cwd} from 'process'; class AngularProject { static ports = new Set(); static randomPort() { - const min = 4000; - const max = 9876; + /** + * Some ports are restricted by Chromium and will fail to connect + * to prevent we start after the + * + * https://source.chromium.org/chromium/chromium/src/+/main:net/base/port_util.cc;l=107?q=kRestrictedPorts&ss=chromium + */ + const min = 10101; + const max = 20202; return Math.floor(Math.random() * (max - min + 1) + min); } static port() { diff --git a/remote/test/puppeteer/packages/ng-schematics/tsconfig.json b/remote/test/puppeteer/packages/ng-schematics/tsconfig.json index 40529c7d17..16b55d5233 100644 --- a/remote/test/puppeteer/packages/ng-schematics/tsconfig.json +++ b/remote/test/puppeteer/packages/ng-schematics/tsconfig.json @@ -10,8 +10,8 @@ "skipDefaultLibCheck": true, "skipLibCheck": true, "sourceMap": true, - "types": ["node"], + "types": ["node"] }, "include": ["src/**/*"], - "exclude": ["src/**/files/**/*"], + "exclude": ["src/**/files/**/*"] } diff --git a/remote/test/puppeteer/packages/puppeteer-core/.gitignore b/remote/test/puppeteer/packages/puppeteer-core/.gitignore index 42061c01a1..3d32a7ba82 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/.gitignore +++ b/remote/test/puppeteer/packages/puppeteer-core/.gitignore @@ -1 +1 @@ -README.md
\ No newline at end of file +/README.md
\ No newline at end of file diff --git a/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md b/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md index 341d706fb4..5076077c9f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md +++ b/remote/test/puppeteer/packages/puppeteer-core/CHANGELOG.md @@ -20,6 +20,146 @@ All notable changes to this project will be documented in this file. See [standa * dependencies * @puppeteer/browsers bumped from 1.5.1 to 1.6.0 +## [22.4.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.3.0...puppeteer-core-v22.4.0) (2024-03-05) + + +### Features + +* implement ElementHandle.uploadFile for WebDriver BiDi ([#11963](https://github.com/puppeteer/puppeteer/issues/11963)) ([accf2b6](https://github.com/puppeteer/puppeteer/commit/accf2b6ca84c93bc700277b4e3382d894fb45a76)) +* **webdriver:** support `Page.deleteCookie()` for WebDriver BiDi ([#12031](https://github.com/puppeteer/puppeteer/issues/12031)) ([7fe22b5](https://github.com/puppeteer/puppeteer/commit/7fe22b533dc96104f28696eb4ff96b2543fd8e5b)) + + +### Bug Fixes + +* roll to Chrome 122.0.6261.94 (r1250580) ([#12012](https://github.com/puppeteer/puppeteer/issues/12012)) ([7ba5529](https://github.com/puppeteer/puppeteer/commit/7ba5529f8d6f8ed085968b7a9bc6f25f8d91abd5)) +* **webdriver:** wait for response if the response has not completed once navigation has finished ([#12018](https://github.com/puppeteer/puppeteer/issues/12018)) ([6d8831a](https://github.com/puppeteer/puppeteer/commit/6d8831a9c398230f2543c3862d3fe5fc7cd2b940)) + +## [22.3.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.2.0...puppeteer-core-v22.3.0) (2024-02-25) + + +### Features + +* implement permissions for WebDriver BiDi ([#11979](https://github.com/puppeteer/puppeteer/issues/11979)) ([3a467c3](https://github.com/puppeteer/puppeteer/commit/3a467c39cb60de4237081ee201bd86051887c2f2)) + + +### Bug Fixes + +* roll to Chrome 122.0.6261.69 (r1250580) ([#11991](https://github.com/puppeteer/puppeteer/issues/11991)) ([eb2c334](https://github.com/puppeteer/puppeteer/commit/eb2c33485ec473e085c6b76b45554758764349d6)) +* supress viewport errors for pages that do not support changing it ([#11970](https://github.com/puppeteer/puppeteer/issues/11970)) ([753a954](https://github.com/puppeteer/puppeteer/commit/753a954456699fc06adf67837225f306711af856)) + +## [22.2.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.1.0...puppeteer-core-v22.2.0) (2024-02-21) + + +### Features + +* roll to Chrome 122.0.6261.57 (r1250580) ([#11958](https://github.com/puppeteer/puppeteer/issues/11958)) ([70ad3b2](https://github.com/puppeteer/puppeteer/commit/70ad3b244826ca102737e93cd2316e451ea310e8)) + + +### Bug Fixes + +* deprecate isIncognito ([#11962](https://github.com/puppeteer/puppeteer/issues/11962)) ([ceab7a9](https://github.com/puppeteer/puppeteer/commit/ceab7a9042fe5fc3f71875e75327bb370f1c43a5)) +* roll to Chrome 121.0.6167.184 (r1233107) ([#11948](https://github.com/puppeteer/puppeteer/issues/11948)) ([03ef7a6](https://github.com/puppeteer/puppeteer/commit/03ef7a62c23f2339e4d508d9abfe0894bd790cdd)) +* update touchscreen tests ([#11960](https://github.com/puppeteer/puppeteer/issues/11960)) ([013bd0b](https://github.com/puppeteer/puppeteer/commit/013bd0b12d3a69f9d62fffe7911a327ad26d33d8)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 2.0.1 to 2.1.0 + +## [22.1.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v22.0.0...puppeteer-core-v22.1.0) (2024-02-17) + + +### Features + +* support closing workers ([#11870](https://github.com/puppeteer/puppeteer/issues/11870)) ([1bdae40](https://github.com/puppeteer/puppeteer/commit/1bdae40ec865326fcb365320939869a6efb18c8a)) + + +### Bug Fixes + +* Chrome for Testing downloads have a new URL ([#11923](https://github.com/puppeteer/puppeteer/issues/11923)) ([f00a94a](https://github.com/puppeteer/puppeteer/commit/f00a94a809d38ee1c2c8cfc8597c66db9f3d243d)) +* deprecate `Page.prototype.target` ([#11872](https://github.com/puppeteer/puppeteer/issues/11872)) ([15c986c](https://github.com/puppeteer/puppeteer/commit/15c986c2bc5f5005a738187674cd6c44bcb3df3d)) +* frameElement should work for framesets ([#11842](https://github.com/puppeteer/puppeteer/issues/11842)) ([c5cee0e](https://github.com/puppeteer/puppeteer/commit/c5cee0e37dec8b90a17bf13400ede7ebdf453ac8)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 2.0.0 to 2.0.1 + +## [22.0.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.11.0...puppeteer-core-v22.0.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* rename createIncognitoBrowserContext to createBrowserContext ([#11834](https://github.com/puppeteer/puppeteer/issues/11834)) +* enable the new-headless mode by default ([#11815](https://github.com/puppeteer/puppeteer/issues/11815)) +* remove networkConditions in favor of PredefinedNetworkConditions ([#11806](https://github.com/puppeteer/puppeteer/issues/11806)) +* use ReadableStreams ([#11805](https://github.com/puppeteer/puppeteer/issues/11805)) +* remove duplicate type names ([#11803](https://github.com/puppeteer/puppeteer/issues/11803)) +* remove add/removeEventListener in favor of on/off ([#11792](https://github.com/puppeteer/puppeteer/issues/11792)) +* make console warn level compatible with WebDriver BiDi ([#11790](https://github.com/puppeteer/puppeteer/issues/11790)) +* remove InterceptResolutionStrategy ([#11788](https://github.com/puppeteer/puppeteer/issues/11788)) +* remove devices in favor of KnownDevices ([#11787](https://github.com/puppeteer/puppeteer/issues/11787)) +* remove `$x` and `waitForXpath` ([#11782](https://github.com/puppeteer/puppeteer/issues/11782)) +* remove waitForTimeout ([#11780](https://github.com/puppeteer/puppeteer/issues/11780)) +* generate accessible PDFs by default ([#11778](https://github.com/puppeteer/puppeteer/issues/11778)) +* remove `error` const, change CustomError to PuppeteerError ([#11777](https://github.com/puppeteer/puppeteer/issues/11777)) +* remove viewport resizing from ElementHandle.screenshot ([#11774](https://github.com/puppeteer/puppeteer/issues/11774)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) +* BiDi cookies ([#11532](https://github.com/puppeteer/puppeteer/issues/11532)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* BiDi cookies ([#11532](https://github.com/puppeteer/puppeteer/issues/11532)) ([9cb1fde](https://github.com/puppeteer/puppeteer/commit/9cb1fde58949811532644decb79b691318031d8c)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) +* generate accessible PDFs by default ([#11778](https://github.com/puppeteer/puppeteer/issues/11778)) ([4fc1402](https://github.com/puppeteer/puppeteer/commit/4fc14026e9bfffeedf317e9b61c7cda8509091ba)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) ([4677281](https://github.com/puppeteer/puppeteer/commit/467728187737283191f6528676e50d53dae6e5ef)) + + +### Bug Fixes + +* make console warn level compatible with WebDriver BiDi ([#11790](https://github.com/puppeteer/puppeteer/issues/11790)) ([d4e9d8d](https://github.com/puppeteer/puppeteer/commit/d4e9d8d591e4fb1e2a33fe3a586a8beaccf263e8)) +* remove viewport resizing from ElementHandle.screenshot ([#11774](https://github.com/puppeteer/puppeteer/issues/11774)) ([ced2235](https://github.com/puppeteer/puppeteer/commit/ced2235ada95ad67227df0ce579070ccb501a47b)) + + +### Code Refactoring + +* enable the new-headless mode by default ([#11815](https://github.com/puppeteer/puppeteer/issues/11815)) ([75c9e11](https://github.com/puppeteer/puppeteer/commit/75c9e117f1bf0d7a4de82c79201d70bf3cee2b6f)) +* remove `$x` and `waitForXpath` ([#11782](https://github.com/puppeteer/puppeteer/issues/11782)) ([53c9134](https://github.com/puppeteer/puppeteer/commit/53c91348094dc0bce59086c98986c5d06a949d08)) +* remove `error` const, change CustomError to PuppeteerError ([#11777](https://github.com/puppeteer/puppeteer/issues/11777)) ([b3bfdd2](https://github.com/puppeteer/puppeteer/commit/b3bfdd2024097be1974e28b3766419189b4a9fe0)) +* remove add/removeEventListener in favor of on/off ([#11792](https://github.com/puppeteer/puppeteer/issues/11792)) ([f160874](https://github.com/puppeteer/puppeteer/commit/f1608743c83e8ce7b56aec98ccdddacc91b86179)) +* remove devices in favor of KnownDevices ([#11787](https://github.com/puppeteer/puppeteer/issues/11787)) ([eb360e3](https://github.com/puppeteer/puppeteer/commit/eb360e3a762d9232a4972d4ec877b7d57a5b60c7)) +* remove duplicate type names ([#11803](https://github.com/puppeteer/puppeteer/issues/11803)) ([514e2d5](https://github.com/puppeteer/puppeteer/commit/514e2d5241dc3a9027c96d739cfc99efc5a02783)) +* remove InterceptResolutionStrategy ([#11788](https://github.com/puppeteer/puppeteer/issues/11788)) ([f18d447](https://github.com/puppeteer/puppeteer/commit/f18d44761cd1acc2e6b867e5eb2ebd753854e9ea)) +* remove networkConditions in favor of PredefinedNetworkConditions ([#11806](https://github.com/puppeteer/puppeteer/issues/11806)) ([7564dfa](https://github.com/puppeteer/puppeteer/commit/7564dfa9110e44b1f50f5fb1543c5c7d8529c182)) +* remove waitForTimeout ([#11780](https://github.com/puppeteer/puppeteer/issues/11780)) ([1900fa9](https://github.com/puppeteer/puppeteer/commit/1900fa94183e0a8654633a91f82b372ad068da71)) +* rename createIncognitoBrowserContext to createBrowserContext ([#11834](https://github.com/puppeteer/puppeteer/issues/11834)) ([46a3ef2](https://github.com/puppeteer/puppeteer/commit/46a3ef2681456d604e775f578fa447a094200610)) +* use ReadableStreams ([#11805](https://github.com/puppeteer/puppeteer/issues/11805)) ([84d9a94](https://github.com/puppeteer/puppeteer/commit/84d9a94d6228800e9f80914472ff2e5a4ee71b18)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @puppeteer/browsers bumped from 1.9.1 to 2.0.0 + +## [21.11.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.10.0...puppeteer-core-v21.11.0) (2024-02-02) + + +### Features + +* add outline to PDF generation ([#11779](https://github.com/puppeteer/puppeteer/issues/11779)) ([b99d478](https://github.com/puppeteer/puppeteer/commit/b99d478cd48adc261878836e04eac55ecc2890f2)) +* **bidi:** implement UserContexts ([#11784](https://github.com/puppeteer/puppeteer/issues/11784)) ([2930a70](https://github.com/puppeteer/puppeteer/commit/2930a70c884ce6835ec6bcff27b32f7d273c8af0)) + + +### Bug Fixes + +* use shareReplay for inflight requests ([#11810](https://github.com/puppeteer/puppeteer/issues/11810)) ([0f0813d](https://github.com/puppeteer/puppeteer/commit/0f0813db38aa0eb14d7514d725852d0cb66f4f0e)) + ## [21.10.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-core-v21.9.0...puppeteer-core-v21.10.0) (2024-01-29) diff --git a/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs b/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs index 723fa2868a..972a080ba0 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs +++ b/remote/test/puppeteer/packages/puppeteer-core/Herebyfile.mjs @@ -1,10 +1,19 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {mkdir, readFile, readdir, writeFile} from 'fs/promises'; -import {join} from 'path/posix'; +import Module from 'node:module'; +import path from 'path'; +import posixPath from 'path/posix'; import esbuild from 'esbuild'; import {execa} from 'execa'; import {task} from 'hereby'; +const require = Module.createRequire(import.meta.url); + export const generateVersionTask = task({ name: 'generate:version', run: async () => { @@ -91,20 +100,52 @@ export const buildTask = task({ }); const builders = []; for (const format of formats) { - const folder = join('lib', format, 'third_party'); + const folder = posixPath.join('lib', format, 'third_party'); for (const name of packages) { - const path = join(folder, name, `${name}.js`); + const entrypoint = posixPath.join(folder, name, `${name}.js`); builders.push( await esbuild.build({ - entryPoints: [path], - outfile: path, + entryPoints: [entrypoint], + outfile: entrypoint, bundle: true, allowOverwrite: true, format, target: 'node16', minify: true, + legalComments: 'inline', }) ); + let license = ''; + switch (name) { + case 'rxjs': + license = await readFile( + path.join( + path.dirname(require.resolve('rxjs')), + '..', + '..', + 'LICENSE.txt' + ), + 'utf-8' + ); + break; + case 'mitt': + license = await readFile( + path.join(path.dirname(require.resolve('mitt')), '..', 'LICENSE'), + 'utf-8' + ); + break; + default: + throw new Error(`Add license handling for ${path}`); + } + const content = await readFile(entrypoint, 'utf-8'); + await writeFile( + entrypoint, + `/** +${license} +*/ +${content}`, + 'utf-8' + ); } } await Promise.all(builders); diff --git a/remote/test/puppeteer/packages/puppeteer-core/package.json b/remote/test/puppeteer/packages/puppeteer-core/package.json index 2f1943bd2f..1d4d564c4f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/package.json +++ b/remote/test/puppeteer/packages/puppeteer-core/package.json @@ -1,6 +1,6 @@ { "name": "puppeteer-core", - "version": "21.10.0", + "version": "22.4.0", "description": "A high-level API to control headless Chrome over the DevTools Protocol", "keywords": [ "puppeteer", @@ -31,13 +31,13 @@ "url": "https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "scripts": { "build:docs": "wireit", "build": "wireit", "check": "tsx tools/ensure-correct-devtools-protocol-package", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "prepack": "wireit", "unit": "wireit" }, @@ -77,7 +77,8 @@ "files": [ "{src,third_party}/**", "../../versions.js", - "!src/generated" + "!src/generated", + "Herebyfile.mjs" ], "output": [ "lib/{cjs,esm}/**" @@ -118,11 +119,11 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.9.1", - "chromium-bidi": "0.5.6", + "@puppeteer/browsers": "2.1.0", + "chromium-bidi": "0.5.12", "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1232444", + "devtools-protocol": "0.0.1249869", "ws": "8.16.0" }, "devDependencies": { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts index e3b465c80e..6d7ea19d49 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Browser.ts @@ -9,7 +9,6 @@ import type {ChildProcess} from 'child_process'; import type {Protocol} from 'devtools-protocol'; import { - filterAsync, firstValueFrom, from, merge, @@ -17,7 +16,12 @@ import { } from '../../third_party/rxjs/rxjs.js'; import type {ProtocolType} from '../common/ConnectOptions.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; -import {debugError, fromEmitterEvent, timeout} from '../common/util.js'; +import { + debugError, + fromEmitterEvent, + filterAsync, + timeout, +} from '../common/util.js'; import {asyncDisposeSymbol, disposeSymbol} from '../util/disposable.js'; import type {BrowserContext} from './BrowserContext.js'; @@ -136,7 +140,7 @@ export const enum BrowserEvent { * Emitted when the URL of a target changes. Contains a {@link Target} * instance. * - * @remarks Note that this includes target changes in incognito browser + * @remarks Note that this includes target changes in all browser * contexts. */ TargetChanged = 'targetchanged', @@ -147,7 +151,7 @@ export const enum BrowserEvent { * * Contains a {@link Target} instance. * - * @remarks Note that this includes target creations in incognito browser + * @remarks Note that this includes target creations in all browser * contexts. */ TargetCreated = 'targetcreated', @@ -155,7 +159,7 @@ export const enum BrowserEvent { * Emitted when a target is destroyed, for example when a page is closed. * Contains a {@link Target} instance. * - * @remarks Note that this includes target destructions in incognito browser + * @remarks Note that this includes target destructions in all browser * contexts. */ TargetDestroyed = 'targetdestroyed', @@ -165,13 +169,6 @@ export const enum BrowserEvent { TargetDiscovered = 'targetdiscovered', } -export { - /** - * @deprecated Use {@link BrowserEvent}. - */ - BrowserEvent as BrowserEmittedEvents, -}; - /** * @public */ @@ -251,7 +248,7 @@ export abstract class Browser extends EventEmitter<BrowserEvents> { abstract process(): ChildProcess | null; /** - * Creates a new incognito {@link BrowserContext | browser context}. + * Creates a new {@link BrowserContext | browser context}. * * This won't share cookies/cache with other {@link BrowserContext | browser contexts}. * @@ -261,15 +258,15 @@ export abstract class Browser extends EventEmitter<BrowserEvents> { * import puppeteer from 'puppeteer'; * * const browser = await puppeteer.launch(); - * // Create a new incognito browser context. - * const context = await browser.createIncognitoBrowserContext(); + * // Create a new browser context. + * const context = await browser.createBrowserContext(); * // Create a new page in a pristine context. * const page = await context.newPage(); * // Do stuff * await page.goto('https://example.com'); * ``` */ - abstract createIncognitoBrowserContext( + abstract createBrowserContext( options?: BrowserContextOptions ): Promise<BrowserContext>; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts index 79335eb9ed..5e6a5d5d5c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/BrowserContext.ts @@ -4,8 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { + firstValueFrom, + from, + merge, + raceWith, +} from '../../third_party/rxjs/rxjs.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; -import {debugError} from '../common/util.js'; +import { + debugError, + fromEmitterEvent, + filterAsync, + timeout, +} from '../common/util.js'; import {asyncDisposeSymbol, disposeSymbol} from '../util/disposable.js'; import type {Browser, Permission, WaitForTargetOptions} from './Browser.js'; @@ -38,13 +49,6 @@ export const enum BrowserContextEvent { TargetDestroyed = 'targetdestroyed', } -export { - /** - * @deprecated Use {@link BrowserContextEvent} - */ - BrowserContextEvent as BrowserContextEmittedEvents, -}; - /** * @public */ @@ -55,12 +59,13 @@ export interface BrowserContextEvents extends Record<EventType, unknown> { } /** - * {@link BrowserContext} represents individual sessions within a + * {@link BrowserContext} represents individual user contexts within a * {@link Browser | browser}. * * When a {@link Browser | browser} is launched, it has a single * {@link BrowserContext | browser context} by default. Others can be created - * using {@link Browser.createIncognitoBrowserContext}. + * using {@link Browser.createBrowserContext}. Each context has isolated storage + * (cookies/localStorage/etc.) * * {@link BrowserContext} {@link EventEmitter | emits} various events which are * documented in the {@link BrowserContextEvent} enum. @@ -69,11 +74,11 @@ export interface BrowserContextEvents extends Record<EventType, unknown> { * `window.open`, the popup will belong to the parent {@link Page.browserContext * | page's browser context}. * - * @example Creating an incognito {@link BrowserContext | browser context}: + * @example Creating a new {@link BrowserContext | browser context}: * * ```ts - * // Create a new incognito browser context - * const context = await browser.createIncognitoBrowserContext(); + * // Create a new browser context + * const context = await browser.createBrowserContext(); * // Create a new page inside context. * const page = await context.newPage(); * // ... do stuff with page ... @@ -114,10 +119,19 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents> * ); * ``` */ - abstract waitForTarget( + async waitForTarget( predicate: (x: Target) => boolean | Promise<boolean>, - options?: WaitForTargetOptions - ): Promise<Target>; + options: WaitForTargetOptions = {} + ): Promise<Target> { + const {timeout: ms = 30000} = options; + return await firstValueFrom( + merge( + fromEmitterEvent(this, BrowserContextEvent.TargetCreated), + fromEmitterEvent(this, BrowserContextEvent.TargetChanged), + from(this.targets()) + ).pipe(filterAsync(predicate), raceWith(timeout(ms))) + ); + } /** * Gets a list of all open {@link Page | pages} inside this @@ -131,8 +145,20 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents> /** * Whether this {@link BrowserContext | browser context} is incognito. * - * The {@link Browser.defaultBrowserContext | default browser context} is the - * only non-incognito browser context. + * In Chrome, the + * {@link Browser.defaultBrowserContext | default browser context} is the only + * non-incognito browser context. + * + * @deprecated In Chrome, the + * {@link Browser.defaultBrowserContext | default browser context} can also be + * "icognito" if configured via the arguments and in such cases this getter + * returns wrong results (see + * https://github.com/puppeteer/puppeteer/issues/8836). Also, the term + * "incognito" is not applicable to other browsers. To migrate, check the + * {@link Browser.defaultBrowserContext | default browser context} instead: in + * Chrome all non-default contexts are incognito, and the default context + * might be incognito if you provide the `--incognito` argument when launching + * the browser. */ abstract isIncognito(): boolean; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts index 8bdf96f954..3a1fdf1e24 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/CDPSession.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js'; import type {Connection} from '../cdp/Connection.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts index 43fec58e37..9b1326f998 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/ElementHandle.ts @@ -17,15 +17,10 @@ import type { NodeFor, } from '../common/types.js'; import type {KeyInput} from '../common/USKeyboardLayout.js'; -import { - debugError, - isString, - withSourcePuppeteerURLIfNone, -} from '../common/util.js'; +import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js'; import {assert} from '../util/assert.js'; import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {throwIfDisposed} from '../util/decorators.js'; -import {AsyncDisposableStack} from '../util/disposable.js'; import {_isElementHandle} from './ElementHandleSymbol.js'; import type { @@ -482,27 +477,6 @@ export abstract class ElementHandle< } /** - * @deprecated Use {@link ElementHandle.$$} with the `xpath` prefix. - * - * Example: `await elementHandle.$$('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the elementHandle. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * If there are no such elements, the method will resolve to an empty array. - * @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate} - */ - @throwIfDisposed() - @ElementHandle.bindIsolatedHandle - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - if (expression.startsWith('//')) { - expression = `.${expression}`; - } - return await this.$$(`xpath/${expression}`); - } - - /** * Wait for an element matching the given selector to appear in the current * element. * @@ -587,84 +561,6 @@ export abstract class ElementHandle< } /** - * @deprecated Use {@link ElementHandle.waitForSelector} with the `xpath` - * prefix. - * - * Example: `await elementHandle.waitForSelector('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the elementHandle. - * - * Wait for the `xpath` within the element. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * @example - * This method works across navigation. - * - * ```ts - * import puppeteer from 'puppeteer'; - * (async () => { - * const browser = await puppeteer.launch(); - * const page = await browser.newPage(); - * let currentURL; - * page - * .waitForXPath('//img') - * .then(() => console.log('First URL with image: ' + currentURL)); - * for (currentURL of [ - * 'https://example.com', - * 'https://google.com', - * 'https://bbc.com', - * ]) { - * await page.goto(currentURL); - * } - * await browser.close(); - * })(); - * ``` - * - * @param xpath - A - * {@link https://developer.mozilla.org/en-US/docs/Web/XPath | xpath} of an - * element to wait for - * @param options - Optional waiting parameters - * @returns Promise which resolves when element specified by xpath string is - * added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is - * not found in DOM, otherwise resolves to `ElementHandle`. - * @remarks - * The optional Argument `options` have properties: - * - * - `visible`: A boolean to wait for element to be present in DOM and to be - * visible, i.e. to not have `display: none` or `visibility: hidden` CSS - * properties. Defaults to `false`. - * - * - `hidden`: A boolean wait for element to not be found in the DOM or to be - * hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. - * Defaults to `false`. - * - * - `timeout`: A number which is maximum time to wait for in milliseconds. - * Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The - * default value can be changed by using the {@link Page.setDefaultTimeout} - * method. - */ - @throwIfDisposed() - @ElementHandle.bindIsolatedHandle - async waitForXPath( - xpath: string, - options: { - visible?: boolean; - hidden?: boolean; - timeout?: number; - } = {} - ): Promise<ElementHandle<Node> | null> { - if (xpath.startsWith('//')) { - xpath = `.${xpath}`; - } - return await this.waitForSelector(`xpath/${xpath}`, options); - } - - /** * Converts the current handle to the given element type. * * @example @@ -1346,30 +1242,6 @@ export abstract class ElementHandle< const page = this.frame.page(); - // If the element is larger than the viewport, `captureBeyondViewport` will - // _not_ affect element rendering, so we need to adjust the viewport to - // properly render the element. - const viewport = page.viewport() ?? { - width: clip.width, - height: clip.height, - }; - await using stack = new AsyncDisposableStack(); - if (clip.width > viewport.width || clip.height > viewport.height) { - await this.frame.page().setViewport({ - ...viewport, - width: Math.max(viewport.width, Math.ceil(clip.width)), - height: Math.max(viewport.height, Math.ceil(clip.height)), - }); - - stack.defer(async () => { - try { - await this.frame.page().setViewport(viewport); - } catch (error) { - debugError(error); - } - }); - } - // Only scroll the element into view if the user wants it. if (scrollIntoView) { await this.scrollIntoViewIfNeeded(); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts index 757ec872c6..19b5eb7fa0 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Frame.ts @@ -14,7 +14,6 @@ import type { WaitTimeoutOptions, } from '../api/Page.js'; import type {DeviceRequestPrompt} from '../cdp/DeviceRequestPrompt.js'; -import type {IsolatedWorldChart} from '../cdp/IsolatedWorld.js'; import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js'; @@ -38,8 +37,8 @@ import type {CDPSession} from './CDPSession.js'; import type {KeyboardTypeOptions} from './Input.js'; import { FunctionLocator, - type Locator, NodeLocator, + type Locator, } from './locators/locators.js'; import type {Realm} from './Realm.js'; @@ -273,11 +272,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { /** * @internal */ - worlds!: IsolatedWorldChart; - - /** - * @internal - */ _name?: string; /** @@ -339,12 +333,7 @@ export abstract class Frame extends EventEmitter<FrameEvents> { */ abstract goto( url: string, - options?: { - referer?: string; - referrerPolicy?: string; - timeout?: number; - waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]; - } + options?: GoToOptions ): Promise<HTTPResponse | null>; /** @@ -425,12 +414,12 @@ export abstract class Frame extends EventEmitter<FrameEvents> { return null; } using list = await parentFrame.isolatedRealm().evaluateHandle(() => { - return document.querySelectorAll('iframe'); + return document.querySelectorAll('iframe,frame'); }); for await (using iframe of transposeIterableHandle(list)) { const frame = await iframe.contentFrame(); - if (frame._id === this._id) { - return iframe.move(); + if (frame?._id === this._id) { + return (iframe as HandleFor<HTMLIFrameElement>).move(); } } return null; @@ -624,23 +613,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Use {@link Frame.$$} with the `xpath` prefix. - * - * Example: `await frame.$$('xpath/' + xpathExpression)` - * - * This method evaluates the given XPath expression and returns the results. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * @param expression - the XPath expression to evaluate. - */ - @throwIfDetached - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - // eslint-disable-next-line rulesdir/use-using -- This is cached. - const document = await this.#document(); - return await document.$x(expression); - } - - /** * Waits for an element matching the given selector to appear in the frame. * * This method works across navigations. @@ -690,39 +662,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Use {@link Frame.waitForSelector} with the `xpath` prefix. - * - * Example: `await frame.waitForSelector('xpath/' + xpathExpression)` - * - * The method evaluates the XPath expression relative to the Frame. - * If `xpath` starts with `//` instead of `.//`, the dot will be appended - * automatically. - * - * Wait for the `xpath` to appear in page. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the xpath doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * For a code example, see the example for {@link Frame.waitForSelector}. That - * function behaves identically other than taking a CSS selector rather than - * an XPath. - * - * @param xpath - the XPath expression to wait for. - * @param options - options to configure the visibility of the element and how - * long to wait before timing out. - */ - @throwIfDetached - async waitForXPath( - xpath: string, - options: WaitForSelectorOptions = {} - ): Promise<ElementHandle<Node> | null> { - if (xpath.startsWith('//')) { - xpath = `.${xpath}`; - } - return await this.waitForSelector(`xpath/${xpath}`, options); - } - - /** * @example * The `waitForFunction` can be used to observe viewport size change: * @@ -799,13 +738,7 @@ export abstract class Frame extends EventEmitter<FrameEvents> { * @param options - Options to configure how long before timing out and at * what point to consider the content setting successful. */ - abstract setContent( - html: string, - options?: { - timeout?: number; - waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]; - } - ): Promise<void>; + abstract setContent(html: string, options?: WaitForOptions): Promise<void>; /** * @internal @@ -1152,32 +1085,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> { } /** - * @deprecated Replace with `new Promise(r => setTimeout(r, milliseconds));`. - * - * Causes your script to wait for the given number of milliseconds. - * - * @remarks - * It's generally recommended to not wait for a number of seconds, but instead - * use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or - * {@link Frame.waitForFunction} to wait for exactly the conditions you want. - * - * @example - * - * Wait for 1 second: - * - * ```ts - * await frame.waitForTimeout(1000); - * ``` - * - * @param milliseconds - the number of milliseconds to wait. - */ - async waitForTimeout(milliseconds: number): Promise<void> { - return await new Promise(resolve => { - setTimeout(resolve, milliseconds); - }); - } - - /** * The frame's title. */ @throwIfDetached diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts index 3c952371ee..d72f088686 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/HTTPRequest.ts @@ -94,7 +94,8 @@ export abstract class HTTPRequest { /** * @internal */ - _requestId = ''; + abstract get id(): string; + /** * @internal */ @@ -395,13 +396,6 @@ export enum InterceptResolutionAction { /** * @public - * - * @deprecated please use {@link InterceptResolutionAction} instead. - */ -export type InterceptResolutionStrategy = InterceptResolutionAction; - -/** - * @public */ export type ErrorCode = | 'aborted' diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts index deb04628fd..b094d14b2f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/Page.ts @@ -4,26 +4,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - import type {Protocol} from 'devtools-protocol'; import { concat, EMPTY, filter, - filterAsync, first, firstValueFrom, from, map, merge, mergeMap, + mergeScan, of, - race, raceWith, + ReplaySubject, startWith, switchMap, + take, takeUntil, timer, type Observable, @@ -36,6 +35,11 @@ import type {DeviceRequestPrompt} from '../cdp/DeviceRequestPrompt.js'; import type {Credentials, NetworkConditions} from '../cdp/NetworkManager.js'; import type {Tracing} from '../cdp/Tracing.js'; import type {ConsoleMessage} from '../common/ConsoleMessage.js'; +import type { + Cookie, + CookieParam, + DeleteCookiesRequest, +} from '../common/Cookie.js'; import type {Device} from '../common/Device.js'; import {TargetCloseError} from '../common/Errors.js'; import { @@ -58,6 +62,7 @@ import type { import { debugError, fromEmitterEvent, + filterAsync, importFSPromises, isString, NETWORK_IDLE_TIME, @@ -477,15 +482,6 @@ export const enum PageEvent { WorkerDestroyed = 'workerdestroyed', } -export { - /** - * All the events that a page instance may emit. - * - * @deprecated Use {@link PageEvent}. - */ - PageEvent as PageEmittedEvents, -}; - /** * Denotes the objects received by callback functions for page events. * @@ -516,13 +512,6 @@ export interface PageEvents extends Record<EventType, unknown> { [PageEvent.WorkerDestroyed]: WebWorker; } -export type { - /** - * @deprecated Use {@link PageEvents}. - */ - PageEvents as PageEventObject, -}; - /** * @public */ @@ -604,8 +593,7 @@ export abstract class Page extends EventEmitter<PageEvents> { #requestHandlers = new WeakMap<Handler<HTTPRequest>, Handler<HTTPRequest>>(); - #requestsInFlight = 0; - #inflight$: Observable<number>; + #inflight$ = new ReplaySubject<number>(1); /** * @internal @@ -613,39 +601,37 @@ export abstract class Page extends EventEmitter<PageEvents> { constructor() { super(); - this.#inflight$ = fromEmitterEvent(this, PageEvent.Request).pipe( - takeUntil(fromEmitterEvent(this, PageEvent.Close)), - mergeMap(request => { - return concat( - of(1), - race( - fromEmitterEvent(this, PageEvent.Response).pipe( - filter(response => { - return response.request()._requestId === request._requestId; - }) - ), - fromEmitterEvent(this, PageEvent.RequestFailed).pipe( - filter(failure => { - return failure._requestId === request._requestId; - }) - ), - fromEmitterEvent(this, PageEvent.RequestFinished).pipe( - filter(success => { - return success._requestId === request._requestId; + fromEmitterEvent(this, PageEvent.Request) + .pipe( + mergeMap(originalRequest => { + return concat( + of(1), + merge( + fromEmitterEvent(this, PageEvent.RequestFailed), + fromEmitterEvent(this, PageEvent.RequestFinished), + fromEmitterEvent(this, PageEvent.Response).pipe( + map(response => { + return response.request(); + }) + ) + ).pipe( + filter(request => { + return request.id === originalRequest.id; + }), + take(1), + map(() => { + return -1; }) ) - ).pipe( - map(() => { - return -1; - }) - ) - ); - }) - ); - - this.#inflight$.subscribe(count => { - this.#requestsInFlight += count; - }); + ); + }), + mergeScan((acc, addend) => { + return of(acc + addend); + }, 0), + takeUntil(fromEmitterEvent(this, PageEvent.Close)), + startWith(0) + ) + .subscribe(this.#inflight$); } /** @@ -771,6 +757,8 @@ export abstract class Page extends EventEmitter<PageEvents> { /** * A target this page was created from. + * + * @deprecated Use {@link Page.createCDPSession} directly. */ abstract target(): Target; @@ -1287,28 +1275,12 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * The method evaluates the XPath expression relative to the page document as - * its context node. If there are no such elements, the method resolves to an - * empty array. - * - * @remarks - * Shortcut for {@link Frame.$x | Page.mainFrame().$x(expression) }. - * - * @param expression - Expression to evaluate - */ - async $x(expression: string): Promise<Array<ElementHandle<Node>>> { - return await this.mainFrame().$x(expression); - } - - /** * If no URLs are specified, this method returns cookies for the current page * URL. If URLs are specified, only cookies for those URLs are returned. */ - abstract cookies(...urls: string[]): Promise<Protocol.Network.Cookie[]>; + abstract cookies(...urls: string[]): Promise<Cookie[]>; - abstract deleteCookie( - ...cookies: Protocol.Network.DeleteCookiesRequest[] - ): Promise<void>; + abstract deleteCookie(...cookies: DeleteCookiesRequest[]): Promise<void>; /** * @example @@ -1317,7 +1289,7 @@ export abstract class Page extends EventEmitter<PageEvents> { * await page.setCookie(cookieObject1, cookieObject2); * ``` */ - abstract setCookie(...cookies: Protocol.Network.CookieParam[]): Promise<void>; + abstract setCookie(...cookies: CookieParam[]): Promise<void>; /** * Adds a `<script>` tag into the page with the desired URL or content. @@ -1776,13 +1748,11 @@ export abstract class Page extends EventEmitter<PageEvents> { } = options; return this.#inflight$.pipe( - startWith(this.#requestsInFlight), - switchMap(() => { - if (this.#requestsInFlight > concurrency) { + switchMap(inflight => { + if (inflight > concurrency) { return EMPTY; - } else { - return timer(idleTime); } + return timer(idleTime); }), map(() => {}), raceWith( @@ -2604,7 +2574,9 @@ export abstract class Page extends EventEmitter<PageEvents> { * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust | `-webkit-print-color-adjust`} * property to force rendering of exact colors. */ - abstract createPDFStream(options?: PDFOptions): Promise<Readable>; + abstract createPDFStream( + options?: PDFOptions + ): Promise<ReadableStream<Uint8Array>>; /** * {@inheritDoc Page.createPDFStream} @@ -2785,31 +2757,6 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * @deprecated Replace with `new Promise(r => setTimeout(r, milliseconds));`. - * - * Causes your script to wait for the given number of milliseconds. - * - * @remarks - * - * It's generally recommended to not wait for a number of seconds, but instead - * use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or - * {@link Frame.waitForFunction} to wait for exactly the conditions you want. - * - * @example - * - * Wait for 1 second: - * - * ```ts - * await page.waitForTimeout(1000); - * ``` - * - * @param milliseconds - the number of milliseconds to wait. - */ - waitForTimeout(milliseconds: number): Promise<void> { - return this.mainFrame().waitForTimeout(milliseconds); - } - - /** * Wait for the `selector` to appear in page. If at the moment of calling the * method the `selector` already exists, the method will return immediately. If * the `selector` doesn't appear after the `timeout` milliseconds of waiting, the @@ -2869,64 +2816,6 @@ export abstract class Page extends EventEmitter<PageEvents> { } /** - * Wait for the `xpath` to appear in page. If at the moment of calling the - * method the `xpath` already exists, the method will return immediately. If - * the `xpath` doesn't appear after the `timeout` milliseconds of waiting, the - * function will throw. - * - * @example - * This method works across navigation - * - * ```ts - * import puppeteer from 'puppeteer'; - * (async () => { - * const browser = await puppeteer.launch(); - * const page = await browser.newPage(); - * let currentURL; - * page - * .waitForXPath('//img') - * .then(() => console.log('First URL with image: ' + currentURL)); - * for (currentURL of [ - * 'https://example.com', - * 'https://google.com', - * 'https://bbc.com', - * ]) { - * await page.goto(currentURL); - * } - * await browser.close(); - * })(); - * ``` - * - * @param xpath - A - * {@link https://developer.mozilla.org/en-US/docs/Web/XPath | xpath} of an - * element to wait for - * @param options - Optional waiting parameters - * @returns Promise which resolves when element specified by xpath string is - * added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is - * not found in DOM, otherwise resolves to `ElementHandle`. - * @remarks - * The optional Argument `options` have properties: - * - * - `visible`: A boolean to wait for element to be present in DOM and to be - * visible, i.e. to not have `display: none` or `visibility: hidden` CSS - * properties. Defaults to `false`. - * - * - `hidden`: A boolean wait for element to not be found in the DOM or to be - * hidden, i.e. have `display: none` or `visibility: hidden` CSS properties. - * Defaults to `false`. - * - * - `timeout`: A number which is maximum time to wait for in milliseconds. - * Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default - * value can be changed by using the {@link Page.setDefaultTimeout} method. - */ - waitForXPath( - xpath: string, - options?: WaitForSelectorOptions - ): Promise<ElementHandle<Node> | null> { - return this.mainFrame().waitForXPath(xpath, options); - } - - /** * Waits for the provided function, `pageFunction`, to return a truthy value when * evaluated in the page's context. * diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts index 4de287f146..b65452b650 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/WebWorker.ts @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import {UnsupportedOperation} from '../common/Errors.js'; import {EventEmitter, type EventType} from '../common/EventEmitter.js'; import {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {EvaluateFunc, HandleFor} from '../common/types.js'; @@ -131,4 +132,8 @@ export abstract class WebWorker extends EventEmitter< func = withSourcePuppeteerURLIfNone(this.evaluateHandle.name, func); return await this.mainRealm().evaluateHandle(func, ...args); } + + async close(): Promise<void> { + throw new UnsupportedOperation('WebWorker.close() is not supported'); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts b/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts index 7bec11e38e..d88cc0a17d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/api/locators/locators.ts @@ -109,24 +109,14 @@ export enum LocatorEvent { */ Action = 'action', } -export { - /** - * @deprecated Use {@link LocatorEvent}. - */ - LocatorEvent as LocatorEmittedEvents, -}; + /** * @public */ export interface LocatorEvents extends Record<EventType, unknown> { [LocatorEvent.Action]: undefined; } -export type { - /** - * @deprecated Use {@link LocatorEvents}. - */ - LocatorEvents as LocatorEventObject, -}; + /** * Locators describe a strategy of locating objects and performing an action on * them. If the action fails because the object is not ready for the action, the diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts index 42979790c9..8798d8325d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Browser.ts @@ -8,6 +8,7 @@ import type {ChildProcess} from 'child_process'; import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import type {BrowserEvents} from '../api/Browser.js'; import { Browser, BrowserEvent, @@ -19,22 +20,17 @@ import {BrowserContextEvent} from '../api/BrowserContext.js'; import type {Page} from '../api/Page.js'; import type {Target} from '../api/Target.js'; import {UnsupportedOperation} from '../common/Errors.js'; -import type {Handler} from '../common/EventEmitter.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; +import {bubble} from '../util/decorators.js'; import {BidiBrowserContext} from './BrowserContext.js'; -import {BrowsingContext, BrowsingContextEvent} from './BrowsingContext.js'; import type {BidiConnection} from './Connection.js'; import type {Browser as BrowserCore} from './core/Browser.js'; import {Session} from './core/Session.js'; import type {UserContext} from './core/UserContext.js'; -import { - BiDiBrowserTarget, - BiDiBrowsingContextTarget, - BiDiPageTarget, - type BidiTarget, -} from './Target.js'; +import {BidiBrowserTarget} from './Target.js'; /** * @internal @@ -89,28 +85,18 @@ export class BidiBrowser extends Browser { const browser = new BidiBrowser(session.browser, opts); browser.#initialize(); - await browser.#getTree(); return browser; } + @bubble() + accessor #trustedEmitter = new EventEmitter<BrowserEvents>(); + #process?: ChildProcess; #closeCallback?: BrowserCloseCallback; #browserCore: BrowserCore; #defaultViewport: Viewport | null; - #targets = new Map<string, BidiTarget>(); #browserContexts = new WeakMap<UserContext, BidiBrowserContext>(); - #browserTarget: BiDiBrowserTarget; - - #connectionEventHandlers = new Map< - Bidi.BrowsingContextEvent['method'], - Handler<any> - >([ - ['browsingContext.contextCreated', this.#onContextCreated.bind(this)], - ['browsingContext.contextDestroyed', this.#onContextDestroyed.bind(this)], - ['browsingContext.domContentLoaded', this.#onContextDomLoaded.bind(this)], - ['browsingContext.fragmentNavigated', this.#onContextNavigation.bind(this)], - ['browsingContext.navigationStarted', this.#onContextNavigation.bind(this)], - ]); + #target = new BidiBrowserTarget(this); private constructor(browserCore: BrowserCore, opts: BidiBrowserOptions) { super(); @@ -118,22 +104,22 @@ export class BidiBrowser extends Browser { this.#closeCallback = opts.closeCallback; this.#browserCore = browserCore; this.#defaultViewport = opts.defaultViewport; - this.#browserTarget = new BiDiBrowserTarget(this); - this.#createBrowserContext(this.#browserCore.defaultUserContext); } #initialize() { + // Initializing existing contexts. + for (const userContext of this.#browserCore.userContexts) { + this.#createBrowserContext(userContext); + } + this.#browserCore.once('disconnected', () => { - this.emit(BrowserEvent.Disconnected, undefined); + this.#trustedEmitter.emit(BrowserEvent.Disconnected, undefined); + this.#trustedEmitter.removeAllListeners(); }); this.#process?.once('close', () => { this.#browserCore.dispose('Browser process exited.', true); this.connection.dispose(); }); - - for (const [eventName, handler] of this.#connectionEventHandlers) { - this.connection.on(eventName, handler); - } } get #browserName() { @@ -143,82 +129,40 @@ export class BidiBrowser extends Browser { return this.#browserCore.session.capabilities.browserVersion; } + get cdpSupported(): boolean { + return !this.#browserName.toLocaleLowerCase().includes('firefox'); + } + override userAgent(): never { throw new UnsupportedOperation(); } #createBrowserContext(userContext: UserContext) { - const browserContext = new BidiBrowserContext(this, userContext, { + const browserContext = BidiBrowserContext.from(this, userContext, { defaultViewport: this.#defaultViewport, }); this.#browserContexts.set(userContext, browserContext); - return browserContext; - } - - #onContextDomLoaded(event: Bidi.BrowsingContext.Info) { - const target = this.#targets.get(event.context); - if (target) { - this.emit(BrowserEvent.TargetChanged, target); - } - } - - #onContextNavigation(event: Bidi.BrowsingContext.NavigationInfo) { - const target = this.#targets.get(event.context); - if (target) { - this.emit(BrowserEvent.TargetChanged, target); - target.browserContext().emit(BrowserContextEvent.TargetChanged, target); - } - } - #onContextCreated(event: Bidi.BrowsingContext.ContextCreated['params']) { - const context = new BrowsingContext( - this.connection, - event, - this.#browserName + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetCreated, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetCreated, target); + } + ); + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetChanged, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetChanged, target); + } + ); + browserContext.trustedEmitter.on( + BrowserContextEvent.TargetDestroyed, + target => { + this.#trustedEmitter.emit(BrowserEvent.TargetDestroyed, target); + } ); - this.connection.registerBrowsingContexts(context); - // TODO: once more browsing context types are supported, this should be - // updated to support those. Currently, all top-level contexts are treated - // as pages. - const browserContext = this.browserContexts().at(-1); - if (!browserContext) { - throw new Error('Missing browser contexts'); - } - const target = !context.parent - ? new BiDiPageTarget(browserContext, context) - : new BiDiBrowsingContextTarget(browserContext, context); - this.#targets.set(event.context, target); - - this.emit(BrowserEvent.TargetCreated, target); - target.browserContext().emit(BrowserContextEvent.TargetCreated, target); - - if (context.parent) { - const topLevel = this.connection.getTopLevelContext(context.parent); - topLevel.emit(BrowsingContextEvent.Created, context); - } - } - - async #getTree(): Promise<void> { - const {result} = await this.connection.send('browsingContext.getTree', {}); - for (const context of result.contexts) { - this.#onContextCreated(context); - } - } - async #onContextDestroyed( - event: Bidi.BrowsingContext.ContextDestroyed['params'] - ) { - const context = this.connection.getBrowsingContext(event.context); - const topLevelContext = this.connection.getTopLevelContext(event.context); - topLevelContext.emit(BrowsingContextEvent.Destroyed, context); - const target = this.#targets.get(event.context); - const page = await target?.page(); - await page?.close().catch(debugError); - this.#targets.delete(event.context); - if (target) { - this.emit(BrowserEvent.TargetDestroyed, target); - target.browserContext().emit(BrowserContextEvent.TargetDestroyed, target); - } + return browserContext; } get connection(): BidiConnection { @@ -231,9 +175,6 @@ export class BidiBrowser extends Browser { } override async close(): Promise<void> { - for (const [eventName, handler] of this.#connectionEventHandlers) { - this.connection.off(eventName, handler); - } if (this.connection.closed) { return; } @@ -250,14 +191,14 @@ export class BidiBrowser extends Browser { } override get connected(): boolean { - return !this.#browserCore.disposed; + return !this.#browserCore.disconnected; } override process(): ChildProcess | null { return this.#process ?? null; } - override async createIncognitoBrowserContext( + override async createBrowserContext( _options?: BrowserContextOptions ): Promise<BidiBrowserContext> { const userContext = await this.#browserCore.createUserContext(); @@ -283,19 +224,16 @@ export class BidiBrowser extends Browser { } override targets(): Target[] { - return [this.#browserTarget, ...Array.from(this.#targets.values())]; - } - - _getTargetById(id: string): BidiTarget { - const target = this.#targets.get(id); - if (!target) { - throw new Error('Target not found'); - } - return target; + return [ + this.#target, + ...this.browserContexts().flatMap(context => { + return context.targets(); + }), + ]; } - override target(): Target { - return this.#browserTarget; + override target(): BidiBrowserTarget { + return this.#target; } override async disconnect(): Promise<void> { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts index feb5e9951d..9976e4cc6a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowserContext.ts @@ -6,18 +6,25 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type {WaitForTargetOptions} from '../api/Browser.js'; -import {BrowserContext} from '../api/BrowserContext.js'; -import type {Page} from '../api/Page.js'; +import type {Permission} from '../api/Browser.js'; +import {WEB_PERMISSION_TO_PROTOCOL_PERMISSION} from '../api/Browser.js'; +import type {BrowserContextEvents} from '../api/BrowserContext.js'; +import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js'; +import {PageEvent, type Page} from '../api/Page.js'; import type {Target} from '../api/Target.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; +import {bubble} from '../util/decorators.js'; import type {BidiBrowser} from './Browser.js'; -import type {BidiConnection} from './Connection.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; import {UserContext} from './core/UserContext.js'; -import type {BidiPage} from './Page.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiPage} from './Page.js'; +import {BidiWorkerTarget} from './Target.js'; +import {BidiFrameTarget, BidiPageTarget} from './Target.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal @@ -30,56 +37,134 @@ export interface BidiBrowserContextOptions { * @internal */ export class BidiBrowserContext extends BrowserContext { - #browser: BidiBrowser; - #connection: BidiConnection; - #defaultViewport: Viewport | null; - #userContext: UserContext; + static from( + browser: BidiBrowser, + userContext: UserContext, + options: BidiBrowserContextOptions + ): BidiBrowserContext { + const context = new BidiBrowserContext(browser, userContext, options); + context.#initialize(); + return context; + } + + @bubble() + accessor trustedEmitter = new EventEmitter<BrowserContextEvents>(); + + readonly #browser: BidiBrowser; + readonly #defaultViewport: Viewport | null; + // This is public because of cookies. + readonly userContext: UserContext; + readonly #pages = new WeakMap<BrowsingContext, BidiPage>(); + readonly #targets = new Map< + BidiPage, + [ + BidiPageTarget, + Map<BidiFrame | BidiWebWorker, BidiFrameTarget | BidiWorkerTarget>, + ] + >(); - constructor( + #overrides: Array<{origin: string; permission: Permission}> = []; + + private constructor( browser: BidiBrowser, userContext: UserContext, options: BidiBrowserContextOptions ) { super(); this.#browser = browser; - this.#userContext = userContext; - this.#connection = this.#browser.connection; + this.userContext = userContext; this.#defaultViewport = options.defaultViewport; } - override targets(): Target[] { - return this.#browser.targets().filter(target => { - return target.browserContext() === this; + #initialize() { + // Create targets for existing browsing contexts. + for (const browsingContext of this.userContext.browsingContexts) { + this.#createPage(browsingContext); + } + + this.userContext.on('browsingcontext', ({browsingContext}) => { + this.#createPage(browsingContext); + }); + this.userContext.on('closed', () => { + this.trustedEmitter.removeAllListeners(); }); } - override waitForTarget( - predicate: (x: Target) => boolean | Promise<boolean>, - options: WaitForTargetOptions = {} - ): Promise<Target> { - return this.#browser.waitForTarget(target => { - return target.browserContext() === this && predicate(target); - }, options); - } + #createPage(browsingContext: BrowsingContext): BidiPage { + const page = BidiPage.from(this, browsingContext); + this.#pages.set(browsingContext, page); + page.trustedEmitter.on(PageEvent.Close, () => { + this.#pages.delete(browsingContext); + }); - get connection(): BidiConnection { - return this.#connection; - } + // -- Target stuff starts here -- + const pageTarget = new BidiPageTarget(page); + const pageTargets = new Map(); + this.#targets.set(page, [pageTarget, pageTargets]); - override async newPage(): Promise<Page> { - const {result} = await this.#connection.send('browsingContext.create', { - type: Bidi.BrowsingContext.CreateType.Tab, + page.trustedEmitter.on(PageEvent.FrameAttached, frame => { + const bidiFrame = frame as BidiFrame; + const target = new BidiFrameTarget(bidiFrame); + pageTargets.set(bidiFrame, target); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, target); + }); + page.trustedEmitter.on(PageEvent.FrameNavigated, frame => { + const bidiFrame = frame as BidiFrame; + const target = pageTargets.get(bidiFrame); + // If there is no target, then this is the page's frame. + if (target === undefined) { + this.trustedEmitter.emit(BrowserContextEvent.TargetChanged, pageTarget); + } else { + this.trustedEmitter.emit(BrowserContextEvent.TargetChanged, target); + } + }); + page.trustedEmitter.on(PageEvent.FrameDetached, frame => { + const bidiFrame = frame as BidiFrame; + const target = pageTargets.get(bidiFrame); + if (target === undefined) { + return; + } + pageTargets.delete(bidiFrame); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, target); + }); + + page.trustedEmitter.on(PageEvent.WorkerCreated, worker => { + const bidiWorker = worker as BidiWebWorker; + const target = new BidiWorkerTarget(bidiWorker); + pageTargets.set(bidiWorker, target); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, target); + }); + page.trustedEmitter.on(PageEvent.WorkerDestroyed, worker => { + const bidiWorker = worker as BidiWebWorker; + const target = pageTargets.get(bidiWorker); + if (target === undefined) { + return; + } + pageTargets.delete(worker); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, target); }); - const target = this.#browser._getTargetById(result.context); - // TODO: once BiDi has some concept matching BrowserContext, the newly - // created contexts should get automatically assigned to the right - // BrowserContext. For now, we assume that only explicitly created pages go - // to the current BrowserContext. Otherwise, the contexts get assigned to - // the default BrowserContext by the Browser. - target._setBrowserContext(this); + page.trustedEmitter.on(PageEvent.Close, () => { + this.#targets.delete(page); + this.trustedEmitter.emit(BrowserContextEvent.TargetDestroyed, pageTarget); + }); + this.trustedEmitter.emit(BrowserContextEvent.TargetCreated, pageTarget); + // -- Target stuff ends here -- + + return page; + } + + override targets(): Target[] { + return [...this.#targets.values()].flatMap(([target, frames]) => { + return [target, ...frames.values()]; + }); + } - const page = await target.page(); + override async newPage(): Promise<Page> { + const context = await this.userContext.createBrowsingContext( + Bidi.BrowsingContext.CreateType.Tab + ); + const page = this.#pages.get(context)!; if (!page) { throw new Error('Page is not found'); } @@ -99,18 +184,8 @@ export class BidiBrowserContext extends BrowserContext { throw new Error('Default context cannot be closed!'); } - // TODO: Remove once we have adopted the new browsing contexts. - for (const target of this.targets()) { - const page = await target?.page(); - try { - await page?.close(); - } catch (error) { - debugError(error); - } - } - try { - await this.#userContext.remove(); + await this.userContext.remove(); } catch (error) { debugError(error); } @@ -121,25 +196,73 @@ export class BidiBrowserContext extends BrowserContext { } override async pages(): Promise<BidiPage[]> { - const results = await Promise.all( - [...this.targets()].map(t => { - return t.page(); - }) - ); - return results.filter((p): p is BidiPage => { - return p !== null; + return [...this.userContext.browsingContexts].map(context => { + return this.#pages.get(context)!; }); } override isIncognito(): boolean { - return this.#userContext.id !== UserContext.DEFAULT; + return this.userContext.id !== UserContext.DEFAULT; } - override overridePermissions(): never { - throw new UnsupportedOperation(); + override async overridePermissions( + origin: string, + permissions: Permission[] + ): Promise<void> { + const permissionsSet = new Set( + permissions.map(permission => { + const protocolPermission = + WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission); + if (!protocolPermission) { + throw new Error('Unknown permission: ' + permission); + } + return permission; + }) + ); + await Promise.all( + Array.from(WEB_PERMISSION_TO_PROTOCOL_PERMISSION.keys()).map( + permission => { + const result = this.userContext.setPermissions( + origin, + { + name: permission, + }, + permissionsSet.has(permission) + ? Bidi.Permissions.PermissionState.Granted + : Bidi.Permissions.PermissionState.Denied + ); + this.#overrides.push({origin, permission}); + // TODO: some permissions are outdated and setting them to denied does + // not work. + if (!permissionsSet.has(permission)) { + return result.catch(debugError); + } + return result; + } + ) + ); } - override clearPermissionOverrides(): never { - throw new UnsupportedOperation(); + override async clearPermissionOverrides(): Promise<void> { + const promises = this.#overrides.map(({permission, origin}) => { + return this.userContext + .setPermissions( + origin, + { + name: permission, + }, + Bidi.Permissions.PermissionState.Prompt + ) + .catch(debugError); + }); + this.#overrides = []; + await Promise.all(promises); + } + + override get id(): string | undefined { + if (this.userContext.id === UserContext.DEFAULT) { + return undefined; + } + return this.userContext.id; } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts deleted file mode 100644 index 0804628c06..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/BrowsingContext.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js'; - -import {CDPSession} from '../api/CDPSession.js'; -import type {Connection as CdpConnection} from '../cdp/Connection.js'; -import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; -import type {EventType} from '../common/EventEmitter.js'; -import {debugError} from '../common/util.js'; -import {Deferred} from '../util/Deferred.js'; - -import type {BidiConnection} from './Connection.js'; -import {BidiRealm} from './Realm.js'; - -/** - * @internal - */ -export const cdpSessions = new Map<string, CdpSessionWrapper>(); - -/** - * @internal - */ -export class CdpSessionWrapper extends CDPSession { - #context: BrowsingContext; - #sessionId = Deferred.create<string>(); - #detached = false; - - constructor(context: BrowsingContext, sessionId?: string) { - super(); - this.#context = context; - if (!this.#context.supportsCdp()) { - return; - } - if (sessionId) { - this.#sessionId.resolve(sessionId); - cdpSessions.set(sessionId, this); - } else { - context.connection - .send('cdp.getSession', { - context: context.id, - }) - .then(session => { - this.#sessionId.resolve(session.result.session!); - cdpSessions.set(session.result.session!, this); - }) - .catch(err => { - this.#sessionId.reject(err); - }); - } - } - - override connection(): CdpConnection | undefined { - return undefined; - } - - override async send<T extends keyof ProtocolMapping.Commands>( - method: T, - ...paramArgs: ProtocolMapping.Commands[T]['paramsType'] - ): Promise<ProtocolMapping.Commands[T]['returnType']> { - if (!this.#context.supportsCdp()) { - throw new UnsupportedOperation( - 'CDP support is required for this feature. The current browser does not support CDP.' - ); - } - if (this.#detached) { - throw new TargetCloseError( - `Protocol error (${method}): Session closed. Most likely the page has been closed.` - ); - } - const session = await this.#sessionId.valueOrThrow(); - const {result} = await this.#context.connection.send('cdp.sendCommand', { - method: method, - params: paramArgs[0], - session, - }); - return result.result; - } - - override async detach(): Promise<void> { - cdpSessions.delete(this.id()); - if (!this.#detached && this.#context.supportsCdp()) { - await this.#context.cdpSession.send('Target.detachFromTarget', { - sessionId: this.id(), - }); - } - this.#detached = true; - } - - override id(): string { - const val = this.#sessionId.value(); - return val instanceof Error || val === undefined ? '' : val; - } -} - -/** - * Internal events that the BrowsingContext class emits. - * - * @internal - */ -// eslint-disable-next-line @typescript-eslint/no-namespace -export namespace BrowsingContextEvent { - /** - * Emitted on the top-level context, when a descendant context is created. - */ - export const Created = Symbol('BrowsingContext.created'); - /** - * Emitted on the top-level context, when a descendant context or the - * top-level context itself is destroyed. - */ - export const Destroyed = Symbol('BrowsingContext.destroyed'); -} - -/** - * @internal - */ -export interface BrowsingContextEvents extends Record<EventType, unknown> { - [BrowsingContextEvent.Created]: BrowsingContext; - [BrowsingContextEvent.Destroyed]: BrowsingContext; -} - -/** - * @internal - */ -export class BrowsingContext extends BidiRealm { - #id: string; - #url: string; - #cdpSession: CDPSession; - #parent?: string | null; - #browserName = ''; - - constructor( - connection: BidiConnection, - info: Bidi.BrowsingContext.Info, - browserName: string - ) { - super(connection); - this.#id = info.context; - this.#url = info.url; - this.#parent = info.parent; - this.#browserName = browserName; - this.#cdpSession = new CdpSessionWrapper(this, undefined); - - this.on('browsingContext.domContentLoaded', this.#updateUrl.bind(this)); - this.on('browsingContext.fragmentNavigated', this.#updateUrl.bind(this)); - this.on('browsingContext.load', this.#updateUrl.bind(this)); - } - - supportsCdp(): boolean { - return !this.#browserName.toLowerCase().includes('firefox'); - } - - #updateUrl(info: Bidi.BrowsingContext.NavigationInfo) { - this.#url = info.url; - } - - createRealmForSandbox(): BidiRealm { - return new BidiRealm(this.connection); - } - - get url(): string { - return this.#url; - } - - get id(): string { - return this.#id; - } - - get parent(): string | undefined | null { - return this.#parent; - } - - get cdpSession(): CDPSession { - return this.#cdpSession; - } - - async sendCdpCommand<T extends keyof ProtocolMapping.Commands>( - method: T, - ...paramArgs: ProtocolMapping.Commands[T]['paramsType'] - ): Promise<ProtocolMapping.Commands[T]['returnType']> { - return await this.#cdpSession.send(method, ...paramArgs); - } - - dispose(): void { - this.removeAllListeners(); - this.connection.unregisterBrowsingContexts(this.#id); - void this.#cdpSession.detach().catch(debugError); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts new file mode 100644 index 0000000000..1e0c503498 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/CDPSession.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js'; + +import {CDPSession} from '../api/CDPSession.js'; +import type {Connection as CdpConnection} from '../cdp/Connection.js'; +import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; +import {Deferred} from '../util/Deferred.js'; + +import type {BidiConnection} from './Connection.js'; +import type {BidiFrame} from './Frame.js'; + +/** + * @internal + */ +export class BidiCdpSession extends CDPSession { + static sessions = new Map<string, BidiCdpSession>(); + + #detached = false; + readonly #connection: BidiConnection | undefined = undefined; + readonly #sessionId = Deferred.create<string>(); + readonly frame: BidiFrame; + + constructor(frame: BidiFrame, sessionId?: string) { + super(); + this.frame = frame; + if (!this.frame.page().browser().cdpSupported) { + return; + } + + const connection = this.frame.page().browser().connection; + this.#connection = connection; + + if (sessionId) { + this.#sessionId.resolve(sessionId); + BidiCdpSession.sessions.set(sessionId, this); + } else { + (async () => { + try { + const session = await connection.send('cdp.getSession', { + context: frame._id, + }); + this.#sessionId.resolve(session.result.session!); + BidiCdpSession.sessions.set(session.result.session!, this); + } catch (error) { + this.#sessionId.reject(error as Error); + } + })(); + } + + // SAFETY: We never throw #sessionId. + BidiCdpSession.sessions.set(this.#sessionId.value() as string, this); + } + + override connection(): CdpConnection | undefined { + return undefined; + } + + override async send<T extends keyof ProtocolMapping.Commands>( + method: T, + params?: ProtocolMapping.Commands[T]['paramsType'][0] + ): Promise<ProtocolMapping.Commands[T]['returnType']> { + if (this.#connection === undefined) { + throw new UnsupportedOperation( + 'CDP support is required for this feature. The current browser does not support CDP.' + ); + } + if (this.#detached) { + throw new TargetCloseError( + `Protocol error (${method}): Session closed. Most likely the page has been closed.` + ); + } + const session = await this.#sessionId.valueOrThrow(); + const {result} = await this.#connection.send('cdp.sendCommand', { + method: method, + params: params, + session, + }); + return result.result; + } + + override async detach(): Promise<void> { + if (this.#connection === undefined || this.#detached) { + return; + } + try { + await this.frame.client.send('Target.detachFromTarget', { + sessionId: this.id(), + }); + } finally { + BidiCdpSession.sessions.delete(this.id()); + this.#detached = true; + } + } + + override id(): string { + const value = this.#sessionId.value(); + return typeof value === 'string' ? value : ''; + } +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts index bce952ba39..dd688c309a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Connection.ts @@ -14,10 +14,10 @@ import {EventEmitter} from '../common/EventEmitter.js'; import {debugError} from '../common/util.js'; import {assert} from '../util/assert.js'; -import {cdpSessions, type BrowsingContext} from './BrowsingContext.js'; +import {BidiCdpSession} from './CDPSession.js'; import type { - BidiEvents, Commands as BidiCommands, + BidiEvents, Connection, } from './core/Connection.js'; @@ -36,6 +36,10 @@ export interface Commands extends BidiCommands { params: Bidi.Cdp.GetSessionParameters; returnType: Bidi.Cdp.GetSessionResult; }; + 'cdp.resolveRealm': { + params: Bidi.Cdp.ResolveRealmParameters; + returnType: Bidi.Cdp.ResolveRealmResult; + }; } /** @@ -51,7 +55,6 @@ export class BidiConnection #timeout? = 0; #closed = false; #callbacks = new CallbackRegistry(); - #browsingContexts = new Map<string, BrowsingContext>(); #emitters: Array<EventEmitter<any>> = []; constructor( @@ -137,12 +140,11 @@ export class BidiConnection return; case 'event': if (isCdpEvent(object)) { - cdpSessions + BidiCdpSession.sessions .get(object.params.session) ?.emit(object.params.event, object.params.params); return; } - this.#maybeEmitOnContext(object); // SAFETY: We know the method and parameter still match here. this.emit( object.method, @@ -163,52 +165,6 @@ export class BidiConnection debugError(object); } - #maybeEmitOnContext(event: Bidi.ChromiumBidi.Event) { - let context: BrowsingContext | undefined; - // Context specific events - if ('context' in event.params && event.params.context !== null) { - context = this.#browsingContexts.get(event.params.context); - // `log.entryAdded` specific context - } else if ( - 'source' in event.params && - event.params.source.context !== undefined - ) { - context = this.#browsingContexts.get(event.params.source.context); - } - context?.emit(event.method, event.params); - } - - registerBrowsingContexts(context: BrowsingContext): void { - this.#browsingContexts.set(context.id, context); - } - - getBrowsingContext(contextId: string): BrowsingContext { - const currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - return currentContext; - } - - getTopLevelContext(contextId: string): BrowsingContext { - let currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - while (currentContext.parent) { - contextId = currentContext.parent; - currentContext = this.#browsingContexts.get(contextId); - if (!currentContext) { - throw new Error(`BrowsingContext ${contextId} does not exist.`); - } - } - return currentContext; - } - - unregisterBrowsingContexts(id: string): void { - this.#browsingContexts.delete(id); - } - /** * Unbinds the connection, but keeps the transport open. Useful when the transport will * be reused by other connection e.g. with different protocol. @@ -223,7 +179,6 @@ export class BidiConnection this.#transport.onmessage = () => {}; this.#transport.onclose = () => {}; - this.#browsingContexts.clear(); this.#callbacks.clear(); } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts index 14b87d403b..20dc8d9fc9 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Deserializer.ts @@ -12,40 +12,30 @@ import {debugError} from '../common/util.js'; * @internal */ export class BidiDeserializer { - static deserializeNumber(value: Bidi.Script.SpecialNumber | number): number { - switch (value) { - case '-0': - return -0; - case 'NaN': - return NaN; - case 'Infinity': - return Infinity; - case '-Infinity': - return -Infinity; - default: - return value; + static deserialize(result: Bidi.Script.RemoteValue): any { + if (!result) { + debugError('Service did not produce a result.'); + return undefined; } - } - static deserializeLocalValue(result: Bidi.Script.RemoteValue): unknown { switch (result.type) { case 'array': return result.value?.map(value => { - return BidiDeserializer.deserializeLocalValue(value); + return this.deserialize(value); }); case 'set': return result.value?.reduce((acc: Set<unknown>, value) => { - return acc.add(BidiDeserializer.deserializeLocalValue(value)); + return acc.add(this.deserialize(value)); }, new Set()); case 'object': return result.value?.reduce((acc: Record<any, unknown>, tuple) => { - const {key, value} = BidiDeserializer.deserializeTuple(tuple); + const {key, value} = this.#deserializeTuple(tuple); acc[key as any] = value; return acc; }, {}); case 'map': return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => { - const {key, value} = BidiDeserializer.deserializeTuple(tuple); + const {key, value} = this.#deserializeTuple(tuple); return acc.set(key, value); }, new Map()); case 'promise': @@ -59,7 +49,7 @@ export class BidiDeserializer { case 'null': return null; case 'number': - return BidiDeserializer.deserializeNumber(result.value); + return this.#deserializeNumber(result.value); case 'bigint': return BigInt(result.value); case 'boolean': @@ -72,25 +62,31 @@ export class BidiDeserializer { return undefined; } - static deserializeTuple([serializedKey, serializedValue]: [ + static #deserializeNumber(value: Bidi.Script.SpecialNumber | number): number { + switch (value) { + case '-0': + return -0; + case 'NaN': + return NaN; + case 'Infinity': + return Infinity; + case '-Infinity': + return -Infinity; + default: + return value; + } + } + + static #deserializeTuple([serializedKey, serializedValue]: [ Bidi.Script.RemoteValue | string, Bidi.Script.RemoteValue, ]): {key: unknown; value: unknown} { const key = typeof serializedKey === 'string' ? serializedKey - : BidiDeserializer.deserializeLocalValue(serializedKey); - const value = BidiDeserializer.deserializeLocalValue(serializedValue); + : this.deserialize(serializedKey); + const value = this.deserialize(serializedValue); return {key, value}; } - - static deserialize(result: Bidi.Script.RemoteValue): any { - if (!result) { - debugError('Service did not produce a result.'); - return undefined; - } - - return BidiDeserializer.deserializeLocalValue(result); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts index ce22223461..1774a29f6b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Dialog.ts @@ -4,40 +4,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - import {Dialog} from '../api/Dialog.js'; -import type {BrowsingContext} from './BrowsingContext.js'; +import type {UserPrompt} from './core/UserPrompt.js'; -/** - * @internal - */ export class BidiDialog extends Dialog { - #context: BrowsingContext; + static from(prompt: UserPrompt): BidiDialog { + return new BidiDialog(prompt); + } - /** - * @internal - */ - constructor( - context: BrowsingContext, - type: Bidi.BrowsingContext.UserPromptOpenedParameters['type'], - message: string, - defaultValue?: string - ) { - super(type, message, defaultValue); - this.#context = context; + #prompt: UserPrompt; + private constructor(prompt: UserPrompt) { + super(prompt.info.type, prompt.info.message, prompt.info.defaultValue); + this.#prompt = prompt; } - /** - * @internal - */ override async handle(options: { accept: boolean; text?: string; }): Promise<void> { - await this.#context.connection.send('browsingContext.handleUserPrompt', { - context: this.#context.id, + await this.#prompt.handle({ accept: options.accept, userText: options.text, }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts index fd886e8c26..4263697671 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ElementHandle.ts @@ -6,14 +6,12 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {type AutofillData, ElementHandle} from '../api/ElementHandle.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {ElementHandle, type AutofillData} from '../api/ElementHandle.js'; import {throwIfDisposed} from '../util/decorators.js'; import type {BidiFrame} from './Frame.js'; import {BidiJSHandle} from './JSHandle.js'; -import type {BidiRealm} from './Realm.js'; -import type {Sandbox} from './Sandbox.js'; +import type {BidiFrameRealm} from './Realm.js'; /** * @internal @@ -21,28 +19,28 @@ import type {Sandbox} from './Sandbox.js'; export class BidiElementHandle< ElementType extends Node = Element, > extends ElementHandle<ElementType> { + static from<ElementType extends Node = Element>( + value: Bidi.Script.RemoteValue, + realm: BidiFrameRealm + ): BidiElementHandle<ElementType> { + return new BidiElementHandle(value, realm); + } + declare handle: BidiJSHandle<ElementType>; - constructor(sandbox: Sandbox, remoteValue: Bidi.Script.RemoteValue) { - super(new BidiJSHandle(sandbox, remoteValue)); + constructor(value: Bidi.Script.RemoteValue, realm: BidiFrameRealm) { + super(BidiJSHandle.from(value, realm)); } - override get realm(): Sandbox { - return this.handle.realm; + override get realm(): BidiFrameRealm { + // SAFETY: See the super call in the constructor. + return this.handle.realm as BidiFrameRealm; } override get frame(): BidiFrame { return this.realm.environment; } - context(): BidiRealm { - return this.handle.context(); - } - - get isPrimitiveValue(): boolean { - return this.handle.isPrimitiveValue; - } - remoteValue(): Bidi.Script.RemoteValue { return this.handle.remoteValue(); } @@ -69,19 +67,53 @@ export class BidiElementHandle< @ElementHandle.bindIsolatedHandle override async contentFrame(): Promise<BidiFrame | null> { using handle = (await this.evaluateHandle(element => { - if (element instanceof HTMLIFrameElement) { + if ( + element instanceof HTMLIFrameElement || + element instanceof HTMLFrameElement + ) { return element.contentWindow; } return; })) as BidiJSHandle; const value = handle.remoteValue(); if (value.type === 'window') { - return this.frame.page().frame(value.value.context); + return ( + this.frame + .page() + .frames() + .find(frame => { + return frame._id === value.value.context; + }) ?? null + ); } return null; } - override uploadFile(this: ElementHandle<HTMLInputElement>): never { - throw new UnsupportedOperation(); + override async uploadFile( + this: BidiElementHandle<HTMLInputElement>, + ...files: string[] + ): Promise<void> { + // Locate all files and confirm that they exist. + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + let path: typeof import('path'); + try { + path = await import('path'); + } catch (error) { + if (error instanceof TypeError) { + throw new Error( + `JSHandle#uploadFile can only be used in Node-like environments.` + ); + } + throw error; + } + + files = files.map(file => { + if (path.win32.isAbsolute(file) || path.posix.isAbsolute(file)) { + return file; + } else { + return path.resolve(file); + } + }); + await this.frame.setFiles(this, files); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts deleted file mode 100644 index de95695785..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/EmulationManager.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ -import type {Viewport} from '../common/Viewport.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; - -/** - * @internal - */ -export class EmulationManager { - #browsingContext: BrowsingContext; - - constructor(browsingContext: BrowsingContext) { - this.#browsingContext = browsingContext; - } - - async emulateViewport(viewport: Viewport): Promise<void> { - await this.#browsingContext.connection.send('browsingContext.setViewport', { - context: this.#browsingContext.id, - viewport: - viewport.width && viewport.height - ? { - width: viewport.width, - height: viewport.height, - } - : null, - devicePixelRatio: viewport.deviceScaleFactor - ? viewport.deviceScaleFactor - : null, - }); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts index 62c6b5e37e..f6e1304a55 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/ExposedFunction.ts @@ -6,97 +6,91 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import type {Awaitable, FlattenHandle} from '../common/types.js'; import {debugError} from '../common/util.js'; -import {assert} from '../util/assert.js'; -import {Deferred} from '../util/Deferred.js'; +import {DisposableStack} from '../util/disposable.js'; import {interpolateFunction, stringifyFunction} from '../util/Function.js'; -import type {BidiConnection} from './Connection.js'; -import {BidiDeserializer} from './Deserializer.js'; +import type {Connection} from './core/Connection.js'; +import {BidiElementHandle} from './ElementHandle.js'; import type {BidiFrame} from './Frame.js'; -import {BidiSerializer} from './Serializer.js'; - -type SendArgsChannel<Args> = (value: [id: number, args: Args]) => void; -type SendResolveChannel<Ret> = ( - value: [id: number, resolve: (ret: FlattenHandle<Awaited<Ret>>) => void] -) => void; -type SendRejectChannel = ( - value: [id: number, reject: (error: unknown) => void] +import {BidiJSHandle} from './JSHandle.js'; + +type CallbackChannel<Args, Ret> = ( + value: [ + resolve: (ret: FlattenHandle<Awaited<Ret>>) => void, + reject: (error: unknown) => void, + args: Args, + ] ) => void; -interface RemotePromiseCallbacks { - resolve: Deferred<Bidi.Script.RemoteValue>; - reject: Deferred<Bidi.Script.RemoteValue>; -} - /** * @internal */ export class ExposeableFunction<Args extends unknown[], Ret> { + static async from<Args extends unknown[], Ret>( + frame: BidiFrame, + name: string, + apply: (...args: Args) => Awaitable<Ret>, + isolate = false + ): Promise<ExposeableFunction<Args, Ret>> { + const func = new ExposeableFunction(frame, name, apply, isolate); + await func.#initialize(); + return func; + } + readonly #frame; readonly name; readonly #apply; + readonly #isolate; - readonly #channels; - readonly #callerInfos = new Map< - string, - Map<number, RemotePromiseCallbacks> - >(); + readonly #channel; - #preloadScriptId?: Bidi.Script.PreloadScript; + #scripts: Array<[BidiFrame, Bidi.Script.PreloadScript]> = []; + #disposables = new DisposableStack(); constructor( frame: BidiFrame, name: string, - apply: (...args: Args) => Awaitable<Ret> + apply: (...args: Args) => Awaitable<Ret>, + isolate = false ) { this.#frame = frame; this.name = name; this.#apply = apply; + this.#isolate = isolate; - this.#channels = { - args: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_args`, - resolve: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_resolve`, - reject: `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}_reject`, - }; + this.#channel = `__puppeteer__${this.#frame._id}_page_exposeFunction_${this.name}`; } - async expose(): Promise<void> { + async #initialize() { const connection = this.#connection; - const channelArguments = this.#channelArguments; + const channel = { + type: 'channel' as const, + value: { + channel: this.#channel, + ownership: Bidi.Script.ResultOwnership.Root, + }, + }; - // TODO(jrandolf): Implement cleanup with removePreloadScript. - connection.on( - Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleArgumentsMessage + const connectionEmitter = this.#disposables.use( + new EventEmitter(connection) ); - connection.on( + connectionEmitter.on( Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleResolveMessage - ); - connection.on( - Bidi.ChromiumBidi.Script.EventNames.Message, - this.#handleRejectMessage + this.#handleMessage ); const functionDeclaration = stringifyFunction( interpolateFunction( - ( - sendArgs: SendArgsChannel<Args>, - sendResolve: SendResolveChannel<Ret>, - sendReject: SendRejectChannel - ) => { - let id = 0; + (callback: CallbackChannel<Args, Ret>) => { Object.assign(globalThis, { [PLACEHOLDER('name') as string]: function (...args: Args) { return new Promise<FlattenHandle<Awaited<Ret>>>( (resolve, reject) => { - sendArgs([id, args]); - sendResolve([id, resolve]); - sendReject([id, reject]); - ++id; + callback([resolve, reject, args]); } ); }, @@ -106,179 +100,133 @@ export class ExposeableFunction<Args extends unknown[], Ret> { ) ); - const {result} = await connection.send('script.addPreloadScript', { - functionDeclaration, - arguments: channelArguments, - contexts: [this.#frame.page().mainFrame()._id], - }); - this.#preloadScriptId = result.script; + const frames = [this.#frame]; + for (const frame of frames) { + frames.push(...frame.childFrames()); + } await Promise.all( - this.#frame - .page() - .frames() - .map(async frame => { - return await connection.send('script.callFunction', { - functionDeclaration, - arguments: channelArguments, - awaitPromise: false, - target: frame.mainRealm().realm.target, - }); - }) + frames.map(async frame => { + const realm = this.#isolate ? frame.isolatedRealm() : frame.mainRealm(); + try { + const [script] = await Promise.all([ + frame.browsingContext.addPreloadScript(functionDeclaration, { + arguments: [channel], + sandbox: realm.sandbox, + }), + realm.realm.callFunction(functionDeclaration, false, { + arguments: [channel], + }), + ]); + this.#scripts.push([frame, script]); + } catch (error) { + // If it errors, the frame probably doesn't support call function. We + // fail gracefully. + debugError(error); + } + }) ); } - #handleArgumentsMessage = async (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.args) { + get #connection(): Connection { + return this.#frame.page().browser().connection; + } + + #handleMessage = async (params: Bidi.Script.MessageParameters) => { + if (params.channel !== this.#channel) { return; } - const connection = this.#connection; - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - const args = remoteValue.value?.[1]; - assert(args); + const realm = this.#getRealm(params.source); + if (!realm) { + // Unrelated message. + return; + } + + using dataHandle = BidiJSHandle.from< + [ + resolve: (ret: FlattenHandle<Awaited<Ret>>) => void, + reject: (error: unknown) => void, + args: Args, + ] + >(params.data, realm); + + using argsHandle = await dataHandle.evaluateHandle(([, , args]) => { + return args; + }); + + using stack = new DisposableStack(); + const args = []; + for (const [index, handle] of await argsHandle.getProperties()) { + stack.use(handle); + + // Element handles are passed as is. + if (handle instanceof BidiElementHandle) { + args[+index] = handle; + stack.use(handle); + continue; + } + + // Everything else is passed as the JS value. + args[+index] = handle.jsonValue(); + } + + let result; try { - const result = await this.#apply(...BidiDeserializer.deserialize(args)); - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction(([_, resolve]: any, result) => { - resolve(result); - }), - arguments: [ - (await callbacks.resolve.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(result), - ], - awaitPromise: false, - target: { - realm: params.source.realm, - }, - }); + result = await this.#apply(...((await Promise.all(args)) as Args)); } catch (error) { try { if (error instanceof Error) { - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction( - ( - [_, reject]: [unknown, (error: Error) => void], - name: string, - message: string, - stack?: string - ) => { - const error = new Error(message); - error.name = name; - if (stack) { - error.stack = stack; - } - reject(error); + await dataHandle.evaluate( + ([, reject], name, message, stack) => { + const error = new Error(message); + error.name = name; + if (stack) { + error.stack = stack; } - ), - arguments: [ - (await callbacks.reject.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(error.name), - BidiSerializer.serializeRemoteValue(error.message), - BidiSerializer.serializeRemoteValue(error.stack), - ], - awaitPromise: false, - target: { - realm: params.source.realm, + reject(error); }, - }); + error.name, + error.message, + error.stack + ); } else { - await connection.send('script.callFunction', { - functionDeclaration: stringifyFunction( - ( - [_, reject]: [unknown, (error: unknown) => void], - error: unknown - ) => { - reject(error); - } - ), - arguments: [ - (await callbacks.reject.valueOrThrow()) as Bidi.Script.LocalValue, - BidiSerializer.serializeRemoteValue(error), - ], - awaitPromise: false, - target: { - realm: params.source.realm, - }, - }); + await dataHandle.evaluate(([, reject], error) => { + reject(error); + }, error); } } catch (error) { debugError(error); } - } - }; - - get #connection(): BidiConnection { - return this.#frame.context().connection; - } - - get #channelArguments() { - return [ - { - type: 'channel' as const, - value: { - channel: this.#channels.args, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - { - type: 'channel' as const, - value: { - channel: this.#channels.resolve, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - { - type: 'channel' as const, - value: { - channel: this.#channels.reject, - ownership: Bidi.Script.ResultOwnership.Root, - }, - }, - ]; - } - - #handleResolveMessage = (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.resolve) { return; } - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - callbacks.resolve.resolve(remoteValue); - }; - #handleRejectMessage = (params: Bidi.Script.MessageParameters) => { - if (params.channel !== this.#channels.reject) { - return; + try { + await dataHandle.evaluate(([resolve], result) => { + resolve(result); + }, result); + } catch (error) { + debugError(error); } - const {callbacks, remoteValue} = this.#getCallbacksAndRemoteValue(params); - callbacks.reject.resolve(remoteValue); }; - #getCallbacksAndRemoteValue(params: Bidi.Script.MessageParameters) { - const {data, source} = params; - assert(data.type === 'array'); - assert(data.value); - - const callerIdRemote = data.value[0]; - assert(callerIdRemote); - assert(callerIdRemote.type === 'number'); - assert(typeof callerIdRemote.value === 'number'); - - let bindingMap = this.#callerInfos.get(source.realm); - if (!bindingMap) { - bindingMap = new Map(); - this.#callerInfos.set(source.realm, bindingMap); + #getRealm(source: Bidi.Script.Source) { + const frame = this.#findFrame(source.context as string); + if (!frame) { + // Unrelated message. + return; } + return frame.realm(source.realm); + } - const callerId = callerIdRemote.value; - let callbacks = bindingMap.get(callerId); - if (!callbacks) { - callbacks = { - resolve: new Deferred(), - reject: new Deferred(), - }; - bindingMap.set(callerId, callbacks); + #findFrame(id: string) { + const frames = [this.#frame]; + for (const frame of frames) { + if (frame._id === id) { + return frame; + } + frames.push(...frame.childFrames()); } - return {callbacks, remoteValue: data}; + return; } [Symbol.dispose](): void { @@ -286,10 +234,21 @@ export class ExposeableFunction<Args extends unknown[], Ret> { } async [Symbol.asyncDispose](): Promise<void> { - if (this.#preloadScriptId) { - await this.#connection.send('script.removePreloadScript', { - script: this.#preloadScriptId, - }); - } + this.#disposables.dispose(); + await Promise.all( + this.#scripts.map(async ([frame, script]) => { + const realm = this.#isolate ? frame.isolatedRealm() : frame.mainRealm(); + try { + await Promise.all([ + realm.evaluate(name => { + delete (globalThis as any)[name]; + }, this.name), + frame.browsingContext.removePreloadScript(script), + ]); + } catch (error) { + debugError(error); + } + }) + ); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts index 1638c2cbdf..f2bfd5f64e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Frame.ts @@ -6,15 +6,18 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import type {Observable} from '../../third_party/rxjs/rxjs.js'; import { + combineLatest, + defer, + delayWhen, + filter, first, firstValueFrom, - forkJoin, - from, map, - merge, + of, raceWith, - zip, + switchMap, } from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; import type {ElementHandle} from '../api/ElementHandle.js'; @@ -25,85 +28,228 @@ import { type WaitForOptions, } from '../api/Frame.js'; import type {WaitForSelectorOptions} from '../api/Page.js'; -import {UnsupportedOperation} from '../common/Errors.js'; +import {PageEvent} from '../api/Page.js'; +import { + ConsoleMessage, + type ConsoleMessageLocation, +} from '../common/ConsoleMessage.js'; +import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; import type {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {Awaitable, NodeFor} from '../common/types.js'; -import { - fromEmitterEvent, - NETWORK_IDLE_TIME, - timeout, - UTILITY_WORLD_NAME, -} from '../common/util.js'; -import {Deferred} from '../util/Deferred.js'; -import {disposeSymbol} from '../util/disposable.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; +import {debugError, fromEmitterEvent, timeout} from '../common/util.js'; + +import {BidiCdpSession} from './CDPSession.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; +import type {Navigation} from './core/Navigation.js'; +import type {Request} from './core/Request.js'; +import {BidiDeserializer} from './Deserializer.js'; +import {BidiDialog} from './Dialog.js'; +import type {BidiElementHandle} from './ElementHandle.js'; import {ExposeableFunction} from './ExposedFunction.js'; +import {BidiHTTPRequest, requests} from './HTTPRequest.js'; import type {BidiHTTPResponse} from './HTTPResponse.js'; -import { - getBiDiLifecycleEvent, - getBiDiReadinessState, - rewriteNavigationError, -} from './lifecycle.js'; +import {BidiJSHandle} from './JSHandle.js'; import type {BidiPage} from './Page.js'; -import { - MAIN_SANDBOX, - PUPPETEER_SANDBOX, - Sandbox, - type SandboxChart, -} from './Sandbox.js'; +import type {BidiRealm} from './Realm.js'; +import {BidiFrameRealm} from './Realm.js'; +import {rewriteNavigationError} from './util.js'; +import {BidiWebWorker} from './WebWorker.js'; -/** - * Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation - * @internal - */ export class BidiFrame extends Frame { - #page: BidiPage; - #context: BrowsingContext; - #timeoutSettings: TimeoutSettings; - #abortDeferred = Deferred.create<never>(); - #disposed = false; - sandboxes: SandboxChart; - override _id: string; - - constructor( - page: BidiPage, - context: BrowsingContext, - timeoutSettings: TimeoutSettings, - parentId?: string | null + static from( + parent: BidiPage | BidiFrame, + browsingContext: BrowsingContext + ): BidiFrame { + const frame = new BidiFrame(parent, browsingContext); + frame.#initialize(); + return frame; + } + + readonly #parent: BidiPage | BidiFrame; + readonly browsingContext: BrowsingContext; + readonly #frames = new WeakMap<BrowsingContext, BidiFrame>(); + readonly realms: {default: BidiFrameRealm; internal: BidiFrameRealm}; + + override readonly _id: string; + override readonly client: BidiCdpSession; + + private constructor( + parent: BidiPage | BidiFrame, + browsingContext: BrowsingContext ) { super(); - this.#page = page; - this.#context = context; - this.#timeoutSettings = timeoutSettings; - this._id = this.#context.id; - this._parentId = parentId ?? undefined; - - this.sandboxes = { - [MAIN_SANDBOX]: new Sandbox(undefined, this, context, timeoutSettings), - [PUPPETEER_SANDBOX]: new Sandbox( - UTILITY_WORLD_NAME, - this, - context.createRealmForSandbox(), - timeoutSettings + this.#parent = parent; + this.browsingContext = browsingContext; + + this._id = browsingContext.id; + this.client = new BidiCdpSession(this); + this.realms = { + default: BidiFrameRealm.from(this.browsingContext.defaultRealm, this), + internal: BidiFrameRealm.from( + this.browsingContext.createWindowRealm( + `__puppeteer_internal_${Math.ceil(Math.random() * 10000)}` + ), + this ), }; } - override get client(): CDPSession { - return this.context().cdpSession; + #initialize(): void { + for (const browsingContext of this.browsingContext.children) { + this.#createFrameTarget(browsingContext); + } + + this.browsingContext.on('browsingcontext', ({browsingContext}) => { + this.#createFrameTarget(browsingContext); + }); + this.browsingContext.on('closed', () => { + for (const session of BidiCdpSession.sessions.values()) { + if (session.frame === this) { + void session.detach().catch(debugError); + } + } + this.page().trustedEmitter.emit(PageEvent.FrameDetached, this); + }); + + this.browsingContext.on('request', ({request}) => { + const httpRequest = BidiHTTPRequest.from(request, this); + request.once('success', () => { + // SAFETY: BidiHTTPRequest will create this before here. + this.page().trustedEmitter.emit(PageEvent.RequestFinished, httpRequest); + }); + + request.once('error', () => { + this.page().trustedEmitter.emit(PageEvent.RequestFailed, httpRequest); + }); + }); + + this.browsingContext.on('navigation', ({navigation}) => { + navigation.once('fragment', () => { + this.page().trustedEmitter.emit(PageEvent.FrameNavigated, this); + }); + }); + this.browsingContext.on('load', () => { + this.page().trustedEmitter.emit(PageEvent.Load, undefined); + }); + this.browsingContext.on('DOMContentLoaded', () => { + this._hasStartedLoading = true; + this.page().trustedEmitter.emit(PageEvent.DOMContentLoaded, undefined); + this.page().trustedEmitter.emit(PageEvent.FrameNavigated, this); + }); + + this.browsingContext.on('userprompt', ({userPrompt}) => { + this.page().trustedEmitter.emit( + PageEvent.Dialog, + BidiDialog.from(userPrompt) + ); + }); + + this.browsingContext.on('log', ({entry}) => { + if (this._id !== entry.source.context) { + return; + } + if (isConsoleLogEntry(entry)) { + const args = entry.args.map(arg => { + return this.mainRealm().createHandle(arg); + }); + + const text = args + .reduce((value, arg) => { + const parsedValue = + arg instanceof BidiJSHandle && arg.isPrimitiveValue + ? BidiDeserializer.deserialize(arg.remoteValue()) + : arg.toString(); + return `${value} ${parsedValue}`; + }, '') + .slice(1); + + this.page().trustedEmitter.emit( + PageEvent.Console, + new ConsoleMessage( + entry.method as any, + text, + args, + getStackTraceLocations(entry.stackTrace) + ) + ); + } else if (isJavaScriptLogEntry(entry)) { + const error = new Error(entry.text ?? ''); + + const messageHeight = error.message.split('\n').length; + const messageLines = error.stack!.split('\n').splice(0, messageHeight); + + const stackLines = []; + if (entry.stackTrace) { + for (const frame of entry.stackTrace.callFrames) { + // Note we need to add `1` because the values are 0-indexed. + stackLines.push( + ` at ${frame.functionName || '<anonymous>'} (${frame.url}:${ + frame.lineNumber + 1 + }:${frame.columnNumber + 1})` + ); + if (stackLines.length >= Error.stackTraceLimit) { + break; + } + } + } + + error.stack = [...messageLines, ...stackLines].join('\n'); + this.page().trustedEmitter.emit(PageEvent.PageError, error); + } else { + debugError( + `Unhandled LogEntry with type "${entry.type}", text "${entry.text}" and level "${entry.level}"` + ); + } + }); + + this.browsingContext.on('worker', ({realm}) => { + const worker = BidiWebWorker.from(this, realm); + realm.on('destroyed', () => { + this.page().trustedEmitter.emit(PageEvent.WorkerDestroyed, worker); + }); + this.page().trustedEmitter.emit(PageEvent.WorkerCreated, worker); + }); + } + + #createFrameTarget(browsingContext: BrowsingContext) { + const frame = BidiFrame.from(this, browsingContext); + this.#frames.set(browsingContext, frame); + this.page().trustedEmitter.emit(PageEvent.FrameAttached, frame); + + browsingContext.on('closed', () => { + this.#frames.delete(browsingContext); + }); + + return frame; + } + + get timeoutSettings(): TimeoutSettings { + return this.page()._timeoutSettings; } - override mainRealm(): Sandbox { - return this.sandboxes[MAIN_SANDBOX]; + override mainRealm(): BidiFrameRealm { + return this.realms.default; } - override isolatedRealm(): Sandbox { - return this.sandboxes[PUPPETEER_SANDBOX]; + override isolatedRealm(): BidiFrameRealm { + return this.realms.internal; + } + + realm(id: string): BidiRealm | undefined { + for (const realm of Object.values(this.realms)) { + if (realm.realm.id === id) { + return realm; + } + } + return; } override page(): BidiPage { - return this.#page; + let parent = this.#parent; + while (parent instanceof BidiFrame) { + parent = parent.#parent; + } + return parent; } override isOOPFrame(): never { @@ -111,15 +257,36 @@ export class BidiFrame extends Frame { } override url(): string { - return this.#context.url; + return this.browsingContext.url; } override parentFrame(): BidiFrame | null { - return this.#page.frame(this._parentId ?? ''); + if (this.#parent instanceof BidiFrame) { + return this.#parent; + } + return null; } override childFrames(): BidiFrame[] { - return this.#page.childFrames(this.#context.id); + return [...this.browsingContext.children].map(child => { + return this.#frames.get(child)!; + }); + } + + #detached$() { + return defer(() => { + if (this.detached) { + return of(this as Frame); + } + return fromEmitterEvent( + this.page().trustedEmitter, + PageEvent.FrameDetached + ).pipe( + filter(detachedFrame => { + return detachedFrame === this; + }) + ); + }); } @throwIfDetached @@ -127,40 +294,23 @@ export class BidiFrame extends Frame { url: string, options: GoToOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [readiness, networkIdle] = getBiDiReadinessState(waitUntil); - - const result$ = zip( - from( - this.#context.connection.send('browsingContext.navigate', { - context: this.#context.id, - url, - wait: readiness, - }) + const [response] = await Promise.all([ + this.waitForNavigation(options), + // Some implementations currently only report errors when the + // readiness=interactive. + // + // Related: https://bugzilla.mozilla.org/show_bug.cgi?id=1846601 + this.browsingContext.navigate( + url, + Bidi.BrowsingContext.ReadinessState.Interactive ), - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())), - rewriteNavigationError(url, ms) + ]).catch( + rewriteNavigationError( + url, + options.timeout ?? this.timeoutSettings.navigationTimeout() + ) ); - - const result = await firstValueFrom(result$); - return this.#page.getNavigationResponse(result.navigation); + return response; } @throwIfDetached @@ -168,95 +318,105 @@ export class BidiFrame extends Frame { html: string, options: WaitForOptions = {} ): Promise<void> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [waitEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil); - - const result$ = zip( - forkJoin([ - fromEmitterEvent(this.#context, waitEvent).pipe(first()), - from(this.setFrameContent(html)), - ]).pipe( - map(() => { - return null; - }) + await Promise.all([ + this.setFrameContent(html), + firstValueFrom( + combineLatest([ + this.#waitForLoad$(options), + this.#waitForNetworkIdle$(options), + ]) ), - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())), - rewriteNavigationError('setContent', ms) - ); - - await firstValueFrom(result$); - } - - context(): BrowsingContext { - return this.#context; + ]); } @throwIfDetached override async waitForNavigation( options: WaitForOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this.#timeoutSettings.navigationTimeout(), - } = options; - - const [waitUntilEvent, networkIdle] = getBiDiLifecycleEvent(waitUntil); - - const navigation$ = merge( - forkJoin([ - fromEmitterEvent( - this.#context, - Bidi.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted - ).pipe(first()), - fromEmitterEvent(this.#context, waitUntilEvent).pipe(first()), - ]), - fromEmitterEvent( - this.#context, - Bidi.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated + const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options; + + const frames = this.childFrames().map(frame => { + return frame.#detached$(); + }); + return await firstValueFrom( + combineLatest([ + fromEmitterEvent(this.browsingContext, 'navigation').pipe( + switchMap(({navigation}) => { + return this.#waitForLoad$(options).pipe( + delayWhen(() => { + if (frames.length === 0) { + return of(undefined); + } + return combineLatest(frames); + }), + raceWith( + fromEmitterEvent(navigation, 'fragment'), + fromEmitterEvent(navigation, 'failed').pipe( + map(({url}) => { + throw new Error(`Navigation failed: ${url}`); + }) + ), + fromEmitterEvent(navigation, 'aborted').pipe( + map(({url}) => { + throw new Error(`Navigation aborted: ${url}`); + }) + ) + ), + switchMap(() => { + if (navigation.request) { + function requestFinished$( + request: Request + ): Observable<Navigation> { + // Reduces flakiness if the response events arrive after + // the load event. + // Usually, the response or error is already there at this point. + if (request.response || request.error) { + return of(navigation); + } + if (request.redirect) { + return requestFinished$(request.redirect); + } + return fromEmitterEvent(request, 'success') + .pipe( + raceWith(fromEmitterEvent(request, 'error')), + raceWith(fromEmitterEvent(request, 'redirect')) + ) + .pipe( + switchMap(() => { + return requestFinished$(request); + }) + ); + } + return requestFinished$(navigation.request); + } + return of(navigation); + }) + ); + }) + ), + this.#waitForNetworkIdle$(options), + ]).pipe( + map(([navigation]) => { + const request = navigation.request; + if (!request) { + return null; + } + const httpRequest = requests.get(request)!; + const lastRedirect = httpRequest.redirectChain().at(-1); + return ( + lastRedirect !== undefined ? lastRedirect : httpRequest + ).response(); + }), + raceWith( + timeout(ms), + this.#detached$().pipe( + map(() => { + throw new TargetCloseError('Frame detached.'); + }) + ) + ) ) - ).pipe( - map(result => { - if (Array.isArray(result)) { - return {result: result[1]}; - } - return {result}; - }) ); - - const result$ = zip( - navigation$, - ...(networkIdle !== null - ? [ - this.#page.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#abortDeferred.valueOrThrow())) - ); - - const result = await firstValueFrom(result$); - return this.#page.getNavigationResponse(result.navigation); } override waitForDevicePrompt(): never { @@ -264,18 +424,7 @@ export class BidiFrame extends Frame { } override get detached(): boolean { - return this.#disposed; - } - - [disposeSymbol](): void { - if (this.#disposed) { - return; - } - this.#disposed = true; - this.#abortDeferred.reject(new Error('Frame detached')); - this.#context.dispose(); - this.sandboxes[MAIN_SANDBOX][disposeSymbol](); - this.sandboxes[PUPPETEER_SANDBOX][disposeSymbol](); + return this.browsingContext.closed; } #exposedFunctions = new Map<string, ExposeableFunction<never[], unknown>>(); @@ -288,21 +437,27 @@ export class BidiFrame extends Frame { `Failed to add page binding with name ${name}: globalThis['${name}'] already exists!` ); } - const exposeable = new ExposeableFunction(this, name, apply); + const exposeable = await ExposeableFunction.from(this, name, apply); this.#exposedFunctions.set(name, exposeable); - try { - await exposeable.expose(); - } catch (error) { - this.#exposedFunctions.delete(name); - throw error; + } + + async removeExposedFunction(name: string): Promise<void> { + const exposedFunction = this.#exposedFunctions.get(name); + if (!exposedFunction) { + throw new Error( + `Failed to remove page binding with name ${name}: window['${name}'] does not exists!` + ); } + + this.#exposedFunctions.delete(name); + await exposedFunction[Symbol.asyncDispose](); } override waitForSelector<Selector extends string>( selector: Selector, options?: WaitForSelectorOptions ): Promise<ElementHandle<NodeFor<Selector>> | null> { - if (selector.startsWith('aria')) { + if (selector.startsWith('aria') && !this.page().browser().cdpSupported) { throw new UnsupportedOperation( 'ARIA selector is not supported for BiDi!' ); @@ -310,4 +465,124 @@ export class BidiFrame extends Frame { return super.waitForSelector(selector, options); } + + async createCDPSession(): Promise<CDPSession> { + const {sessionId} = await this.client.send('Target.attachToTarget', { + targetId: this._id, + flatten: true, + }); + return new BidiCdpSession(this, sessionId); + } + + @throwIfDetached + #waitForLoad$(options: WaitForOptions = {}): Observable<void> { + let {waitUntil = 'load'} = options; + const {timeout: ms = this.timeoutSettings.navigationTimeout()} = options; + + if (!Array.isArray(waitUntil)) { + waitUntil = [waitUntil]; + } + + const events = new Set<'load' | 'DOMContentLoaded'>(); + for (const lifecycleEvent of waitUntil) { + switch (lifecycleEvent) { + case 'load': { + events.add('load'); + break; + } + case 'domcontentloaded': { + events.add('DOMContentLoaded'); + break; + } + } + } + if (events.size === 0) { + return of(undefined); + } + + return combineLatest( + [...events].map(event => { + return fromEmitterEvent(this.browsingContext, event); + }) + ).pipe( + map(() => {}), + first(), + raceWith( + timeout(ms), + this.#detached$().pipe( + map(() => { + throw new Error('Frame detached.'); + }) + ) + ) + ); + } + + @throwIfDetached + #waitForNetworkIdle$(options: WaitForOptions = {}): Observable<void> { + let {waitUntil = 'load'} = options; + if (!Array.isArray(waitUntil)) { + waitUntil = [waitUntil]; + } + + let concurrency = Infinity; + for (const event of waitUntil) { + switch (event) { + case 'networkidle0': { + concurrency = Math.min(0, concurrency); + break; + } + case 'networkidle2': { + concurrency = Math.min(2, concurrency); + break; + } + } + } + if (concurrency === Infinity) { + return of(undefined); + } + + return this.page().waitForNetworkIdle$({ + idleTime: 500, + timeout: options.timeout ?? this.timeoutSettings.timeout(), + concurrency, + }); + } + + @throwIfDetached + async setFiles(element: BidiElementHandle, files: string[]): Promise<void> { + await this.browsingContext.setFiles( + // SAFETY: ElementHandles are always remote references. + element.remoteValue() as Bidi.Script.SharedReference, + files + ); + } +} + +function isConsoleLogEntry( + event: Bidi.Log.Entry +): event is Bidi.Log.ConsoleLogEntry { + return event.type === 'console'; +} + +function isJavaScriptLogEntry( + event: Bidi.Log.Entry +): event is Bidi.Log.JavascriptLogEntry { + return event.type === 'javascript'; +} + +function getStackTraceLocations( + stackTrace?: Bidi.Script.StackTrace +): ConsoleMessageLocation[] { + const stackTraceLocations: ConsoleMessageLocation[] = []; + if (stackTrace) { + for (const callFrame of stackTrace.callFrames) { + stackTraceLocations.push({ + url: callFrame.url, + lineNumber: callFrame.lineNumber, + columnNumber: callFrame.columnNumber, + }); + } + } + return stackTraceLocations; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts index 57cb801b8c..e75bb0cf3c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPRequest.ts @@ -5,106 +5,126 @@ */ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import type {Frame} from '../api/Frame.js'; +import type {CDPSession} from '../api/CDPSession.js'; import type { ContinueRequestOverrides, ResponseForRequest, } from '../api/HTTPRequest.js'; import {HTTPRequest, type ResourceType} from '../api/HTTPRequest.js'; +import {PageEvent} from '../api/Page.js'; import {UnsupportedOperation} from '../common/Errors.js'; -import type {BidiHTTPResponse} from './HTTPResponse.js'; +import type {Request} from './core/Request.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiHTTPResponse} from './HTTPResponse.js'; + +export const requests = new WeakMap<Request, BidiHTTPRequest>(); /** * @internal */ export class BidiHTTPRequest extends HTTPRequest { - override _response: BidiHTTPResponse | null = null; - override _redirectChain: BidiHTTPRequest[]; - _navigationId: string | null; - - #url: string; - #resourceType: ResourceType; - - #method: string; - #postData?: string; - #headers: Record<string, string> = {}; - #initiator: Bidi.Network.Initiator; - #frame: Frame | null; - - constructor( - event: Bidi.Network.BeforeRequestSentParameters, - frame: Frame | null, - redirectChain: BidiHTTPRequest[] = [] - ) { + static from( + bidiRequest: Request, + frame: BidiFrame | undefined + ): BidiHTTPRequest { + const request = new BidiHTTPRequest(bidiRequest, frame); + request.#initialize(); + return request; + } + + #redirect: BidiHTTPRequest | undefined; + #response: BidiHTTPResponse | null = null; + override readonly id: string; + readonly #frame: BidiFrame | undefined; + readonly #request: Request; + + private constructor(request: Request, frame: BidiFrame | undefined) { super(); + requests.set(request, this); - this.#url = event.request.url; - this.#resourceType = event.initiator.type.toLowerCase() as ResourceType; - this.#method = event.request.method; - this.#postData = undefined; - this.#initiator = event.initiator; + this.#request = request; this.#frame = frame; - - this._requestId = event.request.request; - this._redirectChain = redirectChain; - this._navigationId = event.navigation; - - for (const header of event.request.headers) { - // TODO: How to handle Binary Headers - // https://w3c.github.io/webdriver-bidi/#type-network-Header - if (header.value.type === 'string') { - this.#headers[header.name.toLowerCase()] = header.value.value; - } - } + this.id = request.id; } - override get client(): never { + override get client(): CDPSession { throw new UnsupportedOperation(); } + #initialize() { + this.#request.on('redirect', request => { + this.#redirect = BidiHTTPRequest.from(request, this.#frame); + }); + this.#request.once('success', data => { + this.#response = BidiHTTPResponse.from(data, this); + }); + + this.#frame?.page().trustedEmitter.emit(PageEvent.Request, this); + } + override url(): string { - return this.#url; + return this.#request.url; } override resourceType(): ResourceType { - return this.#resourceType; + return this.initiator().type.toLowerCase() as ResourceType; } override method(): string { - return this.#method; + return this.#request.method; } override postData(): string | undefined { - return this.#postData; + throw new UnsupportedOperation(); } override hasPostData(): boolean { - return this.#postData !== undefined; + throw new UnsupportedOperation(); } override async fetchPostData(): Promise<string | undefined> { - return this.#postData; + throw new UnsupportedOperation(); } override headers(): Record<string, string> { - return this.#headers; + const headers: Record<string, string> = {}; + for (const header of this.#request.headers) { + headers[header.name.toLowerCase()] = header.value.value; + } + return headers; } override response(): BidiHTTPResponse | null { - return this._response; + return this.#response; + } + + override failure(): {errorText: string} | null { + if (this.#request.error === undefined) { + return null; + } + return {errorText: this.#request.error}; } override isNavigationRequest(): boolean { - return Boolean(this._navigationId); + return this.#request.navigation !== undefined; } override initiator(): Bidi.Network.Initiator { - return this.#initiator; + return this.#request.initiator; } override redirectChain(): BidiHTTPRequest[] { - return this._redirectChain.slice(); + if (this.#redirect === undefined) { + return []; + } + const redirects = [this.#redirect]; + for (const redirect of redirects) { + if (redirect.#redirect !== undefined) { + redirects.push(redirect.#redirect); + } + } + return redirects; } override enqueueInterceptAction( @@ -114,8 +134,8 @@ export class BidiHTTPRequest extends HTTPRequest { void pendingHandler(); } - override frame(): Frame | null { - return this.#frame; + override frame(): BidiFrame | null { + return this.#frame ?? null; } override continueRequestOverrides(): never { @@ -156,8 +176,4 @@ export class BidiHTTPRequest extends HTTPRequest { ): never { throw new UnsupportedOperation(); } - - override failure(): never { - throw new UnsupportedOperation(); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts index ce28820a65..bad44ff089 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/HTTPResponse.ts @@ -7,11 +7,10 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import type Protocol from 'devtools-protocol'; import type {Frame} from '../api/Frame.js'; -import { - HTTPResponse as HTTPResponse, - type RemoteAddress, -} from '../api/HTTPResponse.js'; +import {HTTPResponse, type RemoteAddress} from '../api/HTTPResponse.js'; +import {PageEvent} from '../api/Page.js'; import {UnsupportedOperation} from '../common/Errors.js'; +import {invokeAtMostOnceForArguments} from '../util/decorators.js'; import type {BidiHTTPRequest} from './HTTPRequest.js'; @@ -19,62 +18,62 @@ import type {BidiHTTPRequest} from './HTTPRequest.js'; * @internal */ export class BidiHTTPResponse extends HTTPResponse { + static from( + data: Bidi.Network.ResponseData, + request: BidiHTTPRequest + ): BidiHTTPResponse { + const response = new BidiHTTPResponse(data, request); + response.#initialize(); + return response; + } + + #data: Bidi.Network.ResponseData; #request: BidiHTTPRequest; - #remoteAddress: RemoteAddress; - #status: number; - #statusText: string; - #url: string; - #fromCache: boolean; - #headers: Record<string, string> = {}; - #timings: Record<string, string> | null; - - constructor( - request: BidiHTTPRequest, - {response}: Bidi.Network.ResponseCompletedParameters + + private constructor( + data: Bidi.Network.ResponseData, + request: BidiHTTPRequest ) { super(); + this.#data = data; this.#request = request; + } - this.#remoteAddress = { - ip: '', - port: -1, - }; - - this.#url = response.url; - this.#fromCache = response.fromCache; - this.#status = response.status; - this.#statusText = response.statusText; - // TODO: File and issue with BiDi spec - this.#timings = null; - - // TODO: Removed once the Firefox implementation is compliant with https://w3c.github.io/webdriver-bidi/#get-the-response-data. - for (const header of response.headers || []) { - // TODO: How to handle Binary Headers - // https://w3c.github.io/webdriver-bidi/#type-network-Header - if (header.value.type === 'string') { - this.#headers[header.name.toLowerCase()] = header.value.value; - } - } + #initialize() { + this.#request.frame()?.page().trustedEmitter.emit(PageEvent.Response, this); } + @invokeAtMostOnceForArguments override remoteAddress(): RemoteAddress { - return this.#remoteAddress; + return { + ip: '', + port: -1, + }; } override url(): string { - return this.#url; + return this.#data.url; } override status(): number { - return this.#status; + return this.#data.status; } override statusText(): string { - return this.#statusText; + return this.#data.statusText; } override headers(): Record<string, string> { - return this.#headers; + const headers: Record<string, string> = {}; + // TODO: Remove once the Firefox implementation is compliant with https://w3c.github.io/webdriver-bidi/#get-the-response-data. + for (const header of this.#data.headers || []) { + // TODO: How to handle Binary Headers + // https://w3c.github.io/webdriver-bidi/#type-network-Header + if (header.value.type === 'string') { + headers[header.name.toLowerCase()] = header.value.value; + } + } + return headers; } override request(): BidiHTTPRequest { @@ -82,11 +81,12 @@ export class BidiHTTPResponse extends HTTPResponse { } override fromCache(): boolean { - return this.#fromCache; + return this.#data.fromCache; } override timing(): Protocol.Network.ResourceTiming | null { - return this.#timings as any; + // TODO: File and issue with BiDi spec + throw new UnsupportedOperation(); } override frame(): Frame | null { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts index 5406556d64..dc70850c12 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Input.ts @@ -12,9 +12,9 @@ import { Mouse, MouseButton, Touchscreen, + type KeyboardTypeOptions, type KeyDownOptions, type KeyPressOptions, - type KeyboardTypeOptions, type MouseClickOptions, type MouseMoveOptions, type MouseOptions, @@ -23,7 +23,6 @@ import { import {UnsupportedOperation} from '../common/Errors.js'; import type {KeyInput} from '../common/USKeyboardLayout.js'; -import type {BrowsingContext} from './BrowsingContext.js'; import type {BidiPage} from './Page.js'; const enum InputId { @@ -288,39 +287,33 @@ export class BidiKeyboard extends Keyboard { key: KeyInput, _options?: Readonly<KeyDownOptions> ): Promise<void> { - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions: [ - { - type: ActionType.KeyDown, - value: getBidiKeyValue(key), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions: [ + { + type: ActionType.KeyDown, + value: getBidiKeyValue(key), + }, + ], + }, + ]); } override async up(key: KeyInput): Promise<void> { - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions: [ - { - type: ActionType.KeyUp, - value: getBidiKeyValue(key), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions: [ + { + type: ActionType.KeyUp, + value: getBidiKeyValue(key), + }, + ], + }, + ]); } override async press( @@ -344,16 +337,13 @@ export class BidiKeyboard extends Keyboard { type: ActionType.KeyUp, value: getBidiKeyValue(key), }); - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions, + }, + ]); } override async type( @@ -396,16 +386,13 @@ export class BidiKeyboard extends Keyboard { ); } } - await this.#page.connection.send('input.performActions', { - context: this.#page.mainFrame()._id, - actions: [ - { - type: SourceActionsType.Key, - id: InputId.Keyboard, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Key, + id: InputId.Keyboard, + actions, + }, + ]); } override async sendCharacter(char: string): Promise<void> { @@ -460,19 +447,17 @@ const getBidiButton = (button: MouseButton) => { * @internal */ export class BidiMouse extends Mouse { - #context: BrowsingContext; + #page: BidiPage; #lastMovePoint: Point = {x: 0, y: 0}; - constructor(context: BrowsingContext) { + constructor(page: BidiPage) { super(); - this.#context = context; + this.#page = page; } override async reset(): Promise<void> { this.#lastMovePoint = {x: 0, y: 0}; - await this.#context.connection.send('input.releaseActions', { - context: this.#context.id, - }); + await this.#page.mainFrame().browsingContext.releaseActions(); } override async move( @@ -502,52 +487,43 @@ export class BidiMouse extends Mouse { }); // https://w3c.github.io/webdriver-bidi/#command-input-performActions:~:text=input.PointerMoveAction%20%3D%20%7B%0A%20%20type%3A%20%22pointerMove%22%2C%0A%20%20x%3A%20js%2Dint%2C this.#lastMovePoint = to; - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions, + }, + ]); } override async down(options: Readonly<MouseOptions> = {}): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions: [ - { - type: ActionType.PointerDown, - button: getBidiButton(options.button ?? MouseButton.Left), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions: [ + { + type: ActionType.PointerDown, + button: getBidiButton(options.button ?? MouseButton.Left), + }, + ], + }, + ]); } override async up(options: Readonly<MouseOptions> = {}): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions: [ - { - type: ActionType.PointerUp, - button: getBidiButton(options.button ?? MouseButton.Left), - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions: [ + { + type: ActionType.PointerUp, + button: getBidiButton(options.button ?? MouseButton.Left), + }, + ], + }, + ]); } override async click( @@ -582,41 +558,35 @@ export class BidiMouse extends Mouse { }); } actions.push(pointerUpAction); - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Mouse, - actions, - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Mouse, + actions, + }, + ]); } override async wheel( options: Readonly<MouseWheelOptions> = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Wheel, - id: InputId.Wheel, - actions: [ - { - type: ActionType.Scroll, - ...(this.#lastMovePoint ?? { - x: 0, - y: 0, - }), - deltaX: options.deltaX ?? 0, - deltaY: options.deltaY ?? 0, - }, - ], - }, - ], - }); + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Wheel, + id: InputId.Wheel, + actions: [ + { + type: ActionType.Scroll, + ...(this.#lastMovePoint ?? { + x: 0, + y: 0, + }), + deltaX: options.deltaX ?? 0, + deltaY: options.deltaY ?? 0, + }, + ], + }, + ]); } override drag(): never { @@ -644,11 +614,11 @@ export class BidiMouse extends Mouse { * @internal */ export class BidiTouchscreen extends Touchscreen { - #context: BrowsingContext; + #page: BidiPage; - constructor(context: BrowsingContext) { + constructor(page: BidiPage) { super(); - this.#context = context; + this.#page = page; } override async touchStart( @@ -656,30 +626,27 @@ export class BidiTouchscreen extends Touchscreen { y: number, options: BidiTouchMoveOptions = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerMove, - x: Math.round(x), - y: Math.round(y), - origin: options.origin, - }, - { - type: ActionType.PointerDown, - button: 0, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerMove, + x: Math.round(x), + y: Math.round(y), + origin: options.origin, + }, + { + type: ActionType.PointerDown, + button: 0, + }, + ], + }, + ]); } override async touchMove( @@ -687,46 +654,40 @@ export class BidiTouchscreen extends Touchscreen { y: number, options: BidiTouchMoveOptions = {} ): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerMove, - x: Math.round(x), - y: Math.round(y), - origin: options.origin, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerMove, + x: Math.round(x), + y: Math.round(y), + origin: options.origin, + }, + ], + }, + ]); } override async touchEnd(): Promise<void> { - await this.#context.connection.send('input.performActions', { - context: this.#context.id, - actions: [ - { - type: SourceActionsType.Pointer, - id: InputId.Finger, - parameters: { - pointerType: Bidi.Input.PointerType.Touch, - }, - actions: [ - { - type: ActionType.PointerUp, - button: 0, - }, - ], + await this.#page.mainFrame().browsingContext.performActions([ + { + type: SourceActionsType.Pointer, + id: InputId.Finger, + parameters: { + pointerType: Bidi.Input.PointerType.Touch, }, - ], - }); + actions: [ + { + type: ActionType.PointerUp, + button: 0, + }, + ], + }, + ]); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts index 7104601553..10f564f78a 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/JSHandle.ts @@ -12,29 +12,28 @@ import {UnsupportedOperation} from '../common/Errors.js'; import {BidiDeserializer} from './Deserializer.js'; import type {BidiRealm} from './Realm.js'; -import type {Sandbox} from './Sandbox.js'; -import {releaseReference} from './util.js'; /** * @internal */ export class BidiJSHandle<T = unknown> extends JSHandle<T> { - #disposed = false; - readonly #sandbox: Sandbox; + static from<T>( + value: Bidi.Script.RemoteValue, + realm: BidiRealm + ): BidiJSHandle<T> { + return new BidiJSHandle(value, realm); + } + readonly #remoteValue: Bidi.Script.RemoteValue; - constructor(sandbox: Sandbox, remoteValue: Bidi.Script.RemoteValue) { - super(); - this.#sandbox = sandbox; - this.#remoteValue = remoteValue; - } + override readonly realm: BidiRealm; - context(): BidiRealm { - return this.realm.environment.context(); - } + #disposed = false; - override get realm(): Sandbox { - return this.#sandbox; + constructor(value: Bidi.Script.RemoteValue, realm: BidiRealm) { + super(); + this.#remoteValue = value; + this.realm = realm; } override get disposed(): boolean { @@ -56,12 +55,7 @@ export class BidiJSHandle<T = unknown> extends JSHandle<T> { return; } this.#disposed = true; - if ('handle' in this.#remoteValue) { - await releaseReference( - this.context(), - this.#remoteValue as Bidi.Script.RemoteReference - ); - } + await this.realm.destroyHandles([this]); } get isPrimitiveValue(): boolean { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts deleted file mode 100644 index 2caaf0ad50..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/NetworkManager.ts +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - -import {EventEmitter, EventSubscription} from '../common/EventEmitter.js'; -import { - NetworkManagerEvent, - type NetworkManagerEvents, -} from '../common/NetworkManagerEvents.js'; -import {DisposableStack} from '../util/disposable.js'; - -import type {BidiConnection} from './Connection.js'; -import type {BidiFrame} from './Frame.js'; -import {BidiHTTPRequest} from './HTTPRequest.js'; -import {BidiHTTPResponse} from './HTTPResponse.js'; -import type {BidiPage} from './Page.js'; - -/** - * @internal - */ -export class BidiNetworkManager extends EventEmitter<NetworkManagerEvents> { - #connection: BidiConnection; - #page: BidiPage; - #subscriptions = new DisposableStack(); - - #requestMap = new Map<string, BidiHTTPRequest>(); - #navigationMap = new Map<string, BidiHTTPResponse>(); - - constructor(connection: BidiConnection, page: BidiPage) { - super(); - this.#connection = connection; - this.#page = page; - - // TODO: Subscribe to the Frame individually - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.beforeRequestSent', - this.#onBeforeRequestSent.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.responseStarted', - this.#onResponseStarted.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.responseCompleted', - this.#onResponseCompleted.bind(this) - ) - ); - this.#subscriptions.use( - new EventSubscription( - this.#connection, - 'network.fetchError', - this.#onFetchError.bind(this) - ) - ); - } - - #onBeforeRequestSent(event: Bidi.Network.BeforeRequestSentParameters): void { - const frame = this.#page.frame(event.context ?? ''); - if (!frame) { - return; - } - const request = this.#requestMap.get(event.request.request); - let upsertRequest: BidiHTTPRequest; - if (request) { - request._redirectChain.push(request); - upsertRequest = new BidiHTTPRequest(event, frame, request._redirectChain); - } else { - upsertRequest = new BidiHTTPRequest(event, frame, []); - } - this.#requestMap.set(event.request.request, upsertRequest); - this.emit(NetworkManagerEvent.Request, upsertRequest); - } - - #onResponseStarted(_event: Bidi.Network.ResponseStartedParameters) {} - - #onResponseCompleted(event: Bidi.Network.ResponseCompletedParameters): void { - const request = this.#requestMap.get(event.request.request); - if (!request) { - return; - } - const response = new BidiHTTPResponse(request, event); - request._response = response; - if (event.navigation) { - this.#navigationMap.set(event.navigation, response); - } - if (response.fromCache()) { - this.emit(NetworkManagerEvent.RequestServedFromCache, request); - } - this.emit(NetworkManagerEvent.Response, response); - this.emit(NetworkManagerEvent.RequestFinished, request); - } - - #onFetchError(event: Bidi.Network.FetchErrorParameters) { - const request = this.#requestMap.get(event.request.request); - if (!request) { - return; - } - request._failureText = event.errorText; - this.emit(NetworkManagerEvent.RequestFailed, request); - this.#requestMap.delete(event.request.request); - } - - getNavigationResponse(navigationId?: string | null): BidiHTTPResponse | null { - if (!navigationId) { - return null; - } - const response = this.#navigationMap.get(navigationId); - - return response ?? null; - } - - inFlightRequestsCount(): number { - let inFlightRequestCounter = 0; - for (const request of this.#requestMap.values()) { - if (!request.response() || request._failureText) { - inFlightRequestCounter++; - } - } - - return inFlightRequestCounter; - } - - clearMapAfterFrameDispose(frame: BidiFrame): void { - for (const [id, request] of this.#requestMap.entries()) { - if (request.frame() === frame) { - this.#requestMap.delete(id); - } - } - - for (const [id, response] of this.#navigationMap.entries()) { - if (response.frame() === frame) { - this.#navigationMap.delete(id); - } - } - } - - dispose(): void { - this.removeAllListeners(); - this.#requestMap.clear(); - this.#navigationMap.clear(); - this.#subscriptions.dispose(); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts index 053d23b63a..c662496a18 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Page.ts @@ -4,210 +4,115 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - -import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; +import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import type Protocol from 'devtools-protocol'; -import { - firstValueFrom, - from, - map, - raceWith, - zip, -} from '../../third_party/rxjs/rxjs.js'; +import {firstValueFrom, from, raceWith} from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; import type {BoundingBox} from '../api/ElementHandle.js'; import type {WaitForOptions} from '../api/Frame.js'; import type {HTTPResponse} from '../api/HTTPResponse.js'; +import type { + MediaFeature, + GeolocationOptions, + PageEvents, +} from '../api/Page.js'; import { Page, PageEvent, - type GeolocationOptions, - type MediaFeature, type NewDocumentScriptEvaluation, type ScreenshotOptions, } from '../api/Page.js'; import {Accessibility} from '../cdp/Accessibility.js'; import {Coverage} from '../cdp/Coverage.js'; -import {EmulationManager as CdpEmulationManager} from '../cdp/EmulationManager.js'; -import {FrameTree} from '../cdp/FrameTree.js'; +import {EmulationManager} from '../cdp/EmulationManager.js'; import {Tracing} from '../cdp/Tracing.js'; -import { - ConsoleMessage, - type ConsoleMessageLocation, -} from '../common/ConsoleMessage.js'; -import {TargetCloseError, UnsupportedOperation} from '../common/Errors.js'; -import type {Handler} from '../common/EventEmitter.js'; -import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js'; +import type {Cookie, CookieParam, CookieSameSite} from '../common/Cookie.js'; +import type {DeleteCookiesRequest} from '../common/Cookie.js'; +import {UnsupportedOperation} from '../common/Errors.js'; +import {EventEmitter} from '../common/EventEmitter.js'; import type {PDFOptions} from '../common/PDFOptions.js'; import type {Awaitable} from '../common/types.js'; -import { - debugError, - evaluationString, - NETWORK_IDLE_TIME, - parsePDFOptions, - timeout, - validateDialogType, -} from '../common/util.js'; +import {evaluationString, parsePDFOptions, timeout} from '../common/util.js'; import type {Viewport} from '../common/Viewport.js'; import {assert} from '../util/assert.js'; -import {Deferred} from '../util/Deferred.js'; -import {disposeSymbol} from '../util/disposable.js'; +import {bubble} from '../util/decorators.js'; import {isErrorLike} from '../util/ErrorLike.js'; import type {BidiBrowser} from './Browser.js'; import type {BidiBrowserContext} from './BrowserContext.js'; -import { - BrowsingContextEvent, - CdpSessionWrapper, - type BrowsingContext, -} from './BrowsingContext.js'; -import type {BidiConnection} from './Connection.js'; -import {BidiDeserializer} from './Deserializer.js'; -import {BidiDialog} from './Dialog.js'; +import type {BidiCdpSession} from './CDPSession.js'; +import type {BrowsingContext} from './core/BrowsingContext.js'; import {BidiElementHandle} from './ElementHandle.js'; -import {EmulationManager} from './EmulationManager.js'; import {BidiFrame} from './Frame.js'; -import type {BidiHTTPRequest} from './HTTPRequest.js'; import type {BidiHTTPResponse} from './HTTPResponse.js'; import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js'; import type {BidiJSHandle} from './JSHandle.js'; -import {getBiDiReadinessState, rewriteNavigationError} from './lifecycle.js'; -import {BidiNetworkManager} from './NetworkManager.js'; -import {createBidiHandle} from './Realm.js'; -import type {BiDiPageTarget} from './Target.js'; +import {rewriteNavigationError} from './util.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ export class BidiPage extends Page { - #accessibility: Accessibility; - #connection: BidiConnection; - #frameTree = new FrameTree<BidiFrame>(); - #networkManager: BidiNetworkManager; - #viewport: Viewport | null = null; - #closedDeferred = Deferred.create<never, TargetCloseError>(); - #subscribedEvents = new Map<Bidi.Event['method'], Handler<any>>([ - ['log.entryAdded', this.#onLogEntryAdded.bind(this)], - ['browsingContext.load', this.#onFrameLoaded.bind(this)], - [ - 'browsingContext.fragmentNavigated', - this.#onFrameFragmentNavigated.bind(this), - ], - [ - 'browsingContext.domContentLoaded', - this.#onFrameDOMContentLoaded.bind(this), - ], - ['browsingContext.userPromptOpened', this.#onDialog.bind(this)], - ]); - readonly #networkManagerEvents = [ - [ - NetworkManagerEvent.Request, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.Request, request); - }, - ], - [ - NetworkManagerEvent.RequestServedFromCache, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestServedFromCache, request); - }, - ], - [ - NetworkManagerEvent.RequestFailed, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestFailed, request); - }, - ], - [ - NetworkManagerEvent.RequestFinished, - (request: BidiHTTPRequest) => { - this.emit(PageEvent.RequestFinished, request); - }, - ], - [ - NetworkManagerEvent.Response, - (response: BidiHTTPResponse) => { - this.emit(PageEvent.Response, response); - }, - ], - ] as const; - - readonly #browsingContextEvents = new Map<symbol, Handler<any>>([ - [BrowsingContextEvent.Created, this.#onContextCreated.bind(this)], - [BrowsingContextEvent.Destroyed, this.#onContextDestroyed.bind(this)], - ]); - #tracing: Tracing; - #coverage: Coverage; - #cdpEmulationManager: CdpEmulationManager; - #emulationManager: EmulationManager; - #mouse: BidiMouse; - #touchscreen: BidiTouchscreen; - #keyboard: BidiKeyboard; - #browsingContext: BrowsingContext; - #browserContext: BidiBrowserContext; - #target: BiDiPageTarget; - - _client(): CDPSession { - return this.mainFrame().context().cdpSession; - } - - constructor( - browsingContext: BrowsingContext, + static from( browserContext: BidiBrowserContext, - target: BiDiPageTarget - ) { - super(); - this.#browsingContext = browsingContext; - this.#browserContext = browserContext; - this.#target = target; - this.#connection = browsingContext.connection; + browsingContext: BrowsingContext + ): BidiPage { + const page = new BidiPage(browserContext, browsingContext); + page.#initialize(); + return page; + } - for (const [event, subscriber] of this.#browsingContextEvents) { - this.#browsingContext.on(event, subscriber); - } + @bubble() + accessor trustedEmitter = new EventEmitter<PageEvents>(); - this.#networkManager = new BidiNetworkManager(this.#connection, this); + readonly #browserContext: BidiBrowserContext; + readonly #frame: BidiFrame; + #viewport: Viewport | null = null; + readonly #workers = new Set<BidiWebWorker>(); - for (const [event, subscriber] of this.#subscribedEvents) { - this.#connection.on(event, subscriber); - } + readonly keyboard: BidiKeyboard; + readonly mouse: BidiMouse; + readonly touchscreen: BidiTouchscreen; + readonly accessibility: Accessibility; + readonly tracing: Tracing; + readonly coverage: Coverage; + readonly #cdpEmulationManager: EmulationManager; - for (const [event, subscriber] of this.#networkManagerEvents) { - // TODO: remove any - this.#networkManager.on(event, subscriber as any); - } + _client(): BidiCdpSession { + return this.#frame.client; + } - const frame = new BidiFrame( - this, - this.#browsingContext, - this._timeoutSettings, - this.#browsingContext.parent - ); - this.#frameTree.addFrame(frame); - this.emit(PageEvent.FrameAttached, frame); + private constructor( + browserContext: BidiBrowserContext, + browsingContext: BrowsingContext + ) { + super(); + this.#browserContext = browserContext; + this.#frame = BidiFrame.from(this, browsingContext); - // TODO: https://github.com/w3c/webdriver-bidi/issues/443 - this.#accessibility = new Accessibility( - this.mainFrame().context().cdpSession - ); - this.#tracing = new Tracing(this.mainFrame().context().cdpSession); - this.#coverage = new Coverage(this.mainFrame().context().cdpSession); - this.#cdpEmulationManager = new CdpEmulationManager( - this.mainFrame().context().cdpSession - ); - this.#emulationManager = new EmulationManager(browsingContext); - this.#mouse = new BidiMouse(this.mainFrame().context()); - this.#touchscreen = new BidiTouchscreen(this.mainFrame().context()); - this.#keyboard = new BidiKeyboard(this); + this.#cdpEmulationManager = new EmulationManager(this.#frame.client); + this.accessibility = new Accessibility(this.#frame.client); + this.tracing = new Tracing(this.#frame.client); + this.coverage = new Coverage(this.#frame.client); + this.keyboard = new BidiKeyboard(this); + this.mouse = new BidiMouse(this); + this.touchscreen = new BidiTouchscreen(this); } - /** - * @internal - */ - get connection(): BidiConnection { - return this.#connection; + #initialize() { + this.#frame.browsingContext.on('closed', () => { + this.trustedEmitter.emit(PageEvent.Close, undefined); + this.trustedEmitter.removeAllListeners(); + }); + + this.trustedEmitter.on(PageEvent.WorkerCreated, worker => { + this.#workers.add(worker as BidiWebWorker); + }); + this.trustedEmitter.on(PageEvent.WorkerDestroyed, worker => { + this.#workers.delete(worker as BidiWebWorker); + }); } override async setUserAgent( @@ -234,46 +139,15 @@ export class BidiPage extends Page { prototypeHandle.id, 'Prototype JSHandle must not be referencing primitive value' ); - const response = await this.mainFrame().client.send( - 'Runtime.queryObjects', - { - prototypeObjectId: prototypeHandle.id, - } - ); - return createBidiHandle(this.mainFrame().mainRealm(), { + const response = await this.#frame.client.send('Runtime.queryObjects', { + prototypeObjectId: prototypeHandle.id, + }); + return this.#frame.mainRealm().createHandle({ type: 'array', handle: response.objects.objectId, }) as BidiJSHandle<Prototype[]>; } - _setBrowserContext(browserContext: BidiBrowserContext): void { - this.#browserContext = browserContext; - } - - override get accessibility(): Accessibility { - return this.#accessibility; - } - - override get tracing(): Tracing { - return this.#tracing; - } - - override get coverage(): Coverage { - return this.#coverage; - } - - override get mouse(): BidiMouse { - return this.#mouse; - } - - override get touchscreen(): BidiTouchscreen { - return this.#touchscreen; - } - - override get keyboard(): BidiKeyboard { - return this.#keyboard; - } - override browser(): BidiBrowser { return this.browserContext().browser(); } @@ -283,14 +157,9 @@ export class BidiPage extends Page { } override mainFrame(): BidiFrame { - const mainFrame = this.#frameTree.getMainFrame(); - assert(mainFrame, 'Requesting main frame too early!'); - return mainFrame; + return this.#frame; } - /** - * @internal - */ async focusedFrame(): Promise<BidiFrame> { using frame = await this.mainFrame() .isolatedRealm() @@ -310,216 +179,38 @@ export class BidiPage extends Page { } override frames(): BidiFrame[] { - return Array.from(this.#frameTree.frames()); - } - - frame(frameId?: string): BidiFrame | null { - return this.#frameTree.getById(frameId ?? '') || null; - } - - childFrames(frameId: string): BidiFrame[] { - return this.#frameTree.childFrames(frameId); - } - - #onFrameLoaded(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame && this.mainFrame() === frame) { - this.emit(PageEvent.Load, undefined); - } - } - - #onFrameFragmentNavigated(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame) { - this.emit(PageEvent.FrameNavigated, frame); - } - } - - #onFrameDOMContentLoaded(info: Bidi.BrowsingContext.NavigationInfo): void { - const frame = this.frame(info.context); - if (frame) { - frame._hasStartedLoading = true; - if (this.mainFrame() === frame) { - this.emit(PageEvent.DOMContentLoaded, undefined); - } - this.emit(PageEvent.FrameNavigated, frame); - } - } - - #onContextCreated(context: BrowsingContext): void { - if ( - !this.frame(context.id) && - (this.frame(context.parent ?? '') || !this.#frameTree.getMainFrame()) - ) { - const frame = new BidiFrame( - this, - context, - this._timeoutSettings, - context.parent - ); - this.#frameTree.addFrame(frame); - if (frame !== this.mainFrame()) { - this.emit(PageEvent.FrameAttached, frame); - } - } - } - - #onContextDestroyed(context: BrowsingContext): void { - const frame = this.frame(context.id); - - if (frame) { - if (frame === this.mainFrame()) { - this.emit(PageEvent.Close, undefined); - } - this.#removeFramesRecursively(frame); - } - } - - #removeFramesRecursively(frame: BidiFrame): void { - for (const child of frame.childFrames()) { - this.#removeFramesRecursively(child); - } - frame[disposeSymbol](); - this.#networkManager.clearMapAfterFrameDispose(frame); - this.#frameTree.removeFrame(frame); - this.emit(PageEvent.FrameDetached, frame); - } - - #onLogEntryAdded(event: Bidi.Log.Entry): void { - const frame = this.frame(event.source.context); - if (!frame) { - return; - } - if (isConsoleLogEntry(event)) { - const args = event.args.map(arg => { - return createBidiHandle(frame.mainRealm(), arg); - }); - - const text = args - .reduce((value, arg) => { - const parsedValue = arg.isPrimitiveValue - ? BidiDeserializer.deserialize(arg.remoteValue()) - : arg.toString(); - return `${value} ${parsedValue}`; - }, '') - .slice(1); - - this.emit( - PageEvent.Console, - new ConsoleMessage( - event.method as any, - text, - args, - getStackTraceLocations(event.stackTrace) - ) - ); - } else if (isJavaScriptLogEntry(event)) { - const error = new Error(event.text ?? ''); - - const messageHeight = error.message.split('\n').length; - const messageLines = error.stack!.split('\n').splice(0, messageHeight); - - const stackLines = []; - if (event.stackTrace) { - for (const frame of event.stackTrace.callFrames) { - // Note we need to add `1` because the values are 0-indexed. - stackLines.push( - ` at ${frame.functionName || '<anonymous>'} (${frame.url}:${ - frame.lineNumber + 1 - }:${frame.columnNumber + 1})` - ); - if (stackLines.length >= Error.stackTraceLimit) { - break; - } - } - } - - error.stack = [...messageLines, ...stackLines].join('\n'); - this.emit(PageEvent.PageError, error); - } else { - debugError( - `Unhandled LogEntry with type "${event.type}", text "${event.text}" and level "${event.level}"` - ); - } - } - - #onDialog(event: Bidi.BrowsingContext.UserPromptOpenedParameters): void { - const frame = this.frame(event.context); - if (!frame) { - return; + const frames = [this.#frame]; + for (const frame of frames) { + frames.push(...frame.childFrames()); } - const type = validateDialogType(event.type); - - const dialog = new BidiDialog( - frame.context(), - type, - event.message, - event.defaultValue - ); - this.emit(PageEvent.Dialog, dialog); - } - - getNavigationResponse(id?: string | null): BidiHTTPResponse | null { - return this.#networkManager.getNavigationResponse(id); + return frames; } override isClosed(): boolean { - return this.#closedDeferred.finished(); + return this.#frame.detached; } override async close(options?: {runBeforeUnload?: boolean}): Promise<void> { - if (this.#closedDeferred.finished()) { + try { + await this.#frame.browsingContext.close(options?.runBeforeUnload); + } catch { return; } - - this.#closedDeferred.reject(new TargetCloseError('Page closed!')); - this.#networkManager.dispose(); - - await this.#connection.send('browsingContext.close', { - context: this.mainFrame()._id, - promptUnload: options?.runBeforeUnload ?? false, - }); - - this.emit(PageEvent.Close, undefined); - this.removeAllListeners(); } override async reload( options: WaitForOptions = {} ): Promise<BidiHTTPResponse | null> { - const { - waitUntil = 'load', - timeout: ms = this._timeoutSettings.navigationTimeout(), - } = options; - - const [readiness, networkIdle] = getBiDiReadinessState(waitUntil); - - const result$ = zip( - from( - this.#connection.send('browsingContext.reload', { - context: this.mainFrame()._id, - wait: readiness, - }) - ), - ...(networkIdle !== null - ? [ - this.waitForNetworkIdle$({ - timeout: ms, - concurrency: networkIdle === 'networkidle2' ? 2 : 0, - idleTime: NETWORK_IDLE_TIME, - }), - ] - : []) - ).pipe( - map(([{result}]) => { - return result; - }), - raceWith(timeout(ms), from(this.#closedDeferred.valueOrThrow())), - rewriteNavigationError(this.url(), ms) + const [response] = await Promise.all([ + this.#frame.waitForNavigation(options), + this.#frame.browsingContext.reload(), + ]).catch( + rewriteNavigationError( + this.url(), + options.timeout ?? this._timeoutSettings.navigationTimeout() + ) ); - - const result = await firstValueFrom(result$); - return this.getNavigationResponse(result.navigation); + return response; } override setDefaultNavigationTimeout(timeout: number): void { @@ -578,8 +269,19 @@ export class BidiPage extends Page { } override async setViewport(viewport: Viewport): Promise<void> { - if (!this.#browsingContext.supportsCdp()) { - await this.#emulationManager.emulateViewport(viewport); + if (!this.browser().cdpSupported) { + await this.#frame.browsingContext.setViewport({ + viewport: + viewport.width && viewport.height + ? { + width: viewport.width, + height: viewport.height, + } + : null, + devicePixelRatio: viewport.deviceScaleFactor + ? viewport.deviceScaleFactor + : null, + }); this.#viewport = viewport; return; } @@ -609,10 +311,9 @@ export class BidiPage extends Page { preferCSSPageSize, } = parsePDFOptions(options, 'cm'); const pageRanges = ranges ? ranges.split(', ') : []; - const {result} = await firstValueFrom( + const data = await firstValueFrom( from( - this.#connection.send('browsingContext.print', { - context: this.mainFrame()._id, + this.#frame.browsingContext.print({ background, margin, orientation: landscape ? 'landscape' : 'portrait', @@ -627,7 +328,7 @@ export class BidiPage extends Page { ).pipe(raceWith(timeout(ms))) ); - const buffer = Buffer.from(result.data, 'base64'); + const buffer = Buffer.from(data, 'base64'); await this._maybeWriteBufferToFile(path, buffer); @@ -636,19 +337,15 @@ export class BidiPage extends Page { override async createPDFStream( options?: PDFOptions | undefined - ): Promise<Readable> { + ): Promise<ReadableStream<Uint8Array>> { const buffer = await this.pdf(options); - try { - const {Readable} = await import('stream'); - return Readable.from(buffer); - } catch (error) { - if (error instanceof TypeError) { - throw new Error( - 'Can only pass a file path in a Node-like environment.' - ); - } - throw error; - } + + return new ReadableStream({ + start(controller) { + controller.enqueue(buffer); + controller.close(); + }, + }); } override async _screenshot( @@ -697,10 +394,7 @@ export class BidiPage extends Page { } } - const { - result: {data}, - } = await this.#connection.send('browsingContext.captureScreenshot', { - context: this.mainFrame()._id, + const data = await this.#frame.browsingContext.captureScreenshot({ origin: captureBeyondViewport ? 'document' : 'viewport', format: { type: `image/${type}`, @@ -712,19 +406,11 @@ export class BidiPage extends Page { } override async createCDPSession(): Promise<CDPSession> { - const {sessionId} = await this.mainFrame() - .context() - .cdpSession.send('Target.attachToTarget', { - targetId: this.mainFrame()._id, - flatten: true, - }); - return new CdpSessionWrapper(this.mainFrame().context(), sessionId); + return await this.#frame.createCDPSession(); } override async bringToFront(): Promise<void> { - await this.#connection.send('browsingContext.activate', { - context: this.mainFrame()._id, - }); + await this.#frame.browsingContext.activate(); } override async evaluateOnNewDocument< @@ -735,20 +421,16 @@ export class BidiPage extends Page { ...args: Params ): Promise<NewDocumentScriptEvaluation> { const expression = evaluationExpression(pageFunction, ...args); - const {result} = await this.#connection.send('script.addPreloadScript', { - functionDeclaration: expression, - contexts: [this.mainFrame()._id], - }); + const script = + await this.#frame.browsingContext.addPreloadScript(expression); - return {identifier: result.script}; + return {identifier: script}; } override async removeScriptToEvaluateOnNewDocument( id: string ): Promise<void> { - await this.#connection.send('script.removePreloadScript', { - script: id, - }); + await this.#frame.browsingContext.removePreloadScript(id); } override async exposeFunction<Args extends unknown[], Ret>( @@ -774,20 +456,37 @@ export class BidiPage extends Page { }); } + override async cookies(...urls: string[]): Promise<Cookie[]> { + const normalizedUrls = (urls.length ? urls : [this.url()]).map(url => { + return new URL(url); + }); + + const cookies = await this.#frame.browsingContext.getCookies(); + return cookies + .map(cookie => { + return bidiToPuppeteerCookie(cookie); + }) + .filter(cookie => { + return normalizedUrls.some(url => { + return testUrlMatchCookie(cookie, url); + }); + }); + } + override isServiceWorkerBypassed(): never { throw new UnsupportedOperation(); } - override target(): BiDiPageTarget { - return this.#target; + override target(): never { + throw new UnsupportedOperation(); } override waitForFileChooser(): never { throw new UnsupportedOperation(); } - override workers(): never { - throw new UnsupportedOperation(); + override workers(): BidiWebWorker[] { + return [...this.#workers]; } override setRequestInterception(): never { @@ -810,21 +509,98 @@ export class BidiPage extends Page { throw new UnsupportedOperation(); } - override cookies(): never { - throw new UnsupportedOperation(); - } + override async setCookie(...cookies: CookieParam[]): Promise<void> { + const pageURL = this.url(); + const pageUrlStartsWithHTTP = pageURL.startsWith('http'); + for (const cookie of cookies) { + let cookieUrl = cookie.url || ''; + if (!cookieUrl && pageUrlStartsWithHTTP) { + cookieUrl = pageURL; + } + assert( + cookieUrl !== 'about:blank', + `Blank page can not have cookie "${cookie.name}"` + ); + assert( + !String.prototype.startsWith.call(cookieUrl || '', 'data:'), + `Data URL page can not have cookie "${cookie.name}"` + ); - override setCookie(): never { - throw new UnsupportedOperation(); + const normalizedUrl = URL.canParse(cookieUrl) + ? new URL(cookieUrl) + : undefined; + + const domain = cookie.domain ?? normalizedUrl?.hostname; + assert( + domain !== undefined, + `At least one of the url and domain needs to be specified` + ); + + const bidiCookie: Bidi.Storage.PartialCookie = { + domain: domain, + name: cookie.name, + value: { + type: 'string', + value: cookie.value, + }, + ...(cookie.path !== undefined ? {path: cookie.path} : {}), + ...(cookie.httpOnly !== undefined ? {httpOnly: cookie.httpOnly} : {}), + ...(cookie.secure !== undefined ? {secure: cookie.secure} : {}), + ...(cookie.sameSite !== undefined + ? {sameSite: convertCookiesSameSiteCdpToBiDi(cookie.sameSite)} + : {}), + ...(cookie.expires !== undefined ? {expiry: cookie.expires} : {}), + // Chrome-specific properties. + ...cdpSpecificCookiePropertiesFromPuppeteerToBidi( + cookie, + 'sameParty', + 'sourceScheme', + 'priority', + 'url' + ), + }; + + if (cookie.partitionKey !== undefined) { + await this.browserContext().userContext.setCookie( + bidiCookie, + cookie.partitionKey + ); + } else { + await this.#frame.browsingContext.setCookie(bidiCookie); + } + } } - override deleteCookie(): never { - throw new UnsupportedOperation(); + override async deleteCookie( + ...cookies: DeleteCookiesRequest[] + ): Promise<void> { + await Promise.all( + cookies.map(async deleteCookieRequest => { + const cookieUrl = deleteCookieRequest.url ?? this.url(); + const normalizedUrl = URL.canParse(cookieUrl) + ? new URL(cookieUrl) + : undefined; + + const domain = deleteCookieRequest.domain ?? normalizedUrl?.hostname; + assert( + domain !== undefined, + `At least one of the url and domain needs to be specified` + ); + + const filter = { + domain: domain, + name: deleteCookieRequest.name, + ...(deleteCookieRequest.path !== undefined + ? {path: deleteCookieRequest.path} + : {}), + }; + await this.#frame.browsingContext.deleteCookie(filter); + }) + ); } - override removeExposedFunction(): never { - // TODO: Quick win? - throw new UnsupportedOperation(); + override async removeExposedFunction(name: string): Promise<void> { + await this.#frame.removeExposedFunction(name); } override authenticate(): never { @@ -848,7 +624,7 @@ export class BidiPage extends Page { override async goForward( options: WaitForOptions = {} ): Promise<HTTPResponse | null> { - return await this.#go(+1, options); + return await this.#go(1, options); } async #go( @@ -856,22 +632,19 @@ export class BidiPage extends Page { options: WaitForOptions ): Promise<HTTPResponse | null> { try { - const result = await Promise.all([ + const [response] = await Promise.all([ this.waitForNavigation(options), - this.#connection.send('browsingContext.traverseHistory', { - delta, - context: this.mainFrame()._id, - }), + this.#frame.browsingContext.traverseHistory(delta), ]); - return result[0]; - } catch (err) { + return response; + } catch (error) { // TODO: waitForNavigation should be cancelled if an error happens. - if (isErrorLike(err)) { - if (err.message.includes('no such history entry')) { + if (isErrorLike(error)) { + if (error.message.includes('no such history entry')) { return null; } } - throw err; + throw error; } } @@ -880,34 +653,137 @@ export class BidiPage extends Page { } } -function isConsoleLogEntry( - event: Bidi.Log.Entry -): event is Bidi.Log.ConsoleLogEntry { - return event.type === 'console'; +function evaluationExpression(fun: Function | string, ...args: unknown[]) { + return `() => {${evaluationString(fun, ...args)}}`; } -function isJavaScriptLogEntry( - event: Bidi.Log.Entry -): event is Bidi.Log.JavascriptLogEntry { - return event.type === 'javascript'; +/** + * Check domains match. + * According to cookies spec, this check should match subdomains as well, but CDP + * implementation does not do that, so this method matches only the exact domains, not + * what is written in the spec: + * https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3 + */ +function testUrlMatchCookieHostname( + cookie: Cookie, + normalizedUrl: URL +): boolean { + const cookieDomain = cookie.domain.toLowerCase(); + const urlHostname = normalizedUrl.hostname.toLowerCase(); + return cookieDomain === urlHostname; } -function getStackTraceLocations( - stackTrace?: Bidi.Script.StackTrace -): ConsoleMessageLocation[] { - const stackTraceLocations: ConsoleMessageLocation[] = []; - if (stackTrace) { - for (const callFrame of stackTrace.callFrames) { - stackTraceLocations.push({ - url: callFrame.url, - lineNumber: callFrame.lineNumber, - columnNumber: callFrame.columnNumber, - }); +/** + * Check paths match. + * Spec: https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4 + */ +function testUrlMatchCookiePath(cookie: Cookie, normalizedUrl: URL): boolean { + const uriPath = normalizedUrl.pathname; + const cookiePath = cookie.path; + + if (uriPath === cookiePath) { + // The cookie-path and the request-path are identical. + return true; + } + if (uriPath.startsWith(cookiePath)) { + // The cookie-path is a prefix of the request-path. + if (cookiePath.endsWith('/')) { + // The last character of the cookie-path is %x2F ("/"). + return true; + } + if (uriPath[cookiePath.length] === '/') { + // The first character of the request-path that is not included in the cookie-path + // is a %x2F ("/") character. + return true; } } - return stackTraceLocations; + return false; } -function evaluationExpression(fun: Function | string, ...args: unknown[]) { - return `() => {${evaluationString(fun, ...args)}}`; +/** + * Checks the cookie matches the URL according to the spec: + */ +function testUrlMatchCookie(cookie: Cookie, url: URL): boolean { + const normalizedUrl = new URL(url); + assert(cookie !== undefined); + if (!testUrlMatchCookieHostname(cookie, normalizedUrl)) { + return false; + } + return testUrlMatchCookiePath(cookie, normalizedUrl); +} + +function bidiToPuppeteerCookie(bidiCookie: Bidi.Network.Cookie): Cookie { + return { + name: bidiCookie.name, + // Presents binary value as base64 string. + value: bidiCookie.value.value, + domain: bidiCookie.domain, + path: bidiCookie.path, + size: bidiCookie.size, + httpOnly: bidiCookie.httpOnly, + secure: bidiCookie.secure, + sameSite: convertCookiesSameSiteBiDiToCdp(bidiCookie.sameSite), + expires: bidiCookie.expiry ?? -1, + session: bidiCookie.expiry === undefined || bidiCookie.expiry <= 0, + // Extending with CDP-specific properties with `goog:` prefix. + ...cdpSpecificCookiePropertiesFromBidiToPuppeteer( + bidiCookie, + 'sameParty', + 'sourceScheme', + 'partitionKey', + 'partitionKeyOpaque', + 'priority' + ), + }; +} + +const CDP_SPECIFIC_PREFIX = 'goog:'; + +/** + * Gets CDP-specific properties from the BiDi cookie and returns them as a new object. + */ +function cdpSpecificCookiePropertiesFromBidiToPuppeteer( + bidiCookie: Bidi.Network.Cookie, + ...propertyNames: Array<keyof Cookie> +): Partial<Cookie> { + const result: Partial<Cookie> = {}; + for (const property of propertyNames) { + if (bidiCookie[CDP_SPECIFIC_PREFIX + property] !== undefined) { + result[property] = bidiCookie[CDP_SPECIFIC_PREFIX + property]; + } + } + return result; +} + +/** + * Gets CDP-specific properties from the cookie, adds CDP-specific prefixes and returns + * them as a new object which can be used in BiDi. + */ +function cdpSpecificCookiePropertiesFromPuppeteerToBidi( + cookieParam: CookieParam, + ...propertyNames: Array<keyof CookieParam> +): Record<string, unknown> { + const result: Record<string, unknown> = {}; + for (const property of propertyNames) { + if (cookieParam[property] !== undefined) { + result[CDP_SPECIFIC_PREFIX + property] = cookieParam[property]; + } + } + return result; +} + +function convertCookiesSameSiteBiDiToCdp( + sameSite: Bidi.Network.SameSite | undefined +): CookieSameSite { + return sameSite === 'strict' ? 'Strict' : sameSite === 'lax' ? 'Lax' : 'None'; +} + +function convertCookiesSameSiteCdpToBiDi( + sameSite: CookieSameSite | undefined +): Bidi.Network.SameSite { + return sameSite === 'Strict' + ? Bidi.Network.SameSite.Strict + : sameSite === 'Lax' + ? Bidi.Network.SameSite.Lax + : Bidi.Network.SameSite.None; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts index 84f13bc703..1027941e2f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Realm.ts @@ -1,80 +1,63 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {EventEmitter, type EventType} from '../common/EventEmitter.js'; +import type {JSHandle} from '../api/JSHandle.js'; +import {Realm} from '../api/Realm.js'; +import {ARIAQueryHandler} from '../cdp/AriaQueryHandler.js'; +import {LazyArg} from '../common/LazyArg.js'; import {scriptInjector} from '../common/ScriptInjector.js'; +import type {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {EvaluateFunc, HandleFor} from '../common/types.js'; import { - PuppeteerURL, - SOURCE_URL_REGEX, + debugError, getSourcePuppeteerURLIfAvailable, getSourceUrlComment, isString, + PuppeteerURL, + SOURCE_URL_REGEX, } from '../common/util.js'; import type PuppeteerUtil from '../injected/injected.js'; -import {disposeSymbol} from '../util/disposable.js'; +import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {stringifyFunction} from '../util/Function.js'; -import type {BidiConnection} from './Connection.js'; +import type { + Realm as BidiRealmCore, + DedicatedWorkerRealm, + SharedWorkerRealm, +} from './core/Realm.js'; +import type {WindowRealm} from './core/Realm.js'; import {BidiDeserializer} from './Deserializer.js'; import {BidiElementHandle} from './ElementHandle.js'; +import {ExposeableFunction} from './ExposedFunction.js'; +import type {BidiFrame} from './Frame.js'; import {BidiJSHandle} from './JSHandle.js'; -import type {Sandbox} from './Sandbox.js'; import {BidiSerializer} from './Serializer.js'; import {createEvaluationError} from './util.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ -export class BidiRealm extends EventEmitter<Record<EventType, any>> { - readonly connection: BidiConnection; - - #id!: string; - #sandbox!: Sandbox; +export abstract class BidiRealm extends Realm { + readonly realm: BidiRealmCore; - constructor(connection: BidiConnection) { - super(); - this.connection = connection; + constructor(realm: BidiRealmCore, timeoutSettings: TimeoutSettings) { + super(timeoutSettings); + this.realm = realm; } - get target(): Bidi.Script.Target { - return { - context: this.#sandbox.environment._id, - sandbox: this.#sandbox.name, - }; - } - - handleRealmDestroyed = async ( - params: Bidi.Script.RealmDestroyed['params'] - ): Promise<void> => { - if (params.realm === this.#id) { - // Note: The Realm is destroyed, so in theory the handle should be as - // well. + protected initialize(): void { + this.realm.on('destroyed', ({reason}) => { + this.taskManager.terminateAll(new Error(reason)); + }); + this.realm.on('updated', () => { this.internalPuppeteerUtil = undefined; - this.#sandbox.environment.clearDocumentHandle(); - } - }; - - handleRealmCreated = (params: Bidi.Script.RealmCreated['params']): void => { - if ( - params.type === 'window' && - params.context === this.#sandbox.environment._id && - params.sandbox === this.#sandbox.name - ) { - this.#id = params.realm; - void this.#sandbox.taskManager.rerunAll(); - } - }; - - setSandbox(sandbox: Sandbox): void { - this.#sandbox = sandbox; - this.connection.on( - Bidi.ChromiumBidi.Script.EventNames.RealmCreated, - this.handleRealmCreated - ); - this.connection.on( - Bidi.ChromiumBidi.Script.EventNames.RealmDestroyed, - this.handleRealmDestroyed - ); + void this.taskManager.rerunAll(); + }); } protected internalPuppeteerUtil?: Promise<BidiJSHandle<PuppeteerUtil>>; @@ -95,7 +78,7 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return this.internalPuppeteerUtil as Promise<BidiJSHandle<PuppeteerUtil>>; } - async evaluateHandle< + override async evaluateHandle< Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, >( @@ -105,7 +88,7 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return await this.#evaluate(false, pageFunction, ...args); } - async evaluate< + override async evaluate< Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, >( @@ -144,8 +127,6 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { PuppeteerURL.INTERNAL_URL ); - const sandbox = this.#sandbox; - let responsePromise; const resultOwnership = returnByValue ? Bidi.Script.ResultOwnership.None @@ -161,11 +142,8 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { ? pageFunction : `${pageFunction}\n${sourceUrlComment}\n`; - responsePromise = this.connection.send('script.evaluate', { - expression, - target: this.target, + responsePromise = this.realm.evaluate(expression, true, { resultOwnership, - awaitPromise: true, userActivation: true, serializationOptions, }); @@ -174,24 +152,25 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { functionDeclaration = SOURCE_URL_REGEX.test(functionDeclaration) ? functionDeclaration : `${functionDeclaration}\n${sourceUrlComment}\n`; - responsePromise = this.connection.send('script.callFunction', { + responsePromise = this.realm.callFunction( functionDeclaration, - arguments: args.length - ? await Promise.all( - args.map(arg => { - return BidiSerializer.serialize(sandbox, arg); - }) - ) - : [], - target: this.target, - resultOwnership, - awaitPromise: true, - userActivation: true, - serializationOptions, - }); + /* awaitPromise= */ true, + { + arguments: args.length + ? await Promise.all( + args.map(arg => { + return this.serialize(arg); + }) + ) + : [], + resultOwnership, + userActivation: true, + serializationOptions, + } + ); } - const {result} = await responsePromise; + const result = await responsePromise; if ('type' in result && result.type === 'exception') { throw createEvaluationError(result.exceptionDetails); @@ -199,30 +178,211 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> { return returnByValue ? BidiDeserializer.deserialize(result.result) - : createBidiHandle(sandbox, result.result); + : this.createHandle(result.result); } - [disposeSymbol](): void { - this.connection.off( - Bidi.ChromiumBidi.Script.EventNames.RealmCreated, - this.handleRealmCreated - ); - this.connection.off( - Bidi.ChromiumBidi.Script.EventNames.RealmDestroyed, - this.handleRealmDestroyed + createHandle( + result: Bidi.Script.RemoteValue + ): BidiJSHandle<unknown> | BidiElementHandle<Node> { + if ( + (result.type === 'node' || result.type === 'window') && + this instanceof BidiFrameRealm + ) { + return BidiElementHandle.from(result, this); + } + return BidiJSHandle.from(result, this); + } + + async serialize(arg: unknown): Promise<Bidi.Script.LocalValue> { + if (arg instanceof LazyArg) { + arg = await arg.get(this); + } + + if (arg instanceof BidiJSHandle || arg instanceof BidiElementHandle) { + if (arg.realm !== this) { + if ( + !(arg.realm instanceof BidiFrameRealm) || + !(this instanceof BidiFrameRealm) + ) { + throw new Error( + "Trying to evaluate JSHandle from different global types. Usually this means you're using a handle from a worker in a page or vice versa." + ); + } + if (arg.realm.environment !== this.environment) { + throw new Error( + "Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page." + ); + } + } + if (arg.disposed) { + throw new Error('JSHandle is disposed!'); + } + return arg.remoteValue() as Bidi.Script.RemoteReference; + } + + return BidiSerializer.serialize(arg); + } + + async destroyHandles(handles: Array<BidiJSHandle<unknown>>): Promise<void> { + const handleIds = handles + .map(({id}) => { + return id; + }) + .filter((id): id is string => { + return id !== undefined; + }); + + if (handleIds.length === 0) { + return; + } + + await this.realm.disown(handleIds).catch(error => { + // Exceptions might happen in case of a page been navigated or closed. + // Swallow these since they are harmless and we don't leak anything in this case. + debugError(error); + }); + } + + override async adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { + return (await this.evaluateHandle(node => { + return node; + }, handle)) as unknown as T; + } + + override async transferHandle<T extends JSHandle<Node>>( + handle: T + ): Promise<T> { + if (handle.realm === this) { + return handle; + } + const transferredHandle = this.adoptHandle(handle); + await handle.dispose(); + return await transferredHandle; + } +} + +/** + * @internal + */ +export class BidiFrameRealm extends BidiRealm { + static from(realm: WindowRealm, frame: BidiFrame): BidiFrameRealm { + const frameRealm = new BidiFrameRealm(realm, frame); + frameRealm.#initialize(); + return frameRealm; + } + declare readonly realm: WindowRealm; + + readonly #frame: BidiFrame; + + private constructor(realm: WindowRealm, frame: BidiFrame) { + super(realm, frame.timeoutSettings); + this.#frame = frame; + } + + #initialize() { + super.initialize(); + + // This should run first. + this.realm.on('updated', () => { + this.environment.clearDocumentHandle(); + this.#bindingsInstalled = false; + }); + } + + #bindingsInstalled = false; + override get puppeteerUtil(): Promise<BidiJSHandle<PuppeteerUtil>> { + let promise = Promise.resolve() as Promise<unknown>; + if (!this.#bindingsInstalled) { + promise = Promise.all([ + ExposeableFunction.from( + this.environment as BidiFrame, + '__ariaQuerySelector', + ARIAQueryHandler.queryOne, + !!this.sandbox + ), + ExposeableFunction.from( + this.environment as BidiFrame, + '__ariaQuerySelectorAll', + async ( + element: BidiElementHandle<Node>, + selector: string + ): Promise<JSHandle<Node[]>> => { + const results = ARIAQueryHandler.queryAll(element, selector); + return await element.realm.evaluateHandle( + (...elements) => { + return elements; + }, + ...(await AsyncIterableUtil.collect(results)) + ); + }, + !!this.sandbox + ), + ]); + this.#bindingsInstalled = true; + } + return promise.then(() => { + return super.puppeteerUtil; + }); + } + + get sandbox(): string | undefined { + return this.realm.sandbox; + } + + override get environment(): BidiFrame { + return this.#frame; + } + + override async adoptBackendNode( + backendNodeId?: number | undefined + ): Promise<JSHandle<Node>> { + const {object} = await this.#frame.client.send('DOM.resolveNode', { + backendNodeId, + executionContextId: await this.realm.resolveExecutionContextId(), + }); + using handle = BidiElementHandle.from( + { + handle: object.objectId, + type: 'node', + }, + this ); + // We need the sharedId, so we perform the following to obtain it. + return await handle.evaluateHandle(element => { + return element; + }); } } /** * @internal */ -export function createBidiHandle( - sandbox: Sandbox, - result: Bidi.Script.RemoteValue -): BidiJSHandle<unknown> | BidiElementHandle<Node> { - if (result.type === 'node' || result.type === 'window') { - return new BidiElementHandle(sandbox, result); - } - return new BidiJSHandle(sandbox, result); +export class BidiWorkerRealm extends BidiRealm { + static from( + realm: DedicatedWorkerRealm | SharedWorkerRealm, + worker: BidiWebWorker + ): BidiWorkerRealm { + const workerRealm = new BidiWorkerRealm(realm, worker); + workerRealm.initialize(); + return workerRealm; + } + declare readonly realm: DedicatedWorkerRealm | SharedWorkerRealm; + + readonly #worker: BidiWebWorker; + + private constructor( + realm: DedicatedWorkerRealm | SharedWorkerRealm, + frame: BidiWebWorker + ) { + super(realm, frame.timeoutSettings); + this.#worker = frame; + } + + override get environment(): BidiWebWorker { + return this.#worker; + } + + override async adoptBackendNode(): Promise<JSHandle<Node>> { + throw new Error('Cannot adopt DOM nodes into a worker.'); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts deleted file mode 100644 index 4411b3dbcd..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Sandbox.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {JSHandle} from '../api/JSHandle.js'; -import {Realm} from '../api/Realm.js'; -import type {TimeoutSettings} from '../common/TimeoutSettings.js'; -import type {EvaluateFunc, HandleFor} from '../common/types.js'; -import {withSourcePuppeteerURLIfNone} from '../common/util.js'; - -import type {BrowsingContext} from './BrowsingContext.js'; -import {BidiElementHandle} from './ElementHandle.js'; -import type {BidiFrame} from './Frame.js'; -import type {BidiRealm as BidiRealm} from './Realm.js'; -/** - * A unique key for {@link SandboxChart} to denote the default world. - * Realms are automatically created in the default sandbox. - * - * @internal - */ -export const MAIN_SANDBOX = Symbol('mainSandbox'); -/** - * A unique key for {@link SandboxChart} to denote the puppeteer sandbox. - * This world contains all puppeteer-internal bindings/code. - * - * @internal - */ -export const PUPPETEER_SANDBOX = Symbol('puppeteerSandbox'); - -/** - * @internal - */ -export interface SandboxChart { - [key: string]: Sandbox; - [MAIN_SANDBOX]: Sandbox; - [PUPPETEER_SANDBOX]: Sandbox; -} - -/** - * @internal - */ -export class Sandbox extends Realm { - readonly name: string | undefined; - readonly realm: BidiRealm; - #frame: BidiFrame; - - constructor( - name: string | undefined, - frame: BidiFrame, - // TODO: We should split the Realm and BrowsingContext - realm: BidiRealm | BrowsingContext, - timeoutSettings: TimeoutSettings - ) { - super(timeoutSettings); - this.name = name; - this.realm = realm; - this.#frame = frame; - this.realm.setSandbox(this); - } - - override get environment(): BidiFrame { - return this.#frame; - } - - async evaluateHandle< - Params extends unknown[], - Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, - >( - pageFunction: Func | string, - ...args: Params - ): Promise<HandleFor<Awaited<ReturnType<Func>>>> { - pageFunction = withSourcePuppeteerURLIfNone( - this.evaluateHandle.name, - pageFunction - ); - return await this.realm.evaluateHandle(pageFunction, ...args); - } - - async evaluate< - Params extends unknown[], - Func extends EvaluateFunc<Params> = EvaluateFunc<Params>, - >( - pageFunction: Func | string, - ...args: Params - ): Promise<Awaited<ReturnType<Func>>> { - pageFunction = withSourcePuppeteerURLIfNone( - this.evaluate.name, - pageFunction - ); - return await this.realm.evaluate(pageFunction, ...args); - } - - async adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { - return (await this.evaluateHandle(node => { - return node; - }, handle)) as unknown as T; - } - - async transferHandle<T extends JSHandle<Node>>(handle: T): Promise<T> { - if (handle.realm === this) { - return handle; - } - const transferredHandle = await this.evaluateHandle(node => { - return node; - }, handle); - await handle.dispose(); - return transferredHandle as unknown as T; - } - - override async adoptBackendNode( - backendNodeId?: number - ): Promise<JSHandle<Node>> { - const {object} = await this.environment.client.send('DOM.resolveNode', { - backendNodeId: backendNodeId, - }); - return new BidiElementHandle(this, { - handle: object.objectId, - type: 'node', - }); - } -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts index c147ec9281..523380782b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Serializer.ts @@ -6,13 +6,8 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {LazyArg} from '../common/LazyArg.js'; import {isDate, isPlainObject, isRegExp} from '../common/util.js'; -import {BidiElementHandle} from './ElementHandle.js'; -import {BidiJSHandle} from './JSHandle.js'; -import type {Sandbox} from './Sandbox.js'; - /** * @internal */ @@ -22,7 +17,39 @@ class UnserializableError extends Error {} * @internal */ export class BidiSerializer { - static serializeNumber(arg: number): Bidi.Script.LocalValue { + static serialize(arg: unknown): Bidi.Script.LocalValue { + switch (typeof arg) { + case 'symbol': + case 'function': + throw new UnserializableError(`Unable to serializable ${typeof arg}`); + case 'object': + return this.#serializeObject(arg); + + case 'undefined': + return { + type: 'undefined', + }; + case 'number': + return this.#serializeNumber(arg); + case 'bigint': + return { + type: 'bigint', + value: arg.toString(), + }; + case 'string': + return { + type: 'string', + value: arg, + }; + case 'boolean': + return { + type: 'boolean', + value: arg, + }; + } + } + + static #serializeNumber(arg: number): Bidi.Script.LocalValue { let value: Bidi.Script.SpecialNumber | number; if (Object.is(arg, -0)) { value = '-0'; @@ -41,14 +68,14 @@ export class BidiSerializer { }; } - static serializeObject(arg: object | null): Bidi.Script.LocalValue { + static #serializeObject(arg: object | null): Bidi.Script.LocalValue { if (arg === null) { return { type: 'null', }; } else if (Array.isArray(arg)) { const parsedArray = arg.map(subArg => { - return BidiSerializer.serializeRemoteValue(subArg); + return this.serialize(subArg); }); return { @@ -70,10 +97,7 @@ export class BidiSerializer { const parsedObject: Bidi.Script.MappingLocalValue = []; for (const key in arg) { - parsedObject.push([ - BidiSerializer.serializeRemoteValue(key), - BidiSerializer.serializeRemoteValue(arg[key]), - ]); + parsedObject.push([this.serialize(key), this.serialize(arg[key])]); } return { @@ -99,66 +123,4 @@ export class BidiSerializer { 'Custom object sterilization not possible. Use plain objects instead.' ); } - - static serializeRemoteValue(arg: unknown): Bidi.Script.LocalValue { - switch (typeof arg) { - case 'symbol': - case 'function': - throw new UnserializableError(`Unable to serializable ${typeof arg}`); - case 'object': - return BidiSerializer.serializeObject(arg); - - case 'undefined': - return { - type: 'undefined', - }; - case 'number': - return BidiSerializer.serializeNumber(arg); - case 'bigint': - return { - type: 'bigint', - value: arg.toString(), - }; - case 'string': - return { - type: 'string', - value: arg, - }; - case 'boolean': - return { - type: 'boolean', - value: arg, - }; - } - } - - static async serialize( - sandbox: Sandbox, - arg: unknown - ): Promise<Bidi.Script.LocalValue> { - if (arg instanceof LazyArg) { - arg = await arg.get(sandbox.realm); - } - // eslint-disable-next-line rulesdir/use-using -- We want this to continue living. - const objectHandle = - arg && (arg instanceof BidiJSHandle || arg instanceof BidiElementHandle) - ? arg - : null; - if (objectHandle) { - if ( - objectHandle.realm.environment.context() !== - sandbox.environment.context() - ) { - throw new Error( - 'JSHandles can be evaluated only in the context they were created!' - ); - } - if (objectHandle.disposed) { - throw new Error('JSHandle is disposed!'); - } - return objectHandle.remoteValue() as Bidi.Script.RemoteReference; - } - - return BidiSerializer.serializeRemoteValue(arg); - } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts index fb01c34638..b9d78538aa 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/Target.ts @@ -4,48 +4,46 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {CDPSession} from '../api/CDPSession.js'; -import type {Page} from '../api/Page.js'; import {Target, TargetType} from '../api/Target.js'; import {UnsupportedOperation} from '../common/Errors.js'; +import type {CDPSession} from '../puppeteer-core.js'; import type {BidiBrowser} from './Browser.js'; import type {BidiBrowserContext} from './BrowserContext.js'; -import {type BrowsingContext, CdpSessionWrapper} from './BrowsingContext.js'; +import type {BidiFrame} from './Frame.js'; import {BidiPage} from './Page.js'; +import type {BidiWebWorker} from './WebWorker.js'; /** * @internal */ -export abstract class BidiTarget extends Target { - protected _browserContext: BidiBrowserContext; +export class BidiBrowserTarget extends Target { + #browser: BidiBrowser; - constructor(browserContext: BidiBrowserContext) { + constructor(browser: BidiBrowser) { super(); - this._browserContext = browserContext; + this.#browser = browser; } - _setBrowserContext(browserContext: BidiBrowserContext): void { - this._browserContext = browserContext; + override asPage(): Promise<BidiPage> { + throw new UnsupportedOperation(); } - - override asPage(): Promise<Page> { + override url(): string { + return ''; + } + override createCDPSession(): Promise<CDPSession> { throw new UnsupportedOperation(); } - + override type(): TargetType { + return TargetType.BROWSER; + } override browser(): BidiBrowser { - return this._browserContext.browser(); + return this.#browser; } - override browserContext(): BidiBrowserContext { - return this._browserContext; - } - - override opener(): never { - throw new UnsupportedOperation(); + return this.#browser.defaultBrowserContext(); } - - override createCDPSession(): Promise<CDPSession> { + override opener(): Target | undefined { throw new UnsupportedOperation(); } } @@ -53,39 +51,39 @@ export abstract class BidiTarget extends Target { /** * @internal */ -export class BiDiBrowserTarget extends Target { - #browser: BidiBrowser; +export class BidiPageTarget extends Target { + #page: BidiPage; - constructor(browser: BidiBrowser) { + constructor(page: BidiPage) { super(); - this.#browser = browser; + this.#page = page; } + override async page(): Promise<BidiPage> { + return this.#page; + } + override async asPage(): Promise<BidiPage> { + return BidiPage.from( + this.browserContext(), + this.#page.mainFrame().browsingContext + ); + } override url(): string { - return ''; + return this.#page.url(); } - - override type(): TargetType { - return TargetType.BROWSER; + override createCDPSession(): Promise<CDPSession> { + return this.#page.createCDPSession(); } - - override asPage(): Promise<Page> { - throw new UnsupportedOperation(); + override type(): TargetType { + return TargetType.PAGE; } - override browser(): BidiBrowser { - return this.#browser; + return this.browserContext().browser(); } - override browserContext(): BidiBrowserContext { - return this.#browser.defaultBrowserContext(); - } - - override opener(): never { - throw new UnsupportedOperation(); + return this.#page.browserContext(); } - - override createCDPSession(): Promise<CDPSession> { + override opener(): Target | undefined { throw new UnsupportedOperation(); } } @@ -93,59 +91,80 @@ export class BiDiBrowserTarget extends Target { /** * @internal */ -export class BiDiBrowsingContextTarget extends BidiTarget { - protected _browsingContext: BrowsingContext; +export class BidiFrameTarget extends Target { + #frame: BidiFrame; + #page: BidiPage | undefined; - constructor( - browserContext: BidiBrowserContext, - browsingContext: BrowsingContext - ) { - super(browserContext); - - this._browsingContext = browsingContext; + constructor(frame: BidiFrame) { + super(); + this.#frame = frame; } + override async page(): Promise<BidiPage> { + if (this.#page === undefined) { + this.#page = BidiPage.from( + this.browserContext(), + this.#frame.browsingContext + ); + } + return this.#page; + } + override async asPage(): Promise<BidiPage> { + return BidiPage.from(this.browserContext(), this.#frame.browsingContext); + } override url(): string { - return this._browsingContext.url; + return this.#frame.url(); } - - override async createCDPSession(): Promise<CDPSession> { - const {sessionId} = await this._browsingContext.cdpSession.send( - 'Target.attachToTarget', - { - targetId: this._browsingContext.id, - flatten: true, - } - ); - return new CdpSessionWrapper(this._browsingContext, sessionId); + override createCDPSession(): Promise<CDPSession> { + return this.#frame.createCDPSession(); } - override type(): TargetType { return TargetType.PAGE; } + override browser(): BidiBrowser { + return this.browserContext().browser(); + } + override browserContext(): BidiBrowserContext { + return this.#frame.page().browserContext(); + } + override opener(): Target | undefined { + throw new UnsupportedOperation(); + } } /** * @internal */ -export class BiDiPageTarget extends BiDiBrowsingContextTarget { - #page: BidiPage; - - constructor( - browserContext: BidiBrowserContext, - browsingContext: BrowsingContext - ) { - super(browserContext, browsingContext); +export class BidiWorkerTarget extends Target { + #worker: BidiWebWorker; - this.#page = new BidiPage(browsingContext, browserContext, this); + constructor(worker: BidiWebWorker) { + super(); + this.#worker = worker; } override async page(): Promise<BidiPage> { - return this.#page; + throw new UnsupportedOperation(); } - - override _setBrowserContext(browserContext: BidiBrowserContext): void { - super._setBrowserContext(browserContext); - this.#page._setBrowserContext(browserContext); + override async asPage(): Promise<BidiPage> { + throw new UnsupportedOperation(); + } + override url(): string { + return this.#worker.url(); + } + override createCDPSession(): Promise<CDPSession> { + throw new UnsupportedOperation(); + } + override type(): TargetType { + return TargetType.OTHER; + } + override browser(): BidiBrowser { + return this.browserContext().browser(); + } + override browserContext(): BidiBrowserContext { + return this.#worker.frame.page().browserContext(); + } + override opener(): Target | undefined { + throw new UnsupportedOperation(); } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts new file mode 100644 index 0000000000..a8b0e28846 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/WebWorker.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import {WebWorker} from '../api/WebWorker.js'; +import {UnsupportedOperation} from '../common/Errors.js'; +import type {CDPSession} from '../puppeteer-core.js'; + +import type {DedicatedWorkerRealm, SharedWorkerRealm} from './core/Realm.js'; +import type {BidiFrame} from './Frame.js'; +import {BidiWorkerRealm} from './Realm.js'; + +/** + * @internal + */ +export class BidiWebWorker extends WebWorker { + static from( + frame: BidiFrame, + realm: DedicatedWorkerRealm | SharedWorkerRealm + ): BidiWebWorker { + const worker = new BidiWebWorker(frame, realm); + return worker; + } + + readonly #frame: BidiFrame; + readonly #realm: BidiWorkerRealm; + private constructor( + frame: BidiFrame, + realm: DedicatedWorkerRealm | SharedWorkerRealm + ) { + super(realm.origin); + this.#frame = frame; + this.#realm = BidiWorkerRealm.from(realm, this); + } + + get frame(): BidiFrame { + return this.#frame; + } + + mainRealm(): BidiWorkerRealm { + return this.#realm; + } + + get client(): CDPSession { + throw new UnsupportedOperation(); + } +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts index 373d6d999c..4279ba96fd 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/bidi.ts @@ -7,7 +7,6 @@ export * from './BidiOverCdp.js'; export * from './Browser.js'; export * from './BrowserContext.js'; -export * from './BrowsingContext.js'; export * from './Connection.js'; export * from './ElementHandle.js'; export * from './Frame.js'; @@ -15,8 +14,5 @@ export * from './HTTPRequest.js'; export * from './HTTPResponse.js'; export * from './Input.js'; export * from './JSHandle.js'; -export * from './NetworkManager.js'; export * from './Page.js'; export * from './Realm.js'; -export * from './Sandbox.js'; -export * from './Target.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts index 7c4a8ed01c..efeabc3a59 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Browser.ts @@ -11,7 +11,7 @@ import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {BrowsingContext} from './BrowsingContext.js'; -import type {SharedWorkerRealm} from './Realm.js'; +import {SharedWorkerRealm} from './Realm.js'; import type {Session} from './Session.js'; import {UserContext} from './UserContext.js'; @@ -57,6 +57,7 @@ export class Browser extends EventEmitter<{ readonly #disposables = new DisposableStack(); readonly #userContexts = new Map<string, UserContext>(); readonly session: Session; + readonly #sharedWorkers = new Map<string, SharedWorkerRealm>(); // keep-sorted end private constructor(session: Session) { @@ -64,11 +65,6 @@ export class Browser extends EventEmitter<{ // keep-sorted start this.session = session; // keep-sorted end - - this.#userContexts.set( - UserContext.DEFAULT, - UserContext.create(this, UserContext.DEFAULT) - ); } async #initialize() { @@ -80,14 +76,29 @@ export class Browser extends EventEmitter<{ }); sessionEmitter.on('script.realmCreated', info => { - if (info.type === 'shared-worker') { - // TODO: Create a SharedWorkerRealm. + if (info.type !== 'shared-worker') { + return; } + this.#sharedWorkers.set( + info.realm, + SharedWorkerRealm.from(this, info.realm, info.origin) + ); }); + await this.#syncUserContexts(); await this.#syncBrowsingContexts(); } + async #syncUserContexts() { + const { + result: {userContexts}, + } = await this.session.send('browser.getUserContexts', {}); + + for (const context of userContexts) { + this.#createUserContext(context.userContext); + } + } + async #syncBrowsingContexts() { // In case contexts are created or destroyed during `getTree`, we use this // set to detect them. @@ -99,16 +110,13 @@ export class Browser extends EventEmitter<{ sessionEmitter.on('browsingContext.contextCreated', info => { contextIds.add(info.context); }); - sessionEmitter.on('browsingContext.contextDestroyed', info => { - contextIds.delete(info.context); - }); const {result} = await this.session.send('browsingContext.getTree', {}); contexts = result.contexts; } // Simulating events so contexts are created naturally. for (const info of contexts) { - if (contextIds.has(info.context)) { + if (!contextIds.has(info.context)) { this.session.emit('browsingContext.contextCreated', info); } if (info.children) { @@ -117,6 +125,22 @@ export class Browser extends EventEmitter<{ } } + #createUserContext(id: string) { + const userContext = UserContext.create(this, id); + this.#userContexts.set(userContext.id, userContext); + + const userContextEmitter = this.#disposables.use( + new EventEmitter(userContext) + ); + userContextEmitter.once('closed', () => { + userContextEmitter.removeAllListeners(); + + this.#userContexts.delete(userContext.id); + }); + + return userContext; + } + // keep-sorted start block=yes get closed(): boolean { return this.#closed; @@ -185,30 +209,15 @@ export class Browser extends EventEmitter<{ }); } - static userContextId = 0; @throwIfDisposed<Browser>(browser => { // SAFETY: By definition of `disposed`, `#reason` is defined. return browser.#reason!; }) async createUserContext(): Promise<UserContext> { - // TODO: implement incognito context https://github.com/w3c/webdriver-bidi/issues/289. - // TODO: Call `createUserContext` once available. - // Generating a monotonically increasing context id. - const context = `${++Browser.userContextId}`; - - const userContext = UserContext.create(this, context); - this.#userContexts.set(userContext.id, userContext); - - const userContextEmitter = this.#disposables.use( - new EventEmitter(userContext) - ); - userContextEmitter.once('closed', () => { - userContextEmitter.removeAllListeners(); - - this.#userContexts.delete(context); - }); - - return userContext; + const { + result: {userContext: context}, + } = await this.session.send('browser.createUserContext', {}); + return this.#createUserContext(context); } [disposeSymbol](): void { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts index 9bec2a506c..07309576a3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/BrowsingContext.ts @@ -12,6 +12,7 @@ import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {AddPreloadScriptOptions} from './Browser.js'; import {Navigation} from './Navigation.js'; +import type {DedicatedWorkerRealm} from './Realm.js'; import {WindowRealm} from './Realm.js'; import {Request} from './Request.js'; import type {UserContext} from './UserContext.js'; @@ -60,6 +61,14 @@ export type SetViewportOptions = Omit< /** * @internal */ +export type GetCookiesOptions = Omit< + Bidi.Storage.GetCookiesParameters, + 'partition' +>; + +/** + * @internal + */ export class BrowsingContext extends EventEmitter<{ /** Emitted when this context is closed. */ closed: { @@ -95,6 +104,11 @@ export class BrowsingContext extends EventEmitter<{ DOMContentLoaded: void; /** Emitted whenever the frame emits `load` */ load: void; + /** Emitted whenever a dedicated worker is created */ + worker: { + /** The realm for the new dedicated worker */ + realm: DedicatedWorkerRealm; + }; }> { static from( userContext: UserContext, @@ -135,7 +149,7 @@ export class BrowsingContext extends EventEmitter<{ this.userContext = context; // keep-sorted end - this.defaultRealm = WindowRealm.from(this); + this.defaultRealm = this.#createWindowRealm(); } #initialize() { @@ -202,7 +216,16 @@ export class BrowsingContext extends EventEmitter<{ } this.#url = info.url; - this.#requests.clear(); + for (const [id, request] of this.#requests) { + if (request.disposed) { + this.#requests.delete(id); + } + } + // If the navigation hasn't finished, then this is nested navigation. The + // current navigation will handle this. + if (this.#navigation !== undefined && !this.#navigation.disposed) { + return; + } // Note the navigation ID is null for this event. this.#navigation = Navigation.from(this); @@ -224,7 +247,8 @@ export class BrowsingContext extends EventEmitter<{ if (event.context !== this.id) { return; } - if (this.#requests.has(event.request.request)) { + if (event.redirectCount !== 0) { + // Means the request is a redirect. This is handled in Request. return; } @@ -265,7 +289,12 @@ export class BrowsingContext extends EventEmitter<{ return this.closed; } get realms(): Iterable<WindowRealm> { - return this.#realms.values(); + // eslint-disable-next-line @typescript-eslint/no-this-alias -- Required + const self = this; + return (function* () { + yield self.defaultRealm; + yield* self.#realms.values(); + })(); } get top(): BrowsingContext { let context = this as BrowsingContext; @@ -279,6 +308,14 @@ export class BrowsingContext extends EventEmitter<{ } // keep-sorted end + #createWindowRealm(sandbox?: string) { + const realm = WindowRealm.from(this, sandbox); + realm.on('worker', realm => { + this.emit('worker', {realm}); + }); + return realm; + } + @inertIfDisposed private dispose(reason?: string): void { this.#reason = reason; @@ -345,33 +382,23 @@ export class BrowsingContext extends EventEmitter<{ async navigate( url: string, wait?: Bidi.BrowsingContext.ReadinessState - ): Promise<Navigation> { + ): Promise<void> { await this.#session.send('browsingContext.navigate', { context: this.id, url, wait, }); - return await new Promise(resolve => { - this.once('navigation', ({navigation}) => { - resolve(navigation); - }); - }); } @throwIfDisposed<BrowsingContext>(context => { // SAFETY: Disposal implies this exists. return context.#reason!; }) - async reload(options: ReloadOptions = {}): Promise<Navigation> { + async reload(options: ReloadOptions = {}): Promise<void> { await this.#session.send('browsingContext.reload', { context: this.id, ...options, }); - return await new Promise(resolve => { - this.once('navigation', ({navigation}) => { - resolve(navigation); - }); - }); } @throwIfDisposed<BrowsingContext>(context => { @@ -436,7 +463,7 @@ export class BrowsingContext extends EventEmitter<{ return context.#reason!; }) createWindowRealm(sandbox: string): WindowRealm { - return WindowRealm.from(this, sandbox); + return this.#createWindowRealm(sandbox); } @throwIfDisposed<BrowsingContext>(context => { @@ -464,6 +491,54 @@ export class BrowsingContext extends EventEmitter<{ await this.userContext.browser.removePreloadScript(script); } + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async getCookies( + options: GetCookiesOptions = {} + ): Promise<Bidi.Network.Cookie[]> { + const { + result: {cookies}, + } = await this.#session.send('storage.getCookies', { + ...options, + partition: { + type: 'context', + context: this.id, + }, + }); + return cookies; + } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setCookie(cookie: Bidi.Storage.PartialCookie): Promise<void> { + await this.#session.send('storage.setCookie', { + cookie, + partition: { + type: 'context', + context: this.id, + }, + }); + } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setFiles( + element: Bidi.Script.SharedReference, + files: string[] + ): Promise<void> { + await this.#session.send('input.setFiles', { + context: this.id, + element, + files, + }); + } + [disposeSymbol](): void { this.#reason ??= 'Browsing context already closed, probably because the user context closed.'; @@ -472,4 +547,24 @@ export class BrowsingContext extends EventEmitter<{ this.#disposables.dispose(); super[disposeSymbol](); } + + @throwIfDisposed<BrowsingContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async deleteCookie( + ...cookieFilters: Bidi.Storage.CookieFilter[] + ): Promise<void> { + await Promise.all( + cookieFilters.map(async filter => { + await this.#session.send('storage.deleteCookies', { + filter: filter, + partition: { + type: 'context', + context: this.id, + }, + }); + }) + ); + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts index b9de14372b..9c26a03503 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Connection.ts @@ -38,6 +38,21 @@ export interface Commands { returnType: Bidi.EmptyResult; }; + 'browser.createUserContext': { + params: Bidi.EmptyParams; + returnType: Bidi.Browser.CreateUserContextResult; + }; + 'browser.getUserContexts': { + params: Bidi.EmptyParams; + returnType: Bidi.Browser.GetUserContextsResult; + }; + 'browser.removeUserContext': { + params: { + userContext: Bidi.Browser.UserContext; + }; + returnType: Bidi.Browser.RemoveUserContext; + }; + 'browsingContext.activate': { params: Bidi.BrowsingContext.ActivateParameters; returnType: Bidi.EmptyResult; @@ -91,6 +106,15 @@ export interface Commands { params: Bidi.Input.ReleaseActionsParameters; returnType: Bidi.EmptyResult; }; + 'input.setFiles': { + params: Bidi.Input.SetFilesParameters; + returnType: Bidi.EmptyResult; + }; + + 'permissions.setPermission': { + params: Bidi.Permissions.SetPermissionParameters; + returnType: Bidi.EmptyResult; + }; 'session.end': { params: Bidi.EmptyParams; @@ -112,6 +136,19 @@ export interface Commands { params: Bidi.Session.SubscriptionRequest; returnType: Bidi.EmptyResult; }; + + 'storage.deleteCookies': { + params: Bidi.Storage.DeleteCookiesParameters; + returnType: Bidi.Storage.DeleteCookiesResult; + }; + 'storage.getCookies': { + params: Bidi.Storage.GetCookiesParameters; + returnType: Bidi.Storage.GetCookiesResult; + }; + 'storage.setCookie': { + params: Bidi.Storage.SetCookieParameters; + returnType: Bidi.Storage.SetCookieParameters; + }; } /** @@ -133,7 +170,4 @@ export interface Connection<Events extends BidiEvents = BidiEvents> method: T, params: Commands[T]['params'] ): Promise<{result: Commands[T]['returnType']}>; - - // This will pipe events into the provided emitter. - pipeTo<Events extends BidiEvents>(emitter: EventEmitter<Events>): void; } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts index a7efbfeb2c..50040164a5 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Navigation.ts @@ -41,9 +41,10 @@ export class Navigation extends EventEmitter<{ // keep-sorted start #request: Request | undefined; + #navigation: Navigation | undefined; readonly #browsingContext: BrowsingContext; readonly #disposables = new DisposableStack(); - readonly #id = new Deferred<string>(); + readonly #id = new Deferred<string | null>(); // keep-sorted end private constructor(context: BrowsingContext) { @@ -65,31 +66,48 @@ export class Navigation extends EventEmitter<{ this.dispose(); }); - this.#browsingContext.on('request', ({request}) => { - if (request.navigation === this.#id.value()) { - this.#request = request; - this.emit('request', request); + browsingContextEmitter.on('request', ({request}) => { + if ( + request.navigation === undefined || + this.#request !== undefined || + // If a request with a navigation ID comes in, then the navigation ID is + // for this navigation. + !this.#matches(request.navigation) + ) { + return; } + + this.#request = request; + this.emit('request', request); }); const sessionEmitter = this.#disposables.use( new EventEmitter(this.#session) ); - // To get the navigation ID if any. + sessionEmitter.on('browsingContext.navigationStarted', info => { + if ( + info.context !== this.#browsingContext.id || + this.#navigation !== undefined + ) { + return; + } + this.#navigation = Navigation.from(this.#browsingContext); + }); + for (const eventName of [ 'browsingContext.domContentLoaded', 'browsingContext.load', ] as const) { sessionEmitter.on(eventName, info => { - if (info.context !== this.#browsingContext.id) { - return; - } - if (!info.navigation) { + if ( + info.context !== this.#browsingContext.id || + info.navigation === null || + !this.#matches(info.navigation) + ) { return; } - if (!this.#id.resolved()) { - this.#id.resolve(info.navigation); - } + + this.dispose(); }); } @@ -99,18 +117,15 @@ export class Navigation extends EventEmitter<{ ['browsingContext.navigationAborted', 'aborted'], ] as const) { sessionEmitter.on(eventName, info => { - if (info.context !== this.#browsingContext.id) { - return; - } - if (!info.navigation) { - return; - } - if (!this.#id.resolved()) { - this.#id.resolve(info.navigation); - } - if (this.#id.value() !== info.navigation) { + if ( + info.context !== this.#browsingContext.id || + // Note we don't check if `navigation` is null since `null` means the + // fragment navigated. + !this.#matches(info.navigation) + ) { return; } + this.emit(event, { url: info.url, timestamp: new Date(info.timestamp), @@ -120,6 +135,17 @@ export class Navigation extends EventEmitter<{ } } + #matches(navigation: string | null): boolean { + if (this.#navigation !== undefined && !this.#navigation.disposed) { + return false; + } + if (!this.#id.resolved()) { + this.#id.resolve(navigation); + return true; + } + return this.#id.value() === navigation; + } + // keep-sorted start block=yes get #session() { return this.#browsingContext.userContext.browser.session; @@ -130,6 +156,9 @@ export class Navigation extends EventEmitter<{ get request(): Request | undefined { return this.#request; } + get navigation(): Navigation | undefined { + return this.#navigation; + } // keep-sorted end @inertIfDisposed diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts index d9bbbede50..392194cec8 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Realm.ts @@ -9,7 +9,9 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import {EventEmitter} from '../../common/EventEmitter.js'; import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; +import type {BidiConnection} from '../Connection.js'; +import type {Browser} from './Browser.js'; import type {BrowsingContext} from './BrowsingContext.js'; import type {Session} from './Session.js'; @@ -33,6 +35,8 @@ export type EvaluateOptions = Omit< * @internal */ export abstract class Realm extends EventEmitter<{ + /** Emitted whenever the realm has updated. */ + updated: Realm; /** Emitted when the realm is destroyed. */ destroyed: {reason: string}; /** Emitted when a dedicated worker is created in the realm. */ @@ -55,22 +59,12 @@ export abstract class Realm extends EventEmitter<{ // keep-sorted end } - protected initialize(): void { - const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); - sessionEmitter.on('script.realmDestroyed', info => { - if (info.realm !== this.id) { - return; - } - this.dispose('Realm already destroyed.'); - }); - } - // keep-sorted start block=yes get disposed(): boolean { return this.#reason !== undefined; } protected abstract get session(): Session; - protected get target(): Bidi.Script.Target { + get target(): Bidi.Script.Target { return {realm: this.id}; } // keep-sorted end @@ -128,6 +122,18 @@ export abstract class Realm extends EventEmitter<{ return result; } + @throwIfDisposed<Realm>(realm => { + // SAFETY: Disposal implies this exists. + return realm.#reason!; + }) + async resolveExecutionContextId(): Promise<number> { + const {result} = await (this.session.connection as BidiConnection).send( + 'cdp.resolveRealm', + {realm: this.id} + ); + return result.executionContextId; + } + [disposeSymbol](): void { this.#reason ??= 'Realm already destroyed, probably because all associated browsing contexts closed.'; @@ -144,7 +150,7 @@ export abstract class Realm extends EventEmitter<{ export class WindowRealm extends Realm { static from(context: BrowsingContext, sandbox?: string): WindowRealm { const realm = new WindowRealm(context, sandbox); - realm.initialize(); + realm.#initialize(); return realm; } @@ -153,13 +159,7 @@ export class WindowRealm extends Realm { readonly sandbox?: string; // keep-sorted end - readonly #workers: { - dedicated: Map<string, DedicatedWorkerRealm>; - shared: Map<string, SharedWorkerRealm>; - } = { - dedicated: new Map(), - shared: new Map(), - }; + readonly #workers = new Map<string, DedicatedWorkerRealm>(); private constructor(context: BrowsingContext, sandbox?: string) { super('', ''); @@ -169,16 +169,26 @@ export class WindowRealm extends Realm { // keep-sorted end } - override initialize(): void { - super.initialize(); + #initialize(): void { + const browsingContextEmitter = this.disposables.use( + new EventEmitter(this.browsingContext) + ); + browsingContextEmitter.on('closed', ({reason}) => { + this.dispose(reason); + }); const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); sessionEmitter.on('script.realmCreated', info => { - if (info.type !== 'window') { + if ( + info.type !== 'window' || + info.context !== this.browsingContext.id || + info.sandbox !== this.sandbox + ) { return; } (this as any).id = info.realm; (this as any).origin = info.origin; + this.emit('updated', this); }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { @@ -189,32 +199,16 @@ export class WindowRealm extends Realm { } const realm = DedicatedWorkerRealm.from(this, info.realm, info.origin); - this.#workers.dedicated.set(realm.id, realm); + this.#workers.set(realm.id, realm); const realmEmitter = this.disposables.use(new EventEmitter(realm)); realmEmitter.once('destroyed', () => { realmEmitter.removeAllListeners(); - this.#workers.dedicated.delete(realm.id); + this.#workers.delete(realm.id); }); this.emit('worker', realm); }); - - this.browsingContext.userContext.browser.on('sharedworker', ({realm}) => { - if (!realm.owners.has(this)) { - return; - } - - this.#workers.shared.set(realm.id, realm); - - const realmEmitter = this.disposables.use(new EventEmitter(realm)); - realmEmitter.once('destroyed', () => { - realmEmitter.removeAllListeners(); - this.#workers.shared.delete(realm.id); - }); - - this.emit('sharedworker', realm); - }); } override get session(): Session { @@ -244,7 +238,7 @@ export class DedicatedWorkerRealm extends Realm { origin: string ): DedicatedWorkerRealm { const realm = new DedicatedWorkerRealm(owner, id, origin); - realm.initialize(); + realm.#initialize(); return realm; } @@ -262,10 +256,14 @@ export class DedicatedWorkerRealm extends Realm { this.owners = new Set([owner]); } - override initialize(): void { - super.initialize(); - + #initialize(): void { const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); + sessionEmitter.on('script.realmDestroyed', info => { + if (info.realm !== this.id) { + return; + } + this.dispose('Realm already destroyed.'); + }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { return; @@ -296,34 +294,30 @@ export class DedicatedWorkerRealm extends Realm { * @internal */ export class SharedWorkerRealm extends Realm { - static from( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ): SharedWorkerRealm { - const realm = new SharedWorkerRealm(owners, id, origin); - realm.initialize(); + static from(browser: Browser, id: string, origin: string): SharedWorkerRealm { + const realm = new SharedWorkerRealm(browser, id, origin); + realm.#initialize(); return realm; } // keep-sorted start readonly #workers = new Map<string, DedicatedWorkerRealm>(); - readonly owners: Set<WindowRealm>; + readonly browser: Browser; // keep-sorted end - private constructor( - owners: [WindowRealm, ...WindowRealm[]], - id: string, - origin: string - ) { + private constructor(browser: Browser, id: string, origin: string) { super(id, origin); - this.owners = new Set(owners); + this.browser = browser; } - override initialize(): void { - super.initialize(); - + #initialize(): void { const sessionEmitter = this.disposables.use(new EventEmitter(this.session)); + sessionEmitter.on('script.realmDestroyed', info => { + if (info.realm !== this.id) { + return; + } + this.dispose('Realm already destroyed.'); + }); sessionEmitter.on('script.realmCreated', info => { if (info.type !== 'dedicated-worker') { return; @@ -345,7 +339,6 @@ export class SharedWorkerRealm extends Realm { } override get session(): Session { - // SAFETY: At least one owner will exist. - return this.owners.values().next().value.session; + return this.browser.session; } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts index 2a445f7d87..fd616b668d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Request.ts @@ -66,10 +66,11 @@ export class Request extends EventEmitter<{ new EventEmitter(this.#session) ); sessionEmitter.on('network.beforeRequestSent', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + event.redirectCount !== this.#event.redirectCount + 1 + ) { return; } this.#redirect = Request.from(this.#browsingContext, event); @@ -77,10 +78,11 @@ export class Request extends EventEmitter<{ this.dispose(); }); sessionEmitter.on('network.fetchError', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + this.#event.redirectCount !== event.redirectCount + ) { return; } this.#error = event.errorText; @@ -88,14 +90,19 @@ export class Request extends EventEmitter<{ this.dispose(); }); sessionEmitter.on('network.responseCompleted', event => { - if (event.context !== this.#browsingContext.id) { - return; - } - if (event.request.request !== this.id) { + if ( + event.context !== this.#browsingContext.id || + event.request.request !== this.id || + this.#event.redirectCount !== event.redirectCount + ) { return; } this.#response = event.response; this.emit('success', this.#response); + // In case this is a redirect. + if (this.#response.status >= 300 && this.#response.status < 400) { + return; + } this.dispose(); }); } @@ -126,7 +133,7 @@ export class Request extends EventEmitter<{ return this.#event.navigation ?? undefined; } get redirect(): Request | undefined { - return this.redirect; + return this.#redirect; } get response(): Bidi.Network.ResponseData | undefined { return this.#response; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts index b6e28061f1..ffd39769e7 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/Session.ts @@ -8,7 +8,11 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import {EventEmitter} from '../../common/EventEmitter.js'; import {debugError} from '../../common/util.js'; -import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; +import { + bubble, + inertIfDisposed, + throwIfDisposed, +} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import {Browser} from './Browser.js'; @@ -81,7 +85,8 @@ export class Session readonly #disposables = new DisposableStack(); readonly #info: Bidi.Session.NewResult; readonly browser!: Browser; - readonly connection: Connection; + @bubble() + accessor connection: Connection; // keep-sorted end private constructor(connection: Connection, info: Bidi.Session.NewResult) { @@ -93,8 +98,6 @@ export class Session } async #initialize(): Promise<void> { - this.connection.pipeTo(this); - // SAFETY: We use `any` to allow assignment of the readonly property. (this as any).browser = await Browser.from(this); @@ -102,6 +105,19 @@ export class Session browserEmitter.once('closed', ({reason}) => { this.dispose(reason); }); + + // TODO: Currently, some implementations do not emit navigationStarted event + // for fragment navigations (as per spec) and some do. This could emits a + // synthetic navigationStarted to work around this inconsistency. + const seen = new WeakSet(); + this.on('browsingContext.fragmentNavigated', info => { + if (seen.has(info)) { + return; + } + seen.add(info); + this.emit('browsingContext.navigationStarted', info); + this.emit('browsingContext.fragmentNavigated', info); + }); } // keep-sorted start block=yes @@ -125,10 +141,6 @@ export class Session this[disposeSymbol](); } - pipeTo<Events extends BidiEvents>(emitter: EventEmitter<Events>): void { - this.connection.pipeTo(emitter); - } - /** * Currently, there is a 1:1 relationship between the session and the * session. In the future, we might support multiple sessions and in that diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts index 01ee5c7649..72859c6a53 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/core/UserContext.ts @@ -12,6 +12,7 @@ import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import type {Browser} from './Browser.js'; +import type {GetCookiesOptions} from './BrowsingContext.js'; import {BrowsingContext} from './BrowsingContext.js'; /** @@ -43,7 +44,7 @@ export class UserContext extends EventEmitter<{ reason: string; }; }> { - static DEFAULT = 'default'; + static DEFAULT = 'default' as const; static create(browser: Browser, id: string): UserContext { const context = new UserContext(browser, id); @@ -84,6 +85,10 @@ export class UserContext extends EventEmitter<{ return; } + if (info.userContext !== this.#id) { + return; + } + const browsingContext = BrowsingContext.from( this, undefined, @@ -143,6 +148,7 @@ export class UserContext extends EventEmitter<{ type, ...options, referenceContext: options.referenceContext?.id, + userContext: this.#id, }); const browsingContext = this.#browsingContexts.get(contextId); @@ -161,12 +167,71 @@ export class UserContext extends EventEmitter<{ }) async remove(): Promise<void> { try { - // TODO: Call `removeUserContext` once available. + await this.#session.send('browser.removeUserContext', { + userContext: this.#id, + }); } finally { this.dispose('User context already closed.'); } } + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async getCookies( + options: GetCookiesOptions = {}, + sourceOrigin: string | undefined = undefined + ): Promise<Bidi.Network.Cookie[]> { + const { + result: {cookies}, + } = await this.#session.send('storage.getCookies', { + ...options, + partition: { + type: 'storageKey', + userContext: this.#id, + sourceOrigin, + }, + }); + return cookies; + } + + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setCookie( + cookie: Bidi.Storage.PartialCookie, + sourceOrigin?: string + ): Promise<void> { + await this.#session.send('storage.setCookie', { + cookie, + partition: { + type: 'storageKey', + sourceOrigin, + userContext: this.id, + }, + }); + } + + @throwIfDisposed<UserContext>(context => { + // SAFETY: Disposal implies this exists. + return context.#reason!; + }) + async setPermissions( + origin: string, + descriptor: Bidi.Permissions.PermissionDescriptor, + state: Bidi.Permissions.PermissionState + ): Promise<void> { + await this.#session.send('permissions.setPermission', { + origin, + descriptor, + state, + // @ts-expect-error not standard implementation. + 'goog:userContext': this.#id, + }); + } + [disposeSymbol](): void { this.#reason ??= 'User context already closed, probably because the browser disconnected/closed.'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts deleted file mode 100644 index 73b86cba9c..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/lifecycle.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ -import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; - -import type { - ObservableInput, - ObservedValueOf, - OperatorFunction, -} from '../../third_party/rxjs/rxjs.js'; -import {catchError} from '../../third_party/rxjs/rxjs.js'; -import type {PuppeteerLifeCycleEvent} from '../cdp/LifecycleWatcher.js'; -import {ProtocolError, TimeoutError} from '../common/Errors.js'; - -/** - * @internal - */ -export type BiDiNetworkIdle = Extract< - PuppeteerLifeCycleEvent, - 'networkidle0' | 'networkidle2' -> | null; - -/** - * @internal - */ -export function getBiDiLifeCycles( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [ - Extract<PuppeteerLifeCycleEvent, 'load' | 'domcontentloaded'>, - BiDiNetworkIdle, -] { - if (Array.isArray(event)) { - const pageLifeCycle = event.some(lifeCycle => { - return lifeCycle !== 'domcontentloaded'; - }) - ? 'load' - : 'domcontentloaded'; - - const networkLifeCycle = event.reduce((acc, lifeCycle) => { - if (lifeCycle === 'networkidle0') { - return lifeCycle; - } else if (acc !== 'networkidle0' && lifeCycle === 'networkidle2') { - return lifeCycle; - } - return acc; - }, null as BiDiNetworkIdle); - - return [pageLifeCycle, networkLifeCycle]; - } - - if (event === 'networkidle0' || event === 'networkidle2') { - return ['load', event]; - } - - return [event, null]; -} - -/** - * @internal - */ -export const lifeCycleToReadinessState = new Map< - PuppeteerLifeCycleEvent, - Bidi.BrowsingContext.ReadinessState ->([ - ['load', Bidi.BrowsingContext.ReadinessState.Complete], - ['domcontentloaded', Bidi.BrowsingContext.ReadinessState.Interactive], -]); - -export function getBiDiReadinessState( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [Bidi.BrowsingContext.ReadinessState, BiDiNetworkIdle] { - const lifeCycles = getBiDiLifeCycles(event); - const readiness = lifeCycleToReadinessState.get(lifeCycles[0])!; - return [readiness, lifeCycles[1]]; -} - -/** - * @internal - */ -export const lifeCycleToSubscribedEvent = new Map< - PuppeteerLifeCycleEvent, - 'browsingContext.load' | 'browsingContext.domContentLoaded' ->([ - ['load', 'browsingContext.load'], - ['domcontentloaded', 'browsingContext.domContentLoaded'], -]); - -/** - * @internal - */ -export function getBiDiLifecycleEvent( - event: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[] -): [ - 'browsingContext.load' | 'browsingContext.domContentLoaded', - BiDiNetworkIdle, -] { - const lifeCycles = getBiDiLifeCycles(event); - const bidiEvent = lifeCycleToSubscribedEvent.get(lifeCycles[0])!; - return [bidiEvent, lifeCycles[1]]; -} - -/** - * @internal - */ -export function rewriteNavigationError<T, R extends ObservableInput<T>>( - message: string, - ms: number -): OperatorFunction<T, T | ObservedValueOf<R>> { - return catchError<T, R>(error => { - if (error instanceof ProtocolError) { - error.message += ` at ${message}`; - } else if (error instanceof TimeoutError) { - error.message = `Navigation timeout of ${ms} ms exceeded`; - } - throw error; - }); -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts index 41e88e26c2..e1d64c2f4c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/bidi/util.ts @@ -6,32 +6,10 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; -import {PuppeteerURL, debugError} from '../common/util.js'; +import {ProtocolError, TimeoutError} from '../common/Errors.js'; +import {PuppeteerURL} from '../common/util.js'; import {BidiDeserializer} from './Deserializer.js'; -import type {BidiRealm} from './Realm.js'; - -/** - * @internal - */ -export async function releaseReference( - client: BidiRealm, - remoteReference: Bidi.Script.RemoteReference -): Promise<void> { - if (!remoteReference.handle) { - return; - } - await client.connection - .send('script.disown', { - target: client.target, - handles: [remoteReference.handle], - }) - .catch(error => { - // Exceptions might happen in case of a page been navigated or closed. - // Swallow these since they are harmless and we don't leak anything in this case. - debugError(error); - }); -} /** * @internal @@ -79,3 +57,20 @@ export function createEvaluationError( error.stack = [details.text, ...stackLines].join('\n'); return error; } + +/** + * @internal + */ +export function rewriteNavigationError( + message: string, + ms: number +): (error: unknown) => never { + return error => { + if (error instanceof ProtocolError) { + error.message += ` at ${message}`; + } else if (error instanceof TimeoutError) { + error.message = `Navigation timeout of ${ms} ms exceeded`; + } + throw error; + }; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts index 7a6a6f8582..7fe372788f 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Binding.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {JSHandle} from '../api/JSHandle.js'; import {debugError} from '../common/util.js'; import {DisposableStack} from '../util/disposable.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts index 7698acd164..5c8a4c24da 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Browser.ts @@ -18,7 +18,6 @@ import { type IsPageTargetCallback, type Permission, type TargetFilterCallback, - type WaitForTargetOptions, } from '../api/Browser.js'; import {BrowserContext, BrowserContextEvent} from '../api/BrowserContext.js'; import {CDPSessionEvent, type CDPSession} from '../api/CDPSession.js'; @@ -201,7 +200,7 @@ export class CdpBrowser extends BrowserBase { return this.#isPageTargetCallback; } - override async createIncognitoBrowserContext( + override async createBrowserContext( options: BrowserContextOptions = {} ): Promise<CdpBrowserContext> { const {proxyServer, proxyBypassList} = options; @@ -451,15 +450,6 @@ export class CdpBrowserContext extends BrowserContext { }); } - override waitForTarget( - predicate: (x: Target) => boolean | Promise<boolean>, - options: WaitForTargetOptions = {} - ): Promise<Target> { - return this.#browser.waitForTarget(target => { - return target.browserContext() === this && predicate(target); - }, options); - } - override async pages(): Promise<Page[]> { const pages = await Promise.all( this.targets() diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts index 8598967fe7..823b3b462e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/EmulationManager.ts @@ -267,13 +267,23 @@ export class EmulationManager { const hasTouch = viewport.hasTouch || false; await Promise.all([ - client.send('Emulation.setDeviceMetricsOverride', { - mobile, - width, - height, - deviceScaleFactor, - screenOrientation, - }), + client + .send('Emulation.setDeviceMetricsOverride', { + mobile, + width, + height, + deviceScaleFactor, + screenOrientation, + }) + .catch(err => { + if ( + err.message.includes('Target does not support metrics override') + ) { + debugError(err); + return; + } + throw err; + }), client.send('Emulation.setTouchEmulationEnabled', { enabled: hasTouch, }), diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts index 844120d7ff..edc7009b11 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Frame.ts @@ -20,6 +20,7 @@ import type { DeviceRequestPromptManager, } from './DeviceRequestPrompt.js'; import type {FrameManager} from './FrameManager.js'; +import type {IsolatedWorldChart} from './IsolatedWorld.js'; import {IsolatedWorld} from './IsolatedWorld.js'; import {MAIN_WORLD, PUPPETEER_WORLD} from './IsolatedWorlds.js'; import { @@ -35,6 +36,7 @@ export class CdpFrame extends Frame { #url = ''; #detached = false; #client!: CDPSession; + worlds!: IsolatedWorldChart; _frameManager: FrameManager; override _id: string; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts index 029e77470b..1331513e19 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPRequest.ts @@ -28,6 +28,7 @@ import type {CdpHTTPResponse} from './HTTPResponse.js'; * @internal */ export class CdpHTTPRequest extends HTTPRequest { + override id: string; declare _redirectChain: CdpHTTPRequest[]; declare _response: CdpHTTPResponse | null; @@ -91,7 +92,7 @@ export class CdpHTTPRequest extends HTTPRequest { ) { super(); this.#client = client; - this._requestId = data.requestId; + this.id = data.requestId; this.#isNavigationRequest = data.requestId === data.loaderId && data.type === 'Document'; this._interceptionId = interceptionId; @@ -188,7 +189,7 @@ export class CdpHTTPRequest extends HTTPRequest { override async fetchPostData(): Promise<string | undefined> { try { const result = await this.#client.send('Network.getRequestPostData', { - requestId: this._requestId, + requestId: this.id, }); return result.postData; } catch (err) { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts index 2b2264ffd4..eb92ab07e3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/HTTPResponse.ts @@ -130,7 +130,7 @@ export class CdpHTTPResponse extends HTTPResponse { const response = await this.#client.send( 'Network.getResponseBody', { - requestId: this.#request._requestId, + requestId: this.#request.id, } ); return Buffer.from( diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts index 9bfafddcf3..0674ef4634 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Input.ts @@ -10,16 +10,16 @@ import type {CDPSession} from '../api/CDPSession.js'; import type {Point} from '../api/ElementHandle.js'; import { Keyboard, - type KeyDownOptions, - type KeyPressOptions, Mouse, MouseButton, + Touchscreen, + type KeyDownOptions, + type KeyPressOptions, + type KeyboardTypeOptions, type MouseClickOptions, type MouseMoveOptions, type MouseOptions, type MouseWheelOptions, - Touchscreen, - type KeyboardTypeOptions, } from '../api/Input.js'; import { _keyDefinitions, @@ -573,6 +573,7 @@ export class CdpTouchscreen extends Touchscreen { y: Math.round(y), radiusX: 0.5, radiusY: 0.5, + force: 0.5, }, ], modifiers: this.#keyboard._modifiers, @@ -588,6 +589,7 @@ export class CdpTouchscreen extends Touchscreen { y: Math.round(y), radiusX: 0.5, radiusY: 0.5, + force: 0.5, }, ], modifiers: this.#keyboard._modifiers, diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts index a4f5aaa468..fe71ca52fc 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/LifecycleWatcher.ts @@ -191,14 +191,14 @@ export class LifecycleWatcher { } #onRequestFailed(request: HTTPRequest): void { - if (this.#navigationRequest?._requestId !== request._requestId) { + if (this.#navigationRequest?.id !== request.id) { return; } this.#navigationResponseReceived?.resolve(); } #onResponse(response: HTTPResponse): void { - if (this.#navigationRequest?._requestId !== response.request()._requestId) { + if (this.#navigationRequest?.id !== response.request().id) { return; } this.#navigationResponseReceived?.resolve(); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts index c3e9a8f609..96f0d20963 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.test.ts @@ -128,6 +128,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/1.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: '/redirect/2.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -217,6 +218,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/2.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: '/redirect/3.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -321,6 +323,7 @@ describe('NetworkManager', () => { url: 'http://localhost:8907/redirect/3.html', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { location: 'http://localhost:8907/empty.html', Date: 'Fri, 19 Nov 2021 09:53:58 GMT', @@ -433,6 +436,7 @@ describe('NetworkManager', () => { 'Keep-Alive': 'timeout=5', 'Content-Length': '0', }, + charset: 'utf-8', mimeType: 'text/html', connectionReused: true, connectionId: 322, @@ -613,6 +617,7 @@ describe('NetworkManager', () => { connection: 'keep-alive', 'content-length': '85862', }, + charset: 'utf-8', mimeType: 'text/plain', connectionReused: false, connectionId: 119, @@ -725,6 +730,7 @@ describe('NetworkManager', () => { url: 'http://10.1.0.39:42915/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -932,6 +938,7 @@ describe('NetworkManager', () => { url: 'http://127.0.0.1:54590/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -1036,6 +1043,7 @@ describe('NetworkManager', () => { url: 'http://localhost:56295/empty.html', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'no-cache, no-store', Connection: 'keep-alive', @@ -1221,6 +1229,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'max-age=5', Connection: 'keep-alive', @@ -1394,6 +1403,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/redirect', status: 302, statusText: 'Found', + charset: 'utf-8', headers: { Connection: 'keep-alive', Date: 'Wed, 05 Apr 2023 12:39:13 GMT', @@ -1457,6 +1467,7 @@ describe('NetworkManager', () => { url: 'http://localhost:3000/', status: 200, statusText: 'OK', + charset: 'utf-8', headers: { 'Cache-Control': 'max-age=5', 'Content-Type': 'text/html; charset=utf-8', diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts index 8b24b9a748..4fd61116d2 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/NetworkManager.ts @@ -36,11 +36,17 @@ export interface Credentials { * @public */ export interface NetworkConditions { - // Download speed (bytes/s) + /** + * Download speed (bytes/s) + */ download: number; - // Upload speed (bytes/s) + /** + * Upload speed (bytes/s) + */ upload: number; - // Latency (ms) + /** + * Latency (ms) + */ latency: number; } @@ -631,7 +637,7 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> { } #forgetRequest(request: CdpHTTPRequest, events: boolean): void { - const requestId = request._requestId; + const requestId = request.id; const interceptionId = request._interceptionId; this.#networkEventManager.forgetRequest(requestId); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts index 491637f0ea..d5341cf3bb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Page.ts @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {Readable} from 'stream'; - import type {Protocol} from 'devtools-protocol'; import {firstValueFrom, from, raceWith} from '../../third_party/rxjs/rxjs.js'; @@ -32,6 +30,11 @@ import { ConsoleMessage, type ConsoleMessageType, } from '../common/ConsoleMessage.js'; +import type { + Cookie, + DeleteCookiesRequest, + CookieParam, +} from '../common/Cookie.js'; import {TargetCloseError} from '../common/Errors.js'; import {FileChooser} from '../common/FileChooser.js'; import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js'; @@ -80,6 +83,15 @@ import { } from './utils.js'; import {CdpWebWorker} from './WebWorker.js'; +function convertConsoleMessageLevel(method: string): ConsoleMessageType { + switch (method) { + case 'warning': + return 'warn'; + default: + return method as ConsoleMessageType; + } +} + /** * @internal */ @@ -346,6 +358,8 @@ export class CdpPage extends Page { const worker = new CdpWebWorker( session, session._target().url(), + session._target()._targetId, + session._target().type(), this.#addConsoleMessage.bind(this), this.#handleException.bind(this) ); @@ -470,7 +484,12 @@ export class CdpPage extends Page { if (source !== 'worker') { this.emit( PageEvent.Console, - new ConsoleMessage(level, text, [], [{url, lineNumber}]) + new ConsoleMessage( + convertConsoleMessageLevel(level), + text, + [], + [{url, lineNumber}] + ) ); } } @@ -572,16 +591,14 @@ export class CdpPage extends Page { ) as HandleFor<Prototype[]>; } - override async cookies( - ...urls: string[] - ): Promise<Protocol.Network.Cookie[]> { + override async cookies(...urls: string[]): Promise<Cookie[]> { const originalCookies = ( await this.#primaryTargetClient.send('Network.getCookies', { urls: urls.length ? urls : [this.url()], }) ).cookies; - const unsupportedCookieAttributes = ['priority']; + const unsupportedCookieAttributes = ['sourcePort']; const filterUnsupportedAttributes = ( cookie: Protocol.Network.Cookie ): Protocol.Network.Cookie => { @@ -594,7 +611,7 @@ export class CdpPage extends Page { } override async deleteCookie( - ...cookies: Protocol.Network.DeleteCookiesRequest[] + ...cookies: DeleteCookiesRequest[] ): Promise<void> { const pageURL = this.url(); for (const cookie of cookies) { @@ -606,9 +623,7 @@ export class CdpPage extends Page { } } - override async setCookie( - ...cookies: Protocol.Network.CookieParam[] - ): Promise<void> { + override async setCookie(...cookies: CookieParam[]): Promise<void> { const pageURL = this.url(); const startsWithHTTP = pageURL.startsWith('http'); const items = cookies.map(cookie => { @@ -810,7 +825,11 @@ export class CdpPage extends Page { const values = event.args.map(arg => { return createCdpHandle(context._world, arg); }); - this.#addConsoleMessage(event.type, values, event.stackTrace); + this.#addConsoleMessage( + convertConsoleMessageLevel(event.type), + values, + event.stackTrace + ); } async #onBindingCalled( @@ -842,7 +861,7 @@ export class CdpPage extends Page { } #addConsoleMessage( - eventType: ConsoleMessageType, + eventType: string, args: JSHandle[], stackTrace?: Protocol.Runtime.StackTrace ): void { @@ -874,7 +893,7 @@ export class CdpPage extends Page { } } const message = new ConsoleMessage( - eventType, + convertConsoleMessageLevel(eventType), textTokens.join(' '), args, stackTraceLocations @@ -1086,7 +1105,9 @@ export class CdpPage extends Page { return data; } - override async createPDFStream(options: PDFOptions = {}): Promise<Readable> { + override async createPDFStream( + options: PDFOptions = {} + ): Promise<ReadableStream<Uint8Array>> { const {timeout: ms = this._timeoutSettings.timeout()} = options; const { landscape, @@ -1102,6 +1123,7 @@ export class CdpPage extends Page { preferCSSPageSize, omitBackground, tagged: generateTaggedPDF, + outline: generateDocumentOutline, } = parsePDFOptions(options); if (omitBackground) { @@ -1127,6 +1149,7 @@ export class CdpPage extends Page { pageRanges, preferCSSPageSize, generateTaggedPDF, + generateDocumentOutline, } ); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts index df035ae52b..2e30f900c3 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/PredefinedNetworkConditions.ts @@ -40,10 +40,3 @@ export const PredefinedNetworkConditions = Object.freeze({ latency: 150 * 3.75, } as NetworkConditions, }); - -/** - * @deprecated Import {@link PredefinedNetworkConditions}. - * - * @public - */ -export const networkConditions = PredefinedNetworkConditions; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts index b3e9ea83ec..ab8b00475b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts @@ -290,6 +290,8 @@ export class WorkerTarget extends CdpTarget { return new CdpWebWorker( client, this._getTargetInfo().url, + this._targetId, + this.type(), () => {} /* consoleAPICalled */, () => {} /* exceptionThrown */ ); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts index 552e8a6cf5..ed2407ba66 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/WebWorker.ts @@ -7,8 +7,8 @@ import type {Protocol} from 'devtools-protocol'; import type {CDPSession} from '../api/CDPSession.js'; import type {Realm} from '../api/Realm.js'; +import {TargetType} from '../api/Target.js'; import {WebWorker} from '../api/WebWorker.js'; -import type {ConsoleMessageType} from '../common/ConsoleMessage.js'; import {TimeoutSettings} from '../common/TimeoutSettings.js'; import {debugError} from '../common/util.js'; @@ -20,7 +20,7 @@ import {CdpJSHandle} from './JSHandle.js'; * @internal */ export type ConsoleAPICalledCallback = ( - eventType: ConsoleMessageType, + eventType: string, handles: CdpJSHandle[], trace?: Protocol.Runtime.StackTrace ) => void; @@ -38,15 +38,21 @@ export type ExceptionThrownCallback = ( export class CdpWebWorker extends WebWorker { #world: IsolatedWorld; #client: CDPSession; + readonly #id: string; + readonly #targetType: TargetType; constructor( client: CDPSession, url: string, + targetId: string, + targetType: TargetType, consoleAPICalled: ConsoleAPICalledCallback, exceptionThrown: ExceptionThrownCallback ) { super(url); + this.#id = targetId; this.#client = client; + this.#targetType = targetType; this.#world = new IsolatedWorld(this, new TimeoutSettings()); this.#client.once('Runtime.executionContextCreated', async event => { @@ -80,4 +86,25 @@ export class CdpWebWorker extends WebWorker { get client(): CDPSession { return this.#client; } + + override async close(): Promise<void> { + switch (this.#targetType) { + case TargetType.SERVICE_WORKER: + case TargetType.SHARED_WORKER: { + // For service and shared workers we need to close the target and detach to allow + // the worker to stop. + await this.client.connection()?.send('Target.closeTarget', { + targetId: this.#id, + }); + await this.client.connection()?.send('Target.detachFromTarget', { + sessionId: this.client.id(), + }); + break; + } + default: + await this.evaluate(() => { + self.close(); + }); + } + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts index 217e53bedd..4c8308da6e 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/BrowserConnector.ts @@ -14,7 +14,6 @@ import {isErrorLike} from '../util/ErrorLike.js'; import type {ConnectionTransport} from './ConnectionTransport.js'; import type {ConnectOptions} from './ConnectOptions.js'; import type {BrowserConnectOptions} from './ConnectOptions.js'; -import {getFetch} from './fetch.js'; const getWebSocketTransportClass = async () => { return isNode @@ -93,9 +92,8 @@ async function getConnectionTransport( async function getWSEndpoint(browserURL: string): Promise<string> { const endpointURL = new URL('/json/version', browserURL); - const fetch = await getFetch(); try { - const result = await fetch(endpointURL.toString(), { + const result = await globalThis.fetch(endpointURL.toString(), { method: 'GET', }); if (!result.ok) { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts index c64d109a7c..fe71e57587 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Configuration.ts @@ -32,7 +32,13 @@ export interface Configuration { * See {@link PuppeteerNode.launch | puppeteer.launch} on how executable path * is inferred. * - * @defaultValue A compatible-revision of the browser. + * Use a specific browser version (e.g., 119.0.6045.105). If you use an alias + * such `stable` or `canary` it will only work during the installation of + * Puppeteer and it will fail when launching the browser. + * + * @example 119.0.6045.105 + * @defaultValue The pinned browser version supported by the current Puppeteer + * version. */ browserRevision?: string; /** @@ -51,20 +57,12 @@ export interface Configuration { * @remarks * This must include the protocol and may even need a path prefix. * - * @defaultValue Either https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing or + * @defaultValue Either https://storage.googleapis.com/chrome-for-testing-public or * https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central, * depending on the product. */ downloadBaseUrl?: string; /** - * Specifies the path for the downloads folder. - * - * Can be overridden by `PUPPETEER_DOWNLOAD_PATH`. - * - * @defaultValue `<cacheDirectory>` - */ - downloadPath?: string; - /** * Specifies an executable path to be used in * {@link PuppeteerNode.launch | puppeteer.launch}. * diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts index 85d2db9f75..c2aad7679d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/ConsoleMessage.ts @@ -35,7 +35,7 @@ export type ConsoleMessageType = | 'debug' | 'info' | 'error' - | 'warning' + | 'warn' | 'dir' | 'dirxml' | 'table' diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts new file mode 100644 index 0000000000..c9f7283075 --- /dev/null +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Cookie.ts @@ -0,0 +1,186 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Represents the cookie's 'SameSite' status: + * https://tools.ietf.org/html/draft-west-first-party-cookies + * + * @public + */ +export type CookieSameSite = 'Strict' | 'Lax' | 'None'; + +/** + * Represents the cookie's 'Priority' status: + * https://tools.ietf.org/html/draft-west-cookie-priority-00 + * + * @public + */ +export type CookiePriority = 'Low' | 'Medium' | 'High'; + +/** + * Represents the source scheme of the origin that originally set the cookie. A value of + * "Unset" allows protocol clients to emulate legacy cookie scope for the scheme. + * This is a temporary ability and it will be removed in the future. + * + * @public + */ +export type CookieSourceScheme = 'Unset' | 'NonSecure' | 'Secure'; + +/** + * Represents a cookie object. + * + * @public + */ +export interface Cookie { + /** + * Cookie name. + */ + name: string; + /** + * Cookie value. + */ + value: string; + /** + * Cookie domain. + */ + domain: string; + /** + * Cookie path. + */ + path: string; + /** + * Cookie expiration date as the number of seconds since the UNIX epoch. Set to `-1` for + * session cookies + */ + expires: number; + /** + * Cookie size. + */ + size: number; + /** + * True if cookie is http-only. + */ + httpOnly: boolean; + /** + * True if cookie is secure. + */ + secure: boolean; + /** + * True in case of session cookie. + */ + session: boolean; + /** + * Cookie SameSite type. + */ + sameSite?: CookieSameSite; + /** + * Cookie Priority. Supported only in Chrome. + */ + priority?: CookiePriority; + /** + * True if cookie is SameParty. Supported only in Chrome. + */ + sameParty?: boolean; + /** + * Cookie source scheme type. Supported only in Chrome. + */ + sourceScheme?: CookieSourceScheme; + /** + * Cookie partition key. The site of the top-level URL the browser was visiting at the + * start of the request to the endpoint that set the cookie. Supported only in Chrome. + */ + partitionKey?: string; + /** + * True if cookie partition key is opaque. Supported only in Chrome. + */ + partitionKeyOpaque?: boolean; +} + +/** + * Cookie parameter object + * + * @public + */ +export interface CookieParam { + /** + * Cookie name. + */ + name: string; + /** + * Cookie value. + */ + value: string; + /** + * The request-URI to associate with the setting of the cookie. This value can affect + * the default domain, path, and source scheme values of the created cookie. + */ + url?: string; + /** + * Cookie domain. + */ + domain?: string; + /** + * Cookie path. + */ + path?: string; + /** + * True if cookie is secure. + */ + secure?: boolean; + /** + * True if cookie is http-only. + */ + httpOnly?: boolean; + /** + * Cookie SameSite type. + */ + sameSite?: CookieSameSite; + /** + * Cookie expiration date, session cookie if not set + */ + expires?: number; + /** + * Cookie Priority. Supported only in Chrome. + */ + priority?: CookiePriority; + /** + * True if cookie is SameParty. Supported only in Chrome. + */ + sameParty?: boolean; + /** + * Cookie source scheme type. Supported only in Chrome. + */ + sourceScheme?: CookieSourceScheme; + /** + * Cookie partition key. The site of the top-level URL the browser was visiting at the + * start of the request to the endpoint that set the cookie. If not set, the cookie will + * be set as not partitioned. + */ + partitionKey?: string; +} + +/** + * @public + */ +export interface DeleteCookiesRequest { + /** + * Name of the cookies to remove. + */ + name: string; + /** + * If specified, deletes all the cookies with the given name where domain and path match + * provided URL. Otherwise, deletes only cookies related to the current page's domain. + */ + url?: string; + /** + * If specified, deletes only cookies with the exact domain. + */ + domain?: string; + /** + * If specified, deletes only cookies with the exact path. + */ + path?: string; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts index dbf5c13c95..1f1a35dd0b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Device.ts @@ -1543,10 +1543,3 @@ for (const device of knownDevices) { * @public */ export const KnownDevices = Object.freeze(knownDevicesByName); - -/** - * @deprecated Import {@link KnownDevices} - * - * @public - */ -export const devices = KnownDevices; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts index 8225d64f07..4d0a43ea33 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/Errors.ts @@ -5,11 +5,11 @@ */ /** - * @deprecated Do not use. + * The base class for all Puppeteer-specific errors * * @public */ -export class CustomError extends Error { +export class PuppeteerError extends Error { /** * @internal */ @@ -36,14 +36,14 @@ export class CustomError extends Error { * * @public */ -export class TimeoutError extends CustomError {} +export class TimeoutError extends PuppeteerError {} /** * ProtocolError is emitted whenever there is an error from the protocol. * * @public */ -export class ProtocolError extends CustomError { +export class ProtocolError extends PuppeteerError { #code?: number; #originalMessage = ''; @@ -76,49 +76,9 @@ export class ProtocolError extends CustomError { * * @public */ -export class UnsupportedOperation extends CustomError {} +export class UnsupportedOperation extends PuppeteerError {} /** * @internal */ export class TargetCloseError extends ProtocolError {} - -/** - * @deprecated Do not use. - * - * @public - */ -export interface PuppeteerErrors { - TimeoutError: typeof TimeoutError; - ProtocolError: typeof ProtocolError; -} - -/** - * @deprecated Import error classes directly. - * - * Puppeteer methods might throw errors if they are unable to fulfill a request. - * For example, `page.waitForSelector(selector[, options])` might fail if the - * selector doesn't match any nodes during the given timeframe. - * - * For certain types of errors Puppeteer uses specific error classes. These - * classes are available via `puppeteer.errors`. - * - * @example - * An example of handling a timeout error: - * - * ```ts - * try { - * await page.waitForSelector('.foo'); - * } catch (e) { - * if (e instanceof TimeoutError) { - * // Do something if this is a timeout. - * } - * } - * ``` - * - * @public - */ -export const errors: PuppeteerErrors = Object.freeze({ - TimeoutError, - ProtocolError, -}); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts index cf05ef6700..f3875e99e8 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.test.ts @@ -19,7 +19,7 @@ describe('EventEmitter', () => { }); describe('on', () => { - const onTests = (methodName: 'on' | 'addListener'): void => { + const onTests = (methodName: 'on'): void => { it(`${methodName}: adds an event listener that is fired when the event is emitted`, () => { const listener = sinon.spy(); emitter[methodName]('foo', listener); @@ -43,12 +43,10 @@ describe('EventEmitter', () => { }); }; onTests('on'); - // we support addListener for legacy reasons - onTests('addListener'); }); describe('off', () => { - const offTests = (methodName: 'off' | 'removeListener'): void => { + const offTests = (methodName: 'off'): void => { it(`${methodName}: removes the listener so it is no longer called`, () => { const listener = sinon.spy(); emitter.on('foo', listener); @@ -67,8 +65,6 @@ describe('EventEmitter', () => { }); }; offTests('off'); - // we support removeListener for legacy reasons - offTests('removeListener'); }); describe('once', () => { diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts index 4a8bcb801f..0aace8b2eb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/EventEmitter.ts @@ -27,18 +27,6 @@ export interface CommonEventEmitter<Events extends Record<EventType, unknown>> { handler?: Handler<Events[Key]> ): this; emit<Key extends keyof Events>(type: Key, event: Events[Key]): boolean; - /* To maintain parity with the built in NodeJS event emitter which uses removeListener - * rather than `off`. - * If you're implementing new code you should use `off`. - */ - addListener<Key extends keyof Events>( - type: Key, - handler: Handler<Events[Key]> - ): this; - removeListener<Key extends keyof Events>( - type: Key, - handler: Handler<Events[Key]> - ): this; once<Key extends keyof Events>( type: Key, handler: Handler<Events[Key]> @@ -149,30 +137,6 @@ export class EventEmitter<Events extends Record<EventType, unknown>> } /** - * Remove an event listener. - * - * @deprecated please use {@link EventEmitter.off} instead. - */ - removeListener<Key extends keyof EventsWithWildcard<Events>>( - type: Key, - handler: Handler<EventsWithWildcard<Events>[Key]> - ): this { - return this.off(type, handler); - } - - /** - * Add an event listener. - * - * @deprecated please use {@link EventEmitter.on} instead. - */ - addListener<Key extends keyof EventsWithWildcard<Events>>( - type: Key, - handler: Handler<EventsWithWildcard<Events>[Key]> - ): this { - return this.on(type, handler); - } - - /** * Like `on` but the listener will only be fired once and then it will be removed. * @param type - the event you'd like to listen to * @param handler - the handler function to run when the event occurs diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts index 7cae9191a9..f87ec6817b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/PDFOptions.ts @@ -158,11 +158,23 @@ export interface PDFOptions { omitBackground?: boolean; /** * Generate tagged (accessible) PDF. - * @defaultValue `false` + * @defaultValue `true` * @experimental */ tagged?: boolean; /** + * Generate document outline. + * + * @remarks + * If this is enabled the PDF will also be tagged (accessible) + * Currently only works in old Headless (headless = 'shell') + * crbug/840455#c47 + * + * @defaultValue `false` + * @experimental + */ + outline?: boolean; + /** * Timeout in milliseconds. Pass `0` to disable timeout. * @defaultValue `30_000` */ diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts index 0264c9175f..d505d6c5ff 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/ScriptInjector.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {source as injectedSource} from '../generated/injected.js'; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts index 6ef8925605..bf4274fcf1 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/common.ts @@ -10,12 +10,12 @@ export * from './Configuration.js'; export * from './ConnectionTransport.js'; export * from './ConnectOptions.js'; export * from './ConsoleMessage.js'; +export * from './Cookie.js'; export * from './CustomQueryHandler.js'; export * from './Debug.js'; export * from './Device.js'; export * from './Errors.js'; export * from './EventEmitter.js'; -export * from './fetch.js'; export * from './FileChooser.js'; export * from './GetQueryHandler.js'; export * from './HandleIterator.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts deleted file mode 100644 index 6c7a2b451c..0000000000 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/fetch.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright 2020 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Gets the global version if we're in the browser, else loads the node-fetch module. - * - * @internal - */ -export const getFetch = async (): Promise<typeof fetch> => { - return (globalThis as any).fetch || (await import('cross-fetch')).fetch; -}; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts index 2c8f76f664..f84453c612 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/common/util.ts @@ -5,13 +5,19 @@ */ import type FS from 'fs/promises'; -import type {Readable} from 'stream'; -import {map, NEVER, Observable, timer} from '../../third_party/rxjs/rxjs.js'; +import type {OperatorFunction} from '../../third_party/rxjs/rxjs.js'; +import { + filter, + from, + map, + mergeMap, + NEVER, + Observable, + timer, +} from '../../third_party/rxjs/rxjs.js'; import type {CDPSession} from '../api/CDPSession.js'; -import {isNode} from '../environment.js'; import {assert} from '../util/assert.js'; -import {isErrorLike} from '../util/ErrorLike.js'; import {debug} from './Debug.js'; import {TimeoutError} from './Errors.js'; @@ -209,29 +215,39 @@ export async function importFSPromises(): Promise<typeof FS> { * @internal */ export async function getReadableAsBuffer( - readable: Readable, + readable: ReadableStream<Uint8Array>, path?: string ): Promise<Buffer | null> { - const buffers = []; + const buffers: Uint8Array[] = []; + const reader = readable.getReader(); if (path) { const fs = await importFSPromises(); const fileHandle = await fs.open(path, 'w+'); try { - for await (const chunk of readable) { - buffers.push(chunk); - await fileHandle.writeFile(chunk); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + buffers.push(value); + await fileHandle.writeFile(value); } } finally { await fileHandle.close(); } } else { - for await (const chunk of readable) { - buffers.push(chunk); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + buffers.push(value); } } try { return Buffer.concat(buffers); } catch (error) { + debugError(error); return null; } } @@ -239,39 +255,34 @@ export async function getReadableAsBuffer( /** * @internal */ + +/** + * @internal + */ export async function getReadableFromProtocolStream( client: CDPSession, handle: string -): Promise<Readable> { - // TODO: Once Node 18 becomes the lowest supported version, we can migrate to - // ReadableStream. - if (!isNode) { - throw new Error('Cannot create a stream outside of Node.js environment.'); - } +): Promise<ReadableStream<Uint8Array>> { + return new ReadableStream({ + async pull(controller) { + function getUnit8Array(data: string, isBase64: boolean): Uint8Array { + if (isBase64) { + return Uint8Array.from(atob(data), m => { + return m.codePointAt(0)!; + }); + } + const encoder = new TextEncoder(); + return encoder.encode(data); + } - const {Readable} = await import('stream'); + const {data, base64Encoded, eof} = await client.send('IO.read', { + handle, + }); - let eof = false; - return new Readable({ - async read(size: number) { + controller.enqueue(getUnit8Array(data, base64Encoded ?? false)); if (eof) { - return; - } - - try { - const response = await client.send('IO.read', {handle, size}); - this.push(response.data, response.base64Encoded ? 'base64' : undefined); - if (response.eof) { - eof = true; - await client.send('IO.close', {handle}); - this.push(null); - } - } catch (error) { - if (isErrorLike(error)) { - this.destroy(error); - return; - } - throw error; + await client.send('IO.close', {handle}); + controller.close(); } }, }); @@ -349,7 +360,8 @@ export function parsePDFOptions( pageRanges: '', preferCSSPageSize: false, omitBackground: false, - tagged: false, + outline: false, + tagged: true, }; let width = 8.5; @@ -375,6 +387,11 @@ export function parsePDFOptions( convertPrintParameterToInches(options.margin?.right, lengthUnit) || 0, }; + // Quirk https://bugs.chromium.org/p/chromium/issues/detail?id=840455#c44 + if (options.outline) { + options.tagged = true; + } + return { ...defaults, ...options, @@ -445,3 +462,21 @@ export function fromEmitterEvent< }; }); } + +/** + * @internal + */ +export function filterAsync<T>( + predicate: (value: T) => boolean | PromiseLike<boolean> +): OperatorFunction<T, T> { + return mergeMap<T, Observable<T>>((value): Observable<T> => { + return from(Promise.resolve(predicate(value))).pipe( + filter(isMatch => { + return isMatch; + }), + map(() => { + return value; + }) + ); + }); +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts b/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts index 34fe8f7748..cfc209ba57 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/injected/util.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ const HIDDEN_VISIBILITY_VALUES = ['hidden', 'collapse']; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts index 51d5a19983..0cec3de9ae 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/ChromeLauncher.ts @@ -36,25 +36,6 @@ export class ChromeLauncher extends ProductLauncher { } override launch(options: PuppeteerNodeLaunchOptions = {}): Promise<Browser> { - const headless = options.headless ?? true; - if ( - headless === true && - this.puppeteer.configuration.logLevel === 'warn' && - !Boolean(process.env['PUPPETEER_DISABLE_HEADLESS_WARNING']) - ) { - console.warn( - [ - '\x1B[1m\x1B[43m\x1B[30m', - 'Puppeteer old Headless deprecation warning:\x1B[0m\x1B[33m', - ' In the near future `headless: true` will default to the new Headless mode', - ' for Chrome instead of the old Headless implementation. For more', - ' information, please see https://developer.chrome.com/articles/new-headless/.', - ' Consider opting in early by passing `headless: "new"` to `puppeteer.launch()`', - ' If you encounter any bugs, please report them to https://github.com/puppeteer/puppeteer/issues/new/choose.\x1B[0m\n', - ].join('\n ') - ); - } - if ( this.puppeteer.configuration.logLevel === 'warn' && process.platform === 'darwin' && @@ -231,6 +212,7 @@ export class ChromeLauncher extends ProductLauncher { '--disable-sync', '--enable-automation', '--export-tagged-pdf', + '--generate-pdf-document-outline', '--force-color-profile=srgb', '--metrics-recording-only', '--no-first-run', @@ -253,7 +235,7 @@ export class ChromeLauncher extends ProductLauncher { } if (headless) { chromeArguments.push( - headless === 'new' ? '--headless=new' : '--headless', + headless === 'shell' ? '--headless' : '--headless=new', '--hide-scrollbars', '--mute-audio' ); @@ -271,7 +253,7 @@ export class ChromeLauncher extends ProductLauncher { override executablePath( channel?: ChromeReleaseChannel, - headless?: boolean | 'new' + headless?: boolean | 'shell' ): string { if (channel) { return computeSystemExecutablePath({ diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts index eb4f375fc7..1af09192ec 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/FirefoxLauncher.ts @@ -43,12 +43,20 @@ export class FirefoxLauncher extends ProductLauncher { return { ...extraPrefsFirefox, ...(protocol === 'webDriverBiDi' - ? {} + ? { + // Only enable the WebDriver BiDi protocol + 'remote.active-protocols': 1, + } : { // Do not close the window when the last tab gets closed 'browser.tabs.closeWindowWithLastTab': false, + // Prevent various error message on the console + // jest-puppeteer asserts that no error message is emitted by the console + 'network.cookie.cookieBehavior': 0, // Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263) 'fission.bfcacheInParent': false, + // Only enable the CDP protocol + 'remote.active-protocols': 2, }), // Force all web content to use a single content process. TODO: remove // this once Firefox supports mouse event dispatch from the main frame diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts index 28e0b595df..d7717e45c5 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/LaunchOptions.ts @@ -17,13 +17,18 @@ export interface BrowserLaunchArgumentOptions { * Whether to run the browser in headless mode. * * @remarks - * In the future `headless: true` will be equivalent to `headless: 'new'`. - * You can read more about the change {@link https://developer.chrome.com/articles/new-headless/ | here}. - * Consider opting in early by setting the value to `"new"`. + * + * - `true` launches the browser in the + * {@link https://developer.chrome.com/articles/new-headless/ | new headless} + * mode. + * + * - `'shell'` launches + * {@link https://developer.chrome.com/blog/chrome-headless-shell | shell} + * known as the old headless mode. * * @defaultValue `true` */ - headless?: boolean | 'new'; + headless?: boolean | 'shell'; /** * Path to a user data directory. * {@link https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/user_data_dir.md | see the Chromium docs} diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts index ab3432cd3a..2da07e8f7c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/ProductLauncher.ts @@ -393,7 +393,7 @@ export abstract class ProductLauncher { /** * @internal */ - protected resolveExecutablePath(headless?: boolean | 'new'): string { + protected resolveExecutablePath(headless?: boolean | 'shell'): string { let executablePath = this.puppeteer.configuration.executablePath; if (executablePath) { if (!existsSync(executablePath)) { @@ -404,10 +404,10 @@ export abstract class ProductLauncher { return executablePath; } - function productToBrowser(product?: Product, headless?: boolean | 'new') { + function productToBrowser(product?: Product, headless?: boolean | 'shell') { switch (product) { case 'chrome': - if (headless === true) { + if (headless === 'shell') { return InstalledBrowser.CHROMEHEADLESSSHELL; } return InstalledBrowser.CHROME; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts b/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts index e50e09acdb..726ee24cbb 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/node/PuppeteerNode.ts @@ -223,7 +223,7 @@ export class PuppeteerNode extends Puppeteer { * @internal */ get defaultDownloadPath(): string | undefined { - return this.configuration.downloadPath ?? this.configuration.cacheDirectory; + return this.configuration.cacheDirectory; } /** @@ -283,8 +283,7 @@ export class PuppeteerNode extends Puppeteer { throw new Error('The current platform is not supported.'); } - const cacheDir = - this.configuration.downloadPath ?? this.configuration.cacheDirectory!; + const cacheDir = this.configuration.cacheDirectory!; const installedBrowsers = await getInstalledBrowsers({ cacheDir, }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts b/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts index 37360204d8..c543cd9517 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/revisions.ts @@ -8,7 +8,7 @@ * @internal */ export const PUPPETEER_REVISIONS = Object.freeze({ - chrome: '121.0.6167.85', - 'chrome-headless-shell': '121.0.6167.85', + chrome: '122.0.6261.94', + 'chrome-headless-shell': '122.0.6261.94', firefox: 'latest', }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts index 0dfb013bb3..6699ace36d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/Deferred.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {TimeoutError} from '../common/Errors.js'; /** diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts index 9498bac306..f789837def 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/Mutex.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {Deferred} from './Deferred.js'; import {disposeSymbol} from './disposable.js'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts index 4cdaf15d5b..bc476b0153 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.test.ts @@ -9,7 +9,9 @@ import {describe, it} from 'node:test'; import expect from 'expect'; import sinon from 'sinon'; -import {invokeAtMostOnceForArguments} from './decorators.js'; +import {EventEmitter} from '../common/EventEmitter.js'; + +import {bubble, invokeAtMostOnceForArguments} from './decorators.js'; describe('decorators', function () { describe('invokeAtMostOnceForArguments', () => { @@ -76,4 +78,48 @@ describe('decorators', function () { }).toThrow(); }); }); + + describe('bubble', () => { + it('should work', () => { + class Test extends EventEmitter<any> { + @bubble() + accessor field = new EventEmitter(); + } + + const t = new Test(); + let a = false; + t.on('a', (value: boolean) => { + a = value; + }); + + t.field.emit('a', true); + expect(a).toBeTruthy(); + + // Set a new emitter. + t.field = new EventEmitter(); + a = false; + + t.field.emit('a', true); + expect(a).toBeTruthy(); + }); + + it('should not bubble down', () => { + class Test extends EventEmitter<any> { + @bubble() + accessor field = new EventEmitter<any>(); + } + + const t = new Test(); + let a = false; + t.field.on('a', (value: boolean) => { + a = value; + }); + + t.emit('a', true); + expect(a).toBeFalsy(); + + t.field.emit('a', true); + expect(a).toBeTruthy(); + }); + }); }); diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts index af21c5fe29..c4dc3b6c0d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import type {EventType} from '../common/EventEmitter.js'; +import type {EventEmitter} from '../common/EventEmitter.js'; import type {Disposed, Moveable} from '../common/types.js'; import {asyncDisposeSymbol, disposeSymbol} from './disposable.js'; @@ -138,3 +140,67 @@ export function guarded<T extends object>( }; }; } + +const bubbleHandlers = new WeakMap<object, Map<any, any>>(); + +/** + * Event emitter fields marked with `bubble` will have their events bubble up + * the field owner. + */ +// The type is too complicated to type. +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export function bubble<T extends EventType[]>(events?: T) { + return <This extends EventEmitter<any>, Value extends EventEmitter<any>>( + {set, get}: ClassAccessorDecoratorTarget<This, Value>, + context: ClassAccessorDecoratorContext<This, Value> + ): ClassAccessorDecoratorResult<This, Value> => { + context.addInitializer(function () { + const handlers = bubbleHandlers.get(this) ?? new Map(); + if (handlers.has(events)) { + return; + } + + const handler = + events !== undefined + ? (type: EventType, event: unknown) => { + if (events.includes(type)) { + this.emit(type, event); + } + } + : (type: EventType, event: unknown) => { + this.emit(type, event); + }; + + handlers.set(events, handler); + bubbleHandlers.set(this, handlers); + }); + return { + set(emitter) { + const handler = bubbleHandlers.get(this)!.get(events)!; + + // In case we are re-setting. + const oldEmitter = get.call(this); + if (oldEmitter !== undefined) { + oldEmitter.off('*', handler); + } + + if (emitter === undefined) { + return; + } + emitter.on('*', handler); + set.call(this, emitter); + }, + // @ts-expect-error -- TypeScript incorrectly types init to require a + // return. + init(emitter) { + if (emitter === undefined) { + return; + } + const handler = bubbleHandlers.get(this)!.get(events)!; + + emitter.on('*', handler); + return emitter; + }, + }; + }; +} diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts b/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts index c20aaa8342..1d522c780b 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/mitt/mitt.ts @@ -1,8 +1,3 @@ -/** - * @license - * Copyright 2022 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - +// esline-disable rulesdir/check-license export * from 'mitt'; export {default as default} from 'mitt'; diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts b/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts index b8b64788ae..6f4f844f5d 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/rxjs/rxjs.ts @@ -1,13 +1,11 @@ -/** - * @license - * Copyright 2023 Google Inc. - * SPDX-License-Identifier: Apache-2.0 - */ +// esline-disable rulesdir/check-license export { bufferCount, catchError, + combineLatest, concat, concatMap, + debounceTime, defaultIfEmpty, defer, delay, @@ -16,6 +14,7 @@ export { first, firstValueFrom, forkJoin, + delayWhen, from, fromEvent, identity, @@ -24,6 +23,7 @@ export { map, merge, mergeMap, + mergeScan, NEVER, noop, Observable, @@ -31,9 +31,11 @@ export { pipe, race, raceWith, + ReplaySubject, retry, startWith, switchMap, + take, takeUntil, tap, throwIfEmpty, @@ -42,20 +44,3 @@ export { } from 'rxjs'; export type * from 'rxjs'; - -import {filter, from, map, mergeMap, type Observable} from 'rxjs'; - -export function filterAsync<T>( - predicate: (value: T) => boolean | PromiseLike<boolean> -) { - return mergeMap<T, Observable<T>>(value => { - return from(Promise.resolve(predicate(value))).pipe( - filter(isMatch => { - return isMatch; - }), - map(() => { - return value; - }) - ); - }); -} diff --git a/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json b/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json index 25c438c57d..cfe3a26f4c 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer-core/third_party/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "declarationMap": false, "outDir": "../lib/esm/third_party", - "sourceMap": false, - }, + "sourceMap": false + } } diff --git a/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json b/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json index b662532a01..a219f8b704 100644 --- a/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer-core/tsconfig.json @@ -3,6 +3,6 @@ "files": [], "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md b/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md index c3d834c5f5..8f98608527 100644 --- a/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md +++ b/remote/test/puppeteer/packages/puppeteer/CHANGELOG.md @@ -29,6 +29,99 @@ All notable changes to this project will be documented in this file. See [standa * puppeteer-core bumped from 21.0.2 to 21.0.3 * @puppeteer/browsers bumped from 1.5.1 to 1.6.0 +## [22.4.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.3.0...puppeteer-v22.4.0) (2024-03-05) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.3.0 to 22.4.0 + +## [22.3.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.2.0...puppeteer-v22.3.0) (2024-02-25) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.2.0 to 22.3.0 + +## [22.2.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.1.0...puppeteer-v22.2.0) (2024-02-21) + + +### Features + +* support local aliases when launching a browser ([#11947](https://github.com/puppeteer/puppeteer/issues/11947)) ([561e4cd](https://github.com/puppeteer/puppeteer/commit/561e4cd6ee79b19ac43f2c2fceaa1fce51052c02)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.1.0 to 22.2.0 + * @puppeteer/browsers bumped from 2.0.1 to 2.1.0 + +## [22.1.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v22.0.0...puppeteer-v22.1.0) (2024-02-17) + + +### Miscellaneous Chores + +* **puppeteer:** Synchronize puppeteer versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 22.0.0 to 22.1.0 + * @puppeteer/browsers bumped from 2.0.0 to 2.0.1 + +## [22.0.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.11.0...puppeteer-v22.0.0) (2024-02-05) + + +### âš BREAKING CHANGES + +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) + +### Features + +* drop support for node16 ([#10912](https://github.com/puppeteer/puppeteer/issues/10912)) ([953f420](https://github.com/puppeteer/puppeteer/commit/953f4207b17210fa7231225e6f29a826f77e0832)) +* remove PUPPETEER_DOWNLOAD_PATH in favor of PUPPETEER_CACHE_DIR ([#11605](https://github.com/puppeteer/puppeteer/issues/11605)) ([4677281](https://github.com/puppeteer/puppeteer/commit/467728187737283191f6528676e50d53dae6e5ef)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 21.11.0 to 22.0.0 + * @puppeteer/browsers bumped from 1.9.1 to 2.0.0 + +## [21.11.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.10.0...puppeteer-v21.11.0) (2024-02-02) + + +### Features + +* implement boolean env vars ([#11811](https://github.com/puppeteer/puppeteer/issues/11811)) ([0a9f6d6](https://github.com/puppeteer/puppeteer/commit/0a9f6d670a86c6d1399501b2780fbb46cbe97b2c)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * puppeteer-core bumped from 21.10.0 to 21.11.0 + ## [21.10.0](https://github.com/puppeteer/puppeteer/compare/puppeteer-v21.9.0...puppeteer-v21.10.0) (2024-01-29) diff --git a/remote/test/puppeteer/packages/puppeteer/package.json b/remote/test/puppeteer/packages/puppeteer/package.json index 0419e4b459..88637f3add 100644 --- a/remote/test/puppeteer/packages/puppeteer/package.json +++ b/remote/test/puppeteer/packages/puppeteer/package.json @@ -1,6 +1,6 @@ { "name": "puppeteer", - "version": "21.10.0", + "version": "22.4.0", "description": "A high-level API to control headless Chrome over the DevTools Protocol", "keywords": [ "puppeteer", @@ -32,12 +32,12 @@ "url": "https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer" }, "engines": { - "node": ">=16.13.2" + "node": ">=18" }, "scripts": { "build:docs": "wireit", "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "postinstall": "node install.mjs", "prepack": "wireit" }, @@ -124,8 +124,8 @@ "license": "Apache-2.0", "dependencies": { "cosmiconfig": "9.0.0", - "puppeteer-core": "21.10.0", - "@puppeteer/browsers": "1.9.1" + "puppeteer-core": "22.4.0", + "@puppeteer/browsers": "2.1.0" }, "devDependencies": { "@types/node": "18.17.15" diff --git a/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts index 28cf026eb7..6fd88678a4 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/getConfiguration.ts @@ -10,6 +10,22 @@ import {join} from 'path'; import {cosmiconfigSync} from 'cosmiconfig'; import type {Configuration, Product} from 'puppeteer-core'; +function getBooleanEnvVar(name: string) { + const env = process.env[name]; + if (env === undefined) { + return; + } + switch (env.toLowerCase()) { + case '': + case '0': + case 'false': + case 'off': + return false; + default: + return true; + } +} + /** * @internal */ @@ -58,27 +74,29 @@ export const getConfiguration = (): Configuration => { // Set skipDownload explicitly or from default configuration.skipDownload = Boolean( - process.env['PUPPETEER_SKIP_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_download'] ?? - process.env['npm_package_config_puppeteer_skip_download'] ?? + getBooleanEnvVar('PUPPETEER_SKIP_DOWNLOAD') ?? + getBooleanEnvVar('npm_config_puppeteer_skip_download') ?? + getBooleanEnvVar('npm_package_config_puppeteer_skip_download') ?? configuration.skipDownload ); // Set skipChromeDownload explicitly or from default configuration.skipChromeDownload = Boolean( - process.env['PUPPETEER_SKIP_CHROME_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_chrome_download'] ?? - process.env['npm_package_config_puppeteer_skip_chrome_download'] ?? + getBooleanEnvVar('PUPPETEER_SKIP_CHROME_DOWNLOAD') ?? + getBooleanEnvVar('npm_config_puppeteer_skip_chrome_download') ?? + getBooleanEnvVar('npm_package_config_puppeteer_skip_chrome_download') ?? configuration.skipChromeDownload ); // Set skipChromeDownload explicitly or from default configuration.skipChromeHeadlessShellDownload = Boolean( - process.env['PUPPETEER_SKIP_CHROME_HEADLESS_SHELL_DOWNLOAD'] ?? - process.env['npm_config_puppeteer_skip_chrome_headless_shell_download'] ?? - process.env[ + getBooleanEnvVar('PUPPETEER_SKIP_CHROME_HEADLESS_SHELL_DOWNLOAD') ?? + getBooleanEnvVar( + 'npm_config_puppeteer_skip_chrome_headless_shell_download' + ) ?? + getBooleanEnvVar( 'npm_package_config_puppeteer_skip_chrome_headless_shell_download' - ] ?? + ) ?? configuration.skipChromeHeadlessShellDownload ); @@ -107,12 +125,6 @@ export const getConfiguration = (): Configuration => { process.env['npm_package_config_puppeteer_download_base_url'] ?? configuration.downloadBaseUrl ?? downloadHost; - - configuration.downloadPath = - process.env['PUPPETEER_DOWNLOAD_PATH'] ?? - process.env['npm_config_puppeteer_download_path'] ?? - process.env['npm_package_config_puppeteer_download_path'] ?? - configuration.downloadPath; } configuration.cacheDirectory = diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts index 9a25c59327..39c1736e41 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/node/cli.ts @@ -11,10 +11,7 @@ import {PUPPETEER_REVISIONS} from 'puppeteer-core/internal/revisions.js'; import puppeteer from '../puppeteer.js'; -// TODO: deprecate downloadPath in favour of cacheDirectory. -const cacheDir = - puppeteer.configuration.downloadPath ?? - puppeteer.configuration.cacheDirectory!; +const cacheDir = puppeteer.configuration.cacheDirectory!; void new CLI({ cachePath: cacheDir, diff --git a/remote/test/puppeteer/packages/puppeteer/src/node/install.ts b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts index 76bad868b8..1af3105ee9 100644 --- a/remote/test/puppeteer/packages/puppeteer/src/node/install.ts +++ b/remote/test/puppeteer/packages/puppeteer/src/node/install.ts @@ -53,8 +53,7 @@ export async function downloadBrowser(): Promise<void> { PUPPETEER_REVISIONS['chrome-headless-shell'] || 'latest'; - // TODO: deprecate downloadPath in favour of cacheDirectory. - const cacheDir = configuration.downloadPath ?? configuration.cacheDirectory!; + const cacheDir = configuration.cacheDirectory!; try { const installationJobs = []; @@ -75,6 +74,8 @@ export async function downloadBrowser(): Promise<void> { buildId, downloadProgressCallback: makeProgressCallback(browser, buildId), baseUrl: downloadBaseUrl, + buildIdAlias: + buildId !== unresolvedBuildId ? unresolvedBuildId : undefined, }) .then(result => { logPolitely( @@ -113,6 +114,10 @@ export async function downloadBrowser(): Promise<void> { shellBuildId ), baseUrl: downloadBaseUrl, + buildIdAlias: + shellBuildId !== unresolvedShellBuildId + ? unresolvedShellBuildId + : undefined, }) .then(result => { logPolitely( diff --git a/remote/test/puppeteer/packages/puppeteer/tsconfig.json b/remote/test/puppeteer/packages/puppeteer/tsconfig.json index 11314a80e3..405998de4b 100644 --- a/remote/test/puppeteer/packages/puppeteer/tsconfig.json +++ b/remote/test/puppeteer/packages/puppeteer/tsconfig.json @@ -6,11 +6,11 @@ // just stick with ol'fashion path resolution. "baseUrl": ".", "paths": { - "puppeteer-core/internal/*": ["../puppeteer-core/lib/esm/puppeteer/*"], - }, + "puppeteer-core/internal/*": ["../puppeteer-core/lib/esm/puppeteer/*"] + } }, "references": [ {"path": "src/tsconfig.esm.json"}, - {"path": "src/tsconfig.cjs.json"}, - ], + {"path": "src/tsconfig.cjs.json"} + ] } diff --git a/remote/test/puppeteer/packages/testserver/package.json b/remote/test/puppeteer/packages/testserver/package.json index 3a9ecf9c65..a3a7ac7148 100644 --- a/remote/test/puppeteer/packages/testserver/package.json +++ b/remote/test/puppeteer/packages/testserver/package.json @@ -5,7 +5,7 @@ "main": "lib/index.js", "scripts": { "build": "wireit", - "clean": "../../tools/clean.js" + "clean": "../../tools/clean.mjs" }, "wireit": { "build": { diff --git a/remote/test/puppeteer/packages/testserver/src/index.ts b/remote/test/puppeteer/packages/testserver/src/index.ts index 2618fd4d0d..89439a08dd 100644 --- a/remote/test/puppeteer/packages/testserver/src/index.ts +++ b/remote/test/puppeteer/packages/testserver/src/index.ts @@ -98,6 +98,15 @@ export class TestServer { // Disable this as sometimes the socket will timeout // We rely on the fact that we will close the server at the end this.#server.keepAliveTimeout = 0; + this.#server.on('clientError', err => { + if ( + 'code' in err && + err.code === 'ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN' + ) { + return; + } + console.error('test-server client error', err); + }); this.#wsServer = new WebSocketServer({server: this.#server}); this.#wsServer.on('connection', this.#onWebSocketConnection); } diff --git a/remote/test/puppeteer/packages/testserver/tsconfig.json b/remote/test/puppeteer/packages/testserver/tsconfig.json index 08e6681481..6f0893ee41 100644 --- a/remote/test/puppeteer/packages/testserver/tsconfig.json +++ b/remote/test/puppeteer/packages/testserver/tsconfig.json @@ -6,7 +6,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "lib", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts b/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts index 581b248b8a..40d0f9106b 100644 --- a/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts +++ b/remote/test/puppeteer/test-d/CommonEventEmitter.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ // eslint-disable-next-line no-restricted-imports import {EventEmitter as NodeEventEmitter} from 'node:events'; diff --git a/remote/test/puppeteer/test-d/ElementHandle.test-d.ts b/remote/test/puppeteer/test-d/ElementHandle.test-d.ts index 469150933b..aa01ca2b28 100644 --- a/remote/test/puppeteer/test-d/ElementHandle.test-d.ts +++ b/remote/test/puppeteer/test-d/ElementHandle.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectNotType, expectType} from 'tsd'; import type {ElementHandle} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/JSHandle.test-d.ts b/remote/test/puppeteer/test-d/JSHandle.test-d.ts index fa7348d28e..67a56760c2 100644 --- a/remote/test/puppeteer/test-d/JSHandle.test-d.ts +++ b/remote/test/puppeteer/test-d/JSHandle.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectNotAssignable, expectNotType, expectType} from 'tsd'; import type {ElementHandle, JSHandle} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/NodeFor.test-d.ts b/remote/test/puppeteer/test-d/NodeFor.test-d.ts index 0a40b4e689..53487619e9 100644 --- a/remote/test/puppeteer/test-d/NodeFor.test-d.ts +++ b/remote/test/puppeteer/test-d/NodeFor.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectType, expectNotType} from 'tsd'; import type {NodeFor} from 'puppeteer'; diff --git a/remote/test/puppeteer/test-d/puppeteer.test-d.ts b/remote/test/puppeteer/test-d/puppeteer.test-d.ts index f7a45c0db4..66baff695a 100644 --- a/remote/test/puppeteer/test-d/puppeteer.test-d.ts +++ b/remote/test/puppeteer/test-d/puppeteer.test-d.ts @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ import {expectType} from 'tsd'; import puppeteer, { diff --git a/remote/test/puppeteer/test/.eslintrc.js b/remote/test/puppeteer/test/.eslintrc.js index 489868b6ed..5f7746a76b 100644 --- a/remote/test/puppeteer/test/.eslintrc.js +++ b/remote/test/puppeteer/test/.eslintrc.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ module.exports = { rules: { 'no-restricted-imports': [ diff --git a/remote/test/puppeteer/test/TestExpectations.json b/remote/test/puppeteer/test/TestExpectations.json index f19c2f72e0..e55f223441 100644 --- a/remote/test/puppeteer/test/TestExpectations.json +++ b/remote/test/puppeteer/test/TestExpectations.json @@ -1,357 +1,255 @@ [ { - "testIdPattern": "*", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["SKIP", "TIMEOUT"] - }, - { - "testIdPattern": "[autofill.spec] *", + "testIdPattern": "[ariaqueryhandler.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[autofill.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[bfcache.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[click.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[debugInfo.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[debugInfo.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[device-request-prompt.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[dialog.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[drag-and-drop.spec] *", + "testIdPattern": "[devtools.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] Legacy Drag n' Drop *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[elementhandle.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[evaluation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[fixtures.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[frame.spec] Frame specs *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[injected.spec] *", + "testIdPattern": "[extensions.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[jshandle.spec] *", + "testIdPattern": "[headful.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["headless", "firefox"], + "expectations": ["SKIP"], + "comment": "Cannot be run in headless mode" }, { - "testIdPattern": "[keyboard.spec] Keyboard *", + "testIdPattern": "[idle_override.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch *", - "platforms": ["darwin", "linux"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch *", "platforms": ["win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[locator.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[mouse.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goBack *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate *", "platforms": ["darwin", "linux"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate *", "platforms": ["win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.json *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] - }, - { - "testIdPattern": "[page.spec] Page *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[prerender.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] *", + "testIdPattern": "[page.spec] Page Page.metrics *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryselector.spec] querySelector *", + "testIdPattern": "[pdf.spec] Page.pdf *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] *", + "testIdPattern": "[proxy.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "Chrome-specific test" }, { - "testIdPattern": "[screenshot.spec] *", + "testIdPattern": "[requestinterception-experimental.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Cdp *", + "testIdPattern": "[requestinterception.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace *", + "testIdPattern": "[screencast.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] *", + "testIdPattern": "[screenshot.spec] Screenshots Cdp *", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[accessibility.spec] *", + "testIdPattern": "[worker.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP", "TIMEOUT"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[accessibility.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] *", - "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP", "TIMEOUT"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have an error message specifically for awaiting an element to be hidden", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have correct stack trace for timeout", + "testIdPattern": "[accessibility.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should respect timeout", + "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"button\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should throw when frame is detached", + "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"heading\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[autofill.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "headless"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "chrome-headless-shell"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.target should return browser target", + "testIdPattern": "[browsercontext.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should be prompt by default", @@ -399,7 +297,8 @@ "testIdPattern": "[CDPSession.spec] Target.createCDPSession *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[CDPSession.spec] Target.createCDPSession should not report created targets for custom CDP sessions", @@ -411,343 +310,281 @@ "testIdPattern": "[chromiumonly.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |pipe| option *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[Connection.spec] WebDriver BiDi Connection should work", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL regardless of the current page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "The test relies on the default page partition key do not contain the source origin. This is not the case for Firefox." }, { "testIdPattern": "[coverage.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[coverage.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[coverage.spec] Coverage specs JSCoverage should ignore pptr internal scripts if reportAnonymousScripts is true", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should expose DevTools as a page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should open devtools when \"devtools: true\" option is given", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if asPage is used", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if custom isPageTarget is provided", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[drag-and-drop.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should not work if the click box is not visible due to the iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[emulation.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should get the proper viewport size", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support mobile emulation", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should replace symbols with undefined", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should return properly serialize objects with unknown type fields", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work for circular object", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[fixtures.spec] Fixtures dumpio option should work with pipe option", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[frame.spec] Frame specs Frame Management should handle nested frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[headful.spec] *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[idle_override.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[input.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should not throw for circular objects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should work with dates", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[jshandle.spec] JSHandle Page.evaluateHandle should return the RemoteObject", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[jshandle.spec] JSHandle Page.evaluateHandle should use the same JS wrappers", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter in iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect *", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath when executable path is configured its value is used", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch can launch and close the browser", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should launch Chrome properly with --no-startup-window and waitForInitialPage=false", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", - "platforms": ["linux"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir argument with non-existent dir", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should not throw if buttons are pressed twice", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should reset properly", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should send referer", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished", @@ -765,19 +602,15 @@ "testIdPattern": "[network.spec] network Page.setBypassServiceWorker *", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.initiator should return the initiator", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work", @@ -792,10 +625,18 @@ "expectations": ["PASS"] }, { + "testIdPattern": "[network.spec] network Request.postData should be |undefined| when there is no post data", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "Unsupported" + }, + { "testIdPattern": "[network.spec] network Request.postData should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work with blobs", @@ -808,127 +649,99 @@ "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.timing returns timing information", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should provide access to elements", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support evaluating in oop iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support frames within OOP frames", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should support frames within OOP iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should track navigations within OOP iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF should treat OOP iframes and normal iframes the same", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[oopif.spec] OOPIF waitForFrame should resolve immediately if the frame already exists", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addStyleTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should *not* run beforeunload by default", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should *not* run beforeunload by default", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location when fetch fails", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", + "testIdPattern": "[page.spec] Page Page.Events.Console should return remote objects", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with logging functions", + "testIdPattern": "[page.spec] Page Page.Events.Console should return remote objects", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.error should throw when page crashes", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.exposeFunction *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.exposeFunction should work with loading frames", @@ -938,1762 +751,2086 @@ "comment": "Missing request interception" }, { - "testIdPattern": "[page.spec] Page Page.metrics metrics event fired on console.timeStamp", + "testIdPattern": "[page.spec] Page Page.pdf should respect timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.metrics should get metrics from a page", + "testIdPattern": "[page.spec] Page Page.setBypassCSP *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.pdf can print to PDF with accessible", + "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.pdf should respect timeout", + "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["SKIP"] + "parameters": ["webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.removeExposedFunction should work", + "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setBypassCSP *", + "testIdPattern": "[page.spec] Page Page.setUserAgent *", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", + "testIdPattern": "[pdf.spec] Page.pdf *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setGeolocation should work", + "testIdPattern": "[prerender.spec] Prerender can screencast", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setUserAgent *", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests", + "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[queryObjects.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[requestinterception-experimental.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] *", + "testIdPattern": "[requestinterception.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at browser level", + "testIdPattern": "[screencast.spec] Screencasts Page.screencast should validate options", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], + "parameters": ["firefox"], "expectations": ["PASS"] }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at context level", + "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", + "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["headless"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", + "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should get screenshot bigger than the viewport", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", + "testIdPattern": "[stacktrace.spec] Stack trace *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", + "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "parameters": ["webDriverBiDi", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1882401" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with :hover", + "testIdPattern": "[target.spec] Target should close a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[queryhandler.spec] Query handler tests Text selectors in Page should clear caches", + "testIdPattern": "[TargetManager.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[queryObjects.spec] *", + "testIdPattern": "[TargetManager.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[requestinterception-experimental.spec] *", + "testIdPattern": "[touchscreen.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[requestinterception.spec] *", + "testIdPattern": "[tracing.spec] *", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] *", + "testIdPattern": "[tracing.spec] *", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screencast.spec] Screencasts Page.screencast should validate options", + "testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should get screenshot bigger than the viewport", + "testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace *", + "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.pages should return all of the pages", + "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.targets should return all of the targets", + "testIdPattern": "[browser.spec] Browser specs Browser.userAgent should include Browser engine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.waitForTarget should timeout waiting for a non-existent target", + "testIdPattern": "[browser.spec] Browser specs Browser.userAgent should include Browser engine", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should be able to use async waitForTarget", + "testIdPattern": "[browser.spec] Browser specs Browser.version should return version", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should be able to use the default page in the browser", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should deny permission when not listed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should contain browser target", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should fail when bad permission is given", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a new page is created and closed", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts", "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[TargetManager.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[touchscreen.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[tracing.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should create new incognito context", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[tracing.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "In BiDi currently more events than needed are fired (because target is updated more often). We probably need to adjust the test as the behavior is not broken per se" }, { - "testIdPattern": "[worker.spec] *", + "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[accessibility.spec] Accessibility filtering children of leaf nodes rich text editable fields should have children", + "testIdPattern": "[browsercontext.spec] BrowserContext should have default context", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["firefox", "webDriverBiDi"], "expectations": ["PASS"] }, { - "testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated", + "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler parseAriaSelector should find button", + "testIdPattern": "[browsercontext.spec] BrowserContext should work across sessions", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryAll should find menu by name", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryAllArray $$eval should handle many elements", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find button by name and role", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should expose the underlying connection", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find button by role", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find by name", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne should find first matching element", + "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should be able to connect using browserUrl, with and without trailing slash", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Page Tests Page.setRequestInterception should work with intervention headers", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[chromiumonly.spec] Chromium-Specific Page Tests Page.setRequestInterception should work with intervention headers", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state", + "testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", + "testIdPattern": "[click.spec] Page.click should click the button if window.Node is removed", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[click.spec] Page.click should click the button with deviceScaleFactor set", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.target should return browser target", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browser.spec] Browser specs Browser.version should return version", + "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should deny permission when not listed", + "testIdPattern": "[click.spec] Page.click should click with disabled javascript", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed", + "testIdPattern": "[click.spec] Page.click should click with disabled javascript", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage", + "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts", + "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should get cookies from nested path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should not get cookies from not nested path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should close all belonging targets once closing context", + "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should not get cookies from subdomain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should create new incognito context", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should fire target events", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should provide a context id", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should timeout waiting for a non-existent target", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", + "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "Not supported with cdp" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should wait for a target", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should default to setting secure cookie for HTTPS websites", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chromium-specific test. The test relies on the cookie in secure context to be secure. This is not the case for Firefox." }, { - "testIdPattern": "[browsercontext.spec] BrowserContext should work across sessions", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should isolate cookies in browser contexts", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[browsercontext.spec] BrowserContext window.open should use parent tab context", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie on a different domain", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should be able to detach session", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookie with reasonable defaults", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should enable and disable domains independently", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should respect custom timeout", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should throw nice errors", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set secure same-site cookies from a frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chromium-specific test. The test relies on the cookie in secure context to be secure. This is not the case for Firefox." }, { - "testIdPattern": "[CDPSession.spec] Target.createCDPSession should work", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should be able to connect using browserUrl, with and without trailing slash", + "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click on checkbox input and toggle", + "testIdPattern": "[debugInfo.spec] DebugInfo Browser.debugInfo should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.cookies() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "https://github.com/puppeteer/puppeteer/issues/12010" }, { - "testIdPattern": "[click.spec] Page.click should click the button if window.Node is removed", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button inside an iframe", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click the button with deviceScaleFactor set", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1884648" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[device-request-prompt.spec] device request prompt does not crash", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe", + "testIdPattern": "[drag-and-drop.spec] Drag n' Drop should drag and drop", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click with disabled javascript", + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should click with disabled javascript", + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work with svg elements", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should double click the button", + "testIdPattern": "[emulation.spec] Emulation Page.emulate should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript", + "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[click.spec] Page.click should select the text by triple clicking", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.cookies should get cookies from multiple urls", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should work", + "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should default to setting secure cookie for HTTPS websites", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should isolate cookies in browser contexts", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie on a different domain", + "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set a cookie with a path", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookie with reasonable defaults", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set cookies from a frame", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set multiple cookies", + "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should set secure same-site cookies from a frame", + "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should work", + "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[coverage.spec] Coverage specs CSSCoverage should work with complicated usecases", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should be detectable by Modernizr", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[coverage.spec] Coverage specs JSCoverage should not ignore eval() scripts if reportAnonymousScripts is true", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should detect touch when applying viewport with touches", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.cookies() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should load correct pictures when emulation dpr", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.setCookie() should work", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should support touch emulation", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[dialog.spec] Page.Events.Dialog should allow accepting prompts", + "testIdPattern": "[emulation.spec] Emulation Page.viewport should update media queries when resoltion changes", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[drag-and-drop.spec] Drag n' Drop should drag and drop", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw when evaluation triggers reload", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boundingBox should handle nested frames", + "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.boxModel should work", + "testIdPattern": "[extensions.spec] extensions background_page target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", + "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should return Point data", + "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes", + "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes", + "testIdPattern": "[fixtures.spec] Fixtures should close the browser when the node process closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.contentFrame should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should click elements in a frameset", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "New test for framesets (does not seem to pass in Firefox CDP)." }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work with svg elements", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame from-inside shadow DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateCPUThrottling should change the CPU throttling rate successfully", + "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should throw in case of bad argument", + "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should work", + "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should throw in case of bad argument", + "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateMediaType should work", + "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", + "testIdPattern": "[frame.spec] Frame specs Frame.executionContext should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateNetworkConditions should change navigator.connection.effectiveType", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should throw for invalid timezone IDs", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateTimezone should work", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should throw for invalid vision deficiencies", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should be |null| for non-secure requests", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.emulateVisionDeficiency should work", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should be |null| for non-secure requests", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should detect touch when applying viewport with touches", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should get the proper viewport size", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support landscape emulation", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[emulation.spec] Emulation Page.viewport should support touch emulation", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Frame.evaluate should have different execution contexts", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should await promise", + "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture", + "testIdPattern": "[input.spec] input tests FileChooser.accept should accept single file", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames", + "testIdPattern": "[input.spec] input tests FileChooser.accept should accept single file", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to read selected file", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw when evaluation triggers reload", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to read selected file", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to reset selected files with empty file list", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions background_page target type should be available", + "testIdPattern": "[input.spec] input tests FileChooser.accept should be able to reset selected files with empty file list", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", + "testIdPattern": "[input.spec] input tests FileChooser.accept should error on read of non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", + "testIdPattern": "[input.spec] input tests FileChooser.accept should error on read of non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", + "testIdPattern": "[input.spec] input tests FileChooser.accept should fail when accepting file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[fixtures.spec] Fixtures should close the browser when the node process closes", + "testIdPattern": "[input.spec] input tests FileChooser.accept should fail when accepting file chooser twice", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should detach child frames on navigation", + "testIdPattern": "[input.spec] input tests FileChooser.accept should not accept multiple files for single-file input", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests FileChooser.accept should not accept multiple files for single-file input", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", + "testIdPattern": "[input.spec] input tests FileChooser.accept should succeed even for non-existent files", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report different frame instance when frame re-attaches", + "testIdPattern": "[input.spec] input tests FileChooser.accept should succeed even for non-existent files", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame from-inside shadow DOM", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should cancel dialog", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.name()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should cancel dialog", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should fail when canceling file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should report frame.parent()", + "testIdPattern": "[input.spec] input tests FileChooser.cancel should fail when canceling file chooser twice", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"multiple\"", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should send events when frames are manipulated dynamically", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"multiple\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"webkitdirectory\"", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support framesets", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for \"webkitdirectory\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for single file pick", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame Management should support lazy frames", + "testIdPattern": "[input.spec] input tests FileChooser.isMultiple should work for single file pick", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should prioritize exact timeout over default timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.evaluate should throw for detached frames", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should prioritize exact timeout over default timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[frame.spec] Frame specs Frame.executionContext should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect default timeout when there is no custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect default timeout when there is no custom timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should respect timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should return the same file chooser when there are many watchdogs simultaneously", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should return the same file chooser when there are many watchdogs simultaneously", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is not attached to DOM", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work when file input is not attached to DOM", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with mixed content", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work with no timeout", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors should work with request interception", + "testIdPattern": "[input.spec] input tests Page.waitForFileChooser should work with no timeout", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard ElementHandle.press should not support |text| option", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should report shiftKey", "platforms": ["darwin"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should send a character with sendCharacter in iframe", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should specify location", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should specify repeat property", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type all kinds of characters", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type emoji", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[keyboard.spec] Keyboard should type emoji into an iframe", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[keyboard.spec] Keyboard should type emoji into an iframe", + "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Browser target events should work", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.close should terminate network waiters", + "testIdPattern": "[launcher.spec] Launcher specs Browser.Events.disconnected should be emitted when: browser gets closed, disconnected or underlying websocket gets closed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.close should terminate network waiters", "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", + "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "https://github.com/puppeteer/puppeteer/issues/11849" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to close remote browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect multiple times to the same browser", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "chrome"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath should work", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option in puppeteer.launch", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option in puppeteer.launch", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch can launch and close the browser", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should be able to launch Firefox", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "headless"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should close browser with beforeunload page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should filter out ignored default argument in Firefox", "platforms": ["linux"], "parameters": ["firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should filter out ignored default arguments in Chrome", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should have custom URL when launching browser", + "platforms": ["darwin"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "For some reason it times out on MacOS. Perhaps it's a bug in chromium-bidi" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir option should restore cookies", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF", + "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[locator.spec] Locator Locator.race races multiple locators", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should send mouse wheel events", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[mouse.spec] Mouse should trigger hover state with removed window.Node", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.goto should navigate subframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should reject when frame detaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.goto should return matching responses", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should fail when frame detaches", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation should work", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goBack should work with HistoryAPI", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[navigation.spec] navigation Page.goto should fail when main resources failed to load", + "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should fail when server returns 204", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to dataURL and fire dataURL requests", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle0", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to empty page with networkidle2", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to page with iframe and networkidle0", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should not leak listeners during navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should not leak listeners during navigation of 11 pages", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should return response when page changes its URL after load", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should send referer", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should wait for network idle to succeed navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to data url", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when navigating to data url", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work when page calls history API in beforeunload", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[navigation.spec] navigation Page.goto should work with anchor navigation", - "platforms": ["linux"], - "parameters": ["chrome", "headless"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["FAIL"], + "comment": "History navigation is breaking the Puppeteer expecation about navigation." }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work with anchor navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "headless"], - "expectations": ["PASS", "TIMEOUT"] + "parameters": ["chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.goto should work with subframes return 204", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work when subframe issues window.stop()", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with DOM history.back()/history.forward()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.pushState()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "https://github.com/puppeteer/puppeteer/issues/11854" }, { "testIdPattern": "[navigation.spec] navigation Page.waitForNavigation should work with history.replaceState()", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFailed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestFinished", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestServedFromCache", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.RequestServedFromCache", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Response", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should fire events in proper order", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should fire events in proper order", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should support redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events should support redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should allow disable authentication", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should fail if wrong credentials", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should not disable caching", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.authenticate should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network Page.Events.Request should fire for iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network Page.Events.Request should fire for iframes", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation", + "testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", - "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[network.spec] network Request.frame should work for subframe navigation request", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[network.spec] network Request.frame should work for subframe navigation request", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.initiator should return the initiator", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.isNavigationRequest should work with request interception", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Request.postData should work with blobs", @@ -2706,529 +2843,561 @@ "testIdPattern": "[network.spec] network Response.buffer should throw if the response does not have a body", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[network.spec] network Response.buffer should throw if the response does not have a body", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.buffer should work with compression", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "Needs investigation, it looks like a bug in Puppeteer" }, { "testIdPattern": "[network.spec] network Response.fromCache should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.fromServiceWorker Response.fromServiceWorker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[network.spec] network Response.headers should work", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.json should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should return uncompressed text", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should throw when requesting body of redirected response", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should wait until response completes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should wait until response completes", "platforms": ["win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.text should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Response.timing returns timing information", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", + "testIdPattern": "[oopif.spec] OOPIF should detect existing OOPIFs when Puppeteer connects to an existing page", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should expose events within OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should expose events within OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should keep track of a frames OOP state", "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Failed previously and currently times out" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should load oopif iframes with subresources and request interception", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should load oopif iframes with subresources and request interception", + "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should report google.com frame", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF should provide access to elements", + "testIdPattern": "[oopif.spec] OOPIF should report google.com frame", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL"], + "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=187816" }, { - "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes becoming normal iframes again", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[oopif.spec] OOPIF should support lazy OOP frames", + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes becoming normal iframes again", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes getting detached", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support OOP iframes getting detached", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should support wait for navigation for transitions from local to OOPIF", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should wait for inner OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[oopif.spec] OOPIF should wait for inner OOPIFs", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "Chrome-specific test (uses DNS mapping); does not work with Firefox." }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.addScriptTag should throw when added with content to the CSP page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.client should return the client instance", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should reject all promises when page is closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should run beforeunload if asked for", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.close should terminate network waiters", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location and stack trace for console API calls", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should have location when fetch fails", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should not fail for window object", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should trigger correct Log", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with logging functions", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Console should work for different console API calls with timing functions", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.error should throw when page crashes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and rel=noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and with rel=opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with clicking target=_blank and without rel=opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with fake-clicking target=_blank and rel=noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.Events.Popup should work with noopener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[page.spec] Page Page.exposeFunction should be callable from-inside evaluateOnNewDocument", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.metrics metrics event fired on console.timeStamp", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.metrics should get metrics from a page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.pdf can print to PDF with accessible", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.removeExposedFunction should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.select should work when re-defining top-level Event class", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass after cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass after cross-process navigation", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP header", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP header", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP in iframes as well", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP in iframes as well", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP meta tag", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[page.spec] Page Page.setBypassCSP should bypass CSP meta tag", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should enable or disable the cache based on the state passed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should enable or disable the cache based on the state passed", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setCacheEnabled should stay disabled when toggling request interception on/off", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setGeolocation should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", + "testIdPattern": "[page.spec] Page Page.setGeolocation should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setJavaScriptEnabled should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setOfflineMode should emulate navigator.onLine", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setOfflineMode should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.setUserAgent should work with additional userAgentMetdata", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[prerender.spec] Prerender can navigate to a prerendered page via Puppeteer", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender can screencast", + "testIdPattern": "[pdf.spec] Page.pdf can print to PDF with outline", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "headful"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[prerender.spec] Prerender via frame can navigate to a prerendered page via Puppeteer", + "testIdPattern": "[pdf.spec] Page.pdf can print to PDF with outline", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "headless"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at browser level", + "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: investigate" }, { "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "Windows version of Chrome has a long-standing bug" }, { "testIdPattern": "[proxy.spec] request proxy in incognito browser context should proxy requests when configured at context level", "platforms": ["linux"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at browser level", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy in incognito browser context should respect proxy bypass list when configured at context level", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should proxy requests when configured", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[proxy.spec] request proxy should respect proxy bypass list", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "TIMEOUT"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[queryObjects.spec] page.queryObjects should fail for disposed handles", @@ -3246,469 +3415,524 @@ "testIdPattern": "[queryObjects.spec] page.queryObjects should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[queryObjects.spec] page.queryObjects should work for non-trivial page", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception \"after each\" hook in \"request interception\"", "platforms": ["win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should load fonts if cache enabled", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["PASS", "TIMEOUT"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception-experimental.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should navigate to URL with hash and fire requests without hash", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots Cdp should use scale for clip", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should capture full element when larger than viewport", - "platforms": ["win32"], + "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", + "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" + }, + { + "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should clip clip bigger than the viewport without \"captureBeyondViewport\"", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[stacktrace.spec] Stack trace should work for none error objects", + "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.targets should return all of the targets", + "testIdPattern": "[stacktrace.spec] Stack trace should work for none error objects", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], + "parameters": ["cdp", "firefox"], "expectations": ["PASS"] }, { "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target Browser.waitForTarget should wait for a target", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[target.spec] Target should be able to use async waitForTarget", + "testIdPattern": "[target.spec] Target should close a shared worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "not supported" }, { - "testIdPattern": "[target.spec] Target should contain browser target", + "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should create a worker from a shared worker", + "testIdPattern": "[target.spec] Target should create a worker from a service worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should have an opener", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] - }, - { - "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should not report uninitialized pages", + "testIdPattern": "[target.spec] Target should create a worker from a shared worker", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a new page is created and closed", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[target.spec] Target should have an opener", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[target.spec] Target should report when a target url changes", + "testIdPattern": "[target.spec] Target should not crash while redirecting if original request was missed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", + "testIdPattern": "[target.spec] Target should not report uninitialized pages", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome"], - "expectations": ["FAIL"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", + "testIdPattern": "[target.spec] Target should not report uninitialized pages", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", + "testIdPattern": "[target.spec] Target should report when a new page is created and closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive navigations", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work when resolved right before execution context disposal", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", + "testIdPattern": "[target.spec] Target should report when a service worker is created and destroyed", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", + "testIdPattern": "[target.spec] Target should report when a target url changes", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", + "testIdPattern": "[TargetManager.spec] TargetManager should handle targets", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.tap should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.tap should work", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[touchscreen.spec] Touchscreen Touchscreen.prototype.touchMove should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["TIMEOUT"] + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["FAIL", "PASS", "TIMEOUT"] + "parameters": ["cdp", "firefox"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work when resolved right before execution context disposal", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["FAIL", "PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForFunction should work with strict CSP policy", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should work with removed MutationObserver", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector Page.waitForSelector is shortcut for main frame", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should run in specified frame", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should run in specified frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should run in specified frame", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[waittask.spec] waittask specs Frame.waitForXPath should throw when frame is detached", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should survive cross-process navigation", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report console logs", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should throw when frame is detached", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report console logs", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector should work with removed MutationObserver", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector xpath should run in specified frame", "platforms": ["darwin", "linux", "win32"], - "parameters": ["firefox", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[waittask.spec] waittask specs Frame.waitForSelector xpath should throw when frame is detached", "platforms": ["darwin", "linux", "win32"], - "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "parameters": ["cdp", "firefox"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[worker.spec] Workers should report errors", + "testIdPattern": "[worker.spec] Workers can be closed", "platforms": ["darwin", "linux", "win32"], "parameters": ["chrome", "webDriverBiDi"], - "expectations": ["PASS"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", "platforms": ["win32"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |pipe| option should fire \"disconnected\" when closing with pipe", - "platforms": ["darwin"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL"], - "comment": "Remove with M121" + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should expose DevTools as a page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools should open devtools when \"devtools: true\" option is given", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if asPage is used", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[devtools.spec] DevTools target.page() should return a DevTools page if custom isPageTarget is provided", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions background_page target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions service_worker target type should be available", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[extensions.spec] extensions target.page() should return a background_page", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir option restores preferences", "platforms": ["win32"], "parameters": ["firefox", "headless", "webDriverBiDi"], - "expectations": ["SKIP"] + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network Network Events Page.Events.Request", "platforms": ["linux"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie subresource", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[page.spec] Page Page.bringToFront should work", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["SKIP"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should be abortable", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["win32"], - "parameters": ["cdp", "chrome", "new-headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "headless"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[requestinterception.spec] request interception Page.setRequestInterception should work with redirects", "platforms": ["win32"], "parameters": ["cdp", "chrome", "headful"], - "expectations": ["FAIL", "PASS"] - }, - { - "testIdPattern": "[screenshot.spec] Screenshots Cdp should work in \"fromSurface: false\" mode", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "headless"], - "expectations": ["SKIP"] + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work for an element with an offset", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { "testIdPattern": "[screenshot.spec] Screenshots ElementHandle.screenshot should work with a rotated element", "platforms": ["darwin", "linux", "win32"], "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] - }, - { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox", "headful"], - "expectations": ["FAIL"] + "expectations": ["FAIL"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" }, { - "testIdPattern": "[screenshot.spec] Screenshots Page.screenshot should take fullPage screenshots", + "testIdPattern": "[target.spec] Target should close a service worker", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "firefox", "headless"], - "expectations": ["FAIL"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["SKIP"], + "comment": "For some reason service_workers do not close in chrome-headless-shell" }, { "testIdPattern": "[worker.spec] Workers Page.workers", "platforms": ["darwin", "linux", "win32"], - "parameters": ["cdp", "chrome", "headless"], - "expectations": ["FAIL", "PASS"] + "parameters": ["cdp", "chrome", "chrome-headless-shell"], + "expectations": ["FAIL", "PASS"], + "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)" } ] diff --git a/remote/test/puppeteer/test/TestSuites.json b/remote/test/puppeteer/test/TestSuites.json index 32adc45d3c..3c36f8d7a4 100644 --- a/remote/test/puppeteer/test/TestSuites.json +++ b/remote/test/puppeteer/test/TestSuites.json @@ -13,9 +13,9 @@ "expectedLineCoverage": 93 }, { - "id": "chrome-new-headless", + "id": "chrome-headless-shell", "platforms": ["linux"], - "parameters": ["chrome", "new-headless", "cdp"], + "parameters": ["chrome", "chrome-headless-shell", "cdp"], "expectedLineCoverage": 93 }, { @@ -45,7 +45,7 @@ { "id": "chrome-bidi", "platforms": ["linux"], - "parameters": ["chrome", "headless", "webDriverBiDi"], + "parameters": ["chrome", "chrome-headless-shell", "webDriverBiDi"], "expectedLineCoverage": 56 } ], @@ -63,8 +63,8 @@ "headful": { "HEADLESS": "false" }, - "new-headless": { - "HEADLESS": "new" + "chrome-headless-shell": { + "HEADLESS": "shell" }, "webDriverBiDi": { "PUPPETEER_PROTOCOL": "webDriverBiDi" diff --git a/remote/test/puppeteer/test/assets/abort-request.html b/remote/test/puppeteer/test/assets/abort-request.html index 77c056a422..2977efa36f 100644 --- a/remote/test/puppeteer/test/assets/abort-request.html +++ b/remote/test/puppeteer/test/assets/abort-request.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <button id="abort"></button> <script> diff --git a/remote/test/puppeteer/test/assets/beforeunload.html b/remote/test/puppeteer/test/assets/beforeunload.html index 3cef6763f3..e6502a9ee1 100644 --- a/remote/test/puppeteer/test/assets/beforeunload.html +++ b/remote/test/puppeteer/test/assets/beforeunload.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <div>beforeunload demo.</div> <script> window.addEventListener('beforeunload', event => { diff --git a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html index 857914bb6d..ce1fd52cff 100644 --- a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html +++ b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe-container.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <body>BFCached<a href="target.html">next</a></body> <script> window.addEventListener('DOMContentLoaded', () => { diff --git a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html index 9233f557c5..b98b0a1ef8 100644 --- a/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html +++ b/remote/test/puppeteer/test/assets/cached/bfcache/worker-iframe.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> const worker = new Worker('worker.mjs', {type: 'module'}) </script> diff --git a/remote/test/puppeteer/test/assets/cached/one-style-font.html b/remote/test/puppeteer/test/assets/cached/one-style-font.html index 8e7236dfb3..4afa507291 100644 --- a/remote/test/puppeteer/test/assets/cached/one-style-font.html +++ b/remote/test/puppeteer/test/assets/cached/one-style-font.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style-font.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/cached/one-style.html b/remote/test/puppeteer/test/assets/cached/one-style.html index 4760f2b9f7..b3a6eeeebe 100644 --- a/remote/test/puppeteer/test/assets/cached/one-style.html +++ b/remote/test/puppeteer/test/assets/cached/one-style.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/csp.html b/remote/test/puppeteer/test/assets/csp.html index 34fc1fc1a5..4789cc21d3 100644 --- a/remote/test/puppeteer/test/assets/csp.html +++ b/remote/test/puppeteer/test/assets/csp.html @@ -1 +1,2 @@ +<!DOCTYPE html> <meta http-equiv="Content-Security-Policy" content="default-src 'self'"> diff --git a/remote/test/puppeteer/test/assets/csscoverage/empty.html b/remote/test/puppeteer/test/assets/csscoverage/empty.html index b3845c366d..eef2af1807 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/empty.html +++ b/remote/test/puppeteer/test/assets/csscoverage/empty.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style></style> <div>empty style tag</div> diff --git a/remote/test/puppeteer/test/assets/csscoverage/involved.html b/remote/test/puppeteer/test/assets/csscoverage/involved.html index bcd9845b93..4b944ae7a8 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/involved.html +++ b/remote/test/puppeteer/test/assets/csscoverage/involved.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @charset "utf-8"; @namespace svg url(http://www.w3.org/2000/svg); diff --git a/remote/test/puppeteer/test/assets/csscoverage/media.html b/remote/test/puppeteer/test/assets/csscoverage/media.html index bfb89f8f75..57af00e2f6 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/media.html +++ b/remote/test/puppeteer/test/assets/csscoverage/media.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @media screen { div { color: green; } } </style> <div>hello, world</div> diff --git a/remote/test/puppeteer/test/assets/csscoverage/multiple.html b/remote/test/puppeteer/test/assets/csscoverage/multiple.html index 0fd97e962a..a1d57415f9 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/multiple.html +++ b/remote/test/puppeteer/test/assets/csscoverage/multiple.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <link rel="stylesheet" href="stylesheet1.css"> <link rel="stylesheet" href="stylesheet2.css"> <script> diff --git a/remote/test/puppeteer/test/assets/csscoverage/simple.html b/remote/test/puppeteer/test/assets/csscoverage/simple.html index 3beae21829..f51dd11ac9 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/simple.html +++ b/remote/test/puppeteer/test/assets/csscoverage/simple.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> div { color: green; } a { color: blue; } diff --git a/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html b/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html index df4e9c276c..592019fe1a 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html +++ b/remote/test/puppeteer/test/assets/csscoverage/sourceurl.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> body { padding: 10px; diff --git a/remote/test/puppeteer/test/assets/csscoverage/unused.html b/remote/test/puppeteer/test/assets/csscoverage/unused.html index 5b8186a3bf..2e8706cc31 100644 --- a/remote/test/puppeteer/test/assets/csscoverage/unused.html +++ b/remote/test/puppeteer/test/assets/csscoverage/unused.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> @media screen { a { color: green; } diff --git a/remote/test/puppeteer/test/assets/dynamic-oopif.html b/remote/test/puppeteer/test/assets/dynamic-oopif.html index 38614d0289..dbe93a9923 100644 --- a/remote/test/puppeteer/test/assets/dynamic-oopif.html +++ b/remote/test/puppeteer/test/assets/dynamic-oopif.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/empty.html b/remote/test/puppeteer/test/assets/empty.html index e69de29bb2..763b0739be 100644 --- a/remote/test/puppeteer/test/assets/empty.html +++ b/remote/test/puppeteer/test/assets/empty.html @@ -0,0 +1 @@ +<!DOCTYPE html>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/error.html b/remote/test/puppeteer/test/assets/error.html index 130400c006..6929791e11 100644 --- a/remote/test/puppeteer/test/assets/error.html +++ b/remote/test/puppeteer/test/assets/error.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> a(); diff --git a/remote/test/puppeteer/test/assets/frames/frame.html b/remote/test/puppeteer/test/assets/frames/frame.html index 8f20d2da9f..29e7426dbc 100644 --- a/remote/test/puppeteer/test/assets/frames/frame.html +++ b/remote/test/puppeteer/test/assets/frames/frame.html @@ -1,8 +1,11 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./style.css'> <script src='./script.js' type='text/javascript'></script> <style> div { line-height: 18px; + width: 300px; + box-sizing: border-box; } </style> <div>Hi, I'm frame</div> diff --git a/remote/test/puppeteer/test/assets/frames/frameset.html b/remote/test/puppeteer/test/assets/frames/frameset.html index 4d56f88839..7ef2faaa8d 100644 --- a/remote/test/puppeteer/test/assets/frames/frameset.html +++ b/remote/test/puppeteer/test/assets/frames/frameset.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <frameset> <frameset> <frame src='./frame.html'></frame> diff --git a/remote/test/puppeteer/test/assets/frames/lazy-frame.html b/remote/test/puppeteer/test/assets/frames/lazy-frame.html index 4821cd76cd..45f9be020b 100644 --- a/remote/test/puppeteer/test/assets/frames/lazy-frame.html +++ b/remote/test/puppeteer/test/assets/frames/lazy-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <iframe width="100%" height="300" src="about:blank"></iframe> <div style="height: 800vh"></div> <iframe width="100%" height="300" src='./frame.html' loading="lazy"></iframe>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/frames/nested-frames.html b/remote/test/puppeteer/test/assets/frames/nested-frames.html index e9c5d83c03..331462afe8 100644 --- a/remote/test/puppeteer/test/assets/frames/nested-frames.html +++ b/remote/test/puppeteer/test/assets/frames/nested-frames.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> :root { scrollbar-width: none; diff --git a/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html b/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html index d1462641ff..bc2266ad78 100644 --- a/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html +++ b/remote/test/puppeteer/test/assets/frames/one-frame-url-fragment.html @@ -1 +1,2 @@ +<!DOCTYPE html> <iframe src='./frame.html?param=value#fragment'></iframe> diff --git a/remote/test/puppeteer/test/assets/frames/one-frame.html b/remote/test/puppeteer/test/assets/frames/one-frame.html index e941d795a2..d520733f5c 100644 --- a/remote/test/puppeteer/test/assets/frames/one-frame.html +++ b/remote/test/puppeteer/test/assets/frames/one-frame.html @@ -1 +1,2 @@ +<!DOCTYPE html> <iframe src='./frame.html'></iframe> diff --git a/remote/test/puppeteer/test/assets/frames/two-frames.html b/remote/test/puppeteer/test/assets/frames/two-frames.html index b2ee853eda..9c7a6cbca1 100644 --- a/remote/test/puppeteer/test/assets/frames/two-frames.html +++ b/remote/test/puppeteer/test/assets/frames/two-frames.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> body { display: flex; diff --git a/remote/test/puppeteer/test/assets/global-var.html b/remote/test/puppeteer/test/assets/global-var.html index b6be975038..37ab45f9c3 100644 --- a/remote/test/puppeteer/test/assets/global-var.html +++ b/remote/test/puppeteer/test/assets/global-var.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> var globalVar = 123; </script>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/grid.html b/remote/test/puppeteer/test/assets/grid.html index 437193573d..f5d4ea6d60 100644 --- a/remote/test/puppeteer/test/assets/grid.html +++ b/remote/test/puppeteer/test/assets/grid.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> document.addEventListener('DOMContentLoaded', function() { function generatePalette(amount) { diff --git a/remote/test/puppeteer/test/assets/historyapi.html b/remote/test/puppeteer/test/assets/historyapi.html index bacaf9e9a0..cea5cbdab1 100644 --- a/remote/test/puppeteer/test/assets/historyapi.html +++ b/remote/test/puppeteer/test/assets/historyapi.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { history.pushState({}, '', '#1'); diff --git a/remote/test/puppeteer/test/assets/initiator.html b/remote/test/puppeteer/test/assets/initiator.html index 12889d3242..df88f5e954 100644 --- a/remote/test/puppeteer/test/assets/initiator.html +++ b/remote/test/puppeteer/test/assets/initiator.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <iframe src="./frames/frame.html"></iframe> <script src="./initiator.js"></script> diff --git a/remote/test/puppeteer/test/assets/inner-frame1.html b/remote/test/puppeteer/test/assets/inner-frame1.html index 00f19ec166..becdb4a466 100644 --- a/remote/test/puppeteer/test/assets/inner-frame1.html +++ b/remote/test/puppeteer/test/assets/inner-frame1.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/inner-frame2.html b/remote/test/puppeteer/test/assets/inner-frame2.html index 9a236cc48f..39dcf4c25c 100644 --- a/remote/test/puppeteer/test/assets/inner-frame2.html +++ b/remote/test/puppeteer/test/assets/inner-frame2.html @@ -1 +1,2 @@ +<!DOCTYPE html> <button>click</button> diff --git a/remote/test/puppeteer/test/assets/input/touchscreen.html b/remote/test/puppeteer/test/assets/input/touchscreen.html index 76e31c97f9..b3a51e7f91 100644 --- a/remote/test/puppeteer/test/assets/input/touchscreen.html +++ b/remote/test/puppeteer/test/assets/input/touchscreen.html @@ -1,10 +1,10 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <title>Touch test</title> </head> - <body> + <body style="touch-action: none"> <style> button { box-sizing: border-box; @@ -20,103 +20,53 @@ <button>Click target</button> <script> var allEvents = []; - globalThis.addEventListener( - "touchstart", - (event) => { - allEvents.push({ - type: "touchstart", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]), - }); - }, - true, - ); - globalThis.addEventListener( - "touchmove", - (event) => { - allEvents.push({ - type: "touchmove", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]), - }); - }, - true, - ); - globalThis.addEventListener( - "touchend", - (event) => { - allEvents.push({ - type: "touchend", - touches: [...event.changedTouches].map((touch) => [ - touch.clientX, - touch.clientY, - touch.radiusX, - touch.radiusY, - ]) - }); - }, - true, - ); - globalThis.addEventListener( - "pointerdown", - (event) => { - allEvents.push({ - type: "pointerdown", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "pointermove", - (event) => { - allEvents.push({ - type: "pointermove", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "pointerup", - (event) => { - allEvents.push({ - type: "pointerup", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); - globalThis.addEventListener( - "click", - (event) => { - allEvents.push({ - type: "click", - x: event.x, - y: event.y, - width: event.width, - height: event.height, - }); - }, - true, - ); + for (const name of ["touchstart", "touchmove", "touchend"]) { + globalThis.addEventListener( + name, + (event) => { + allEvents.push({ + type: name, + changedTouches: [...event.changedTouches].map((touch) => ({ + clientX: touch.clientX, + clientY: touch.clientY, + radiusX: touch.radiusX, + radiusY: touch.radiusY, + force: touch.force, + })), + activeTouches: [...event.touches].map((touch) => ({ + clientX: touch.clientX, + clientY: touch.clientY, + radiusX: touch.radiusX, + radiusY: touch.radiusY, + force: touch.force, + })), + }); + }, + true, + ); + } + for (const name of ['pointerdown', 'pointermove', 'pointerup', 'click']) { + globalThis.addEventListener( + name, + (event) => { + allEvents.push({ + type: name, + x: event.x, + y: event.y, + width: event.width, + height: event.height, + altitudeAngle: event.altitudeAngle, + azimuthAngle: event.azimuthAngle, + pressure: event.pressure, + pointerType: event.pointerType, + twist: event.twist, + tiltX: event.tiltX, + tiltY: event.tiltY, + }); + }, + true, + ); + } </script> </body> </html> diff --git a/remote/test/puppeteer/test/assets/jscoverage/eval.html b/remote/test/puppeteer/test/assets/jscoverage/eval.html index 838ae28763..dadc7d7b02 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/eval.html +++ b/remote/test/puppeteer/test/assets/jscoverage/eval.html @@ -1 +1,2 @@ +<!DOCTYPE html> <script>eval('console.log("foo")')</script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/involved.html b/remote/test/puppeteer/test/assets/jscoverage/involved.html index fcc32ba2ca..c900801860 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/involved.html +++ b/remote/test/puppeteer/test/assets/jscoverage/involved.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> function foo() { if (1 > 2) diff --git a/remote/test/puppeteer/test/assets/jscoverage/multiple.html b/remote/test/puppeteer/test/assets/jscoverage/multiple.html index bdef59885b..683e10b99d 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/multiple.html +++ b/remote/test/puppeteer/test/assets/jscoverage/multiple.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script src='script1.js'></script> <script src='script2.js'></script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/ranges.html b/remote/test/puppeteer/test/assets/jscoverage/ranges.html index 3d02670aea..2535e740d7 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/ranges.html +++ b/remote/test/puppeteer/test/assets/jscoverage/ranges.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script> function unused(){}console.log('used!');if(true===false)console.log('unused!');</script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/simple.html b/remote/test/puppeteer/test/assets/jscoverage/simple.html index 49eeeea6ae..9694f57d3e 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/simple.html +++ b/remote/test/puppeteer/test/assets/jscoverage/simple.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <script> function foo() {function bar() { } console.log(1); } foo(); </script> diff --git a/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html b/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html index e477750320..c3c5251ad3 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html +++ b/remote/test/puppeteer/test/assets/jscoverage/sourceurl.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> console.log(1); //# sourceURL=nicename.js diff --git a/remote/test/puppeteer/test/assets/jscoverage/unused.html b/remote/test/puppeteer/test/assets/jscoverage/unused.html index 59c4a5a70b..80db364242 100644 --- a/remote/test/puppeteer/test/assets/jscoverage/unused.html +++ b/remote/test/puppeteer/test/assets/jscoverage/unused.html @@ -1 +1,2 @@ +<!DOCTYPE html> <script>function foo() { }</script> diff --git a/remote/test/puppeteer/test/assets/lazy-oopif-frame.html b/remote/test/puppeteer/test/assets/lazy-oopif-frame.html index 83a420d029..71d00a3f72 100644 --- a/remote/test/puppeteer/test/assets/lazy-oopif-frame.html +++ b/remote/test/puppeteer/test/assets/lazy-oopif-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <iframe width="100%" height="300" src="about:blank"></iframe> <div style="height: 800vh"></div> <iframe width="100%" height="300" src="https://www.example.com" loading="lazy"></iframe> diff --git a/remote/test/puppeteer/test/assets/main-frame.html b/remote/test/puppeteer/test/assets/main-frame.html index 0c50feff85..ce223b5c2a 100644 --- a/remote/test/puppeteer/test/assets/main-frame.html +++ b/remote/test/puppeteer/test/assets/main-frame.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); diff --git a/remote/test/puppeteer/test/assets/mobile.html b/remote/test/puppeteer/test/assets/mobile.html index 8e94b2fe29..427cf74aa5 100644 --- a/remote/test/puppeteer/test/assets/mobile.html +++ b/remote/test/puppeteer/test/assets/mobile.html @@ -1 +1,2 @@ +<!DOCTYPE html> <meta name = "viewport" content = "initial-scale = 1, user-scalable = no"> diff --git a/remote/test/puppeteer/test/assets/networkidle.html b/remote/test/puppeteer/test/assets/networkidle.html index 910ae1736d..cbe0e153d0 100644 --- a/remote/test/puppeteer/test/assets/networkidle.html +++ b/remote/test/puppeteer/test/assets/networkidle.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> async function sleep(delay) { return new Promise(resolve => setTimeout(resolve, delay)); diff --git a/remote/test/puppeteer/test/assets/one-style.html b/remote/test/puppeteer/test/assets/one-style.html index 4760f2b9f7..b3a6eeeebe 100644 --- a/remote/test/puppeteer/test/assets/one-style.html +++ b/remote/test/puppeteer/test/assets/one-style.html @@ -1,2 +1,3 @@ +<!DOCTYPE html> <link rel='stylesheet' href='./one-style.css'> <div>hello, world!</div> diff --git a/remote/test/puppeteer/test/assets/oopif.html b/remote/test/puppeteer/test/assets/oopif.html index f04b9127af..39e35eea96 100644 --- a/remote/test/puppeteer/test/assets/oopif.html +++ b/remote/test/puppeteer/test/assets/oopif.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <a id="navigate-within-document" href="#nav">Navigate within document</a> <a name="nav"></a> <script> diff --git a/remote/test/puppeteer/test/assets/p-selectors.html b/remote/test/puppeteer/test/assets/p-selectors.html index 24900623d8..e442a53d88 100644 --- a/remote/test/puppeteer/test/assets/p-selectors.html +++ b/remote/test/puppeteer/test/assets/p-selectors.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <div id="a">hello <button id="b">world</button> <span id="f"></span> <div id="c"></div> diff --git a/remote/test/puppeteer/test/assets/pdf.html b/remote/test/puppeteer/test/assets/pdf.html index 987df27ebe..ef046e3d36 100644 --- a/remote/test/puppeteer/test/assets/pdf.html +++ b/remote/test/puppeteer/test/assets/pdf.html @@ -6,6 +6,12 @@ <title>PDF</title> </head> <body> - <div>PDF Content</div> + <h1>PDF Content</h1> + <section> + <h1>PDF Subcontent 1</h1> + </section> + <section> + <h1>PDF Subcontent 2</h1> + </section> </body> </html> diff --git a/remote/test/puppeteer/test/assets/resetcss.html b/remote/test/puppeteer/test/assets/resetcss.html index e4e04b1f8a..7e020d6ed2 100644 --- a/remote/test/puppeteer/test/assets/resetcss.html +++ b/remote/test/puppeteer/test/assets/resetcss.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 diff --git a/remote/test/puppeteer/test/assets/self-request.html b/remote/test/puppeteer/test/assets/self-request.html index 88aff620ff..682c326412 100644 --- a/remote/test/puppeteer/test/assets/self-request.html +++ b/remote/test/puppeteer/test/assets/self-request.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> var req = new XMLHttpRequest(); req.open('GET', '/self-request.html'); diff --git a/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html b/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html index bef85d985b..21e9d5dbd4 100644 --- a/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html +++ b/remote/test/puppeteer/test/assets/serviceworkers/empty/sw.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.registrationPromise = navigator.serviceWorker.register('sw.js'); </script> diff --git a/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html b/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html index a9d28acb09..c9a918c2d9 100644 --- a/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html +++ b/remote/test/puppeteer/test/assets/serviceworkers/fetch/sw.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <link rel="stylesheet" href="./style.css"> <script> window.registrationPromise = navigator.serviceWorker.register('sw.js'); diff --git a/remote/test/puppeteer/test/assets/shadow.html b/remote/test/puppeteer/test/assets/shadow.html index 3796ca768c..cd64eb0faf 100644 --- a/remote/test/puppeteer/test/assets/shadow.html +++ b/remote/test/puppeteer/test/assets/shadow.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> let h1 = null; diff --git a/remote/test/puppeteer/test/assets/tamperable.html b/remote/test/puppeteer/test/assets/tamperable.html index d027e97038..501d92c3ac 100644 --- a/remote/test/puppeteer/test/assets/tamperable.html +++ b/remote/test/puppeteer/test/assets/tamperable.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <script> window.result = window.injected; </script>
\ No newline at end of file diff --git a/remote/test/puppeteer/test/assets/title.html b/remote/test/puppeteer/test/assets/title.html index 88a86ce412..6e81f4091a 100644 --- a/remote/test/puppeteer/test/assets/title.html +++ b/remote/test/puppeteer/test/assets/title.html @@ -1 +1,2 @@ +<!DOCTYPE html> <title>Woof-Woof</title> diff --git a/remote/test/puppeteer/test/assets/wrappedlink.html b/remote/test/puppeteer/test/assets/wrappedlink.html index 429b6e9156..da2cd0da3d 100644 --- a/remote/test/puppeteer/test/assets/wrappedlink.html +++ b/remote/test/puppeteer/test/assets/wrappedlink.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <style> :root { font-family: monospace; diff --git a/remote/test/puppeteer/test/fixtures/closeme.js b/remote/test/puppeteer/test/fixtures/closeme.js index dbe798f70d..a534f9acde 100644 --- a/remote/test/puppeteer/test/fixtures/closeme.js +++ b/remote/test/puppeteer/test/fixtures/closeme.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ (async () => { const [, , puppeteerRoot, options] = process.argv; const browser = await require(puppeteerRoot).launch(JSON.parse(options)); diff --git a/remote/test/puppeteer/test/fixtures/dumpio.js b/remote/test/puppeteer/test/fixtures/dumpio.js index a16cf4d633..3df71b43b5 100644 --- a/remote/test/puppeteer/test/fixtures/dumpio.js +++ b/remote/test/puppeteer/test/fixtures/dumpio.js @@ -1,3 +1,8 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ (async () => { const [, , puppeteerRoot, options] = process.argv; const browser = await require(puppeteerRoot).launch(JSON.parse(options)); diff --git a/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json index ce77dbf8d9..fa9c8a13fd 100644 --- a/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json +++ b/remote/test/puppeteer/test/installation/assets/puppeteer/tsconfig.json @@ -2,6 +2,6 @@ "compilerOptions": { "target": "ES2022", "module": "NodeNext", - "moduleResolution": "NodeNext", - }, + "moduleResolution": "NodeNext" + } } diff --git a/remote/test/puppeteer/test/installation/package.json b/remote/test/puppeteer/test/installation/package.json index f5e804d99c..bd21ac4b0a 100644 --- a/remote/test/puppeteer/test/installation/package.json +++ b/remote/test/puppeteer/test/installation/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "build": "wireit", - "clean": "../../tools/clean.js", + "clean": "../../tools/clean.mjs", "test": "mocha" }, "wireit": { @@ -45,6 +45,6 @@ ], "dependencies": { "glob": "10.3.10", - "mocha": "10.2.0" + "mocha": "10.3.0" } } diff --git a/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts index d7b8757284..ac0a96f1d1 100644 --- a/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts +++ b/remote/test/puppeteer/test/installation/src/puppeteer.spec.ts @@ -41,31 +41,6 @@ describe('`puppeteer`', () => { // Skipping this test on Windows as windows runners are much slower. (platform() === 'win32' ? describe.skip : describe)( - '`puppeteer` with PUPPETEER_DOWNLOAD_PATH', - () => { - configureSandbox({ - dependencies: ['@puppeteer/browsers', 'puppeteer-core', 'puppeteer'], - env: cwd => { - return { - PUPPETEER_DOWNLOAD_PATH: join(cwd, '.cache', 'puppeteer'), - }; - }, - }); - - it('evaluates', async function () { - const files = await readdir(join(this.sandbox, '.cache', 'puppeteer')); - assert.equal(files.length, 2); - assert(files.includes('chrome')); - assert(files.includes('chrome-headless-shell')); - - const script = await readAsset('puppeteer', 'basic.js'); - await this.runScript(script, 'mjs'); - }); - } -); - -// Skipping this test on Windows as windows runners are much slower. -(platform() === 'win32' ? describe.skip : describe)( '`puppeteer` clears cache', () => { configureSandbox({ diff --git a/remote/test/puppeteer/test/installation/tsconfig.json b/remote/test/puppeteer/test/installation/tsconfig.json index 146127b470..f749dd8a07 100644 --- a/remote/test/puppeteer/test/installation/tsconfig.json +++ b/remote/test/puppeteer/test/installation/tsconfig.json @@ -4,7 +4,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "build", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/test/package.json b/remote/test/puppeteer/test/package.json index 6470297572..df6cc63731 100644 --- a/remote/test/puppeteer/test/package.json +++ b/remote/test/puppeteer/test/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "build": "wireit", - "clean": "../tools/clean.js" + "clean": "../tools/clean.mjs" }, "wireit": { "build": { @@ -24,7 +24,7 @@ } }, "dependencies": { - "diff": "5.1.0", + "diff": "5.2.0", "jpeg-js": "0.4.4", "pixelmatch": "5.3.0", "pngjs": "7.0.0" diff --git a/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts b/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts index 434d01426a..0ffb8ae6a5 100644 --- a/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts +++ b/remote/test/puppeteer/test/src/ariaqueryhandler.spec.ts @@ -370,9 +370,10 @@ describe('AriaQueryHandler', () => { await detachFrame(page, 'frame1'); await waitPromise; expect(waitError).toBeTruthy(); - expect(waitError.message).toContain( - 'waitForFunction failed: frame got detached.' - ); + expect(waitError.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); }); it('should survive cross-process navigation', async () => { diff --git a/remote/test/puppeteer/test/src/browser.spec.ts b/remote/test/puppeteer/test/src/browser.spec.ts index 6f21af5d9a..b8e0c8bb07 100644 --- a/remote/test/puppeteer/test/src/browser.spec.ts +++ b/remote/test/puppeteer/test/src/browser.spec.ts @@ -52,7 +52,9 @@ describe('Browser specs', function () { expect(process!.pid).toBeGreaterThan(0); }); it('should not return child_process for remote browser', async () => { - const {browser, puppeteer} = await getTestState(); + const {browser, puppeteer} = await getTestState({ + skipContextCreation: true, + }); const browserWSEndpoint = browser.wsEndpoint(); const remoteBrowser = await puppeteer.connect({ @@ -66,7 +68,9 @@ describe('Browser specs', function () { describe('Browser.isConnected', () => { it('should set the browser connected state', async () => { - const {browser, puppeteer} = await getTestState(); + const {browser, puppeteer} = await getTestState({ + skipContextCreation: true, + }); const browserWSEndpoint = browser.wsEndpoint(); const newBrowser = await puppeteer.connect({ diff --git a/remote/test/puppeteer/test/src/browsercontext.spec.ts b/remote/test/puppeteer/test/src/browsercontext.spec.ts index 9cbbda60a4..27709e90bf 100644 --- a/remote/test/puppeteer/test/src/browsercontext.spec.ts +++ b/remote/test/puppeteer/test/src/browsercontext.spec.ts @@ -18,9 +18,13 @@ describe('BrowserContext', function () { const {browser} = await getTestState({ skipContextCreation: true, }); - expect(browser.browserContexts()).toHaveLength(1); - const defaultContext = browser.browserContexts()[0]!; - expect(defaultContext!.isIncognito()).toBe(false); + + expect(browser.browserContexts().length).toBeGreaterThanOrEqual(1); + const defaultContext = browser.browserContexts().find(context => { + return !context.isIncognito(); + }); + expect(defaultContext).toBeDefined(); + let error!: Error; await defaultContext!.close().catch(error_ => { return (error = error_); @@ -33,13 +37,14 @@ describe('BrowserContext', function () { skipContextCreation: true, }); - expect(browser.browserContexts()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); + const contextCount = browser.browserContexts().length; + expect(contextCount).toBeGreaterThanOrEqual(1); + const context = await browser.createBrowserContext(); expect(context.isIncognito()).toBe(true); - expect(browser.browserContexts()).toHaveLength(2); + expect(browser.browserContexts()).toHaveLength(contextCount + 1); expect(browser.browserContexts().indexOf(context) !== -1).toBe(true); await context.close(); - expect(browser.browserContexts()).toHaveLength(1); + expect(browser.browserContexts()).toHaveLength(contextCount); }); it('should close all belonging targets once closing context', async () => { const {browser} = await getTestState({ @@ -48,7 +53,7 @@ describe('BrowserContext', function () { expect(await browser.pages()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); await context.newPage(); expect(await browser.pages()).toHaveLength(2); expect(await context.pages()).toHaveLength(1); @@ -128,7 +133,7 @@ describe('BrowserContext', function () { it('should timeout waiting for a non-existent target', async () => { const {browser, server} = await getTestState(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const error = await context .waitForTarget( target => { @@ -151,8 +156,8 @@ describe('BrowserContext', function () { }); // Create two incognito contexts. - const context1 = await browser.createIncognitoBrowserContext(); - const context2 = await browser.createIncognitoBrowserContext(); + const context1 = await browser.createBrowserContext(); + const context2 = await browser.createBrowserContext(); expect(context1.targets()).toHaveLength(0); expect(context2.targets()).toHaveLength(0); @@ -176,9 +181,9 @@ describe('BrowserContext', function () { }); expect(context1.targets()).toHaveLength(1); - expect(context1.targets()[0]).toBe(page1.target()); + expect(await context1.targets()[0]?.page()).toBe(page1); expect(context2.targets()).toHaveLength(1); - expect(context2.targets()[0]).toBe(page2.target()); + expect(await context2.targets()[0]?.page()).toBe(page2); // Make sure pages don't share localstorage or cookies. expect( @@ -213,16 +218,19 @@ describe('BrowserContext', function () { }); expect(browser.browserContexts()).toHaveLength(1); - const context = await browser.createIncognitoBrowserContext(); - expect(browser.browserContexts()).toHaveLength(2); - const remoteBrowser = await puppeteer.connect({ - browserWSEndpoint: browser.wsEndpoint(), - protocol: browser.protocol, - }); - const contexts = remoteBrowser.browserContexts(); - expect(contexts).toHaveLength(2); - await remoteBrowser.disconnect(); - await context.close(); + const context = await browser.createBrowserContext(); + try { + expect(browser.browserContexts()).toHaveLength(2); + const remoteBrowser = await puppeteer.connect({ + browserWSEndpoint: browser.wsEndpoint(), + protocol: browser.protocol, + }); + const contexts = remoteBrowser.browserContexts(); + expect(contexts).toHaveLength(2); + await remoteBrowser.disconnect(); + } finally { + await context.close(); + } }); it('should provide a context id', async () => { @@ -233,7 +241,7 @@ describe('BrowserContext', function () { expect(browser.browserContexts()).toHaveLength(1); expect(browser.browserContexts()[0]!.id).toBeUndefined(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); expect(browser.browserContexts()).toHaveLength(2); expect(browser.browserContexts()[1]!.id).toBeDefined(); await context.close(); @@ -333,7 +341,7 @@ describe('BrowserContext', function () { const {page, server, context, browser} = await getTestState(); await page.goto(server.EMPTY_PAGE); - const otherContext = await browser.createIncognitoBrowserContext(); + const otherContext = await browser.createBrowserContext(); const otherPage = await otherContext.newPage(); await otherPage.goto(server.EMPTY_PAGE); expect(await getPermission(page, 'geolocation')).toBe('prompt'); diff --git a/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts b/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts index 2000c0e435..887152f097 100644 --- a/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/CDPSession.spec.ts @@ -30,7 +30,7 @@ describe('Target.createCDPSession', function () { }); it('should not report created targets for custom CDP sessions', async () => { - const {browser} = await getTestState(); + const {context} = await getTestState(); let called = 0; const handler = async (target: Target) => { called++; @@ -39,9 +39,9 @@ describe('Target.createCDPSession', function () { } await target.createCDPSession(); }; - browser.browserContexts()[0]!.on('targetcreated', handler); - await browser.newPage(); - browser.browserContexts()[0]!.off('targetcreated', handler); + context.on('targetcreated', handler); + await context.newPage(); + context.off('targetcreated', handler); }); it('should send events', async () => { diff --git a/remote/test/puppeteer/test/src/cdp/devtools.spec.ts b/remote/test/puppeteer/test/src/cdp/devtools.spec.ts index c158481af2..c48b4c353b 100644 --- a/remote/test/puppeteer/test/src/cdp/devtools.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/devtools.spec.ts @@ -93,7 +93,7 @@ describe('DevTools', function () { const browser = await launchBrowser( Object.assign({devtools: true}, launchOptions) ); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); await Promise.all([ context.newPage(), browser.waitForTarget((target: {url: () => string | string[]}) => { @@ -106,7 +106,7 @@ describe('DevTools', function () { const browser = await launchBrowser( Object.assign({devtools: true}, launchOptions) ); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const [target] = await Promise.all([ browser.waitForTarget((target: {url: () => string | string[]}) => { return target.url().includes('devtools://'); diff --git a/remote/test/puppeteer/test/src/cdp/pdf.spec.ts b/remote/test/puppeteer/test/src/cdp/pdf.spec.ts new file mode 100644 index 0000000000..06a41de36f --- /dev/null +++ b/remote/test/puppeteer/test/src/cdp/pdf.spec.ts @@ -0,0 +1,55 @@ +/** + * @license + * Copyright 2017 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {readFile, unlink} from 'fs/promises'; + +import expect from 'expect'; + +import {getTestState, setupTestBrowserHooks} from '../mocha-utils.js'; + +describe('Page.pdf', () => { + setupTestBrowserHooks(); + + it('can print to PDF with accessible', async () => { + const {page, server} = await getTestState(); + + const outputFile = __dirname + '/../../assets/output.pdf'; + const outputFileAccessible = + __dirname + '/../../assets/output-accessible.pdf'; + await page.goto(server.PREFIX + '/pdf.html'); + await page.pdf({path: outputFile, tagged: false}); + await page.pdf({path: outputFileAccessible, tagged: true}); + try { + const [base, tagged] = await Promise.all([ + readFile(outputFile), + readFile(outputFileAccessible), + ]); + expect(tagged.byteLength).toBeGreaterThan(base.byteLength); + } finally { + await Promise.all([unlink(outputFile), unlink(outputFileAccessible)]); + } + }); + + it('can print to PDF with outline', async () => { + const {page, server} = await getTestState(); + + const outputFile = __dirname + '/../../assets/output.pdf'; + const outputFileOutlined = __dirname + '/../../assets/output-outlined.pdf'; + await page.goto(server.PREFIX + '/pdf.html'); + await page.pdf({path: outputFile, tagged: true}); + await page.pdf({path: outputFileOutlined, tagged: true, outline: true}); + try { + const [base, outlined] = await Promise.all([ + readFile(outputFile), + readFile(outputFileOutlined), + ]); + + expect(outlined.byteLength).toBeGreaterThan(base.byteLength); + } finally { + await Promise.all([unlink(outputFile), unlink(outputFileOutlined)]); + } + }); +}); diff --git a/remote/test/puppeteer/test/src/screencast.spec.ts b/remote/test/puppeteer/test/src/cdp/screencast.spec.ts index b645f55da7..2833ff4d67 100644 --- a/remote/test/puppeteer/test/src/screencast.spec.ts +++ b/remote/test/puppeteer/test/src/cdp/screencast.spec.ts @@ -8,8 +8,8 @@ import {statSync} from 'fs'; import expect from 'expect'; -import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; -import {getUniqueVideoFilePlaceholder} from './utils.js'; +import {getTestState, setupTestBrowserHooks} from '../mocha-utils.js'; +import {getUniqueVideoFilePlaceholder} from '../utils.js'; describe('Screencasts', function () { setupTestBrowserHooks(); diff --git a/remote/test/puppeteer/test/src/cookies.spec.ts b/remote/test/puppeteer/test/src/cookies.spec.ts index f232831b72..1fa4a9407c 100644 --- a/remote/test/puppeteer/test/src/cookies.spec.ts +++ b/remote/test/puppeteer/test/src/cookies.spec.ts @@ -150,9 +150,7 @@ describe('Cookie specs', () => { expires: -1, size: 11, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, { @@ -164,13 +162,47 @@ describe('Cookie specs', () => { expires: -1, size: 10, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ]); }); + it('should not get cookies from subdomain', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://base_domain.com', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies('https://sub_domain.base_domain.com'); + expect(cookies).toHaveLength(0); + }); + it('should get cookies from nested path', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://foo.com', + path: '/some_path', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies( + 'https://foo.com/some_path/nested_path' + ); + expect(cookies).toHaveLength(1); + }); + it('should not get cookies from not nested path', async () => { + const {page} = await getTestState(); + await page.setCookie({ + url: 'https://foo.com', + path: '/some_path', + name: 'doggo', + value: 'woofs', + }); + const cookies = await page.cookies( + 'https://foo.com/some_path_looks_like_nested' + ); + expect(cookies).toHaveLength(0); + }); }); describe('Page.setCookie', function () { it('should work', async () => { @@ -190,24 +222,27 @@ describe('Cookie specs', () => { it('should isolate cookies in browser contexts', async () => { const {page, server, browser} = await getTestState(); - const anotherContext = await browser.createIncognitoBrowserContext(); - const anotherPage = await anotherContext.newPage(); + const anotherContext = await browser.createBrowserContext(); + try { + const anotherPage = await anotherContext.newPage(); - await page.goto(server.EMPTY_PAGE); - await anotherPage.goto(server.EMPTY_PAGE); - - await page.setCookie({name: 'page1cookie', value: 'page1value'}); - await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'}); - - const cookies1 = await page.cookies(); - const cookies2 = await anotherPage.cookies(); - expect(cookies1).toHaveLength(1); - expect(cookies2).toHaveLength(1); - expect(cookies1[0]!.name).toBe('page1cookie'); - expect(cookies1[0]!.value).toBe('page1value'); - expect(cookies2[0]!.name).toBe('page2cookie'); - expect(cookies2[0]!.value).toBe('page2value'); - await anotherContext.close(); + await page.goto(server.EMPTY_PAGE); + await anotherPage.goto(server.EMPTY_PAGE); + + await page.setCookie({name: 'page1cookie', value: 'page1value'}); + await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'}); + + const cookies1 = await page.cookies(); + const cookies2 = await anotherPage.cookies(); + expect(cookies1).toHaveLength(1); + expect(cookies2).toHaveLength(1); + expect(cookies1[0]!.name).toBe('page1cookie'); + expect(cookies1[0]!.value).toBe('page1value'); + expect(cookies2[0]!.name).toBe('page2cookie'); + expect(cookies2[0]!.value).toBe('page2value'); + } finally { + await anotherContext.close(); + } }); it('should set multiple cookies', async () => { const {page, server} = await getTestState(); @@ -271,7 +306,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ] @@ -298,7 +332,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -401,9 +434,7 @@ describe('Cookie specs', () => { expires: -1, size: 18, httpOnly: false, - secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ]); @@ -446,7 +477,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -465,7 +495,6 @@ describe('Cookie specs', () => { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ] @@ -515,7 +544,6 @@ describe('Cookie specs', () => { sameSite: 'None', secure: true, session: true, - sourcePort: 443, sourceScheme: 'Secure', }, ] @@ -527,7 +555,7 @@ describe('Cookie specs', () => { }); describe('Page.deleteCookie', function () { - it('should work', async () => { + it('should delete cookie', async () => { const {page, server} = await getTestState(); await page.goto(server.EMPTY_PAGE); @@ -553,5 +581,139 @@ describe('Cookie specs', () => { 'cookie1=1; cookie3=3' ); }); + it('should not delete cookie for different domain', async () => { + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + + await page.goto(server.EMPTY_PAGE); + // Set a cookie for the current page. + await page.setCookie({ + name: COOKIE_NAME, + value: 'local page cookie value', + }); + expect(await page.cookies()).toHaveLength(1); + + // Set a cookie for different domain. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'COOKIE_DESTINATION_URL cookie value', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + await page.deleteCookie({name: COOKIE_NAME}); + + // Verify the cookie is deleted for the current page. + expect(await page.cookies()).toHaveLength(0); + + // Verify the cookie is not deleted for different domain. + await expectCookieEquals(await page.cookies(COOKIE_DESTINATION_URL), [ + { + name: COOKIE_NAME, + value: 'COOKIE_DESTINATION_URL cookie value', + domain: 'example.com', + path: '/', + sameParty: false, + expires: -1, + size: 51, + httpOnly: false, + secure: true, + session: true, + sourceScheme: 'Secure', + }, + ]); + }); + it('should delete cookie for specified URL', async () => { + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + + await page.goto(server.EMPTY_PAGE); + // Set a cookie for the current page. + await page.setCookie({ + name: COOKIE_NAME, + value: 'some_cookie_value', + }); + expect(await page.cookies()).toHaveLength(1); + + // Set a cookie for specified URL. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'another_cookie_value', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + // Delete the cookie for specified URL. + await page.deleteCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + }); + + // Verify the cookie is deleted for specified URL. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + + // Verify the cookie is not deleted for the current page. + await expectCookieEquals(await page.cookies(), [ + { + name: COOKIE_NAME, + value: 'some_cookie_value', + domain: 'localhost', + path: '/', + sameParty: false, + expires: -1, + size: 33, + httpOnly: false, + secure: false, + session: true, + sourceScheme: 'NonSecure', + }, + ]); + }); + it('should delete cookie for specified URL regardless of the current page', async () => { + // This test verifies the page.deleteCookie method deletes cookies for the custom + // destination URL, even if it was set from another page. Depending on the cookie + // partitioning implementation, this test case does not pass, if source origin is in + // the default cookie partition. + + const {page, server} = await getTestState(); + const COOKIE_DESTINATION_URL = 'https://example.com'; + const COOKIE_NAME = 'some_cookie_name'; + const URL_1 = server.EMPTY_PAGE; + const URL_2 = server.CROSS_PROCESS_PREFIX + '/empty.html'; + + await page.goto(URL_1); + // Set a cookie for the COOKIE_DESTINATION from URL_1. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'Cookie from URL_1', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + await page.goto(URL_2); + // Set a cookie for the COOKIE_DESTINATION from URL_2. + await page.setCookie({ + url: COOKIE_DESTINATION_URL, + name: COOKIE_NAME, + value: 'Cookie from URL_2', + }); + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1); + + // Delete the cookie for the COOKIE_DESTINATION from URL_2. + await page.deleteCookie({ + name: COOKIE_NAME, + url: COOKIE_DESTINATION_URL, + }); + + // Expect the cookie for the COOKIE_DESTINATION from URL_2 is deleted. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + + // Navigate back to the URL_1. + await page.goto(server.EMPTY_PAGE); + // Expect the cookie for the COOKIE_DESTINATION from URL_1 is deleted. + expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0); + }); }); }); diff --git a/remote/test/puppeteer/test/src/coverage.spec.ts b/remote/test/puppeteer/test/src/coverage.spec.ts index 6a95db541c..612d634007 100644 --- a/remote/test/puppeteer/test/src/coverage.spec.ts +++ b/remote/test/puppeteer/test/src/coverage.spec.ts @@ -49,12 +49,11 @@ describe('Coverage specs', function () { await page.coverage.startJSCoverage({reportAnonymousScripts: true}); await page.goto(server.PREFIX + '/jscoverage/eval.html'); const coverage = await page.coverage.stopJSCoverage(); - expect( - coverage.find(entry => { - return entry.url.startsWith('debugger://'); - }) - ).not.toBe(null); - expect(coverage).toHaveLength(2); + + const filtered = coverage.filter(entry => { + return !entry.url.startsWith('debugger://'); + }); + expect(filtered).toHaveLength(1); }); it('should ignore pptr internal scripts if reportAnonymousScripts is true', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/debugInfo.spec.ts b/remote/test/puppeteer/test/src/debugInfo.spec.ts index 079107cab7..4f79231667 100644 --- a/remote/test/puppeteer/test/src/debugInfo.spec.ts +++ b/remote/test/puppeteer/test/src/debugInfo.spec.ts @@ -15,6 +15,18 @@ describe('DebugInfo', function () { it('should work', async () => { const {page, browser} = await getTestState(); + for (let i = 0; i < 5; i++) { + if (!browser.debugInfo.pendingProtocolErrors.length) { + break; + } + await new Promise(resolve => { + return setTimeout(resolve, 200); + }); + } + + // Insure that the previous test are flushed + expect(browser.debugInfo.pendingProtocolErrors).toHaveLength(0); + const promise = page.evaluate(() => { return new Promise(resolve => { // @ts-expect-error another context diff --git a/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts b/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts index 69a5a069af..662c6826cb 100644 --- a/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts +++ b/remote/test/puppeteer/test/src/defaultbrowsercontext.spec.ts @@ -62,7 +62,6 @@ describe('DefaultBrowserContext', function () { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); @@ -96,7 +95,6 @@ describe('DefaultBrowserContext', function () { httpOnly: false, secure: false, session: true, - sourcePort: 80, sourceScheme: 'NonSecure', }, ]); diff --git a/remote/test/puppeteer/test/src/device-request-prompt.spec.ts b/remote/test/puppeteer/test/src/device-request-prompt.spec.ts index e6e2cdd65e..450a8d800c 100644 --- a/remote/test/puppeteer/test/src/device-request-prompt.spec.ts +++ b/remote/test/puppeteer/test/src/device-request-prompt.spec.ts @@ -28,7 +28,7 @@ describe('device request prompt', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); diff --git a/remote/test/puppeteer/test/src/elementhandle.spec.ts b/remote/test/puppeteer/test/src/elementhandle.spec.ts index 9aaf914224..e0f1e41878 100644 --- a/remote/test/puppeteer/test/src/elementhandle.spec.ts +++ b/remote/test/puppeteer/test/src/elementhandle.spec.ts @@ -34,18 +34,14 @@ describe('ElementHandle specs', function () { expect(box).toEqual({x: 100, y: 50, width: 50, height: 50}); }); it('should handle nested frames', async () => { - const {page, server, isChrome} = await getTestState(); + const {page, server} = await getTestState(); await page.setViewport({width: 500, height: 500}); await page.goto(server.PREFIX + '/frames/nested-frames.html'); const nestedFrame = page.frames()[1]!.childFrames()[1]!; using elementHandle = (await nestedFrame.$('div'))!; const box = await elementHandle.boundingBox(); - if (isChrome) { - expect(box).toEqual({x: 28, y: 182, width: 264, height: 18}); - } else { - expect(box).toEqual({x: 28, y: 182, width: 254, height: 18}); - } + expect(box).toEqual({x: 28, y: 182, width: 300, height: 18}); }); it('should return null for invisible elements', async () => { const {page} = await getTestState(); @@ -472,10 +468,8 @@ describe('ElementHandle specs', function () { }) ).toStrictEqual('bar1'); }); - }); - describe('Element.waitForXPath', () => { - it('should wait correctly with waitForXPath on an element', async () => { + it('should wait correctly with waitForSelector and xpath on an element', async () => { const {page} = await getTestState(); // Set the page content after the waitFor has been started. await page.setContent( @@ -490,20 +484,18 @@ describe('ElementHandle specs', function () { </div>` ); - using el1 = (await page.waitForSelector( + using elById = (await page.waitForSelector( '#el1' )) as ElementHandle<HTMLDivElement>; - for (const path of ['//div', './/div']) { - using e = (await el1.waitForXPath( - path - )) as ElementHandle<HTMLDivElement>; - expect( - await e.evaluate(el => { - return el.id; - }) - ).toStrictEqual('el2'); - } + using elByXpath = (await elById.waitForSelector( + 'xpath/.//div' + )) as ElementHandle<HTMLDivElement>; + expect( + await elByXpath.evaluate(el => { + return el.id; + }) + ).toStrictEqual('el2'); }); }); diff --git a/remote/test/puppeteer/test/src/evaluation.spec.ts b/remote/test/puppeteer/test/src/evaluation.spec.ts index 3305b59cc2..88cccb82dd 100644 --- a/remote/test/puppeteer/test/src/evaluation.spec.ts +++ b/remote/test/puppeteer/test/src/evaluation.spec.ts @@ -408,9 +408,10 @@ describe('Evaluation specs', function () { return (error = error_); }); expect(error).toBeTruthy(); - expect(error.message).toContain( - 'JSHandles can be evaluated only in the context they were created' - ); + expect(error.message).atLeastOneToContain([ + 'JSHandles can be evaluated only in the context they were created', + "Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page.", + ]); }); it('should simulate a user gesture', async () => { const {page} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/fixtures.spec.ts b/remote/test/puppeteer/test/src/fixtures.spec.ts index ca11e94cac..e7a2e1ac9b 100644 --- a/remote/test/puppeteer/test/src/fixtures.spec.ts +++ b/remote/test/puppeteer/test/src/fixtures.spec.ts @@ -18,7 +18,7 @@ describe('Fixtures', function () { it('dumpio option should work with pipe option', async () => { const {defaultBrowserOptions, puppeteerPath, headless} = await getTestState(); - if (headless !== 'true') { + if (headless !== 'shell') { // This test only works in the old headless mode. return; } @@ -42,7 +42,8 @@ describe('Fixtures', function () { expect(dumpioData).toContain('message from dumpio'); }); it('should dump browser process stderr', async () => { - const {defaultBrowserOptions, puppeteerPath} = await getTestState(); + const {defaultBrowserOptions, isFirefox, puppeteerPath} = + await getTestState(); let dumpioData = ''; const options = Object.assign({}, defaultBrowserOptions, {dumpio: true}); @@ -57,7 +58,11 @@ describe('Fixtures', function () { await new Promise(resolve => { return res.on('close', resolve); }); - expect(dumpioData).toContain('DevTools listening on ws://'); + if (isFirefox && defaultBrowserOptions.protocol === 'webDriverBiDi') { + expect(dumpioData).toContain('WebDriver BiDi listening on ws://'); + } else { + expect(dumpioData).toContain('DevTools listening on ws://'); + } }); it('should close the browser when the node process closes', async () => { const {defaultBrowserOptions, puppeteerPath, puppeteer} = diff --git a/remote/test/puppeteer/test/src/frame.spec.ts b/remote/test/puppeteer/test/src/frame.spec.ts index 3b2456821a..a49fb19482 100644 --- a/remote/test/puppeteer/test/src/frame.spec.ts +++ b/remote/test/puppeteer/test/src/frame.spec.ts @@ -205,6 +205,18 @@ describe('Frame specs', function () { expect(detachedFrames).toHaveLength(4); expect(navigatedFrames).toHaveLength(1); }); + + it('should click elements in a frameset', async () => { + const {page, server} = await getTestState(); + await page.goto(server.PREFIX + '/frames/frameset.html'); + const frame = await page.waitForFrame(frame => { + return frame.url().endsWith('/frames/frame.html'); + }); + using div = await frame.waitForSelector('div'); + expect(div).toBeTruthy(); + await div?.click(); + }); + it('should report frame from-inside shadow DOM', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/headful.spec.ts b/remote/test/puppeteer/test/src/headful.spec.ts index 1e3248b4ff..67ae9f335e 100644 --- a/remote/test/puppeteer/test/src/headful.spec.ts +++ b/remote/test/puppeteer/test/src/headful.spec.ts @@ -12,18 +12,18 @@ import expect from 'expect'; import type {PuppeteerLaunchOptions} from 'puppeteer-core/internal/node/PuppeteerNode.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; -import {getTestState, isHeadless, launch} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); -(!isHeadless ? describe : describe.skip)('headful tests', function () { +describe('headful tests', function () { /* These tests fire up an actual browser so let's * allow a higher timeout */ this.timeout(20_000); - let headfulOptions: PuppeteerLaunchOptions | undefined; - let headlessOptions: PuppeteerLaunchOptions & {headless: boolean}; + let headfulOptions: PuppeteerLaunchOptions & {headless: false}; + let headlessOptions: PuppeteerLaunchOptions & {headless: true}; const browsers: Array<() => Promise<void>> = []; @@ -32,10 +32,10 @@ const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); skipLaunch: true, }); headfulOptions = Object.assign({}, defaultBrowserOptions, { - headless: false, + headless: false as const, }); headlessOptions = Object.assign({}, defaultBrowserOptions, { - headless: true, + headless: true as const, }); }); @@ -64,23 +64,30 @@ const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const headfulBrowser = await launchBrowser( Object.assign({userDataDir}, headfulOptions) ); - const headfulPage = await headfulBrowser.newPage(); - await headfulPage.goto(server.EMPTY_PAGE); - await headfulPage.evaluate(() => { - return (document.cookie = - 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); - }); - await headfulBrowser.close(); + try { + const headfulPage = await headfulBrowser.newPage(); + await headfulPage.goto(server.EMPTY_PAGE); + await headfulPage.evaluate(() => { + return (document.cookie = + 'foo=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'); + }); + } finally { + await headfulBrowser.close(); + } // Read the cookie from headless chrome const headlessBrowser = await launchBrowser( Object.assign({userDataDir}, headlessOptions) ); - const headlessPage = await headlessBrowser.newPage(); - await headlessPage.goto(server.EMPTY_PAGE); - const cookie = await headlessPage.evaluate(() => { - return document.cookie; - }); - await headlessBrowser.close(); + let cookie = ''; + try { + const headlessPage = await headlessBrowser.newPage(); + await headlessPage.goto(server.EMPTY_PAGE); + cookie = await headlessPage.evaluate(() => { + return document.cookie; + }); + } finally { + await headlessBrowser.close(); + } // This might throw. See https://github.com/puppeteer/puppeteer/issues/2778 try { rmSync(userDataDir); diff --git a/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts b/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts index 8fb557cb88..d8e5603388 100644 --- a/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts +++ b/remote/test/puppeteer/test/src/ignorehttpserrors.spec.ts @@ -32,7 +32,7 @@ describe('ignoreHTTPSErrors', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); diff --git a/remote/test/puppeteer/test/src/input.spec.ts b/remote/test/puppeteer/test/src/input.spec.ts index 7e4cae6709..47064528d3 100644 --- a/remote/test/puppeteer/test/src/input.spec.ts +++ b/remote/test/puppeteer/test/src/input.spec.ts @@ -17,14 +17,13 @@ const FILE_TO_UPLOAD = path.join(__dirname, '/../assets/file-to-upload.txt'); describe('input tests', function () { setupTestBrowserHooks(); - describe('input', function () { + describe('ElementHandle.uploadFile', function () { it('should upload the file', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/fileupload.html'); - const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD); using input = (await page.$('input'))!; - await page.evaluate((e: HTMLElement) => { + await input.evaluate(e => { (globalThis as any)._inputEvents = []; e.addEventListener('change', ev => { return (globalThis as any)._inputEvents.push(ev.type); @@ -32,34 +31,63 @@ describe('input tests', function () { e.addEventListener('input', ev => { return (globalThis as any)._inputEvents.push(ev.type); }); - }, input); - await input.uploadFile(filePath); + }); + + const file = path.relative(process.cwd(), FILE_TO_UPLOAD); + await input.uploadFile(file); + expect( - await page.evaluate((e: HTMLInputElement) => { - return e.files![0]!.name; - }, input) + await input.evaluate(e => { + return e.files?.[0]?.name; + }) ).toBe('file-to-upload.txt'); expect( - await page.evaluate((e: HTMLInputElement) => { - return e.files![0]!.type; - }, input) + await input.evaluate(e => { + return e.files?.[0]?.type; + }) ).toBe('text/plain'); expect( await page.evaluate(() => { return (globalThis as any)._inputEvents; }) ).toEqual(['input', 'change']); + }); + + it('should read the file', async () => { + const {page, server} = await getTestState(); + + await page.goto(server.PREFIX + '/input/fileupload.html'); + using input = (await page.$('input'))!; + await input.evaluate(e => { + (globalThis as any)._inputEvents = []; + e.addEventListener('change', ev => { + return (globalThis as any)._inputEvents.push(ev.type); + }); + e.addEventListener('input', ev => { + return (globalThis as any)._inputEvents.push(ev.type); + }); + }); + + const file = path.relative(process.cwd(), FILE_TO_UPLOAD); + await input.uploadFile(file); + expect( - await page.evaluate((e: HTMLInputElement) => { + await input.evaluate(e => { + const file = e.files?.[0]; + if (!file) { + throw new Error('No file found'); + } + const reader = new FileReader(); const promise = new Promise(fulfill => { - return (reader.onload = fulfill); + reader.addEventListener('load', fulfill); }); - reader.readAsText(e.files![0]!); + reader.readAsText(file); + return promise.then(() => { return reader.result; }); - }, input) + }) ).toBe('contents of the file'); }); }); diff --git a/remote/test/puppeteer/test/src/launcher.spec.ts b/remote/test/puppeteer/test/src/launcher.spec.ts index f31b22b1e5..876f8d1624 100644 --- a/remote/test/puppeteer/test/src/launcher.spec.ts +++ b/remote/test/puppeteer/test/src/launcher.spec.ts @@ -16,7 +16,7 @@ import type {Page} from 'puppeteer-core/internal/api/Page.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; import sinon from 'sinon'; -import {getTestState, isHeadless, launch} from './mocha-utils.js'; +import {getTestState, launch} from './mocha-utils.js'; import {dumpFrames, waitEvent} from './utils.js'; const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); @@ -48,7 +48,10 @@ describe('Launcher specs', function () { [ 'Navigating frame was detached', 'Protocol error (Page.navigate): Target closed.', - ].includes(error.message) + 'Protocol error (browsingContext.navigate): Target closed', + ].some(message => { + return error.message.startsWith(message); + }) ).toBeTruthy(); } finally { await close(); @@ -99,6 +102,7 @@ describe('Launcher specs', function () { expect(message).atLeastOneToContain([ 'Target closed', 'Page closed!', + 'Browser already closed', ]); expect(message).not.toContain('Timeout'); } @@ -363,9 +367,9 @@ describe('Launcher specs', function () { if (isChrome) { expect(puppeteer.defaultArgs()).toContain('--no-first-run'); - expect(puppeteer.defaultArgs()).toContain('--headless'); + expect(puppeteer.defaultArgs()).toContain('--headless=new'); expect(puppeteer.defaultArgs({headless: false})).not.toContain( - '--headless' + '--headless=new' ); expect(puppeteer.defaultArgs({userDataDir: 'foo'})).toContain( `--user-data-dir=${path.resolve('foo')}` @@ -408,21 +412,18 @@ describe('Launcher specs', function () { expect(puppeteer.product).toBe('firefox'); } }); - (!isHeadless ? it : it.skip)( - 'should work with no default arguments', - async () => { - const {context, close} = await launch({ - ignoreDefaultArgs: true, - }); - try { - const page = await context.newPage(); - expect(await page.evaluate('11 * 11')).toBe(121); - await page.close(); - } finally { - await close(); - } + it('should work with no default arguments', async () => { + const {context, close} = await launch({ + ignoreDefaultArgs: true, + }); + try { + const page = await context.newPage(); + expect(await page.evaluate('11 * 11')).toBe(121); + await page.close(); + } finally { + await close(); } - ); + }); it('should filter out ignored default arguments in Chrome', async () => { const {defaultBrowserOptions, puppeteer} = await getTestState({ skipLaunch: true, @@ -590,31 +591,6 @@ describe('Launcher specs', function () { }); expect(error.message).toContain('either pipe or debugging port'); }); - (!isHeadless ? it : it.skip)( - 'should launch Chrome properly with --no-startup-window and waitForInitialPage=false', - async () => { - const {defaultBrowserOptions} = await getTestState({ - skipLaunch: true, - }); - const options = { - waitForInitialPage: false, - // This is needed to prevent Puppeteer from adding an initial blank page. - // See also https://github.com/puppeteer/puppeteer/blob/ad6b736039436fcc5c0a262e5b575aa041427be3/src/node/Launcher.ts#L200 - ignoreDefaultArgs: true, - ...defaultBrowserOptions, - args: ['--no-startup-window'], - }; - const {browser, close} = await launch(options, { - createContext: false, - }); - try { - const pages = await browser.pages(); - expect(pages).toHaveLength(0); - } finally { - await close(); - } - } - ); }); describe('Puppeteer.launch', function () { diff --git a/remote/test/puppeteer/test/src/mocha-utils.ts b/remote/test/puppeteer/test/src/mocha-utils.ts index 3fff9c9930..333204d83b 100644 --- a/remote/test/puppeteer/test/src/mocha-utils.ts +++ b/remote/test/puppeteer/test/src/mocha-utils.ts @@ -8,13 +8,13 @@ import fs from 'fs'; import path from 'path'; import {TestServer} from '@pptr/testserver'; -import type {Protocol} from 'devtools-protocol'; import expect from 'expect'; import type * as MochaBase from 'mocha'; import puppeteer from 'puppeteer/lib/cjs/puppeteer/puppeteer.js'; import type {Browser} from 'puppeteer-core/internal/api/Browser.js'; import type {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js'; import type {Page} from 'puppeteer-core/internal/api/Page.js'; +import type {Cookie} from 'puppeteer-core/internal/common/Cookie.js'; import type { PuppeteerLaunchOptions, PuppeteerNode, @@ -68,8 +68,8 @@ const product = const headless = (process.env['HEADLESS'] || 'true').trim().toLowerCase() as | 'true' | 'false' - | 'new'; -export const isHeadless = headless === 'true' || headless === 'new'; + | 'shell'; +export const isHeadless = headless === 'true' || headless === 'shell'; const isFirefox = product === 'firefox'; const isChrome = product === 'chrome'; const protocol = (process.env['PUPPETEER_PROTOCOL'] || 'cdp') as @@ -93,7 +93,7 @@ const defaultBrowserOptions = Object.assign( { handleSIGINT: true, executablePath: process.env['BINARY'], - headless: headless === 'new' ? ('new' as const) : isHeadless, + headless: headless === 'shell' ? ('shell' as const) : isHeadless, dumpio: !!process.env['DUMPIO'], protocol, }, @@ -115,7 +115,7 @@ if (defaultBrowserOptions.executablePath) { const processVariables: { product: string; - headless: 'true' | 'false' | 'new'; + headless: 'true' | 'false' | 'shell'; isHeadless: boolean; isFirefox: boolean; isChrome: boolean; @@ -216,7 +216,7 @@ export const getTestState = async ( } if (!skipContextCreation) { - state.context = await state.browser!.createIncognitoBrowserContext(); + state.context = await state.browser!.createBrowserContext(); state.page = await state.context.newPage(); } return state as PuppeteerTestState; @@ -245,7 +245,7 @@ export interface PuppeteerTestState { isFirefox: boolean; isChrome: boolean; isHeadless: boolean; - headless: 'true' | 'false' | 'new'; + headless: 'true' | 'false' | 'shell'; puppeteerPath: string; } const state: Partial<PuppeteerTestState> = {}; @@ -263,7 +263,7 @@ if ( } -> mode: ${ processVariables.isHeadless - ? processVariables.headless === 'new' + ? processVariables.headless === 'true' ? '--headless=new' : '--headless' : 'headful' @@ -372,23 +372,27 @@ expect.extend({ }); export const expectCookieEquals = async ( - cookies: Protocol.Network.Cookie[], - expectedCookies: Array<Partial<Protocol.Network.Cookie>> + cookies: Cookie[], + expectedCookies: Array<Partial<Cookie>> ): Promise<void> => { if (!processVariables.isChrome) { // Only keep standard properties when testing on a browser other than Chrome. expectedCookies = expectedCookies.map(cookie => { - return { - domain: cookie.domain, - expires: cookie.expires, - httpOnly: cookie.httpOnly, - name: cookie.name, - path: cookie.path, - secure: cookie.secure, - session: cookie.session, - size: cookie.size, - value: cookie.value, - }; + return Object.fromEntries( + Object.entries(cookie).filter(([key]) => { + return [ + 'domain', + 'expires', + 'httpOnly', + 'name', + 'path', + 'secure', + 'session', + 'size', + 'value', + ].includes(key); + }) + ); }); } @@ -479,7 +483,7 @@ export const launch = async ( let context: BrowserContext; let page: Page; if (createContext) { - context = await browser.createIncognitoBrowserContext(); + context = await browser.createBrowserContext(); cleanupStorage.push(() => { return context.close(); }); diff --git a/remote/test/puppeteer/test/src/navigation.spec.ts b/remote/test/puppeteer/test/src/navigation.spec.ts index 1f3a51f58a..dd59c98349 100644 --- a/remote/test/puppeteer/test/src/navigation.spec.ts +++ b/remote/test/puppeteer/test/src/navigation.spec.ts @@ -154,10 +154,10 @@ describe('navigation', function () { }); const EXPECTED_SSL_CERT_MESSAGE_REGEX = - /net::ERR_CERT_INVALID|net::ERR_CERT_AUTHORITY_INVALID/; + /net::ERR_CERT_INVALID|net::ERR_CERT_AUTHORITY_INVALID|MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT|SSL_ERROR_UNKNOWN/; it('should fail when navigating to bad SSL', async () => { - const {page, httpsServer, isChrome} = await getTestState(); + const {page, httpsServer} = await getTestState(); // Make sure that network events do not emit 'undefined'. // @see https://crbug.com/750469 @@ -176,18 +176,14 @@ describe('navigation', function () { await page.goto(httpsServer.EMPTY_PAGE).catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); - } else { - expect(error.message).toContain('SSL_ERROR_UNKNOWN'); - } + expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); expect(requests).toHaveLength(2); expect(requests[0]).toBe('request'); expect(requests[1]).toBe('requestfailed'); }); it('should fail when navigating to bad SSL after redirects', async () => { - const {page, server, httpsServer, isChrome} = await getTestState(); + const {page, server, httpsServer} = await getTestState(); server.setRedirect('/redirect/1.html', '/redirect/2.html'); server.setRedirect('/redirect/2.html', '/empty.html'); @@ -195,17 +191,10 @@ describe('navigation', function () { await page.goto(httpsServer.PREFIX + '/redirect/1.html').catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); - } else { - expect(error.message).atLeastOneToContain([ - 'MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT', // Firefox WebDriver BiDi. - 'SSL_ERROR_UNKNOWN ', // Others. - ]); - } + expect(error.message).toMatch(EXPECTED_SSL_CERT_MESSAGE_REGEX); }); it('should fail when main resources failed to load', async () => { - const {page, isChrome} = await getTestState(); + const {page} = await getTestState(); let error!: Error; await page @@ -213,11 +202,9 @@ describe('navigation', function () { .catch(error_ => { return (error = error_); }); - if (isChrome) { - expect(error.message).toContain('net::ERR_CONNECTION_REFUSED'); - } else { - expect(error.message).toContain('NS_ERROR_CONNECTION_REFUSED'); - } + expect(error.message).toMatch( + /net::ERR_CONNECTION_REFUSED|NS_ERROR_CONNECTION_REFUSED/ + ); }); it('should fail when exceeding maximum navigation timeout', async () => { const {page, server} = await getTestState(); diff --git a/remote/test/puppeteer/test/src/oopif.spec.ts b/remote/test/puppeteer/test/src/oopif.spec.ts index c024b76aba..0213e14d5d 100644 --- a/remote/test/puppeteer/test/src/oopif.spec.ts +++ b/remote/test/puppeteer/test/src/oopif.spec.ts @@ -5,10 +5,9 @@ */ import expect from 'expect'; -import type {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js'; import type {CDPSession} from 'puppeteer-core/internal/api/CDPSession.js'; import {CDPSessionEvent} from 'puppeteer-core/internal/api/CDPSession.js'; -import type {CdpTarget} from 'puppeteer-core/internal/cdp/Target.js'; +import type {Page} from 'puppeteer-core/internal/api/Page.js'; import {getTestState, launch} from './mocha-utils.js'; import {attachFrame, detachFrame, navigateFrame} from './utils.js'; @@ -33,7 +32,7 @@ describe('OOPIF', function () { }); beforeEach(async () => { - state.context = await state.browser.createIncognitoBrowserContext(); + state.context = await state.browser.createBrowserContext(); state.page = await state.context.newPage(); }); @@ -222,7 +221,7 @@ describe('OOPIF', function () { it('should provide access to elements', async () => { const {server, isHeadless, headless, page} = state; - if (!isHeadless || headless === 'new') { + if (!isHeadless || headless === 'true') { // TODO: this test is partially blocked on crbug.com/1334119. Enable test once // the upstream is fixed. // TLDR: when we dispatch events to the frame the compositor might @@ -266,24 +265,24 @@ describe('OOPIF', function () { await frame.waitForSelector('#clicked'); }); it('should report oopif frames', async () => { - const {server, page, context} = state; + const {server, page} = state; const frame = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); }); await page.goto(server.PREFIX + '/dynamic-oopif.html'); await frame; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(page.frames()).toHaveLength(2); }); it('should wait for inner OOPIFs', async () => { - const {server, page, context} = state; + const {server, page} = state; await page.goto(`http://mainframe:${server.PORT}/main-frame.html`); const frame2 = await page.waitForFrame(frame => { return frame.url().endsWith('inner-frame2.html'); }); - expect(oopifs(context)).toHaveLength(2); + expect(await iframes(page)).toHaveLength(2); expect( page.frames().filter(frame => { return frame.isOOPFrame(); @@ -297,7 +296,7 @@ describe('OOPIF', function () { }); it('should load oopif iframes with subresources and request interception', async () => { - const {server, page, context} = state; + const {server, page} = state; const framePromise = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); @@ -312,7 +311,7 @@ describe('OOPIF', function () { await page.goto(server.PREFIX + '/dynamic-oopif.html'); const frame = await framePromise; const request = await requestPromise; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(request.frame()).toBe(frame); }); @@ -394,14 +393,14 @@ describe('OOPIF', function () { }); it('should detect existing OOPIFs when Puppeteer connects to an existing page', async () => { - const {server, puppeteer, page, context} = state; + const {server, puppeteer, page} = state; const frame = page.waitForFrame(frame => { return frame.url().endsWith('/oopif.html'); }); await page.goto(server.PREFIX + '/dynamic-oopif.html'); await frame; - expect(oopifs(context)).toHaveLength(1); + expect(await iframes(page)).toHaveLength(1); expect(page.frames()).toHaveLength(2); const browserURL = 'http://127.0.0.1:21222'; @@ -472,7 +471,7 @@ describe('OOPIF', function () { const {server, page} = state; // Setup our session listeners to observe OOPIF activity. - const session = await page.target().createCDPSession(); + const session = await page.createCDPSession(); const networkEvents: string[] = []; const otherSessions: CDPSession[] = []; await session.send('Target.setAutoAttach', { @@ -520,8 +519,13 @@ describe('OOPIF', function () { }); }); -function oopifs(context: BrowserContext) { - return context.targets().filter(target => { - return (target as CdpTarget)._getTargetInfo().type === 'iframe'; +async function iframes(page: Page) { + const iframes = await Promise.all( + page.frames().map(async frame => { + return await frame.frameElement(); + }) + ); + return iframes.filter(frame => { + return frame !== null; }); } diff --git a/remote/test/puppeteer/test/src/page.spec.ts b/remote/test/puppeteer/test/src/page.spec.ts index 79fc69ebbc..d83920d3ff 100644 --- a/remote/test/puppeteer/test/src/page.spec.ts +++ b/remote/test/puppeteer/test/src/page.spec.ts @@ -15,6 +15,7 @@ import type {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js'; import type {Metrics, Page} from 'puppeteer-core/internal/api/Page.js'; import type {CdpPage} from 'puppeteer-core/internal/cdp/Page.js'; import type {ConsoleMessage} from 'puppeteer-core/internal/common/ConsoleMessage.js'; +import {Deferred} from 'puppeteer-core/internal/util/Deferred.js'; import sinon from 'sinon'; import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; @@ -42,9 +43,9 @@ describe('Page', function () { expect(error.message).toContain('Protocol error'); }); it('should not be visible in browser.pages', async () => { - const {browser} = await getTestState(); + const {browser, context} = await getTestState(); - const newPage = await browser.newPage(); + const newPage = await context.newPage(); expect(await browser.pages()).toContain(newPage); await newPage.close(); expect(await browser.pages()).not.toContain(newPage); @@ -102,7 +103,11 @@ describe('Page', function () { ]); for (let i = 0; i < 2; i++) { const message = results[i].message; - expect(message).atLeastOneToContain(['Target closed', 'Page closed!']); + expect(message).atLeastOneToContain([ + 'Target closed', + 'Page closed!', + 'Frame detached', + ]); expect(message).not.toContain('Timeout'); } }); @@ -445,7 +450,7 @@ describe('Page', function () { messages.map(msg => { return msg.type(); }) - ).toEqual(['trace', 'dir', 'warning', 'error', 'log']); + ).toEqual(['trace', 'dir', 'warn', 'error', 'log']); expect( messages.map(msg => { return msg.text(); @@ -492,6 +497,21 @@ describe('Page', function () { 'JSHandle@window', ]); }); + it('should return remote objects', async () => { + const {page} = await getTestState(); + + const logPromise = waitEvent<ConsoleMessage>(page, 'console'); + await page.evaluate(() => { + (globalThis as any).test = 1; + console.log(1, 2, 3, globalThis); + }); + const log = await logPromise; + expect(log.text()).toBe('1 2 3 JSHandle@object'); + expect(log.args()).toHaveLength(4); + expect(await (await log.args()[3]!.getProperty('test')).jsonValue()).toBe( + 1 + ); + }); it('should trigger correct Log', async () => { const {page, server, isChrome} = await getTestState(); @@ -583,14 +603,10 @@ describe('Page', function () { // 3. After that, remove the iframe. frame.remove(); }); - const popupTarget = page - .browserContext() - .targets() - .find(target => { - return target !== page.target(); - })!; - // 4. Connect to the popup and make sure it doesn't throw. - await popupTarget.page(); + // 4. The target will always be the last one. + const popupTarget = page.browserContext().targets().at(-1)!; + // 5. Connect to the popup and make sure it doesn't throw and is not the same page. + expect(await popupTarget.page()).not.toBe(page); }); }); @@ -1015,15 +1031,15 @@ describe('Page', function () { it('should be callable from-inside evaluateOnNewDocument', async () => { const {page} = await getTestState(); - let called = false; + const called = new Deferred<void>(); await page.exposeFunction('woof', function () { - called = true; + called.resolve(); }); await page.evaluateOnNewDocument(() => { return (globalThis as any).woof(); }); await page.reload(); - expect(called).toBe(true); + await called.valueOrThrow(); }); it('should survive navigation', async () => { const {page, server} = await getTestState(); @@ -1217,7 +1233,7 @@ describe('Page', function () { page.goto(server.PREFIX + '/error.html'), ]); expect(error.message).toContain('Fancy'); - expect(error.stack?.split('\n')[1]).toContain('error.html:13'); + expect(error.stack?.split('\n').at(-1)).toContain('error.html:3:1'); }); }); @@ -1940,33 +1956,20 @@ describe('Page', function () { } }); - it('can print to PDF with accessible', async () => { - const {page, server} = await getTestState(); - - const outputFile = __dirname + '/../assets/output.pdf'; - const outputFileAccessible = - __dirname + '/../assets/output-accessible.pdf'; - await page.goto(server.PREFIX + '/pdf.html'); - await page.pdf({path: outputFile}); - await page.pdf({path: outputFileAccessible, tagged: true}); - try { - expect( - fs.readFileSync(outputFileAccessible).byteLength - ).toBeGreaterThan(fs.readFileSync(outputFile).byteLength); - } finally { - fs.unlinkSync(outputFileAccessible); - fs.unlinkSync(outputFile); - } - }); - it('can print to PDF and stream the result', async () => { const {page} = await getTestState(); const stream = await page.createPDFStream(); let size = 0; - for await (const chunk of stream) { - size += chunk.length; + const reader = stream.getReader(); + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } + size += value.length; } + expect(size).toBeGreaterThan(0); }); @@ -2252,9 +2255,9 @@ describe('Page', function () { describe('Page.bringToFront', function () { it('should work', async () => { - const {browser} = await getTestState(); - const page1 = await browser.newPage(); - const page2 = await browser.newPage(); + const {context} = await getTestState(); + const page1 = await context.newPage(); + const page2 = await context.newPage(); await page1.bringToFront(); expect( diff --git a/remote/test/puppeteer/test/src/proxy.spec.ts b/remote/test/puppeteer/test/src/proxy.spec.ts index 07b73cdd0d..1b79cd6665 100644 --- a/remote/test/puppeteer/test/src/proxy.spec.ts +++ b/remote/test/puppeteer/test/src/proxy.spec.ts @@ -150,7 +150,7 @@ describe('request proxy', () => { args: [...defaultArgs, `--proxy-server=${proxyServerUrl}`], }); try { - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const page = await context.newPage(); const response = (await page.goto(emptyPageUrl))!; @@ -174,7 +174,7 @@ describe('request proxy', () => { ], }); try { - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const page = await context.newPage(); const response = (await page.goto(emptyPageUrl))!; @@ -197,7 +197,7 @@ describe('request proxy', () => { args: defaultArgs, }); try { - const context = await browser.createIncognitoBrowserContext({ + const context = await browser.createBrowserContext({ proxyServer: proxyServerUrl, }); const page = await context.newPage(); @@ -219,7 +219,7 @@ describe('request proxy', () => { args: defaultArgs, }); try { - const context = await browser.createIncognitoBrowserContext({ + const context = await browser.createBrowserContext({ proxyServer: proxyServerUrl, proxyBypassList: [new URL(emptyPageUrl).host], }); diff --git a/remote/test/puppeteer/test/src/queryselector.spec.ts b/remote/test/puppeteer/test/src/queryselector.spec.ts index 7fd27f914f..c8df118e5f 100644 --- a/remote/test/puppeteer/test/src/queryselector.spec.ts +++ b/remote/test/puppeteer/test/src/queryselector.spec.ts @@ -174,29 +174,29 @@ describe('querySelector', function () { const elements = await page.$$('div'); expect(elements).toHaveLength(0); }); - }); - describe('Page.$x', function () { - it('should query existing element', async () => { - const {page} = await getTestState(); + describe('xpath', function () { + it('should query existing element', async () => { + const {page} = await getTestState(); - await page.setContent('<section>test</section>'); - const elements = await page.$x('/html/body/section'); - expect(elements[0]).toBeTruthy(); - expect(elements).toHaveLength(1); - }); - it('should return empty array for non-existing element', async () => { - const {page} = await getTestState(); + await page.setContent('<section>test</section>'); + const elements = await page.$$('xpath/html/body/section'); + expect(elements[0]).toBeTruthy(); + expect(elements).toHaveLength(1); + }); + it('should return empty array for non-existing element', async () => { + const {page} = await getTestState(); - const element = await page.$x('/html/body/non-existing-element'); - expect(element).toEqual([]); - }); - it('should return multiple elements', async () => { - const {page} = await getTestState(); + const element = await page.$$('xpath/html/body/non-existing-element'); + expect(element).toEqual([]); + }); + it('should return multiple elements', async () => { + const {page} = await getTestState(); - await page.setContent('<div></div><div></div>'); - const elements = await page.$x('/html/body/div'); - expect(elements).toHaveLength(2); + await page.setContent('<div></div><div></div>'); + const elements = await page.$$('xpath/html/body/div'); + expect(elements).toHaveLength(2); + }); }); }); @@ -347,37 +347,40 @@ describe('querySelector', function () { const elements = await html.$$('div'); expect(elements).toHaveLength(0); }); - }); - describe('ElementHandle.$x', function () { - it('should query existing element', async () => { - const {page, server} = await getTestState(); - - await page.goto(server.PREFIX + '/playground.html'); - await page.setContent( - '<html><body><div class="second"><div class="inner">A</div></div></body></html>' - ); - using html = (await page.$('html'))!; - const second = await html.$x(`./body/div[contains(@class, 'second')]`); - const inner = await second[0]!.$x(`./div[contains(@class, 'inner')]`); - const content = await page.evaluate(e => { - return e.textContent; - }, inner[0]!); - expect(content).toBe('A'); - }); + describe('xpath', function () { + it('should query existing element', async () => { + const {page, server} = await getTestState(); + + await page.goto(server.PREFIX + '/playground.html'); + await page.setContent( + '<html><body><div class="second"><div class="inner">A</div></div></body></html>' + ); + using html = (await page.$('html'))!; + const second = await html.$$( + `xpath/./body/div[contains(@class, 'second')]` + ); + const inner = await second[0]!.$$( + `xpath/./div[contains(@class, 'inner')]` + ); + const content = await page.evaluate(e => { + return e.textContent; + }, inner[0]!); + expect(content).toBe('A'); + }); - it('should return null for non-existing element', async () => { - const {page} = await getTestState(); + it('should return null for non-existing element', async () => { + const {page} = await getTestState(); - await page.setContent( - '<html><body><div class="second"><div class="inner">B</div></div></body></html>' - ); - using html = (await page.$('html'))!; - const second = await html.$x(`/div[contains(@class, 'third')]`); - expect(second).toEqual([]); + await page.setContent( + '<html><body><div class="second"><div class="inner">B</div></div></body></html>' + ); + using html = (await page.$('html'))!; + const second = await html.$$(`xpath/div[contains(@class, 'third')]`); + expect(second).toEqual([]); + }); }); }); - // This is the same tests for `$$eval` and `$$` as above, but with a queryAll // handler that returns an array instead of a list of nodes. describe('QueryAll', function () { diff --git a/remote/test/puppeteer/test/src/requestinterception.spec.ts b/remote/test/puppeteer/test/src/requestinterception.spec.ts index 45827bb3cf..4b88d30a3b 100644 --- a/remote/test/puppeteer/test/src/requestinterception.spec.ts +++ b/remote/test/puppeteer/test/src/requestinterception.spec.ts @@ -118,7 +118,7 @@ describe('request interception', function () { await page.goto(server.EMPTY_PAGE); await page.setRequestInterception(true); - const cdp = await page.target().createCDPSession(); + const cdp = await page.createCDPSession(); await cdp.send('DOM.enable'); const urls: string[] = []; page.on('request', request => { diff --git a/remote/test/puppeteer/test/src/screenshot.spec.ts b/remote/test/puppeteer/test/src/screenshot.spec.ts index ad53b60e95..9176d0c920 100644 --- a/remote/test/puppeteer/test/src/screenshot.spec.ts +++ b/remote/test/puppeteer/test/src/screenshot.spec.ts @@ -8,12 +8,7 @@ import assert from 'assert'; import expect from 'expect'; -import { - getTestState, - isHeadless, - launch, - setupTestBrowserHooks, -} from './mocha-utils.js'; +import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js'; describe('Screenshots', function () { setupTestBrowserHooks(); @@ -366,7 +361,7 @@ describe('Screenshots', function () { it('should run in parallel in multiple pages', async () => { const {browser, server} = await getTestState(); - const context = await browser.createIncognitoBrowserContext(); + const context = await browser.createBrowserContext(); const N = 2; const pages = await Promise.all( @@ -436,18 +431,15 @@ describe('Screenshots', function () { }); expect(screenshot).toBeGolden('white.jpg'); }); - (!isHeadless ? it : it.skip)( - 'should work in "fromSurface: false" mode', - async () => { - const {page, server} = await getTestState(); + it('should work in "fromSurface: false" mode', async () => { + const {page, server} = await getTestState(); - await page.setViewport({width: 500, height: 500}); - await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ - fromSurface: false, - }); - expect(screenshot).toBeDefined(); // toBeGolden('screenshot-fromsurface-false.png'); - } - ); + await page.setViewport({width: 500, height: 500}); + await page.goto(server.PREFIX + '/grid.html'); + const screenshot = await page.screenshot({ + fromSurface: false, + }); + expect(screenshot).toBeDefined(); + }); }); }); diff --git a/remote/test/puppeteer/test/src/target.spec.ts b/remote/test/puppeteer/test/src/target.spec.ts index 28d17a4030..6c1b9cb95e 100644 --- a/remote/test/puppeteer/test/src/target.spec.ts +++ b/remote/test/puppeteer/test/src/target.spec.ts @@ -179,6 +179,29 @@ describe('Target', function () { }) ).toBe('[object ServiceWorkerGlobalScope]'); }); + + it('should close a service worker', async () => { + const {page, server, context} = await getTestState(); + + await page.goto(server.PREFIX + '/serviceworkers/empty/sw.html'); + + const target = await context.waitForTarget( + target => { + return target.type() === 'service_worker'; + }, + {timeout: 3000} + ); + const worker = (await target.worker())!; + + const onceDestroyed = new Promise(resolve => { + context.once('targetdestroyed', event => { + resolve(event); + }); + }); + await worker.close(); + expect(await onceDestroyed).toBe(target); + }); + it('should create a worker from a shared worker', async () => { const {page, server, context} = await getTestState(); @@ -199,6 +222,31 @@ describe('Target', function () { }) ).toBe('[object SharedWorkerGlobalScope]'); }); + + it('should close a shared worker', async () => { + const {page, server, context} = await getTestState(); + + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => { + new SharedWorker('data:text/javascript,console.log("hi2")'); + }); + const target = await context.waitForTarget( + target => { + return target.type() === 'shared_worker'; + }, + {timeout: 3000} + ); + const worker = (await target.worker())!; + + const onceDestroyed = new Promise(resolve => { + context.once('targetdestroyed', event => { + resolve(event); + }); + }); + await worker.close(); + expect(await onceDestroyed).toBe(target); + }); + it('should report when a target url changes', async () => { const {page, server, context} = await getTestState(); @@ -285,7 +333,7 @@ describe('Target', function () { describe('Browser.waitForTarget', () => { it('should wait for a target', async () => { - const {browser, server} = await getTestState(); + const {browser, server, context} = await getTestState(); let resolved = false; const targetPromise = browser.waitForTarget( @@ -306,7 +354,7 @@ describe('Target', function () { throw error; } }); - const page = await browser.newPage(); + const page = await context.newPage(); expect(resolved).toBe(false); await page.goto(server.EMPTY_PAGE); try { diff --git a/remote/test/puppeteer/test/src/touchscreen.spec.ts b/remote/test/puppeteer/test/src/touchscreen.spec.ts index 28a18ec449..94d8e6fecb 100644 --- a/remote/test/puppeteer/test/src/touchscreen.spec.ts +++ b/remote/test/puppeteer/test/src/touchscreen.spec.ts @@ -15,65 +15,235 @@ describe('Touchscreen', () => { describe('Touchscreen.prototype.tap', () => { it('should work', async () => { - const {page, server, isHeadless} = await getTestState(); + const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/touchscreen.html'); await page.tap('button'); expect( - ( - await page.evaluate(() => { - return allEvents; - }) - ).filter(({type}) => { - return type !== 'pointermove' || isHeadless; + await page.evaluate(() => { + return allEvents; }) ).toMatchObject([ - {height: 1, type: 'pointerdown', width: 1, x: 5, y: 5}, - {touches: [[5, 5, 0.5, 0.5]], type: 'touchstart'}, - {height: 1, type: 'pointerup', width: 1, x: 5, y: 5}, - {touches: [[5, 5, 0.5, 0.5]], type: 'touchend'}, - {height: 1, type: 'click', width: 1, x: 5, y: 5}, + { + type: 'pointerdown', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchstart', + changedTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointerup', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchend', + changedTouches: [ + {clientX: 5, clientY: 5, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [], + }, + { + type: 'click', + x: 5, + y: 5, + width: 1, + height: 1, + altitudeAngle: Math.PI / 2, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, ]); }); }); describe('Touchscreen.prototype.touchMove', () => { it('should work', async () => { - const {page, server, isHeadless} = await getTestState(); + const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/input/touchscreen.html'); + // Note that touchmoves are sometimes not triggered if consecutive + // touchmoves are less than 15 pixels. + // + // See https://github.com/puppeteer/puppeteer/issues/10836 await page.touchscreen.touchStart(0, 0); - await page.touchscreen.touchMove(10, 10); - await page.touchscreen.touchMove(15.5, 15); - await page.touchscreen.touchMove(20, 20.4); - await page.touchscreen.touchMove(40, 30); + await page.touchscreen.touchMove(15, 15); + await page.touchscreen.touchMove(30.5, 30); + await page.touchscreen.touchMove(50, 45.4); + await page.touchscreen.touchMove(80, 50); await page.touchscreen.touchEnd(); + expect( - ( - await page.evaluate(() => { - return allEvents; - }) - ).filter(({type}) => { - return type !== 'pointermove' || isHeadless; - }) - ).toMatchObject( - [ - {type: 'pointerdown', x: 0, y: 0, width: 1, height: 1}, - {type: 'touchstart', touches: [[0, 0, 0.5, 0.5]]}, - {type: 'pointermove', x: 10, y: 10, width: 1, height: 1}, - {type: 'touchmove', touches: [[10, 10, 0.5, 0.5]]}, - {type: 'pointermove', x: 16, y: 15, width: 1, height: 1}, - {type: 'touchmove', touches: [[16, 15, 0.5, 0.5]]}, - {type: 'pointermove', x: 20, y: 20, width: 1, height: 1}, - {type: 'touchmove', touches: [[20, 20, 0.5, 0.5]]}, - {type: 'pointermove', x: 40, y: 30, width: 1, height: 1}, - {type: 'touchmove', touches: [[40, 30, 0.5, 0.5]]}, - {type: 'pointerup', x: 40, y: 30, width: 1, height: 1}, - {type: 'touchend', touches: [[40, 30, 0.5, 0.5]]}, - ].filter(({type}) => { - return type !== 'pointermove' || isHeadless; + await page.evaluate(() => { + return allEvents; }) - ); + ).toMatchObject([ + { + type: 'pointerdown', + x: 0, + y: 0, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchstart', + changedTouches: [ + {clientX: 0, clientY: 0, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 0, clientY: 0, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 15, + y: 15, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 15, clientY: 15, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 15, clientY: 15, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 31, + y: 30, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 31, clientY: 30, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 31, clientY: 30, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 50, + y: 45, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 50, clientY: 45, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 50, clientY: 45, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointermove', + x: 80, + y: 50, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0.5, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchmove', + changedTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + }, + { + type: 'pointerup', + x: 80, + y: 50, + width: 1, + height: 1, + altitudeAngle: 1.5707963267948966, + azimuthAngle: 0, + pressure: 0, + pointerType: 'touch', + twist: 0, + tiltX: 0, + tiltY: 0, + }, + { + type: 'touchend', + changedTouches: [ + {clientX: 80, clientY: 50, radiusX: 0.5, radiusY: 0.5, force: 0.5}, + ], + activeTouches: [], + }, + ]); }); }); }); diff --git a/remote/test/puppeteer/test/src/tracing.spec.ts b/remote/test/puppeteer/test/src/tracing.spec.ts index 2c0a5aff19..7ee6d46192 100644 --- a/remote/test/puppeteer/test/src/tracing.spec.ts +++ b/remote/test/puppeteer/test/src/tracing.spec.ts @@ -8,6 +8,8 @@ import fs from 'fs'; import path from 'path'; import expect from 'expect'; +import * as utils from 'puppeteer-core/internal/common/util.js'; +import sinon from 'sinon'; import {launch} from './mocha-utils.js'; @@ -113,16 +115,26 @@ describe('Tracing', function () { await page.tracing.start({screenshots: true}); await page.goto(server.PREFIX + '/grid.html'); - const oldBufferConcat = Buffer.concat; - try { - Buffer.concat = () => { - throw new Error('error'); - }; - const trace = await page.tracing.stop(); - expect(trace).toEqual(undefined); - } finally { - Buffer.concat = oldBufferConcat; - } + const oldGetReadableAsBuffer = utils.getReadableAsBuffer; + sinon.stub(utils, 'getReadableAsBuffer').callsFake(() => { + return oldGetReadableAsBuffer({ + getReader() { + return { + done: false, + read() { + if (!this.done) { + this.done = true; + return {done: false, value: 42}; + } + return {done: true}; + }, + }; + }, + } as unknown as ReadableStream); + }); + + const trace = await page.tracing.stop(); + expect(trace).toEqual(undefined); }); it('should support a buffer without a path', async () => { diff --git a/remote/test/puppeteer/test/src/waittask.spec.ts b/remote/test/puppeteer/test/src/waittask.spec.ts index 8ff52db16f..b9a28c9e7a 100644 --- a/remote/test/puppeteer/test/src/waittask.spec.ts +++ b/remote/test/puppeteer/test/src/waittask.spec.ts @@ -336,39 +336,6 @@ describe('waittask specs', function () { }); }); - describe('Page.waitForTimeout', () => { - it('waits for the given timeout before resolving', async () => { - const {page, server} = await getTestState(); - await page.goto(server.EMPTY_PAGE); - const startTime = Date.now(); - await page.waitForTimeout(1000); - const endTime = Date.now(); - /* In a perfect world endTime - startTime would be exactly 1000 but we - * expect some fluctuations and for it to be off by a little bit. So to - * avoid a flaky test we'll make sure it waited for roughly 1 second. - */ - expect(endTime - startTime).toBeGreaterThan(700); - expect(endTime - startTime).toBeLessThan(1300); - }); - }); - - describe('Frame.waitForTimeout', () => { - it('waits for the given timeout before resolving', async () => { - const {page, server} = await getTestState(); - await page.goto(server.EMPTY_PAGE); - const frame = page.mainFrame(); - const startTime = Date.now(); - await frame.waitForTimeout(1000); - const endTime = Date.now(); - /* In a perfect world endTime - startTime would be exactly 1000 but we - * expect some fluctuations and for it to be off by a little bit. So to - * avoid a flaky test we'll make sure it waited for roughly 1 second - */ - expect(endTime - startTime).toBeGreaterThan(700); - expect(endTime - startTime).toBeLessThan(1300); - }); - }); - describe('Frame.waitForSelector', function () { const addElement = (tag: string) => { return document.body.appendChild(document.createElement(tag)); @@ -479,9 +446,10 @@ describe('waittask specs', function () { await detachFrame(page, 'frame1'); await waitPromise; expect(waitError).toBeTruthy(); - expect(waitError?.message).toContain( - 'waitForFunction failed: frame got detached.' - ); + expect(waitError?.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); }); it('should survive cross-process navigation', async () => { const {page, server} = await getTestState(); @@ -726,142 +694,151 @@ describe('waittask specs', function () { // The extension is ts here as Mocha maps back via sourcemaps. expect(error?.stack).toContain('WaitTask.ts'); }); - }); - describe('Frame.waitForXPath', function () { - const addElement = (tag: string) => { - return document.body.appendChild(document.createElement(tag)); - }; - - it('should support some fancy xpath', async () => { - const {page} = await getTestState(); + describe('xpath', function () { + const addElement = (tag: string) => { + return document.body.appendChild(document.createElement(tag)); + }; - await page.setContent(`<p>red herring</p><p>hello world </p>`); - const waitForXPath = page.waitForXPath( - '//p[normalize-space(.)="hello world"]' - ); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('hello world '); - }); - it('should respect timeout', async () => { - const {page} = await getTestState(); + it('should support some fancy xpath', async () => { + const {page} = await getTestState(); - let error!: Error; - await page.waitForXPath('//div', {timeout: 10}).catch(error_ => { - return (error = error_); + await page.setContent(`<p>red herring</p><p>hello world </p>`); + const waitForSelector = page.waitForSelector( + 'xpath/.//p[normalize-space(.)="hello world"]' + ); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('hello world '); }); - expect(error).toBeInstanceOf(TimeoutError); - expect(error?.message).toContain('Waiting failed: 10ms exceeded'); - }); - it('should run in specified frame', async () => { - const {page, server} = await getTestState(); + it('should respect timeout', async () => { + const {page} = await getTestState(); - await attachFrame(page, 'frame1', server.EMPTY_PAGE); - await attachFrame(page, 'frame2', server.EMPTY_PAGE); - const frame1 = page.frames()[1]!; - const frame2 = page.frames()[2]!; - const waitForXPathPromise = frame2.waitForXPath('//div'); - await frame1.evaluate(addElement, 'div'); - await frame2.evaluate(addElement, 'div'); - using eHandle = await waitForXPathPromise; - expect(eHandle?.frame).toBe(frame2); - }); - it('should throw when frame is detached', async () => { - const {page, server} = await getTestState(); - - await attachFrame(page, 'frame1', server.EMPTY_PAGE); - const frame = page.frames()[1]!; - let waitError: Error | undefined; - const waitPromise = frame - .waitForXPath('//*[@class="box"]') - .catch(error => { - return (waitError = error); - }); - await detachFrame(page, 'frame1'); - await waitPromise; - expect(waitError).toBeTruthy(); - expect(waitError?.message).toContain( - 'waitForFunction failed: frame got detached.' - ); - }); - it('hidden should wait for display: none', async () => { - const {page} = await getTestState(); - - let divHidden = false; - await page.setContent(`<div style='display: block;'>text</div>`); - const waitForXPath = page - .waitForXPath('//div', {hidden: true}) - .then(() => { - return (divHidden = true); + let error!: Error; + await page + .waitForSelector('xpath/.//div', {timeout: 10}) + .catch(error_ => { + return (error = error_); + }); + expect(error).toBeInstanceOf(TimeoutError); + expect(error?.message).toContain('Waiting failed: 10ms exceeded'); + }); + it('should run in specified frame', async () => { + const {page, server} = await getTestState(); + + await attachFrame(page, 'frame1', server.EMPTY_PAGE); + await attachFrame(page, 'frame2', server.EMPTY_PAGE); + const frame1 = page.frames()[1]!; + const frame2 = page.frames()[2]!; + const waitForSelector = frame2.waitForSelector('xpath/.//div'); + await frame1.evaluate(addElement, 'div'); + await frame2.evaluate(addElement, 'div'); + using eHandle = await waitForSelector; + expect(eHandle?.frame).toBe(frame2); + }); + it('should throw when frame is detached', async () => { + const {page, server} = await getTestState(); + + await attachFrame(page, 'frame1', server.EMPTY_PAGE); + const frame = page.frames()[1]!; + let waitError: Error | undefined; + const waitPromise = frame + .waitForSelector('xpath/.//*[@class="box"]') + .catch(error => { + return (waitError = error); + }); + await detachFrame(page, 'frame1'); + await waitPromise; + expect(waitError).toBeTruthy(); + expect(waitError?.message).atLeastOneToContain([ + 'waitForFunction failed: frame got detached.', + 'Browsing context already closed.', + ]); + }); + it('hidden should wait for display: none', async () => { + const {page} = await getTestState(); + + let divHidden = false; + await page.setContent(`<div style='display: block;'>text</div>`); + const waitForSelector = page + .waitForSelector('xpath/.//div', {hidden: true}) + .then(() => { + return (divHidden = true); + }); + await page.waitForSelector('xpath/.//div'); // do a round trip + expect(divHidden).toBe(false); + await page.evaluate(() => { + return document + .querySelector('div') + ?.style.setProperty('display', 'none'); }); - await page.waitForXPath('//div'); // do a round trip - expect(divHidden).toBe(false); - await page.evaluate(() => { - return document - .querySelector('div') - ?.style.setProperty('display', 'none'); + expect(await waitForSelector).toBe(true); + expect(divHidden).toBe(true); }); - expect(await waitForXPath).toBe(true); - expect(divHidden).toBe(true); - }); - it('hidden should return null if the element is not found', async () => { - const {page} = await getTestState(); + it('hidden should return null if the element is not found', async () => { + const {page} = await getTestState(); - using waitForXPath = await page.waitForXPath('//div', {hidden: true}); + using waitForSelector = await page.waitForSelector('xpath/.//div', { + hidden: true, + }); - expect(waitForXPath).toBe(null); - }); - it('hidden should return an empty element handle if the element is found', async () => { - const {page} = await getTestState(); + expect(waitForSelector).toBe(null); + }); + it('hidden should return an empty element handle if the element is found', async () => { + const {page} = await getTestState(); - await page.setContent(`<div style='display: none;'>text</div>`); + await page.setContent(`<div style='display: none;'>text</div>`); - using waitForXPath = await page.waitForXPath('//div', {hidden: true}); + using waitForSelector = await page.waitForSelector('xpath/.//div', { + hidden: true, + }); - expect(waitForXPath).toBeInstanceOf(ElementHandle); - }); - it('should return the element handle', async () => { - const {page} = await getTestState(); + expect(waitForSelector).toBeInstanceOf(ElementHandle); + }); + it('should return the element handle', async () => { + const {page} = await getTestState(); - const waitForXPath = page.waitForXPath('//*[@class="zombo"]'); - await page.setContent(`<div class='zombo'>anything</div>`); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('anything'); - }); - it('should allow you to select a text node', async () => { - const {page} = await getTestState(); + const waitForSelector = page.waitForSelector( + 'xpath/.//*[@class="zombo"]' + ); + await page.setContent(`<div class='zombo'>anything</div>`); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('anything'); + }); + it('should allow you to select a text node', async () => { + const {page} = await getTestState(); - await page.setContent(`<div>some text</div>`); - using text = await page.waitForXPath('//div/text()'); - expect(await (await text!.getProperty('nodeType')!).jsonValue()).toBe( - 3 /* Node.TEXT_NODE */ - ); - }); - it('should allow you to select an element with single slash', async () => { - const {page} = await getTestState(); + await page.setContent(`<div>some text</div>`); + using text = await page.waitForSelector('xpath/.//div/text()'); + expect(await (await text!.getProperty('nodeType')!).jsonValue()).toBe( + 3 /* Node.TEXT_NODE */ + ); + }); + it('should allow you to select an element with single slash', async () => { + const {page} = await getTestState(); - await page.setContent(`<div>some text</div>`); - const waitForXPath = page.waitForXPath('/html/body/div'); - expect( - await page.evaluate( - x => { - return x?.textContent; - }, - await waitForXPath - ) - ).toBe('some text'); + await page.setContent(`<div>some text</div>`); + const waitForSelector = page.waitForSelector('xpath/html/body/div'); + expect( + await page.evaluate( + x => { + return x?.textContent; + }, + await waitForSelector + ) + ).toBe('some text'); + }); }); }); }); diff --git a/remote/test/puppeteer/test/src/worker.spec.ts b/remote/test/puppeteer/test/src/worker.spec.ts index 254ff4a514..b5b7159e6a 100644 --- a/remote/test/puppeteer/test/src/worker.spec.ts +++ b/remote/test/puppeteer/test/src/worker.spec.ts @@ -52,7 +52,10 @@ describe('Workers', function () { const error = await workerThisObj.getProperty('self').catch(error => { return error; }); - expect(error.message).toContain('Most likely the worker has been closed.'); + expect(error.message).atLeastOneToContain([ + 'Most likely the worker has been closed.', + 'Realm already destroyed.', + ]); }); it('should report console logs', async () => { const {page} = await getTestState(); @@ -70,7 +73,7 @@ describe('Workers', function () { columnNumber: 8, }); }); - it('should have JSHandles for console logs', async () => { + it('should work with console logs', async () => { const {page} = await getTestState(); const logPromise = waitEvent<ConsoleMessage>(page, 'console'); @@ -80,9 +83,6 @@ describe('Workers', function () { const log = await logPromise; expect(log.text()).toBe('1 2 3 JSHandle@object'); expect(log.args()).toHaveLength(4); - expect(await (await log.args()[3]!.getProperty('origin')).jsonValue()).toBe( - 'null' - ); }); it('should have an execution context', async () => { const {page} = await getTestState(); @@ -106,4 +106,17 @@ describe('Workers', function () { const errorLog = await errorPromise; expect(errorLog.message).toContain('this is my error'); }); + + it('can be closed', async () => { + const {page, server} = await getTestState(); + + await Promise.all([ + waitEvent(page, 'workercreated'), + page.goto(server.PREFIX + '/worker/worker.html'), + ]); + const worker = page.workers()[0]!; + expect(worker?.url()).toContain('worker.js'); + + await Promise.all([waitEvent(page, 'workerdestroyed'), worker?.close()]); + }); }); diff --git a/remote/test/puppeteer/test/tsconfig.json b/remote/test/puppeteer/test/tsconfig.json index 554d034ff1..fdcd35374d 100644 --- a/remote/test/puppeteer/test/tsconfig.json +++ b/remote/test/puppeteer/test/tsconfig.json @@ -4,7 +4,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "build", - "rootDir": "src", + "rootDir": "src" }, - "include": ["src"], + "include": ["src"] } diff --git a/remote/test/puppeteer/tools/analyze_issue.mjs b/remote/test/puppeteer/tools/analyze_issue.mjs index 9592112de0..eff6a4122e 100755 --- a/remote/test/puppeteer/tools/analyze_issue.mjs +++ b/remote/test/puppeteer/tools/analyze_issue.mjs @@ -1,4 +1,10 @@ #!/usr/bin/env node +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + // @ts-check 'use strict'; diff --git a/remote/test/puppeteer/tools/clean.js b/remote/test/puppeteer/tools/clean.mjs index 049fdc0434..aa4ba516b1 100755 --- a/remote/test/puppeteer/tools/clean.js +++ b/remote/test/puppeteer/tools/clean.mjs @@ -1,7 +1,13 @@ #!/usr/bin/env node -const {exec} = require('child_process'); -const {readdirSync} = require('fs'); +/** + * @license + * Copyright 2022 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {exec} from 'child_process'; +import {readdirSync} from 'fs'; exec( `git clean -Xf ${readdirSync(process.cwd()) diff --git a/remote/test/puppeteer/tools/docgen/package.json b/remote/test/puppeteer/tools/docgen/package.json index f1ca4ea127..82f6d4d6c4 100644 --- a/remote/test/puppeteer/tools/docgen/package.json +++ b/remote/test/puppeteer/tools/docgen/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "scripts": { "build": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { @@ -24,10 +24,10 @@ } }, "devDependencies": { - "@microsoft/api-extractor": "7.39.4", - "@microsoft/api-documenter": "7.23.20", - "@microsoft/api-extractor-model": "7.28.7", + "@microsoft/api-extractor": "7.42.2", + "@microsoft/api-documenter": "7.23.35", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.64.2" + "@rushstack/node-core-library": "4.0.2" } } diff --git a/remote/test/puppeteer/tools/docgen/tsconfig.json b/remote/test/puppeteer/tools/docgen/tsconfig.json index fcaf1db737..27d0d84f5d 100644 --- a/remote/test/puppeteer/tools/docgen/tsconfig.json +++ b/remote/test/puppeteer/tools/docgen/tsconfig.json @@ -6,6 +6,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/doctest/package.json b/remote/test/puppeteer/tools/doctest/package.json index 8c7e9544d0..1d0adb633b 100644 --- a/remote/test/puppeteer/tools/doctest/package.json +++ b/remote/test/puppeteer/tools/doctest/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "scripts": { "build": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { @@ -24,7 +24,7 @@ } }, "devDependencies": { - "@swc/core": "1.3.107", + "@swc/core": "1.4.2", "@types/doctrine": "0.0.9", "@types/source-map-support": "0.5.10", "@types/yargs": "17.0.32", diff --git a/remote/test/puppeteer/tools/doctest/tsconfig.json b/remote/test/puppeteer/tools/doctest/tsconfig.json index bd70c0bd5e..6b8221571b 100644 --- a/remote/test/puppeteer/tools/doctest/tsconfig.json +++ b/remote/test/puppeteer/tools/doctest/tsconfig.json @@ -6,6 +6,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/download_chrome_canary.mjs b/remote/test/puppeteer/tools/download_chrome_canary.mjs new file mode 100644 index 0000000000..9f523aea2a --- /dev/null +++ b/remote/test/puppeteer/tools/download_chrome_canary.mjs @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint-disable no-console */ + +/** + * @fileoverview Installs the latest Chrome Canary using + * `@puppeteer/browsers` to the directory provided as the first argument + * (default: cwd). The executable path is written to the `executablePath` output + * param for GitHub actions. + * + * Examples: + * + * - `node tools/download_chrome_canary.mjs` + * - `node tools/download_chrome_canary.mjs /tmp/cache` + */ +import actions from '@actions/core'; + +import { + Browser, + computeExecutablePath, + install, + resolveBuildId, + detectBrowserPlatform, +} from '@puppeteer/browsers'; + +try { + const cacheDir = process.argv[2] || process.cwd(); + const browser = Browser.CHROME; + const platform = detectBrowserPlatform(); + const buildId = await resolveBuildId(browser, platform, 'canary'); + await install({ + browser, + buildId, + cacheDir, + }); + const executablePath = computeExecutablePath({ + cacheDir, + browser, + buildId, + }); + if (process.argv.indexOf('--shell') === -1) { + actions.setOutput('executablePath', executablePath); + } + console.log(executablePath); +} catch (err) { + actions.setFailed(`Failed to download the browser: ${err.message}`); +} diff --git a/remote/test/puppeteer/tools/eslint/package.json b/remote/test/puppeteer/tools/eslint/package.json index 190367ae43..c7f7f4f38d 100644 --- a/remote/test/puppeteer/tools/eslint/package.json +++ b/remote/test/puppeteer/tools/eslint/package.json @@ -32,6 +32,7 @@ "author": "The Chromium Authors", "license": "Apache-2.0", "devDependencies": { - "@prettier/sync": "0.5.0" + "@prettier/sync": "0.5.1", + "@typescript-eslint/utils": "7.1.0" } } diff --git a/remote/test/puppeteer/tools/eslint/src/check-license.ts b/remote/test/puppeteer/tools/eslint/src/check-license.ts index 7ae1a54384..b8590a7c3f 100644 --- a/remote/test/puppeteer/tools/eslint/src/check-license.ts +++ b/remote/test/puppeteer/tools/eslint/src/check-license.ts @@ -11,15 +11,16 @@ const createRule = ESLintUtils.RuleCreator(name => { return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.ts`; }); -const copyrightPattern = /Copyright ([0-9]{4}) Google Inc\./; +const currentYear = new Date().getFullYear(); -// const currentYear = new Date().getFullYear; - -// const licenseHeader = `/** -// * @license -// * Copyright ${currentYear} Google Inc. -// * SPDX-License-Identifier: Apache-2.0 -// */`; +// Needs to start and end with new line +const licenseHeader = ` +/** + * @license + * Copyright ${currentYear} Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +`; const enforceLicenseRule = createRule<[], 'licenseRule'>({ name: 'check-license', @@ -29,7 +30,7 @@ const enforceLicenseRule = createRule<[], 'licenseRule'>({ description: 'Validate existence of license header', requiresTypeChecking: false, }, - fixable: undefined, // TODO: change to 'code' once fixer works. + fixable: 'code', schema: [], messages: { licenseRule: 'Add license header.', @@ -39,40 +40,52 @@ const enforceLicenseRule = createRule<[], 'licenseRule'>({ create(context) { const sourceCode = context.sourceCode; const comments = sourceCode.getAllComments(); - const header = - comments[0]?.type === 'Block' && isHeaderComment(comments[0]) - ? comments[0] - : null; - - function isHeaderComment(comment: TSESTree.Comment) { - if (comment && comment.range[0] >= 0 && comment.range[1] <= 88) { - return true; - } else { - return false; + let insertAfter = [0, 0] as TSESTree.Range; + let header: TSESTree.Comment | null = null; + // Check only the first 2 comments + for (let index = 0; index < 2; index++) { + const comment = comments[index]; + if (!comment) { + break; + } + // Shebang comments should be at the top + if ( + // Types don't have it debugger showed it... + (comment.type as string) === 'Shebang' || + (comment.type === 'Line' && comment.value.startsWith('#!')) + ) { + insertAfter = comment.range; + continue; + } + if (comment.type === 'Block') { + header = comment; + break; } } return { Program(node) { + if (context.filename.endsWith('.json')) { + return; + } + if ( header && - header.value.includes('@license') && - header.value.includes('SPDX-License-Identifier: Apache-2.0') && - copyrightPattern.test(header.value) + (header.value.includes('@license') || + header.value.includes('License') || + header.value.includes('Copyright')) ) { return; } // Add header license if (!header || !header.value.includes('@license')) { - // const startLoc: [number, number] = [0, 88]; context.report({ node: node, messageId: 'licenseRule', - // TODO: fix the fixer. - // fix(fixer) { - // return fixer.insertTextBeforeRange(startLoc, licenseHeader); - // }, + fix(fixer) { + return fixer.insertTextAfterRange(insertAfter, licenseHeader); + }, }); } }, diff --git a/remote/test/puppeteer/tools/eslint/tsconfig.json b/remote/test/puppeteer/tools/eslint/tsconfig.json index da26cc936b..3a71788a21 100644 --- a/remote/test/puppeteer/tools/eslint/tsconfig.json +++ b/remote/test/puppeteer/tools/eslint/tsconfig.json @@ -7,8 +7,7 @@ "outDir": "./lib", "declaration": false, "declarationMap": false, - "sourceMap": false, "composite": false, - "removeComments": true, - }, + "removeComments": true + } } diff --git a/remote/test/puppeteer/tools/mocha-runner/package.json b/remote/test/puppeteer/tools/mocha-runner/package.json index 26612e504a..a817020d5e 100644 --- a/remote/test/puppeteer/tools/mocha-runner/package.json +++ b/remote/test/puppeteer/tools/mocha-runner/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "wireit", "test": "wireit", - "clean": "../clean.js" + "clean": "../clean.mjs" }, "wireit": { "build": { diff --git a/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts b/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts index 1707e4cc41..93287abe74 100644 --- a/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts +++ b/remote/test/puppeteer/tools/mocha-runner/src/mocha-runner.ts @@ -52,7 +52,7 @@ const { .scriptName('@puppeteer/mocha-runner') .option('coverage', { boolean: true, - default: true, + default: false, }) .option('suggestions', { boolean: true, diff --git a/remote/test/puppeteer/tools/mocha-runner/tsconfig.json b/remote/test/puppeteer/tools/mocha-runner/tsconfig.json index 73a1b17815..220a467ac1 100644 --- a/remote/test/puppeteer/tools/mocha-runner/tsconfig.json +++ b/remote/test/puppeteer/tools/mocha-runner/tsconfig.json @@ -8,6 +8,6 @@ "sourceMap": true, "declaration": false, "declarationMap": false, - "composite": false, - }, + "composite": false + } } diff --git a/remote/test/puppeteer/tools/sort-test-expectations.mjs b/remote/test/puppeteer/tools/sort-test-expectations.mjs index d1c8588d8a..972d244874 100644 --- a/remote/test/puppeteer/tools/sort-test-expectations.mjs +++ b/remote/test/puppeteer/tools/sort-test-expectations.mjs @@ -13,9 +13,22 @@ import prettier from 'prettier'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); const source = 'test/TestExpectations.json'; -const testExpectations = JSON.parse(fs.readFileSync(source, 'utf-8')); +let testExpectations = JSON.parse(fs.readFileSync(source, 'utf-8')); const committedExpectations = structuredClone(testExpectations); +function testIdMatchesExpectationPattern(title, pattern) { + const patternRegExString = pattern + // Replace `*` with non special character + .replace(/\*/g, '--STAR--') + // Escape special characters https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + // Replace placeholder with greedy match + .replace(/--STAR--/g, '(.*)?'); + // Match beginning and end explicitly + const patternRegEx = new RegExp(`^${patternRegExString}$`); + return patternRegEx.test(title); +} + const prettierConfig = await import( path.join(__dirname, '..', '.prettierrc.cjs') ); @@ -43,9 +56,80 @@ testExpectations.forEach(item => { item.parameters.sort(); item.expectations.sort(); item.platforms.sort(); + // Delete comments for PASS expectations. They are likely outdated. + if (item.expectations.length === 1 && item.expectations[0] === 'PASS') { + delete item.comment; + } +}); + +function isSubset(superset, subset) { + let isSubset = true; + + for (const p of subset) { + if (!superset.has(p)) { + isSubset = false; + } + } + + return isSubset; +} + +const toBeRemoved = new Set(); +for (let i = testExpectations.length - 1; i >= 0; i--) { + const expectation = testExpectations[i]; + const params = new Set(expectation.parameters); + const labels = new Set(expectation.expectations); + const platforms = new Set(expectation.platforms); + + let foundMatch = false; + for (let j = i - 1; j >= 0; j--) { + const candidate = testExpectations[j]; + const candidateParams = new Set(candidate.parameters); + const candidateLabels = new Set(candidate.expectations); + const candidatePlatforms = new Set(candidate.platforms); + + if ( + testIdMatchesExpectationPattern( + expectation.testIdPattern, + candidate.testIdPattern + ) && + isSubset(candidateParams, params) && + isSubset(candidatePlatforms, platforms) + ) { + foundMatch = true; + if (isSubset(candidateLabels, labels)) { + console.log('removing', expectation, 'already covered by', candidate); + toBeRemoved.add(expectation); + } + break; + } + } + + if (!foundMatch && isSubset(new Set(['PASS']), labels)) { + console.log( + 'removing', + expectation, + 'because the default expectation is to pass' + ); + toBeRemoved.add(expectation); + } +} + +testExpectations = testExpectations.filter(item => { + return !toBeRemoved.has(item); }); if (process.argv.includes('--lint')) { + const missingComments = []; + testExpectations.forEach(item => { + if (item.expectations.length === 1 && item.expectations[0] === 'PASS') { + return; + } + if (!item.comment) { + missingComments.push(item); + } + }); + if ( JSON.stringify(committedExpectations) !== JSON.stringify(testExpectations) ) { @@ -54,6 +138,14 @@ if (process.argv.includes('--lint')) { ); process.exit(1); } + + if (missingComments.length > 0) { + console.error( + `${source}: missing comments for the following expectations:`, + missingComments + ); + process.exit(1); + } } else { fs.writeFileSync( source, diff --git a/remote/test/puppeteer/tools/tsconfig.json b/remote/test/puppeteer/tools/tsconfig.json index 964d349435..393392c494 100644 --- a/remote/test/puppeteer/tools/tsconfig.json +++ b/remote/test/puppeteer/tools/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../tsconfig.base.json", - "files": ["../package.json"], + "files": ["../package.json"] } diff --git a/remote/test/puppeteer/versions.js b/remote/test/puppeteer/versions.js index cbd835efc6..05d8429789 100644 --- a/remote/test/puppeteer/versions.js +++ b/remote/test/puppeteer/versions.js @@ -7,6 +7,9 @@ const versionsPerRelease = new Map([ // This is a mapping from Chrome version => Puppeteer version. // In Chrome roll patches, use `NEXT` for the Puppeteer version. + ['122.0.6261.94', 'v22.4.0'], + ['122.0.6261.69', 'v22.3.0'], + ['122.0.6261.57', 'v22.2.0'], ['121.0.6167.85', 'v21.9.0'], ['120.0.6099.109', 'v21.8.0'], ['119.0.6045.105', 'v21.5.0'], |