diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index b7477d65..7ab56102 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -24,7 +24,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.x' cache: 'npm' - run: npm ci - run: npm run build --if-present diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..c2062eb9 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Visual Regression + +on: + push: + branches: ["develop"] + pull_request: + branches: ["develop"] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "24.x" + cache: npm + - run: npm ci + - run: npx playwright install --with-deps chromium + - run: npm test + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: playwright-report + path: tests/playwright-report/ + retention-days: 14 diff --git a/.github/workflows/update-snapshots.yml b/.github/workflows/update-snapshots.yml new file mode 100644 index 00000000..3b45f85a --- /dev/null +++ b/.github/workflows/update-snapshots.yml @@ -0,0 +1,27 @@ +name: Update Playwright Snapshots + +on: + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + fetch-depth: 0 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "24.x" + cache: npm + - run: npm ci + - run: npx playwright install --with-deps chromium + - run: npm run build && npx playwright test --update-snapshots + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: update playwright snapshots" + file_pattern: "tests/snapshots/*.png" diff --git a/.gitignore b/.gitignore index 9419a30d..5fbf63ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ node_modules/ *.css.map -tests/backstop_data/ \ No newline at end of file +tests/backstop_data/ +tests/snapshots/local/ +tests/test-results/ +tests/playwright-report/ +blob-report/ +playwright/.cache/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 85aee5a5..18c92ea9 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20 \ No newline at end of file +v24 \ No newline at end of file diff --git a/README.md b/README.md index 4befa4ba..9a330841 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,11 @@ Building and testing are relying on npm packages and scripts. To initialize your npm install ``` -In case you’re encountering an error with Puppeteer, make sure you’re using at least Node v.20.11.1 – it might work with an earlier version but only the latest LTS as of March 21, 2024 has been tested. - -Then create reference bitmaps for visual regression testing: +Then install the Playwright browser binary and generate reference screenshots for visual regression testing: ``` -npm run test:ref +npx playwright install chromium +npm run test:update ``` ### Build @@ -78,10 +77,10 @@ To test the updated styles and catch visual regression bugs: npm run test ``` -To update reference bitmaps after a bugfix: +To update reference screenshots after an intentional change: ``` -npm run test:approve +npm run test:update ``` ## Docs diff --git a/backstop.json b/backstop.json deleted file mode 100644 index 526b1699..00000000 --- a/backstop.json +++ /dev/null @@ -1,294 +0,0 @@ -{ - "id": "ReadiumCSS", - "viewports": [ - { - "label": "tablet", - "width": 1024, - "height": 768 - } - ], - "scenarios": [ - { - "label": "Paged", - "url": "http://localhost:8000/tests/base.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Paged rtl", - "url": "http://localhost:8000/tests/base-rtl.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Paged vertical", - "url": "http://localhost:8000/tests/base-vertical.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "1 column pref", - "url": "http://localhost:8000/tests/cols-1.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "2 columns pref", - "url": "http://localhost:8000/tests/cols-2.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "3 columns pref", - "url": "http://localhost:8000/tests/cols-3.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Line length pref", - "url": "http://localhost:8000/tests/line-length.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Scroll pref", - "url": "http://localhost:8000/tests/scroll.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Scroll vertical pref", - "url": "http://localhost:8000/tests/scroll-vertical.html", - "delay": 0, - "selectors": ["viewport"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Scroll padding pref", - "url": "http://localhost:8000/tests/scroll-padding.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Default colors pref", - "url": "http://localhost:8000/tests/default-colors.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Default custom colors pref", - "url": "http://localhost:8000/tests/default-custom-colors.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Theming (Reading System)", - "url": "http://localhost:8000/tests/theming.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font family pref", - "url": "http://localhost:8000/tests/font-family.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font size pref", - "url": "http://localhost:8000/tests/font-size.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Deprecated font size pref", - "url": "http://localhost:8000/tests/font-size-deprecated.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font size normalize pref", - "url": "http://localhost:8000/tests/font-size-normalize.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Type scale pref", - "url": "http://localhost:8000/tests/type-scale.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Text align pref", - "url": "http://localhost:8000/tests/text-align.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Hyphens pref", - "url": "http://localhost:8000/tests/hyphens.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Line height pref", - "url": "http://localhost:8000/tests/line-height.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Para spacing pref", - "url": "http://localhost:8000/tests/para-spacing.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Para spacing vertical pref", - "url": "http://localhost:8000/tests/para-spacing-vertical.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Wordspacing pref", - "url": "http://localhost:8000/tests/word-spacing.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Letterspacing pref", - "url": "http://localhost:8000/tests/letter-spacing.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Letterspacing CJK pref", - "url": "http://localhost:8000/tests/letter-spacing-cjk.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Ligatures pref", - "url": "http://localhost:8000/tests/arabic-ligatures.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Accessibility font pref", - "url": "http://localhost:8000/tests/a11y-font.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Accessibility normalize pref", - "url": "http://localhost:8000/tests/a11y-normalize.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Accessibility custom pref", - "url": "http://localhost:8000/tests/a11y-custom.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "no Ruby pref", - "url": "http://localhost:8000/tests/no-ruby.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font optical sizing pref", - "url": "http://localhost:8000/tests/font-optical-sizing.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font weight pref", - "url": "http://localhost:8000/tests/font-weight.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font width Keyword pref", - "url": "http://localhost:8000/tests/font-width-keyword.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Font width Percentage pref", - "url": "http://localhost:8000/tests/font-width-percentage.html", - "delay": 500, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Blend Filter pref", - "url": "http://localhost:8000/tests/blend-filter.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Darken Filter pref", - "url": "http://localhost:8000/tests/darken-filter.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - }, - { - "label": "Invert Filter pref", - "url": "http://localhost:8000/tests/invert-filter.html", - "delay": 0, - "selectors": ["document"], - "misMatchThreshold" : 0.1 - } - ], - "paths": { - "bitmaps_reference": "tests/backstop_data/bitmaps_reference", - "bitmaps_test": "tests/backstop_data/bitmaps_test", - "engine_scripts": "tests/backstop_data/engine_scripts", - "html_report": "tests/backstop_data/html_report", - "ci_report": "tests/backstop_data/ci_report" - }, - "report": ["browser"], - "engine": "puppeteer", - "engineOptions": { - "args": ["--no-sandbox"] - }, - "asyncCaptureLimit": 5, - "asyncCompareLimit": 50, - "debug": false, - "debugWindow": false -} diff --git a/css/postcss.config.js b/css/postcss.config.js index a7e48d88..994a8f8b 100644 --- a/css/postcss.config.js +++ b/css/postcss.config.js @@ -1,21 +1,30 @@ -const version = require("../package.json").version; +import { execSync } from 'child_process'; +import pkg from '../package.json' with { type: 'json' }; +import postcssImport from 'postcss-import'; +import postcssCustomSelectors from 'postcss-custom-selectors'; +import postcssImportJson from '@daltontan/postcss-import-json'; +import postcssDiscardComments from 'postcss-discard-comments'; +import stylelint from 'stylelint'; +import postcssSorting from 'postcss-sorting'; +import postcssHeader from 'postcss-header'; + +const { version } = pkg; // Get contributors from git function getContributors() { try { - const log = require("child_process") - .execSync("git log --format='%aN <%aE>' | sort -u") + const log = execSync("git log --format='%aN <%aE>' | sort -u") .toString() .split("\n") .filter(Boolean); - + // Process contributors: filter bots and specific names, extract names, deduplicate, and sort return [ ...new Set( log .filter(contributor => { const name = contributor.toLowerCase(); - return !name.includes("dependabot") && + return !name.includes("dependabot") && !name.includes("[bot]") && !name.includes("bot@") && !name.includes("jaypanoz") && @@ -44,18 +53,18 @@ const header = `/*! ${contributorsSection} */\n`; -module.exports = (ctx) => ({ +export default (ctx) => ({ map: false, plugins: [ - require("postcss-import")({ + postcssImport({ root: ctx.file.dirname }), - require("postcss-custom-selectors")({}), - require("@daltontan/postcss-import-json")({ + postcssCustomSelectors({}), + postcssImportJson({ prefix: "--RS__" }), - require("postcss-discard-comments")({}), - require("stylelint")({ + postcssDiscardComments({}), + stylelint({ "fix": true, "config": { "defaultSeverity": "warning", @@ -70,18 +79,18 @@ module.exports = (ctx) => ({ , "severity": "error" }] , "custom-property-pattern": [ "(RS|USER)__.+", { - "message": "It looks like you’re using a CSS variable prefix which is not supported. It should either start with “--RS__” or “--USER__”." + "message": "It looks like you're using a CSS variable prefix which is not supported. It should either start with '--RS__' or '--USER__'." , "severity": "error" }] , "color-hex-length": [ "long", { "message": "We recommend using long color HEX to prevent unexpected issues." }] , "font-family-name-quotes": [ "always-where-recommended", { - "message": "If looks like there are spaces or digits in your “font-family”, please use quotes." + "message": "It looks like there are spaces or digits in your 'font-family', please use quotes." }] , "function-url-quotes": "always" , "length-zero-no-unit": [ true, { - "message": "The value of this property being 0, you don’t need an unit. Please remove it." + "message": "The value of this property being 0, you don't need a unit. Please remove it." }] , "selector-type-case": "lower" , "function-name-case": "lower" @@ -93,17 +102,17 @@ module.exports = (ctx) => ({ , "rule-empty-line-before": "always" , "no-duplicate-at-import-rules": true , "no-invalid-double-slash-comments": [ true, { - "message": "It looks like you’re using single-line JS comments. This is CSS, you can’t use that." + "message": "It looks like you're using single-line JS comments. This is CSS, you can't use that." , "severity": "error" }] , "max-nesting-depth": [ 0, { - "message": "We’re using Vanilla CSS with PostCSS and our current configuration doesn’t allow nesting selectors as in LESS or SASS." + "message": "We're using Vanilla CSS with PostCSS and our current configuration doesn't allow nesting selectors as in LESS or SASS." , "severity": "error" }] } } }), - require("postcss-sorting")({ + postcssSorting({ "properties-order": [ "object-fit" , "position" @@ -270,9 +279,9 @@ module.exports = (ctx) => ({ ], "unspecified-properties-position": "bottomAlphabetical" }), - require("postcss-header")({ + postcssHeader({ header: header, headerLength: 0 }) ] -}) \ No newline at end of file +}) diff --git a/docs/CSS22-npm.md b/docs/CSS22-npm.md index e0f9fa0c..732bedcd 100644 --- a/docs/CSS22-npm.md +++ b/docs/CSS22-npm.md @@ -21,10 +21,11 @@ This will install all dev dependencies needed and make npm scripts available to Then, once the install is finished, type: ``` -npm run test:ref +npx playwright install chromium +npm run test:update ``` -This will create reference screenshots for the CSS regression tests. +This will install the Playwright browser binary and create reference screenshots for the CSS regression tests. ## Build @@ -84,17 +85,24 @@ Then you must customize the selectors in `ReadiumCSS-config.js` and replace them Finally you will have to enable the `postcss-css-variables` and `postcss-alter-property-value` in the `postcss.config.js` file to be found at the `src` folder’s root. -The following must be added to `plugins`: +First, add the following imports at the top of the file: ``` -require("postcss-css-variables")({ - "preserve": true +import postcssCssVariables from 'postcss-css-variables'; +import postcssAlterPropertyValue from 'postcss-alter-property-value'; +``` + +Then add the following to `plugins`: + +``` +postcssCssVariables({ + preserve: true }), -require("postcss-alter-property-value")({ +postcssAlterPropertyValue({ declarations: { "*": { - task: "remove" - , whenValueEquals: "undefined" + task: "remove", + whenValueEquals: "undefined" } } }) @@ -116,35 +124,18 @@ Here is a list of additionnal PostCSS plugins which might prove useful to implem ## Test -Once you have build `dist` stylesheets, you can run regression tests using [Backstop.js](https://github.com/garris/BackstopJS). +Once you have built `dist` stylesheets, you can run visual regression tests using [Playwright](https://playwright.dev). It helps you check if you didn’t accidentally create a breaking change when customizing stylesheets, and make sure pagination and user settings work as expected. ### Config -You will find the configuration file, `backstop.json` at the root of the project. By default, it runs those tests for a smartphone (portrait) and a tablet (landscape) viewports using Chrome, but you can customize it to fit your needs. - -For instance, if you don’t need to support mobile, you could modify `viewports`: - -``` -"viewports": [ - { - "label": "desktop small", - "width": 800, - "height": 600 - }, - { - "label": "desktop large", - "width": 1600, - "height": 900 - } -] -``` +The test configuration lives in `playwright.config.js` at the root of the project. By default, it runs all tests at a 1024×768 tablet viewport using Chromium. You can adjust the viewport or add browsers there. -And if you want to run tests using Webkit instead of Blink because you’re developing iOS apps: +If you want to run tests with WebKit (useful for iOS development), install the additional browser and update `browserName` in the config: ``` -"engine": "phantomjs" +npx playwright install webkit ``` ### Test files @@ -153,11 +144,10 @@ If you customize flags in `ReadiumCSS-config.css`, you must modify HTML files in ### Available scripts -By default, the following scripts are available: +By default, the following scripts are available: -- `test`, will run tests; -- `test:ref`, will create reference screenshots; -- `test:approve`, will update reference screenshots from the current test. +- `test`, will build stylesheets then run visual regression tests; +- `test:update`, will create or update reference screenshots. ### Usage @@ -167,16 +157,12 @@ First navigate to the `readium-css` folder if you didn’t already, then… npm run test ``` -The regression tests will run against the newly-created `dist` stylesheets, which is why you must build them beforehand. - -Once all scenarios are tested for the viewports you created, which can take up to a minute, a report will automatically open in your browser. +The regression tests will run against the newly-built `dist` stylesheets and compare each page against its stored reference screenshot. -If a unit test is marked as “failed”, it doesn’t necessarily mean the user setting failed, it just means you made a significant change which impacts rendering. Take a closer look at the diff, and if you’re happy with the result, head to the terminal and type: +If a test is marked as failed, it doesn’t necessarily mean the user setting failed — it just means you made a change that impacts rendering. Open the Playwright HTML report to inspect the diff, and if you’re happy with the result, update the references: ``` -npm run test:approve +npm run test:update ``` -This will make the current test screenshots the new reference for the next test. - -**Note:** on some occasions, an error might happen during tests and the process won’t stop. Try `ctrl + c` to stop the current process and run the test again. \ No newline at end of file +This will make the current screenshots the new reference for the next test run. \ No newline at end of file diff --git a/docs/ReadiumCSS_docs.epub b/docs/ReadiumCSS_docs.epub index 405709fa..9248b8c6 100644 Binary files a/docs/ReadiumCSS_docs.epub and b/docs/ReadiumCSS_docs.epub differ diff --git a/docs/ReadiumCSS_docs/OEBPS/Text/Section-022.xhtml b/docs/ReadiumCSS_docs/OEBPS/Text/Section-022.xhtml index 29c6c354..6f89ce6e 100644 --- a/docs/ReadiumCSS_docs/OEBPS/Text/Section-022.xhtml +++ b/docs/ReadiumCSS_docs/OEBPS/Text/Section-022.xhtml @@ -30,9 +30,10 @@

