From 8c9f51b74ac49411aa4689ee4931ed2ff31e1346 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Sat, 21 Feb 2026 23:30:22 +0100 Subject: [PATCH] chore(ci): Setup visual regression testing with BackstopJS --- .gitea/workflows/deploy.yml | 96 ++++- .gitignore | 7 +- backstop.config.js | 66 +++ .../engine_scripts/puppet/onBefore.js | 26 ++ .../engine_scripts/puppet/onReady.js | 20 + package.json | 5 + pnpm-lock.yaml | 390 ++++++++++++++++++ 7 files changed, 607 insertions(+), 3 deletions(-) create mode 100644 backstop.config.js create mode 100644 backstop_data/engine_scripts/puppet/onBefore.js create mode 100644 backstop_data/engine_scripts/puppet/onReady.js diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 62b7f327..cdfa635c 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -596,11 +596,103 @@ jobs: run: pnpm run check:wcag # ────────────────────────────────────────────────────────────────────────────── - # JOB 8: Notifications + # JOB 8: Visual Regression Testing + # ────────────────────────────────────────────────────────────────────────────── + visual_regression: + name: 📸 Visual Diff + needs: [prepare, deploy, smoke_test] + if: success() && needs.prepare.outputs.target != 'skip' + runs-on: docker + container: + image: catthehacker/ubuntu:act-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 10 + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Setup Puppeteer cache + uses: actions/cache@v4 + with: + path: ~/.cache/puppeteer + key: ${{ runner.os }}-puppeteer-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-puppeteer- + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: 🔐 Registry Auth + run: | + echo "@mintel:registry=https://${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}" > .npmrc + echo "//${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}/:_authToken=${{ secrets.REGISTRY_PASS }}" >> .npmrc + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: 🔍 Install Chromium (Native & ARM64) + run: | + apt-get update + apt-get install -y gnupg wget ca-certificates + + # Detect OS + OS_ID=$(. /etc/os-release && echo $ID) + CODENAME=$(. /etc/os-release && echo $VERSION_CODENAME) + + if [ "$OS_ID" = "debian" ]; then + echo "🎯 Debian detected - installing native chromium" + apt-get install -y chromium + else + echo "🎯 Ubuntu detected - adding xtradeb PPA" + mkdir -p /etc/apt/keyrings + KEY_ID="82BB6851C64F6880" + + # Fetch PPA key + wget -qO- "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x$KEY_ID" | gpg --dearmor > /etc/apt/keyrings/xtradeb.gpg + + # Add PPA repository + echo "deb [signed-by=/etc/apt/keyrings/xtradeb.gpg] http://ppa.launchpad.net/xtradeb/apps/ubuntu $CODENAME main" > /etc/apt/sources.list.d/xtradeb-ppa.list + + # PRIORITY PINNING: Force PPA over Snap-dummy + printf "Package: *\nPin: release o=LP-PPA-xtradeb-apps\nPin-Priority: 1001\n" > /etc/apt/preferences.d/xtradeb + + apt-get update + apt-get install -y --allow-downgrades chromium + fi + + # Standardize binary paths + [ -f /usr/bin/chromium ] && ln -sf /usr/bin/chromium /usr/bin/google-chrome + [ -f /usr/bin/chromium ] && ln -sf /usr/bin/chromium /usr/bin/chromium-browser + - name: 📸 Run BackstopJS Test + env: + TEST_URL: ${{ needs.prepare.outputs.next_public_url }} + GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }} + CHROME_PATH: /usr/bin/chromium + run: pnpm backstop:ci + - name: 📤 Upload Report on Failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: backstop-report + path: backstop_data/html_report/ + + # ────────────────────────────────────────────────────────────────────────────── + # JOB 9: Notifications # ────────────────────────────────────────────────────────────────────────────── notifications: name: 🔔 Notify - needs: [prepare, deploy, smoke_test, lighthouse, wcag] + needs: [prepare, deploy, smoke_test, lighthouse, wcag, visual_regression] if: always() runs-on: docker container: diff --git a/.gitignore b/.gitignore index 39e6c78a..cdc3a58f 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,9 @@ directus/uploads .next-docker # Pa11y CI -.pa11yci/ \ No newline at end of file +.pa11yci/ + +# BackstopJS +backstop_data/html_report/ +backstop_data/ci_report/ +backstop_data/bitmaps_test/ \ No newline at end of file diff --git a/backstop.config.js b/backstop.config.js new file mode 100644 index 00000000..38a9fa6b --- /dev/null +++ b/backstop.config.js @@ -0,0 +1,66 @@ +/* eslint-disable */ +module.exports = { + id: 'klz-cables', + viewports: [ + { + label: 'phone', + width: 375, + height: 667, + }, + { + label: 'tablet', + width: 768, + height: 1024, + }, + { + label: 'desktop', + width: 1440, + height: 900, + }, + ], + onBeforeScript: 'puppet/onBefore.js', + onReadyScript: 'puppet/onReady.js', + scenarios: [ + { + label: 'Homepage', + url: `${process.env.TEST_URL || 'http://host.docker.internal:3000'}/`, + referenceUrl: '', + readyEvent: '', + readySelector: '', + delay: 500, + hideSelectors: [], + removeSelectors: [], + hoverSelector: '', + clickSelector: '', + postInteractionWait: 0, + selectors: [], + selectorExpansion: true, + expect: 0, + misMatchThreshold: 0.1, + requireSameDimensions: true, + }, + { + label: '404 Error Page', + url: `${process.env.TEST_URL || 'http://host.docker.internal:3000'}/this-page-does-not-exist`, + delay: 500, + misMatchThreshold: 0.1, + }, + ], + paths: { + bitmaps_reference: 'backstop_data/bitmaps_reference', + bitmaps_test: 'backstop_data/bitmaps_test', + engine_scripts: 'backstop_data/engine_scripts', + html_report: 'backstop_data/html_report', + ci_report: 'backstop_data/ci_report', + }, + report: process.env.CI ? ['CI'] : ['browser'], + engine: 'puppeteer', + engineOptions: { + args: ['--no-sandbox', '--disable-setuid-sandbox'], + executablePath: process.env.CHROME_PATH || undefined, // Use explicit Chrome in CI + }, + asyncCaptureLimit: 5, + asyncCompareLimit: 50, + debug: false, + debugWindow: false, +}; diff --git a/backstop_data/engine_scripts/puppet/onBefore.js b/backstop_data/engine_scripts/puppet/onBefore.js new file mode 100644 index 00000000..53f8c4ac --- /dev/null +++ b/backstop_data/engine_scripts/puppet/onBefore.js @@ -0,0 +1,26 @@ +/* eslint-disable */ +module.exports = async (page, scenario, vp, isReference, browserContext) => { + console.log('onBefore: Setting up Gatekeeper Auth Cookie...'); + + // BackstopJS might be hitting localhost, testing, or staging URLs + const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026'; + + // Extract domain from the scenario URL + let targetDomain = 'localhost'; + try { + const urlObj = new URL(scenario.url); + targetDomain = urlObj.hostname; + } catch (e) { + // ignore + } + + // Inject the ForwardAuth session cookie + await page.setCookie({ + name: 'klz_gatekeeper_session', + value: gatekeeperPassword, + domain: targetDomain, // Puppeteer requires exact or matching domain for cookies + path: '/', + httpOnly: true, + secure: targetDomain !== 'localhost' && targetDomain !== 'host.docker.internal', + }); +}; diff --git a/backstop_data/engine_scripts/puppet/onReady.js b/backstop_data/engine_scripts/puppet/onReady.js new file mode 100644 index 00000000..2f3b361b --- /dev/null +++ b/backstop_data/engine_scripts/puppet/onReady.js @@ -0,0 +1,20 @@ +/* eslint-disable */ +module.exports = async (page, scenario, vp) => { + console.log('SCENARIO > ' + scenario.label); + + // Disable CSS animations instantly to avoid flaky screenshots + await page.evaluate(() => { + const style = document.createElement('style'); + style.innerHTML = ` + * { + animation: none !important; + transition: none !important; + caret-color: transparent !important; + } + `; + document.head.appendChild(style); + }); + + // Example: Wait for fonts to load + await page.evaluate(() => document.fonts.ready); +}; diff --git a/package.json b/package.json index f9311595..707a15c8 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@vitejs/plugin-react": "^5.1.4", "@vitest/ui": "^4.0.16", "autoprefixer": "^10.4.23", + "backstopjs": "^6.3.25", "cheerio": "^1.2.0", "critters": "^0.0.25", "eslint": "^9.18.0", @@ -99,6 +100,10 @@ "check:mdx": "node scripts/validate-mdx.mjs", "check:a11y": "pa11y-ci", "check:wcag": "tsx ./scripts/wcag-sitemap.ts", + "backstop:reference": "backstop reference --docker", + "backstop:test": "backstop test --docker", + "backstop:approve": "backstop approve --docker", + "backstop:ci": "backstop test", "cms:branding:local": "DIRECTUS_URL=${DIRECTUS_URL:-http://cms.klz.localhost} npx tsx --env-file=.env scripts/setup-directus-branding.ts", "cms:branding:testing": "DIRECTUS_URL=https://cms.testing.klz-cables.com npx tsx --env-file=.env scripts/setup-directus-branding.ts", "cms:branding:staging": "DIRECTUS_URL=https://cms.staging.klz-cables.com npx tsx --env-file=.env scripts/setup-directus-branding.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 209596d9..a74b2e6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -195,6 +195,9 @@ importers: autoprefixer: specifier: ^10.4.23 version: 10.4.24(postcss@8.5.6) + backstopjs: + specifier: ^6.3.25 + version: 6.3.25(typescript@5.9.3) cheerio: specifier: ^1.2.0 version: 1.2.0 @@ -1276,6 +1279,9 @@ packages: '@mintel/tsconfig@1.8.3': resolution: {integrity: sha512-IOtxrTZfPZs4XU4Q068dSUtETFb2drf43mgmaF31j+PtltfPkC7pdJcEjXDg365bZ5EUrgTlt9pYlgGmfrCEVQ==} + '@mirzazeyrek/node-resemble-js@1.2.1': + resolution: {integrity: sha512-+z1c7HpC5ysdSVVyUVz67hctVLl337VlRJP/MBwpvXHkKJdlnSUVrBhlRzxgal7xpm1uDE2JeUhWbQh6wPRC4w==} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1669,6 +1675,11 @@ packages: engines: {node: '>=18'} hasBin: true + '@puppeteer/browsers@2.3.0': + resolution: {integrity: sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA==} + engines: {node: '>=18'} + hasBin: true + '@react-email/body@0.0.11': resolution: {integrity: sha512-ZSD2SxVSgUjHGrB0Wi+4tu3MEpB4fYSbezsFNEJk2xCWDBkFiOeEsjTmR5dvi+CxTK691hQTQlHv0XWuP7ENTg==} peerDependencies: @@ -3072,6 +3083,10 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -3273,6 +3288,11 @@ packages: react-native-b4a: optional: true + backstopjs@6.3.25: + resolution: {integrity: sha512-jy0dxlk45tItXLcj9zjRTCyCa6D27M9OMK5kM8To0ELLclKhI/dWn/igUTMBBMJXe4Kql+CGyDRErMtTv2+40Q==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + hasBin: true + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -3391,6 +3411,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -3494,6 +3517,11 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + chromium-bidi@0.6.3: + resolution: {integrity: sha512-qXlsCmpCZJAnoTYI83Iu6EdYQpMYdVkCfq08KDh2pmlVqK5t5IA9mGs4/LwCwp4fqisSOMXZxP3HIh8w8aRn0A==} + peerDependencies: + devtools-protocol: '*' + chromium-bidi@13.1.1: resolution: {integrity: sha512-zB9MpoPd7VJwjowQqiW3FKOvQwffFMjQ8Iejp5ZW+sJaKLRhZX1sTxzl3Zt22TDB4zP0OOqs8lRoY7eAW5geyQ==} peerDependencies: @@ -3513,6 +3541,10 @@ packages: cjs-module-lexer@2.2.0: resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + cli-cursor@2.1.0: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} @@ -3818,6 +3850,10 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + date-format@4.0.3: + resolution: {integrity: sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==} + engines: {node: '>=4.0'} + dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} @@ -3916,6 +3952,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + devtools-protocol@0.0.1312386: + resolution: {integrity: sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==} + devtools-protocol@0.0.1467305: resolution: {integrity: sha512-LxwMLqBoPPGpMdRL4NkLFRNy3QLp6Uqa7GNp1v6JaBheop2QrB9Q7q0A/q/CYYP9sBfZdHOyszVx4gc9zyk7ow==} @@ -3925,6 +3964,13 @@ packages: dfa@1.2.0: resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + diff@3.5.1: + resolution: {integrity: sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==} + engines: {node: '>=0.3.1'} + + diverged@0.1.3: + resolution: {integrity: sha512-W8BLyp4Eo+YW9uQ3F5c9BXDT9ITCARA2CFQVb+v57FWYfkr0XjwNOASZacDCq+syk1i/obZ4BZ3w1qtlRO6hQw==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -4490,12 +4536,21 @@ packages: from@0.1.7: resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + fs-monkey@1.0.3: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -4773,6 +4828,9 @@ packages: icu-minify@4.8.2: resolution: {integrity: sha512-LHBQV+skKkjZSPd590pZ7ZAHftUgda3eFjeuNwA8/15L8T8loCNBktKQyTlkodAU86KovFXeg/9WntlAo5wA5A==} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -4813,10 +4871,17 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -5042,6 +5107,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -5165,10 +5234,20 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jump.js@1.0.2: + resolution: {integrity: sha512-oUkJJ/Y4ATU5qjkXBntCZSKctbSyS3ewe2jrLaUu/cc9jsQiAn0fnTUxQnZz3mJdDdem1Q279zrD6h3n+Cgxtg==} + + junit-report-builder@3.2.1: + resolution: {integrity: sha512-IMCp5XyDQ4YESDE4Za7im3buM0/7cMnRfe17k2X8B05FnUl9vqnaliX6cgOEmPIeWKfJrEe/gANRq/XgqttCqQ==} + engines: {node: '>=8'} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -5843,6 +5922,10 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -5913,6 +5996,11 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true + opn@6.0.0: + resolution: {integrity: sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==} + engines: {node: '>=8'} + deprecated: The package has been renamed to `open` + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -5925,6 +6013,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + os@0.1.2: + resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -5945,6 +6036,10 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -6038,6 +6133,9 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -6109,15 +6207,41 @@ packages: resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true + pixelmatch@4.0.2: + resolution: {integrity: sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==} + hasBin: true + pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + playwright-core@1.58.2: + resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.58.2: + resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} + engines: {node: '>=18'} + hasBin: true + png-js@1.0.0: resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==} + pngjs@3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + + pngjs@6.0.0: + resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} + engines: {node: '>=12.13.0'} + po-parser@2.1.1: resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} + portfinder@1.0.38: + resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==} + engines: {node: '>= 10.12'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -6209,6 +6333,10 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -6253,6 +6381,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + puppeteer-core@22.15.0: + resolution: {integrity: sha512-cHArnywCiAAVXa3t4GGL2vttNxh7GqXtIYGym99egkNJ3oG//wL9LkvO4WE8W1TJe95t1F1ocu9X4xWaGsOKOA==} + engines: {node: '>=18'} + puppeteer-core@24.37.2: resolution: {integrity: sha512-nN8qwE3TGF2vA/+xemPxbesntTuqD9vCGOiZL2uh8HES3pPzLX20MyQjB42dH2rhQ3W3TljZ4ZaKZ0yX/abQuw==} engines: {node: '>=18'} @@ -6261,6 +6393,12 @@ packages: resolution: {integrity: sha512-fokQ8gv+hNgsRWqVuP5rUjGp+wzV5aMTP3fcm8ekNabmLGlJdFHas1OdMscAH9Gzq4Qcf7cfI/Pe6wEcAqQhqg==} engines: {node: '>=18'} + puppeteer@22.15.0: + resolution: {integrity: sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==} + engines: {node: '>=18'} + deprecated: < 24.15.0 is no longer supported + hasBin: true + puppeteer@24.37.3: resolution: {integrity: sha512-AUGGWq0BhPM+IOS2U9A+ZREH3HDFkV1Y5HERYGDg5cbGXjoGsTCT7/A6VZRfNU0UJJdCclyEimZICkZW6pqJyw==} engines: {node: '>=18'} @@ -6485,6 +6623,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -6906,6 +7049,9 @@ packages: babel-plugin-macros: optional: true + super-simple-web-server@1.1.4: + resolution: {integrity: sha512-sQdVXz8ZDBMloocL63mifyVVzhxP55MlO2F0MiYJAJQiHTp42M2C3m2dZBIxGkcC7NUDr1/p0UhvGQvOsxZLpw==} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6954,6 +7100,10 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + temp@0.9.4: + resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} + engines: {node: '>=6.0.0'} + terser-webpack-plugin@5.3.16: resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} engines: {node: '>= 10.13.0'} @@ -7157,6 +7307,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -7208,6 +7361,10 @@ packages: unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -7227,6 +7384,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + use-intl@4.8.2: resolution: {integrity: sha512-3VNXZgDnPFqhIYosQ9W1Hc6K5q+ZelMfawNbexdwL/dY7BTHbceLUBX5Eeex9lgogxTp0pf1SjHuhYNAjr9H3g==} peerDependencies: @@ -7240,6 +7400,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -7564,6 +7727,10 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -7631,6 +7798,9 @@ packages: zod@3.22.3: resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -8607,6 +8777,11 @@ snapshots: '@mintel/tsconfig@1.8.3': {} + '@mirzazeyrek/node-resemble-js@1.2.1': + dependencies: + jpeg-js: 0.4.4 + pngjs: 6.0.0 + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -9036,6 +9211,22 @@ snapshots: - react-native-b4a - supports-color + '@puppeteer/browsers@2.3.0': + dependencies: + debug: 4.4.3 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.5.0 + semver: 7.7.4 + tar-fs: 3.1.1 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + - supports-color + '@react-email/body@0.0.11(react@19.2.4)': dependencies: react: 19.2.4 @@ -10588,6 +10779,11 @@ snapshots: agent-base@7.1.4: {} + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -10791,6 +10987,35 @@ snapshots: b4a@1.7.3: {} + backstopjs@6.3.25(typescript@5.9.3): + dependencies: + os: 0.1.2 + '@mirzazeyrek/node-resemble-js': 1.2.1 + chalk: 4.1.2 + diverged: 0.1.3 + fs-extra: 11.3.3 + jump.js: 1.0.2 + junit-report-builder: 3.2.1 + lodash: 4.17.23 + minimist: 1.2.8 + object-hash: 3.0.0 + opn: 6.0.0 + p-map: 4.0.0 + path: 0.12.7 + playwright: 1.58.2 + portfinder: 1.0.38 + puppeteer: 22.15.0(typescript@5.9.3) + super-simple-web-server: 1.1.4 + temp: 0.9.4 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -10912,6 +11137,11 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: @@ -11048,6 +11278,13 @@ snapshots: chrome-trace-event@1.0.4: {} + chromium-bidi@0.6.3(devtools-protocol@0.0.1312386): + dependencies: + devtools-protocol: 0.0.1312386 + mitt: 3.0.1 + urlpattern-polyfill: 10.0.0 + zod: 3.23.8 + chromium-bidi@13.1.1(devtools-protocol@0.0.1566079): dependencies: devtools-protocol: 0.0.1566079 @@ -11068,6 +11305,8 @@ snapshots: cjs-module-lexer@2.2.0: {} + clean-stack@2.2.0: {} + cli-cursor@2.1.0: dependencies: restore-cursor: 2.0.0 @@ -11379,6 +11618,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + date-format@4.0.3: {} + dateformat@4.6.3: {} debounce-fn@6.0.0: @@ -11449,12 +11690,25 @@ snapshots: dependencies: dequal: 2.0.3 + devtools-protocol@0.0.1312386: {} + devtools-protocol@0.0.1467305: {} devtools-protocol@0.0.1566079: {} dfa@1.2.0: {} + diff@3.5.1: {} + + diverged@0.1.3: + dependencies: + diff: 3.5.1 + pixelmatch: 4.0.2 + pngjs: 3.4.0 + super-simple-web-server: 1.1.4 + transitivePeerDependencies: + - supports-color + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -12287,10 +12541,19 @@ snapshots: from@0.1.7: {} + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-monkey@1.0.3: {} fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -12644,6 +12907,8 @@ snapshots: dependencies: '@formatjs/icu-messageformat-parser': 3.5.1 + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -12681,11 +12946,15 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 + inherits@2.0.3: {} + inherits@2.0.4: {} ini@1.3.8: {} @@ -12903,6 +13172,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@1.1.0: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -13040,6 +13311,12 @@ snapshots: json5@2.2.3: {} + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -13047,6 +13324,15 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jump.js@1.0.2: {} + + junit-report-builder@3.2.1: + dependencies: + date-format: 4.0.3 + lodash: 4.17.23 + make-dir: 3.1.0 + xmlbuilder: 15.1.1 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -13872,6 +14158,8 @@ snapshots: object-assign@4.1.1: {} + object-hash@3.0.0: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -13951,6 +14239,10 @@ snapshots: opener@1.5.2: {} + opn@6.0.0: + dependencies: + is-wsl: 1.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -13974,6 +14266,8 @@ snapshots: os-tmpdir@1.0.2: {} + os@0.1.2: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -13996,6 +14290,10 @@ snapshots: dependencies: p-limit: 3.1.0 + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + p-try@2.2.0: {} pa11y-ci@4.0.1(typescript@5.9.3): @@ -14135,6 +14433,11 @@ snapshots: path-to-regexp@0.1.12: {} + path@0.12.7: + dependencies: + process: 0.11.10 + util: 0.10.4 + pathe@2.0.3: {} pause-stream@0.0.11: @@ -14224,16 +14527,39 @@ snapshots: sonic-boom: 4.2.0 thread-stream: 4.0.0 + pixelmatch@4.0.2: + dependencies: + pngjs: 3.4.0 + pkg-types@2.3.0: dependencies: confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 + playwright-core@1.58.2: {} + + playwright@1.58.2: + dependencies: + playwright-core: 1.58.2 + optionalDependencies: + fsevents: 2.3.2 + png-js@1.0.0: {} + pngjs@3.4.0: {} + + pngjs@6.0.0: {} + po-parser@2.1.1: {} + portfinder@1.0.38: + dependencies: + async: 3.2.6 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + possible-typed-array-names@1.1.0: {} postcss-media-query-parser@0.2.3: {} @@ -14302,6 +14628,8 @@ snapshots: process-warning@5.0.0: {} + process@0.11.10: {} + progress@2.0.3: {} prompts@2.4.2: @@ -14355,6 +14683,21 @@ snapshots: punycode@2.3.1: {} + puppeteer-core@22.15.0: + dependencies: + '@puppeteer/browsers': 2.3.0 + chromium-bidi: 0.6.3(devtools-protocol@0.0.1312386) + debug: 4.4.3 + devtools-protocol: 0.0.1312386 + ws: 8.19.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - utf-8-validate + puppeteer-core@24.37.2: dependencies: '@puppeteer/browsers': 2.12.0 @@ -14389,6 +14732,21 @@ snapshots: - supports-color - utf-8-validate + puppeteer@22.15.0(typescript@5.9.3): + dependencies: + '@puppeteer/browsers': 2.3.0 + cosmiconfig: 9.0.0(typescript@5.9.3) + devtools-protocol: 0.0.1312386 + puppeteer-core: 22.15.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + puppeteer@24.37.3(typescript@5.9.3): dependencies: '@puppeteer/browsers': 2.12.1 @@ -14683,6 +15041,10 @@ snapshots: rfdc@1.4.1: {} + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + rimraf@2.7.1: dependencies: glob: 7.2.3 @@ -15237,6 +15599,12 @@ snapshots: optionalDependencies: '@babel/core': 7.29.0 + super-simple-web-server@1.1.4: + dependencies: + express: 4.22.1 + transitivePeerDependencies: + - supports-color + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -15290,6 +15658,11 @@ snapshots: - bare-abort-controller - react-native-b4a + temp@0.9.4: + dependencies: + mkdirp: 0.5.6 + rimraf: 2.6.3 + terser-webpack-plugin@5.3.16(esbuild@0.25.0)(webpack@5.105.0): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -15497,6 +15870,11 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + undici-types@6.21.0: {} undici@6.23.0: {} @@ -15569,6 +15947,8 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + universalify@2.0.1: {} + unpipe@1.0.0: {} unplugin@1.0.1: @@ -15612,6 +15992,8 @@ snapshots: dependencies: punycode: 2.3.1 + urlpattern-polyfill@10.0.0: {} + use-intl@4.8.2(react@19.2.4): dependencies: '@formatjs/fast-memoize': 3.1.0 @@ -15626,6 +16008,10 @@ snapshots: util-deprecate@1.0.2: {} + util@0.10.4: + dependencies: + inherits: 2.0.3 + utils-merge@1.0.1: {} utrie@1.0.2: @@ -15966,6 +16352,8 @@ snapshots: xml-name-validator@5.0.0: {} + xmlbuilder@15.1.1: {} + xmlchars@2.2.0: {} xtend@4.0.2: {} @@ -16033,6 +16421,8 @@ snapshots: zod@3.22.3: {} + zod@3.23.8: {} + zod@3.25.76: {} zwitch@2.0.4: {}