Then, once the install is finished, type:

-
npm run test:ref
+
npx playwright install chromium
+npm run test:update
-

This will create reference screenshots for the CSS regression tests.

+

This will install the Playwright browser binary and create reference screenshots for the CSS regression tests.

@@ -118,20 +119,25 @@

Then you must customize the selectors in ReadiumCSS-config.js and replace them with either CSS classes or custom attributes so that flags can work as expected.

-

Finally you will have to enable the postcss-css-variables and postcss-alter-property-value in the postcss.config.js file to be found at the src folder’s root.

+

Finally you will have to enable the postcss-css-variables and postcss-alter-property-value in the postcss.config.js file to be found at the src folder's root.

-

The following must be added to plugins:

+

First, add the following imports at the top of the file:

-
require("postcss-css-variables")({ 
-  "preserve": true 
-}), 
-require("postcss-alter-property-value")({ 
-  declarations: { 
-    "*": { 
-      task: "remove" 
-    , whenValueEquals: "undefined" 
-    } 
-  } 
+          
import postcssCssVariables from 'postcss-css-variables';
+import postcssAlterPropertyValue from 'postcss-alter-property-value';
+ +

Then add the following to plugins:

+ +
postcssCssVariables({
+  preserve: true
+}),
+postcssAlterPropertyValue({
+  declarations: {
+    "*": {
+      task: "remove",
+      whenValueEquals: "undefined"
+    }
+  }
 })

This will:

@@ -162,33 +168,18 @@ require("postcss-alter-property-value")({

Test

-

Once you have build dist stylesheets, you can run regression tests using Backstop.js.

+

Once you have built dist stylesheets, you can run visual regression tests using Playwright.

It helps you check if you didn’t accidentally create a breaking change when customizing stylesheets, and make sure pagination and user settings work as expected.

Config

-

You will find the configuration file, backstop.json at the root of the project. By default, it runs those tests for a smartphone (portrait) and a tablet (landscape) viewports using Chrome, but you can customize it to fit your needs.

- -

For instance, if you don’t need to support mobile, you could modify viewports:

- -
"viewports": [ 
-  { 
-    "label": "desktop small", 
-    "width": 800, 
-    "height": 600 
-  }, 
-  { 
-    "label": "desktop large", 
-    "width": 1600, 
-    "height": 900 
-  } 
-]
+

The test configuration lives in playwright.config.js at the root of the project. By default, it runs all tests at a 1024×768 tablet viewport using Chromium. You can adjust the viewport or add browsers there.

-

And if you want to run tests using Webkit instead of Blink because you’re developing iOS apps:

+

If you want to run tests with WebKit (useful for iOS development), install the additional browser and update browserName in the config:

-
"engine": "phantomjs"
+
npx playwright install webkit
@@ -203,11 +194,9 @@ require("postcss-alter-property-value")({

By default, the following scripts are available:

    -
  • test, will run tests;
  • +
  • test, will build stylesheets then run visual regression tests;
  • -
  • test:ref, will create reference screenshots;
  • - -
  • test:approve, will update reference screenshots from the current test.
  • +
  • test:update, will create or update reference screenshots.
@@ -218,17 +207,13 @@ require("postcss-alter-property-value")({
npm run test
-

The regression tests will run against the newly-created dist stylesheets, which is why you must build them beforehand.

- -

Once all scenarios are tested for the viewports you created, which can take up to a minute, a report will automatically open in your browser.

- -

If a unit test is marked as “failed”, it doesn’t necessarily mean the user setting failed, it just means you made a significant change which impacts rendering. Take a closer look at the diff, and if you’re happy with the result, head to the terminal and type:

+

The regression tests will run against the newly-built dist stylesheets and compare each page against its stored reference screenshot.

-
npm run test:approve
+

If a test is marked as failed, it doesn’t necessarily mean the user setting failed — it just means you made a change that impacts rendering. Open the Playwright HTML report to inspect the diff, and if you’re happy with the result, update the references:

-

This will make the current test screenshots the new reference for the next test.

+
npm run test:update
-

Note: on some occasions, an error might happen during tests and the process won’t stop. Try ctrl + c to stop the current process and run the test again.

+

This will make the current screenshots the new reference for the next test run.

diff --git a/package-lock.json b/package-lock.json index fe5e6fea..8297fddf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "devDependencies": { "@daltontan/postcss-import-json": "^1.1.1", - "backstopjs": "^6.3.23", + "@playwright/test": "^1.52.0", "copyfiles": "^2.4.1", "express": "^4.21.1", "postcss-alter-property-value": "^1.1.3", @@ -225,16 +225,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@mirzazeyrek/node-resemble-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@mirzazeyrek/node-resemble-js/-/node-resemble-js-1.2.1.tgz", - "integrity": "sha512-+z1c7HpC5ysdSVVyUVz67hctVLl337VlRJP/MBwpvXHkKJdlnSUVrBhlRzxgal7xpm1uDE2JeUhWbQh6wPRC4w==", - "dev": true, - "dependencies": { - "jpeg-js": "^0.4.2", - "pngjs": "^6.0.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -270,63 +260,21 @@ "node": ">= 8" } }, - "node_modules/@puppeteer/browsers": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.0.tgz", - "integrity": "sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA==", + "node_modules/@playwright/test": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", "dev": true, "dependencies": { - "debug": "^4.3.5", - "extract-zip": "^2.0.1", - "progress": "^2.0.3", - "proxy-agent": "^6.4.0", - "semver": "^7.6.3", - "tar-fs": "^3.0.6", - "unbzip2-stream": "^1.4.3", - "yargs": "^17.7.2" + "playwright": "1.59.1" }, "bin": { - "browsers": "lib/cjs/main-cli.js" + "playwright": "cli.js" }, "engines": { "node": ">=18" } }, - "node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@puppeteer/browsers/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@puppeteer/browsers/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -339,32 +287,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "22.0.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.2.tgz", - "integrity": "sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==", - "dev": true, - "optional": true, - "dependencies": { - "undici-types": "~6.11.1" - } - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -378,54 +300,6 @@ "node": ">= 0.6" } }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "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": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", @@ -503,18 +377,6 @@ "node": ">=8" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -524,167 +386,12 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "dev": true - }, - "node_modules/backstopjs": { - "version": "6.3.25", - "resolved": "https://registry.npmjs.org/backstopjs/-/backstopjs-6.3.25.tgz", - "integrity": "sha512-jy0dxlk45tItXLcj9zjRTCyCa6D27M9OMK5kM8To0ELLclKhI/dWn/igUTMBBMJXe4Kql+CGyDRErMtTv2+40Q==", - "dev": true, - "dependencies": { - "@mirzazeyrek/node-resemble-js": "^1.2.1", - "chalk": "^4.1.2", - "diverged": "^0.1.3", - "fs-extra": "^11.2.0", - "jump.js": "^1.0.2", - "junit-report-builder": "^3.1.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "object-hash": "3.0.0", - "opn": "^6.0.0", - "os": "^0.1.2", - "p-map": "^4.0.0", - "path": "^0.12.7", - "playwright": "^1.40.1", - "portfinder": "^1.0.32", - "puppeteer": "^22.1.0", - "super-simple-web-server": "^1.1.4", - "temp": "^0.9.4" - }, - "bin": { - "backstop": "cli/index.js" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" - } - }, "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==", "dev": true }, - "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, - "node_modules/bare-fs": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.2.tgz", - "integrity": "sha512-S5mmkMesiduMqnz51Bfh0Et9EX0aTCJxhsI4bvzFFLs8Z1AV8RDHadfY5CyLwdoLHgXbNBEN1gQcbEtGwuvixw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-events": "^2.5.4", - "bare-path": "^3.0.0", - "bare-stream": "^2.6.4" - }, - "engines": { - "bare": ">=1.16.0" - }, - "peerDependencies": { - "bare-buffer": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - } - } - }, - "node_modules/bare-os": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", - "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "engines": { - "bare": ">=1.14.0" - } - }, - "node_modules/bare-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-os": "^3.0.1" - } - }, - "node_modules/bare-stream": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", - "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "streamx": "^2.21.0" - }, - "peerDependencies": { - "bare-buffer": "*", - "bare-events": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - }, - "bare-events": { - "optional": true - } - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/basic-ftp": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.2.tgz", - "integrity": "sha512-1tDrzKsdCg70WGvbFss/ulVAxupNauGnOlgpyjKzeQxzyllBLS0CGLV7tjIXTK3ZQA9/FBEm9qyFFN1bciA6pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -772,39 +479,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -854,22 +528,6 @@ "node": ">=6" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -894,29 +552,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/chromium-bidi": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.3.tgz", - "integrity": "sha512-qXlsCmpCZJAnoTYI83Iu6EdYQpMYdVkCfq08KDh2pmlVqK5t5IA9mGs4/LwCwp4fqisSOMXZxP3HIh8w8aRn0A==", - "dev": true, - "dependencies": { - "mitt": "3.0.1", - "urlpattern-polyfill": "10.0.0", - "zod": "3.23.8" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "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/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1174,24 +809,6 @@ "node": ">=4" } }, - "node_modules/data-uri-to-buffer": { - "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==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/date-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", - "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1201,20 +818,6 @@ "ms": "2.0.0" } }, - "node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "dev": true, - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1243,21 +846,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/devtools-protocol": { - "version": "0.0.1312386", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", - "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", - "dev": true - }, - "node_modules/diff": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.1.tgz", - "integrity": "sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1279,27 +867,6 @@ "node": ">=8" } }, - "node_modules/diverged": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/diverged/-/diverged-0.1.3.tgz", - "integrity": "sha512-W8BLyp4Eo+YW9uQ3F5c9BXDT9ITCARA2CFQVb+v57FWYfkr0XjwNOASZacDCq+syk1i/obZ4BZ3w1qtlRO6hQw==", - "dev": true, - "dependencies": { - "diff": "^3.5.0", - "pixelmatch": "^4.0.2", - "pngjs": "^3.3.3", - "super-simple-web-server": "^1.0.0" - } - }, - "node_modules/diverged/node_modules/pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1336,15 +903,6 @@ "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -1420,58 +978,6 @@ "node": ">=0.8.0" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1528,53 +1034,10 @@ "url": "https://opencollective.com/express" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, "node_modules/fast-deep-equal": { @@ -1583,12 +1046,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -1639,15 +1096,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -1831,59 +1279,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-uri": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", - "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", - "dev": true, - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4", - "fs-extra": "^11.2.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/get-uri/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2049,78 +1444,6 @@ "node": ">= 0.8" } }, - "node_modules/http-proxy-agent": { - "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==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2133,26 +1456,6 @@ "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -2187,15 +1490,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2218,19 +1512,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "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==", - "dev": true, - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2318,15 +1599,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -2339,12 +1611,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/jpeg-js": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", - "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", - "dev": true - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2364,12 +1630,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "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==", - "dev": true - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -2400,27 +1660,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jump.js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jump.js/-/jump.js-1.0.2.tgz", - "integrity": "sha512-oUkJJ/Y4ATU5qjkXBntCZSKctbSyS3ewe2jrLaUu/cc9jsQiAn0fnTUxQnZz3mJdDdem1Q279zrD6h3n+Cgxtg==", - "dev": true - }, - "node_modules/junit-report-builder": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-3.2.1.tgz", - "integrity": "sha512-IMCp5XyDQ4YESDE4Za7im3buM0/7cMnRfe17k2X8B05FnUl9vqnaliX6cgOEmPIeWKfJrEe/gANRq/XgqttCqQ==", - "dev": true, - "dependencies": { - "date-format": "4.0.3", - "lodash": "^4.17.21", - "make-dir": "^3.1.0", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2463,43 +1702,12 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, - "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2633,33 +1841,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2694,15 +1875,6 @@ "node": ">= 0.6" } }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/noms": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", @@ -2722,15 +1894,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -2760,98 +1923,9 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/opn": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz", - "integrity": "sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==", - "deprecated": "The package has been renamed to `open`", - "dev": true, - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/os/-/os-0.1.2.tgz", - "integrity": "sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==", - "dev": true - }, - "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/pac-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", - "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", - "dev": true, - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.5", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/pac-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "dev": true, - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" + "dev": true, + "dependencies": { + "wrappy": "1" } }, "node_modules/parent-module": { @@ -2893,16 +1967,6 @@ "node": ">= 0.8" } }, - "node_modules/path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "dev": true, - "dependencies": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2936,12 +2000,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2971,34 +2029,13 @@ "node": ">=0.10.0" } }, - "node_modules/pixelmatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", - "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", - "dev": true, - "dependencies": { - "pngjs": "^3.0.0" - }, - "bin": { - "pixelmatch": "bin/pixelmatch" - } - }, - "node_modules/pixelmatch/node_modules/pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/playwright": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", - "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", "dev": true, "dependencies": { - "playwright-core": "1.56.1" + "playwright-core": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -3011,9 +2048,9 @@ } }, "node_modules/playwright-core": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", - "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -3022,44 +2059,6 @@ "node": ">=18" } }, - "node_modules/pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", - "dev": true, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/portfinder": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", - "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", - "dev": true, - "dependencies": { - "async": "^2.6.4", - "debug": "^3.2.7", - "mkdirp": "^0.5.6" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/portfinder/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/postcss": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", @@ -3325,30 +2324,12 @@ "node": ">= 0.8" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3362,122 +2343,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-agent": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", - "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "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", - "socks-proxy-agent": "^8.0.2" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/puppeteer": { - "version": "22.15.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.15.0.tgz", - "integrity": "sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@puppeteer/browsers": "2.3.0", - "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1312386", - "puppeteer-core": "22.15.0" - }, - "bin": { - "puppeteer": "lib/esm/puppeteer/node/cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/puppeteer-core": { - "version": "22.15.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.15.0.tgz", - "integrity": "sha512-cHArnywCiAAVXa3t4GGL2vttNxh7GqXtIYGym99egkNJ3oG//wL9LkvO4WE8W1TJe95t1F1ocu9X4xWaGsOKOA==", - "dev": true, - "dependencies": { - "@puppeteer/browsers": "2.3.0", - "chromium-bidi": "0.6.3", - "debug": "^4.3.6", - "devtools-protocol": "0.0.1312386", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/puppeteer-core/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/puppeteer-core/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/qs": { "version": "6.14.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", @@ -3653,18 +2518,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3714,15 +2567,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -3900,77 +2744,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3981,12 +2754,6 @@ "node": ">=0.10.0" } }, - "node_modules/sprintf-js": { - "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==", - "dev": true - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -3996,20 +2763,6 @@ "node": ">= 0.8" } }, - "node_modules/streamx": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", - "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -4190,15 +2943,6 @@ "node": ">=8" } }, - "node_modules/super-simple-web-server": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/super-simple-web-server/-/super-simple-web-server-1.1.4.tgz", - "integrity": "sha512-sQdVXz8ZDBMloocL63mifyVVzhxP55MlO2F0MiYJAJQiHTp42M2C3m2dZBIxGkcC7NUDr1/p0UhvGQvOsxZLpw==", - "dev": true, - "dependencies": { - "express": "^4.16.3" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4279,66 +3023,12 @@ "node": ">=8" } }, - "node_modules/tar-fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "dev": true, - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/temp": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", - "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1", - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/text-decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", - "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", - "dev": true, - "dependencies": { - "b4a": "^1.6.4" - } - }, "node_modules/thenby": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", "dev": true }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -4406,12 +3096,6 @@ "node": ">=0.6" } }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -4425,23 +3109,6 @@ "node": ">= 0.6" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/undici-types": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz", - "integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==", - "dev": true, - "optional": true - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -4481,33 +3148,12 @@ "node": ">=8" } }, - "node_modules/urlpattern-polyfill": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", - "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true - }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -4595,36 +3241,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, - "engines": { - "node": ">=8.0" - } - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -4681,25 +3297,6 @@ "engines": { "node": ">=12" } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/package.json b/package.json index 553fc040..c6d1c109 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "ebook-reader", "css" ], + "type": "module", "author": { "name": "readium", "email": "readium-css@edrlab.org", @@ -32,7 +33,7 @@ ], "devDependencies": { "@daltontan/postcss-import-json": "^1.1.1", - "backstopjs": "^6.3.23", + "@playwright/test": "^1.52.0", "copyfiles": "^2.4.1", "express": "^4.21.1", "postcss-alter-property-value": "^1.1.3", @@ -55,8 +56,7 @@ "build:vertical": "postcss css/src/ReadiumCSS-before-cjk-vertical.css -o css/dist/cjk-vertical/ReadiumCSS-before.css && postcss css/src/ReadiumCSS-default-cjk-vertical.css -o css/dist/cjk-vertical/ReadiumCSS-default.css && postcss css/src/ReadiumCSS-after-cjk-vertical.css -o css/dist/cjk-vertical/ReadiumCSS-after.css", "copyPatches": "copyfiles -u 2 css/src/ReadiumCSS-ebpaj_fonts_patch.css css/dist", "start": "node \"./server.js\"", - "test": "npm run build && (npm start & for i in {1..10}; do if curl -s http://localhost:8000 >/dev/null; then backstop test; pkill -f \"node ./server.js\"; echo '\\nVisual Regression testing has been completed.\\n'; exit 0; fi; sleep 1; done; echo 'Failed to start server'; exit 1)", - "test:ref": "npm start & backstop reference && pkill -9 -f \"node ./server.js\" && echo '\nVisual Regression references have been generated.\n'", - "test:approve": "backstop approve" + "test": "npm run build && playwright test", + "test:update": "npm run build && playwright test --update-snapshots" } } diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 00000000..9a3df28e --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,27 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: "./tests", + outputDir: "./tests/test-results", + snapshotPathTemplate: process.env.CI + ? "tests/snapshots/{arg}{ext}" + : "tests/snapshots/local/{arg}{ext}", + reporter: [ + ["json", { outputFile: "tests/test-results/results.json" }], + ["html", { open: process.env.CI || process.argv.includes("--update-snapshots") ? "never" : "always", outputFolder: "tests/playwright-report" }] + ], + use: { + baseURL: "http://localhost:8000", + viewport: { width: 1024, height: 768 }, + browserName: "chromium", + screenshot: "on", + launchOptions: { + args: ["--no-sandbox"], + }, + }, + webServer: { + command: "npm run start", + url: "http://localhost:8000/tests/base.html", + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/scripts/generate-vars-doc.js b/scripts/generate-vars-doc.js index 5a2a3c34..2ebc8d78 100644 --- a/scripts/generate-vars-doc.js +++ b/scripts/generate-vars-doc.js @@ -1,12 +1,13 @@ #!/usr/bin/env node -"use strict"; +import { readFileSync, writeFileSync } from "fs"; +import { join, relative } from "path"; +import { fileURLToPath } from "url"; -const fs = require("fs"); -const path = require("path"); +const __dirname = fileURLToPath(new URL(".", import.meta.url)); -const VARS_DIR = path.join(__dirname, "../css/vars"); -const OUTPUT = path.join(VARS_DIR, "CSS-Variables.md"); +const VARS_DIR = join(__dirname, "../css/vars"); +const OUTPUT = join(VARS_DIR, "CSS-Variables.md"); const FILES = [ { file: "pagination.json", heading: "Pagination", type: "flat" }, @@ -92,8 +93,8 @@ function generate() { const parts = ["# CSS Variables Reference\n"]; for (const { file, heading, type } of FILES) { - const src = path.join(VARS_DIR, file); - const data = JSON.parse(fs.readFileSync(src, "utf8")); + const src = join(VARS_DIR, file); + const data = JSON.parse(readFileSync(src, "utf8")); if (type === "flat") { parts.push(flatSection(heading, data)); @@ -106,8 +107,8 @@ function generate() { } } - fs.writeFileSync(OUTPUT, parts.join("\n")); - console.log(`Generated ${path.relative(process.cwd(), OUTPUT)}`); + writeFileSync(OUTPUT, parts.join("\n")); + console.log(`Generated ${relative(process.cwd(), OUTPUT)}`); } generate(); diff --git a/server.js b/server.js index 4c29095e..08d9b47a 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,9 @@ -const http = require("http"); -const express = require("express"); +import http from 'http'; +import express from 'express'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); const app = express(); const httpPort = 8000; @@ -16,4 +20,4 @@ httpServer.listen(httpPort, (err) => { app.use("/tests", express.static(__dirname + "/tests")); app.use("/css/demo", express.static(__dirname + "/css/demo")); app.use("/css/dist", express.static(__dirname + "/css/dist")); -app.use("/docs/utils", express.static(__dirname + "/docs/utils")); \ No newline at end of file +app.use("/docs/utils", express.static(__dirname + "/docs/utils")); diff --git a/tests/a11y-font.html b/tests/a11y-font.html deleted file mode 100644 index 91e33d5a..00000000 --- a/tests/a11y-font.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Test - - - - - - - -

CHAPTER 1. Loomings.

- -

Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball.[1] With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.

- -

There now is your insular city of the Manhattoes, belted round by wharves as Indian isles by coral reefs—commerce surrounds it with her surf. Right and left, the streets take you waterward. Its extreme downtown is the battery, where that noble mole is washed by waves, and cooled by breezes, which a few hours previous were out of sight of land. Look at the crowds of water-gazers there.

- -

Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears Hook to Coenties Slip, and from thence, by Whitehall, northward. What do you see?—Posted like silent sentinels all around the town, stand thousands upon thousands of mortal men fixed in ocean reveries. Some leaning against the spiles; some seated upon the pier-heads; some looking over the bulwarks of ships from China; some high aloft in the rigging, as if striving to get a still better seaward peep. But these are all landsmen; of week days pent up in lath and plaster—tied to counters, nailed to benches, clinched to desks. How then is this? Are the green fields gone? What do they here?

- - \ No newline at end of file diff --git a/tests/arabic-ligatures.html b/tests/arabic-ligatures.html deleted file mode 100644 index eb15635e..00000000 --- a/tests/arabic-ligatures.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - Test - - - - - - - -

لغة عربية - ويكيبيديا، الموسوعة الحرة

- -

اللُّغَة العَرَبِيّة هي أكثر اللغات تحدثاً ونطقاً ضمن مجموعة اللغات السامية، وإحدى أكثر اللغات انتشاراً في العالم، يتحدثها أكثر من مليون نسمة، ويتوزع متحدثوها في الوطن العربي، بالإضافة إلى العديد من المناطق الأخرى المجاورة كالأحواز وتركيا وتشاد ومالي والسنغال وإرتيريا و إثيوبيا و جنوب السودان و إيران. اللغة العربية ذات أهمية قصوى لدى المسلمين، فهي لغة مقدسة (لغة القرآن)، ولا تتم الصلاة (وعبادات أخرى) في الإسلام إلا بإتقان بعض من كلماتها. العربية هي أيضاً لغة شعائرية رئيسية لدى عدد من الكنائس المسيحية في الوطن العربي، كما كتبت بها كثير من أهم الأعمال الدينية والفكرية اليهودية في العصور الوسطى. وأثّر انتشار الإسلام، وتأسيسه دولاً، في ارتفاع مكانة اللغة العربية، وأصبحت لغة السياسة والعلم والأدب لقرون طويلة في الأراضي التي حكمها المسلمون، وأثرت العربية تأثيراً مباشراً أو غير مباشر على كثير من اللغات الأخرى في العالم الإسلامي، كالتركية والفارسية والأمازيغية والكردية والأردوية والماليزية والإندونيسية والألبانية وبعض اللغات الإفريقية الأخرى مثل الهاوسا والسواحيلية والتجرية والأمهرية و الصومالية، وبعض اللغات الأوروبية وخاصةً المتوسطية كالإسبانية والبرتغالية والمالطية والصقلية. كما أنها تُدرَّس بشكل رسمي أو غير رسمي في الدول الإسلامية والدول الإفريقية المحاذية للوطن العربي.

- -

العربية لغة رسمية في كل دول الوطن العربي إضافة إلى كونها لغة رسمية في تشاد وإريتريا وإسرائيل. وهي إحدى اللغات الرسمية الست في منظمة الأمم المتحدة، ويُحتفل باليوم العالمي للغة العربية في ديسمبر كذكرى اعتماد العربية بين لغات العمل في الأمم المتحدة.

- -

واللغة العربية من أغزر اللغات من حيث المادة اللغوية، فعلى سبيل المثال يحوي معجم لسان العرب لابن منظور من القرن الثالث عشر أكثر من ألف مادة، بينما في اللغة الإنجليزية فإن قاموس صموئيل جونسون - وهو من أوائل من وضع قاموساً إنجليزياً من القرن الثامن عشر يحتوي على ألف كلمة.

-

تحتوي العربية على حرفاً مكتوباً. ويرى بعض اللغويين أنه يجب إضافة حرف الهمزة إلى حروف العربية، ليصبح عدد الحروف تُكتب العربية من اليمين إلى اليسار - ومثلها اللغة الفارسية والعبرية على عكس كثير من اللغات العالمية - ومن أعلى الصفحة إلى أسفلها.

- -

الأسماء

- -

حيث ذهب به إلى أنها للعرب خاصة. غير أن الضاد المقصودة هنا ليست الضاد المعروفة والمستخدمة اليوم في دول مثل جمهورية مصر العربية، والتي هي عبارة عن دال مفخمة، وهي التي لاتُستحسن قراءة القرآن أو الشعر العربي بها، أما الضاد العربية القديمة فهي صوتٌ آخر مزيجٌ بين الظاء واللام، واندمج هذا الصوت مع الظاء في الجزيرة العربية. ولأن الظاء هي ذال مفخمة، أي أنها حرف ما - بين - أسناني، فقد تحولت بدورها في الحواضر إلى دال مفخمة كتحول الثاء إلى تاء والذال إلى دال، وصارت هذه الدال المفخمة هي الضاد الحديثة. فالدال المفخمة ليست خاصة بالعربية، بل هي في الواقع موجودة في لغات كثيرة. وهي ليست الضاد الأصلية التي كان يعنيها المتنبي وابن منظور صاحب لسان العرب وغيرهم.

- -

تصنيفها

- -

تنتمي اللغة العربية إلى أسرة اللغات السامية المتفرعة من مجموعة اللغات الإفريقية الآسيوية. وتضم مجموعة اللغات السامية لغات حضارة الهلال الخصيب القديمة، مثل الأكادية والكنعانية والآرامية واللغة الصيهدية (جنوب الجزيرة العربية) واللغات العربية الشمالية القديمة وبعض لغات القرن الإفريقي كالأمهرية. وعلى وجه التحديد، يضع اللغويون اللغة العربية في المجموعة السامية الوسطى من اللغات السامية الغربية.

- -

والعربية من أحدث هذه اللغات نشأة وتاريخاً، ولكن يعتقد البعض أنها الأقرب إلى اللغة السامية الأم التي انبثقت منها اللغات السامية الأخرى، وذلك لاحتباس العرب في جزيرة العرب فلم تتعرض لما تعرضت له باقي اللغات السامية من اختلاط. ولكن هناك من يخالف هذا الرأي بين علماء اللسانيات، حيث أن تغير اللغة هو عملية مستمرة عبر الزمن والانعزال الجغرافي قد يزيد من حدة هذا التغير حيث يبدأ نشوء أيّة لغة جديدة بنشوء لهجة جديدة في منطقة منعزلة جغرافياً. بالإضافة لافتراض وجود لغة سامية أم لا يعني وجودها بالمعنى المفهوم للغة الواحدة بل هي تعبير مجازي قصد به الإفصاح عن تقارب مجموعة من اللغات فقد كان علماء اللسانيات يعتمدون على قرب لغة وعقلية من يرونه مرشحاً لعضوية عائلة اللغات السامية وبُنيت دراساتهم على أسس جغرافية وسياسية وليس على أُسس عرقية ولا علاقة لها بنظرة التوراة لأبناء سام وكثرة قواعد اللغة العربية ترجح أنها طرأت عليها في فترات لاحقة وأنها مرت بأطوار عديدة مما يضعف فرضية أن هذه اللغة أقرب لما عُرف اصطلاحاً باللغة السامية الأم هذه، ولا توجد لغة في العالم تستطيع الادعاء أنها نقية وصافية من عوامل ومؤثرات خارجية

- - \ No newline at end of file diff --git a/tests/base-rtl.html b/tests/base-rtl.html index 3b0532ba..7330ae00 100644 --- a/tests/base-rtl.html +++ b/tests/base-rtl.html @@ -1,5 +1,5 @@ - + Test diff --git a/tests/ligatures.html b/tests/ligatures.html new file mode 100644 index 00000000..2cf54b88 --- /dev/null +++ b/tests/ligatures.html @@ -0,0 +1,34 @@ + + + + Test + + + + + + + +

CHAPTER 1. Loomings.

+ +

Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular + to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have + of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever + it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and + bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it + requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking + people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. + With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising + in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings + towards the ocean with me.

+ +

Offerings finally flashing efficiently offtrack

+ +

But look! here come more crowds, pacing straight for the water, and seemingly bound for a dive. Strange! Nothing will content + them but the extremest limit of the land; loitering under the shady lee of yonder warehouses will not suffice. No. They + must get just as nigh the water as they possibly can without falling in. And there they stand—miles of them—leagues. + Inlanders all, they come from lanes and alleys, streets and avenues—north, east, south, and west. Yet here they all unite. + Tell me, does the magnetic virtue of the needles of the compasses of all those ships attract them thither? +

+ + \ No newline at end of file diff --git a/tests/visual.spec.js b/tests/visual.spec.js new file mode 100644 index 00000000..4b94c420 --- /dev/null +++ b/tests/visual.spec.js @@ -0,0 +1,67 @@ +import { test, expect } from '@playwright/test'; + +const scenarios = [ + // viewport screenshots (paged mode — content is clipped to columns) + { label: "Paged", url: "/tests/base.html" }, + { label: "Paged RTL", url: "/tests/base-rtl.html" }, + { label: "Paged vertical", url: "/tests/base-vertical.html" }, + { label: "1 column", url: "/tests/cols-1.html" }, + { label: "2 columns", url: "/tests/cols-2.html"}, + { label: "3 columns", url: "/tests/cols-3.html" }, + { label: "Line length", url: "/tests/line-length.html" }, + { label: "Scroll", url: "/tests/scroll.html", fullPage: true }, + { label: "Scroll vertical", url: "/tests/scroll-vertical.html", fullPage: true }, + { label: "Scroll padding", url: "/tests/scroll-padding.html", fullPage: true }, + { label: "Default colors", url: "/tests/default-colors.html", fullPage: true }, + { label: "Default custom colors", url: "/tests/default-custom-colors.html", fullPage: true }, + { label: "Theming", url: "/tests/theming.html", fullPage: true }, + { label: "Font family", url: "/tests/font-family.html", fullPage: true }, + { label: "Font size", url: "/tests/font-size.html", fullPage: true }, + { label: "Font size deprecated", url: "/tests/font-size-deprecated.html", fullPage: true }, + { label: "Font size normalize", url: "/tests/font-size-normalize.html", fullPage: true }, + { label: "Type scale", url: "/tests/type-scale.html", fullPage: true }, + { label: "Text align", url: "/tests/text-align.html", fullPage: true }, + { label: "Hyphens", url: "/tests/hyphens.html", fullPage: true }, + { label: "Line height", url: "/tests/line-height.html", fullPage: true }, + { label: "Para spacing", url: "/tests/para-spacing.html", fullPage: true }, + { label: "Para spacing vertical", url: "/tests/para-spacing-vertical.html", fullPage: true }, + { label: "Word spacing", url: "/tests/word-spacing.html", fullPage: true }, + { label: "Letter spacing", url: "/tests/letter-spacing.html", fullPage: true }, + { label: "Letter spacing CJK", url: "/tests/letter-spacing-cjk.html", fullPage: true }, + { label: "Ligatures", url: "/tests/ligatures.html", fullPage: true }, + { label: "Accessibility normalize", url: "/tests/a11y-normalize.html", fullPage: true }, + { label: "Accessibility custom", url: "/tests/a11y-custom.html", fullPage: true }, + { label: "No ruby", url: "/tests/no-ruby.html", fullPage: true }, + { label: "Font optical sizing", url: "/tests/font-optical-sizing.html", fullPage: true }, + { label: "Font weight", url: "/tests/font-weight.html", fullPage: true }, + { label: "Font width keyword", url: "/tests/font-width-keyword.html", fullPage: true }, + { label: "Font width percentage", url: "/tests/font-width-percentage.html", fullPage: true }, + { label: "Blend filter", url: "/tests/blend-filter.html", fullPage: true }, + { label: "Darken filter", url: "/tests/darken-filter.html", fullPage: true }, + { label: "Invert filter", url: "/tests/invert-filter.html", fullPage: true }, +]; + +for (const { label, url, fullPage = false } of scenarios) { + test(label, async ({ page }) => { + await page.goto(url, { waitUntil: "networkidle" }); + await page.evaluate(async () => { await document.fonts.ready; }); + const name = url.split("/").pop().replace(".html", ""); + + if (fullPage) { + // ReadiumCSS scroll mode sets overflow:auto on :root (html) and + // overflow:clip on body, making html the scroll container rather than + // the window. Playwright's fullPage scrolls the window, so it captures + // only the viewport. We expand the viewport to the full content size instead. + const { scrollWidth, scrollHeight } = await page.evaluate(() => ({ + scrollWidth: document.documentElement.scrollWidth, + scrollHeight: document.documentElement.scrollHeight, + })); + await page.setViewportSize({ width: scrollWidth, height: scrollHeight }); + } + + await expect(page).toHaveScreenshot(`${name}.png`, { + fullPage: false, + maxDiffPixelRatio: 0.001, + }); + }); +}