diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml old mode 100644 new mode 100755 index 98f8a2a..859d246 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,127 +1,13 @@ # .github/workflows/playwright-daily.yml # Runs Playwright test shards every day at **11 : 42 AM IST** (06 : 12 UTC) -# plus anytime you trigger it manually from the Actions tab. - -name: Run Playwright tests - -on: - push: # runs on every push - pull_request: # runs on new PRs or PR updates - schedule: - - cron: '30 3 * * 1-5' - workflow_dispatch: - -jobs: - run-tests: - name: Run shard ${{ matrix.shardIndex }}/5 - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - shardIndex: [1,2,3,4,5] - shardTotal: [5] - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js 18.x - uses: actions/setup-node@v3 - with: - node-version: '18' - - - name: Create .env file - run: | - echo "USERNAME=${{ secrets.USERNAME }}" >> .env - echo "PASSWORD=${{ secrets.PASSWORD }}" >> .env - echo "NEW_PASSWORD=${{ secrets.NEW_PASSWORD }}" >> .env - echo "FIRST_NAME=${{ secrets.FIRST_NAME }}" >> .env - echo "STREET_NAME=${{ secrets.STREET_NAME }}" >> .env - echo "CITY=${{ secrets.CITY }}" >> .env - echo "STATE=${{ secrets.STATE }}" >> .env - echo "COUNTRY=${{ secrets.COUNTRY }}" >> .env - echo "ZIP_CODE=${{ secrets.ZIP_CODE }}" >> .env - - - name: Cache npm dependencies - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Install deps + browsers - run: | - npm ci - npx playwright install --with-deps chromium firefox webkit - - name: List Playwright projects (debug) - run: npx playwright list --projects | cat - - - name: Run shard ${{ matrix.shardIndex }} - run: npx playwright test --grep="@chromium|@firefox|@webkit|@android|@ios|@api" --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - - - name: Upload blob report - if: ${{ !cancelled() }} - uses: actions/upload-artifact@v4 - with: - name: blob-report-${{ matrix.shardIndex }} - path: ./blob-report - retention-days: 1 - - merge-reports: - name: Merge Reports - needs: run-tests - if: always() # run even if some shards fail - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js 18.x - uses: actions/setup-node@v3 - with: - node-version: '18' - - - name: Cache npm dependencies - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Install deps + browsers - run: | - npm ci - npx playwright install --with-deps - - name: Download all blob reports - uses: actions/download-artifact@v4 - with: - path: ./all-blob-reports - pattern: blob-report-* - merge-multiple: true - - - name: Merge HTML & JSON reports - run: npx playwright merge-reports --reporter=html ./all-blob-reports - - - name: Upload combined report - uses: actions/upload-artifact@v4 - with: - name: Playwright Test Report - path: ./playwright-report - retention-days: 14 - - - name: Send TestDino report - run: | - npx --yes tdpw ./playwright-report \ - --token="${{ secrets.TESTDINO_TOKEN }}" \ - --upload-html \ - --verbose - # name: Run Playwright tests # on: -# push: -# pull_request: +# push: # runs on every push +# pull_request: # runs on new PRs or PR updates +# schedule: +# - cron: '30 3 * * 1-5' # workflow_dispatch: # jobs: @@ -132,20 +18,17 @@ jobs: # strategy: # fail-fast: false # matrix: -# shardIndex: [1, 2, 3, 4, 5] +# shardIndex: [1,2,3,4,5] # shardTotal: [5] # steps: -# - name: Checkout repo -# uses: actions/checkout@v4 +# - uses: actions/checkout@v4 -# # ✅ Required Node version -# - name: Setup Node.js 20.x -# uses: actions/setup-node@v4 +# - name: Setup Node.js 18.x +# uses: actions/setup-node@v3 # with: -# node-version: '20' +# node-version: '18' -# # ✅ Required env variables for tests # - name: Create .env file # run: | # echo "USERNAME=${{ secrets.USERNAME }}" >> .env @@ -157,8 +40,7 @@ jobs: # echo "STATE=${{ secrets.STATE }}" >> .env # echo "COUNTRY=${{ secrets.COUNTRY }}" >> .env # echo "ZIP_CODE=${{ secrets.ZIP_CODE }}" >> .env - -# # ✅ Cache npm dependencies + # - name: Cache npm dependencies # uses: actions/cache@v3 # with: @@ -166,28 +48,148 @@ jobs: # key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} # restore-keys: | # ${{ runner.os }}-node- - -# # ✅ Install dependencies + TestDino (.tgz) + Playwright browsers -# - name: Install dependencies & browsers +# - name: Install deps + browsers # run: | -# npm install -# npm install --save-dev @testdino/playwright@latest +# npm ci # npx playwright install --with-deps chromium firefox webkit +# - name: List Playwright projects (debug) +# run: npx playwright list --projects | cat -# # ✅ Run Playwright shard with TestDino -# - name: Run Playwright shard with TestDino -# env: -# TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }} -# run: | -# npx playwright test \ -# --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} \ -# --grep "@chromium|@firefox|@webkit|@android|@ios|@api" \ +# - name: Run shard ${{ matrix.shardIndex }} +# run: npx playwright test --grep="@chromium|@firefox|@webkit|@android|@ios|@api" --reporter=blob --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} -# # ✅ Upload blob report (needed for merge) # - name: Upload blob report # if: ${{ !cancelled() }} # uses: actions/upload-artifact@v4 # with: # name: blob-report-${{ matrix.shardIndex }} # path: ./blob-report -# retention-days: 1 \ No newline at end of file +# retention-days: 1 + +# merge-reports: +# name: Merge Reports +# needs: run-tests +# if: always() # run even if some shards fail +# runs-on: ubuntu-latest + +# steps: +# - uses: actions/checkout@v4 + +# - name: Setup Node.js 18.x +# uses: actions/setup-node@v3 +# with: +# node-version: '18' + +# - name: Cache npm dependencies +# uses: actions/cache@v3 +# with: +# path: ~/.npm +# key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} +# restore-keys: | +# ${{ runner.os }}-node- +# - name: Install deps + browsers +# run: | +# npm ci +# npx playwright install --with-deps +# - name: Download all blob reports +# uses: actions/download-artifact@v4 +# with: +# path: ./all-blob-reports +# pattern: blob-report-* +# merge-multiple: true + +# - name: Merge HTML & JSON reports +# run: npx playwright merge-reports --reporter=html ./all-blob-reports + +# - name: Upload combined report +# uses: actions/upload-artifact@v4 +# with: +# name: Playwright Test Report +# path: ./playwright-report +# retention-days: 14 + + +name: Run Playwright tests + +on: + workflow_dispatch: + inputs: + test_count: + description: 'Number of TC- tests to generate (max 5000)' + required: false + default: '5' + +jobs: + run-tests: + name: Run shard ${{ matrix.shardIndex }}/15 + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + shardIndex: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + shardTotal: [15] + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # ✅ Required Node version + - name: Setup Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: '20' + + # ✅ Required env variables for tests + - name: Create .env file + run: | + echo "USERNAME=${{ secrets.USERNAME }}" >> .env + echo "PASSWORD=${{ secrets.PASSWORD }}" >> .env + echo "NEW_PASSWORD=${{ secrets.NEW_PASSWORD }}" >> .env + echo "FIRST_NAME=${{ secrets.FIRST_NAME }}" >> .env + echo "STREET_NAME=${{ secrets.STREET_NAME }}" >> .env + echo "CITY=${{ secrets.CITY }}" >> .env + echo "STATE=${{ secrets.STATE }}" >> .env + echo "COUNTRY=${{ secrets.COUNTRY }}" >> .env + echo "ZIP_CODE=${{ secrets.ZIP_CODE }}" >> .env + # ✅ Cache npm dependencies + - name: Cache npm dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + # ✅ Install dependencies + TestDino (.tgz) + Playwright browsers + - name: Install dependencies & browsers + run: | + npm install + npx playwright install --with-deps chromium + # ✅ Run Playwright shard with real-time TestDino streaming + - name: Run Playwright shard with TestDino + env: + TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }} + TESTDINO_SERVER_URL: https://stg-analytics.testdino.com + TC_COUNT: ${{ github.event.inputs.test_count || '5' }} + run: | + npx playwright test \ + --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} \ + --workers=7 \ + --pass-with-no-tests \ + --grep="@chromium|@firefox|@webkit|@android|@ios|@api" + # ✅ Upload test results to BuildPulse (runs even when tests fail) + - name: Upload test results to BuildPulse + if: always() + uses: BuildPulseLLC/test-reporter-action@v3 + with: + api-token: ${{ secrets.BUILDPULSE_API_TOKEN }} + path: junit.xml + + # ✅ Upload blob report (needed for merge) + - name: Upload blob report + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: blob-report-${{ matrix.shardIndex }} + path: ./blob-report + retention-days: 1 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENCE b/LICENCE new file mode 100755 index 0000000..6c5b4dc --- /dev/null +++ b/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 TestDino + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 620a189..729981e --- a/README.md +++ b/README.md @@ -3,6 +3,13 @@ Automated end-to-end tests for Ecommerce Demo store using [Playwright](https://playwright.dev/). --- +

+ CI Status + npm version + install size + MIT License +

+ ## Project Structure @@ -45,32 +52,41 @@ npx playwright show-report ## Testdino Integration -[Testdino](https://testdino.com/) enables cloud-based Playwright reporting. - -### Local Execution +[Testdino](https://testdino.com/) enables cloud-based Playwright reporting with real-time streaming via the [`@testdino/playwright`](https://www.npmjs.com/package/@testdino/playwright) reporter. -After your tests complete and the report is generated in `playwright-report`, upload it to Testdino: +The reporter is already configured in `playwright.config.js`: +```js +reporter: [ + ['@testdino/playwright', { token: process.env.TESTDINO_TOKEN }], +], +``` +### Local Execution -Replace the token above with your own Testdino API key. +Set your API token (from the TestDino dashboard) and run tests as usual — results stream to TestDino in real time: -See all available commands: ```sh -npx tdpw --help +export TESTDINO_TOKEN=YOUR_API_TOKEN +npx playwright test ``` +You can also put the token in `.env` (see `.env.example`); it is loaded automatically. + --- ## CI/CD Pipeline Integration ### GitHub Actions -Add the following step to your workflow after tests and report generation: - +Add `TESTDINO_TOKEN` as a repository secret and expose it to the test step: - -Ensure your API key is correctly placed in the command. +```yaml +- name: Run Playwright tests + run: npx playwright test + env: + TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }} +``` --- diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-after-typing-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-after-typing-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-changed-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-changed-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-filled-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-filled-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-initial-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-initial-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/github-login-username-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/github-login-username-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/__screenshots__/visual.spec.js-snapshots/username-input-chromium-darwin.png b/__screenshots__/visual.spec.js-snapshots/username-input-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/github-login.png b/github-login.png old mode 100644 new mode 100755 diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 index 461940b..5e77396 --- a/package-lock.json +++ b/package-lock.json @@ -10,22 +10,22 @@ "license": "ISC", "dependencies": { "dotenv": "^17.2.1", - "playwright": "^1.55.0" + "playwright": "1.59.0" }, "devDependencies": { - "@playwright/test": "^1.54.1", - "@testdino/playwright": "^1.0.7", + "@playwright/test": "1.59.0", + "@testdino/playwright": "file:vendor/testdino-playwright-2.0.0.tgz", "@types/node": "^24.1.0" } }, "node_modules/@playwright/test": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", - "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0.tgz", + "integrity": "sha512-TOA5sTLd49rTDaZpYpvCQ9hGefHQq/OYOyCVnGqS2mjMfX+lGZv2iddIJd0I48cfxqSPttS9S3OuLKyylHcO1w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.58.2" + "playwright": "1.59.0" }, "bin": { "playwright": "cli.js" @@ -55,18 +55,22 @@ } }, "node_modules/@testdino/playwright": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@testdino/playwright/-/playwright-1.0.7.tgz", - "integrity": "sha512-ayFZ7T6BFBTxS5coYPGmANEhmBVRf0nX8CZEBPnTIUpqY5mrM2gtxSpOwEct86aRW/wo5FnchjyxN1wEc0C2Mg==", + "version": "2.0.0", + "resolved": "file:vendor/testdino-playwright-2.0.0.tgz", + "integrity": "sha512-wVBcmAQ7Bbyi/YkFIHFzNGwxIIFn23uZOsvVz/mve5c2gP0vP7bgWsX0rye77SNEmP6IJxpM3WAl2aAGhKNKzQ==", "dev": true, "dependencies": { - "axios": "^1.13.4", + "axios": "^1.18.1", "chalk": "^5.6.2", - "commander": "^14.0.3", - "dotenv": "^17.2.3", + "commander": "^15.0.0", + "dotenv": "^17.4.2", "execa": "^9.6.1", - "jiti": "^2.6.1", - "ws": "^8.19.0" + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "jiti": "^2.7.0", + "kafkajs": "^2.2.4", + "picomatch": "^4.0.4" }, "bin": { "tdpw": "bin/tdpw.js" @@ -88,6 +92,19 @@ "undici-types": "~7.16.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -96,15 +113,16 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz", + "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" } }, "node_modules/call-bind-apply-helpers": { @@ -148,13 +166,13 @@ } }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=22.12.0" } }, "node_modules/cross-spawn": { @@ -172,6 +190,24 @@ "node": ">= 8" } }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -183,9 +219,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.4", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.4.tgz", - "integrity": "sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -230,9 +266,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -302,9 +338,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -323,17 +359,17 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -432,6 +468,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -462,9 +508,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -474,6 +520,27 @@ "node": ">= 0.4" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", @@ -530,16 +597,81 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/kafkajs": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz", + "integrity": "sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "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", @@ -573,6 +705,13 @@ "node": ">= 0.6" } }, + "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, + "license": "MIT" + }, "node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", @@ -626,13 +765,26 @@ "node": ">=8" } }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/playwright": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", - "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0.tgz", + "integrity": "sha512-wihGScriusvATUxmhfENxg0tj1vHEFeIwxlnPFKQTOQVd7aG08mUfvvniRP/PtQOC+2Bs52kBOC/Up1jTXeIbw==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.58.2" + "playwright-core": "1.59.0" }, "bin": { "playwright": "cli.js" @@ -645,9 +797,9 @@ } }, "node_modules/playwright-core": { - "version": "1.58.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", - "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0.tgz", + "integrity": "sha512-PW/X/IoZ6BMUUy8rpwHEZ8Kc0IiLIkgKYGNFaMs5KmQhcfLILNx9yCQD0rnWeWfz1PNeqcFP1BsihQhDOBCwZw==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -673,11 +825,27 @@ } }, "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==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/shebang-command": { "version": "2.0.0", @@ -728,6 +896,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -764,28 +945,6 @@ "node": ">= 8" } }, - "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "dev": true, - "license": "MIT", - "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/yoctocolors": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 0e8ba2a..8b80885 --- a/package.json +++ b/package.json @@ -7,12 +7,12 @@ "license": "ISC", "description": "", "devDependencies": { - "@playwright/test": "^1.54.1", - "@testdino/playwright": "^1.0.7", + "@playwright/test": "1.59.0", + "@testdino/playwright": "file:vendor/testdino-playwright-2.0.0.tgz", "@types/node": "^24.1.0" }, "dependencies": { "dotenv": "^17.2.1", - "playwright": "^1.55.0" + "playwright": "1.59.0" } } diff --git a/pages/AllPages.js b/pages/AllPages.js old mode 100644 new mode 100755 diff --git a/pages/AllProductsPage.js b/pages/AllProductsPage.js old mode 100644 new mode 100755 diff --git a/pages/BasePage.js b/pages/BasePage.js old mode 100644 new mode 100755 diff --git a/pages/CartPage.js b/pages/CartPage.js old mode 100644 new mode 100755 diff --git a/pages/CheckoutPage.js b/pages/CheckoutPage.js old mode 100644 new mode 100755 diff --git a/pages/ContactUsPage.js b/pages/ContactUsPage.js old mode 100644 new mode 100755 diff --git a/pages/HomePage.js b/pages/HomePage.js old mode 100644 new mode 100755 diff --git a/pages/InventoryPage.js b/pages/InventoryPage.js old mode 100644 new mode 100755 diff --git a/pages/LoginPage.js b/pages/LoginPage.js old mode 100644 new mode 100755 diff --git a/pages/OrderDetailsPage.js b/pages/OrderDetailsPage.js old mode 100644 new mode 100755 diff --git a/pages/OrderPage.js b/pages/OrderPage.js old mode 100644 new mode 100755 diff --git a/pages/ProductDetailsPage.js b/pages/ProductDetailsPage.js old mode 100644 new mode 100755 diff --git a/pages/SignupPage.js b/pages/SignupPage.js old mode 100644 new mode 100755 diff --git a/pages/UserPage.js b/pages/UserPage.js old mode 100644 new mode 100755 diff --git a/playwright.config.js b/playwright.config.js old mode 100644 new mode 100755 index 3496e92..358bade --- a/playwright.config.js +++ b/playwright.config.js @@ -9,11 +9,14 @@ const isCI = !!process.env.CI; export default defineConfig({ testDir: './tests', + testMatch: ['bulk-tc.spec.js'], snapshotDir: './__screenshots__', // ✅ Baseline image storage fullyParallel: true, forbidOnly: isCI, - retries: isCI ? 1 : 1, // Enable retries for flaky test behavior - workers: isCI ? 5 : 5, + // 1 retry in CI so intentionally-flaky tests register as "flaky" (pass on + // retry) instead of failing the shard outright. + retries: isCI ? 1 : 0, + workers: 3, timeout: 60 * 1000, expect: { @@ -27,15 +30,21 @@ export default defineConfig({ }], ['blob', { outputDir: 'blob-report' }], // Blob reporter for merging ['json', { outputFile: './playwright-report/report.json' }], - // ['@testdino/playwright', { token: process.env.TESTDINO_TOKEN }], + ['junit', { outputFile: 'junit.xml' }], // JUnit XML for BuildPulse + + // NOTE: ciRunId (shard grouping) intentionally NOT set — runs streamed with + // ciRunId are ingested but never appear on the staging dashboard (backend bug). + // Re-add `ciRunId: process.env.GITHUB_RUN_ID` once server-side grouping is fixed. + ['@testdino/playwright', { token: process.env.TESTDINO_TOKEN }], // Real-time streaming to TestDino ], use: { baseURL: 'https://storedemo.testdino.com/products', headless: true, - trace: 'retain-on-failure', - screenshot: 'only-on-failure', - video: 'retain-on-failure', + // Always record so every artifact reaches TestDino + trace: 'on', + screenshot: 'on', + video: 'on', actionTimeout: 15 * 1000, navigationTimeout: 30 * 1000, }, @@ -44,33 +53,6 @@ export default defineConfig({ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, - grep: /@chromium/, // only run tests tagged @chromium - }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - grep: /@firefox/, // only run tests tagged @firefox - }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - grep: /@webkit/, // only run tests tagged @webkit - }, - { - name: 'android', - use: { ...devices['Pixel 5'] }, - grep: /@android/, // only run tests tagged @android - }, - { - name: 'ios', - use: { ...devices['iPhone 12'] }, - grep: /@ios/, // only run tests tagged @ios - }, - - { - name: 'api', - use: { ...devices['API'] }, - grep: /@api/, // only run tests tagged @api }, ], }); diff --git a/tests/bulk-tc.spec.js b/tests/bulk-tc.spec.js new file mode 100644 index 0000000..4526c73 --- /dev/null +++ b/tests/bulk-tc.spec.js @@ -0,0 +1,41 @@ +// @ts-check +// Bulk-generated suite: one loop, TOTAL_TESTS test cases. +// Each iteration registers an independent test titled TC-, so Playwright +// sees 5,000 real tests and distributes them evenly across shards/workers. +// Override the count with TC_COUNT (e.g. TC_COUNT=5000 npx playwright test). +// Default is 5 for now to keep TestDino streaming runs small. +import { expect, test } from '@playwright/test'; + +const TOTAL_TESTS = Number(process.env.TC_COUNT ?? 5); + +test.describe('Bulk storefront checks', () => { + for (let i = 1; i <= TOTAL_TESTS; i++) { + test(`TC-${i}: Verify storefront loads and title is correct`, { tag: '@chromium' }, async ({ page }) => { + await page.goto('/'); + await page.waitForLoadState('domcontentloaded'); + await expect(page).toHaveTitle(/TestDino/); + }); + } +}); + +// Intentionally flaky tests for BuildPulse/TestDino flake detection. +// Each fails randomly at a different rate, so across runs (and retries) +// they produce the pass/fail-on-same-commit signal flake detectors look for. +test.describe('Flaky suite', () => { + const FLAKE_RATES = { 1: 0.3, 2: 0.4, 3: 0.5, 4: 0.6, 5: 0.2 }; + + for (const [n, rate] of Object.entries(FLAKE_RATES)) { + test(`FLAKY-${n}: intermittent assertion (fails ~${rate * 100}% of runs)`, { tag: '@chromium' }, async ({ page }) => { + await page.goto('/'); + expect(Math.random(), `Simulated flake: random draw fell below ${rate}`).toBeGreaterThan(rate); + await expect(page).toHaveTitle(/TestDino/); + }); + } + + test('FLAKY-6: simulated slow dependency (1-3s) against a 2s budget', { tag: '@chromium' }, async ({ page }) => { + const delay = 1000 + Math.floor(Math.random() * 2000); + await page.goto('/'); + await page.waitForTimeout(delay); + expect(delay, 'Simulated slow dependency exceeded 2s budget').toBeLessThan(2000); + }); +}); diff --git a/tests/cart_checkout.spec.js b/tests/cart_checkout.spec.js old mode 100644 new mode 100755 diff --git a/tests/debug-features-live-trace.spec.js b/tests/debug-features-live-trace.spec.js new file mode 100755 index 0000000..0ef152b --- /dev/null +++ b/tests/debug-features-live-trace.spec.js @@ -0,0 +1,102 @@ +// @ts-check +// Test 2 of 2 — exercises the rest of Playwright 1.59's debugging surface: +// live tracing, ariaSnapshot, console-message filtering, and the +// async-dispose pattern. Fails intentionally. +import { expect, test } from '@playwright/test'; + +// Disable the config's auto-tracing for this file so we can own +// tracing.start()/stop() ourselves and exercise the new `live: true` option. +// test.use({ trace }) must be at file scope — nesting it in a describe fails. +test.use({ trace: 'off' }); + +test.describe('Playwright 1.59 — live trace, aria snapshot, console filter', () => { + + test('aria snapshot + live trace + console filter (fails intentionally)', async ({ browser }, testInfo) => { + const tracePath = testInfo.outputPath('live-run.zip'); + const videoDir = testInfo.outputPath('video'); + + // Spin up our own context so we fully own its tracing and video + // lifecycle. recordVideo on a manually-created context is the only way + // to get a video artifact here (the auto-video fixture only applies to + // the default `page` fixture). + const context = await browser.newContext({ recordVideo: { dir: videoDir } }); + const page = await context.newPage(); + + // ---- live tracing (1.59) --------------------------------------------- + // With `live: true`, trace chunks are flushed to disk continuously. You + // can open them in real time from another terminal: + // npx playwright show-trace --live + // Useful when a long-running test hangs — you can see what it's doing + // right now without waiting for stop(). + await context.tracing.start({ + name: 'live-run', + title: 'aria snapshot run', + screenshots: true, + snapshots: true, + sources: true, + live: true, + }); + + // ---- async-dispose pattern (1.59) ------------------------------------ + // In a TS project you'd write: + // await using cdp = await context.newCDPSession(page); + // and Symbol.asyncDispose would call cdp.detach() at block exit. This + // plain-JS file's parser doesn't accept the syntax, so we do the same + // cleanup manually via try/finally — the underlying disposal hook is + // identical. + const cdp = await context.newCDPSession(page); + await cdp.send('Network.enable'); + + try { + await page.goto('/'); + + // ---- ariaSnapshot (1.59) ------------------------------------------- + // Serialize the accessibility tree as a YAML-ish string. Easy to diff + // across runs and cheap to feed to an LLM for a semantic diff. In 1.59, + // `mode` accepts 'default' (human-readable) or 'ai' (token-efficient + // for LLMs). + const snapshot = await page.locator('body').ariaSnapshot({ mode: 'ai' }); + console.log('--- ARIA SNAPSHOT (first 400 chars) ---'); + console.log(snapshot.slice(0, 400)); + + // Emit console output from the page so we have something to filter on. + await page.evaluate(() => { + console.log('hello from the page'); + console.warn('a benign warning'); + console.error('INTENDED_ERROR: nothing actually broke'); + }); + + // ---- buffered console messages (1.59) ------------------------------ + // 1.59 buffers console messages on the page, so you can pull them + // retroactively — no up-front page.on('console') listener needed. The + // `filter` option is a string: 'all' (everything since the page + // opened) or 'since-navigation' (only since the last top-level nav). + // Then you narrow by type() in JS. Companion APIs: + // page.clearConsoleMessages(), page.pageErrors(), + // page.clearPageErrors(), consoleMessage.timestamp(). + const allMessages = await page.consoleMessages({ filter: 'since-navigation' }); + const errors = allMessages.filter(m => m.type() === 'error'); + + // Intentional failure — we asked for zero errors, we have one. + // The saved trace can then be inspected from the CLI with the new + // agent-friendly commands (1.59): + // npx playwright trace actions --grep "expect" + // npx playwright trace action + // npx playwright trace snapshot --name after + expect(errors, `got ${errors.length} console error(s)`).toHaveLength(0); + } finally { + // Stop + attach in finally so the trace survives intentional failures. + // attach() surfaces the artifacts in the HTML reporter under this test. + await context.tracing.stop({ path: tracePath }); + await cdp.detach(); + const videoFile = await page.video()?.path(); + await context.close(); + + await testInfo.attach('live-run.zip', { path: tracePath, contentType: 'application/zip' }); + if (videoFile) { + await testInfo.attach('video.webm', { path: videoFile, contentType: 'video/webm' }); + } + } + }); + +}); diff --git a/tests/debug-features.spec.js b/tests/debug-features.spec.js new file mode 100755 index 0000000..a083fce --- /dev/null +++ b/tests/debug-features.spec.js @@ -0,0 +1,90 @@ +// @ts-check +// Test 1 of 2 — exercises Playwright 1.59's new page.screencast API. +// Fails intentionally so the reporter retains video + trace artifacts. +import { expect, test } from '@playwright/test'; + +test.describe('Playwright 1.59 — screencast API', () => { + + // --------------------------------------------------------------------------- + // 1.59 introduces page.screencast as a unified capture interface. Unlike + // the context-level `recordVideo` option (set-and-forget), screencast is + // imperative: you call start/stop inside the test, can layer action + // annotations, chapter titles, and custom HTML overlays onto the recording, + // and the output ends up as a test attachment in the HTML reporter. + // + // Relation to videos: screencast *replaces* recordVideo for any case where + // you want control over what's captured. The emitted .webm is exactly + // what the `video` attachment points to. + // + // Relation to traces: every screencast.start / showChapter / showActions / + // showOverlay call is a first-class action in the trace timeline. Open + // the trace and you'll see each chapter switch lined up next to the + // DOM snapshot at that moment — you can scrub video and trace in lockstep. + // --------------------------------------------------------------------------- + test('screencast walkthrough of the store (fails intentionally)', async ({ page }, testInfo) => { + const videoPath = testInfo.outputPath('walkthrough.webm'); + + // start() begins encoding frames into a .webm. + await page.screencast.start({ path: videoPath }); + + // Overlay a badge every time Playwright performs an action (click, fill, + // hover…). This is the "agentic video receipt" feature — reviewers see + // why the cursor moved where it did. position + fontSize configurable. + await page.screencast.showActions({ position: 'top-right', fontSize: 14 }); + + // Chapters render a titled section for `duration` ms, giving the video a + // narrative structure that a reviewer (or LLM) can navigate. + await page.screencast.showChapter('Open storefront', { + description: 'Navigate to the products landing page', + duration: 1200, + }); + + await page.goto('/'); + await page.waitForLoadState('domcontentloaded'); + + await page.screencast.showChapter('Inspect layout', { + description: 'Check the logo and hero copy are present', + duration: 1000, + }); + + // A few selector-agnostic interactions so the screencast has real frames + // and showActions() has actions to annotate before we hit the failure. + await page.locator('body').hover(); + await page.mouse.wheel(0, 400); + await page.waitForTimeout(500); + await page.mouse.wheel(0, 400); + await page.waitForTimeout(500); + + await page.screencast.showChapter('Scan products', { + description: 'Scroll the grid end-to-end', + duration: 1000, + }); + + await page.keyboard.press('End'); + await page.waitForTimeout(800); + await page.keyboard.press('Home'); + await page.waitForTimeout(500); + + // Arbitrary HTML overlay — good for stamping build IDs, test names, etc. + await page.screencast.showOverlay( + `
+ test run — ${new Date().toISOString()} +
`, + { position: 'bottom-left', duration: 2000 } + ); + + await page.screencast.showChapter('Final title check', { + description: 'Assert the page title (intentionally wrong)', + duration: 800, + }); + + // Intentional failure — the real title is "TestDino | Demo Store". The + // failure triggers retain-on-failure for both trace and video, so the + // reporter ends up with the screencast.webm AND a trace.zip whose + // timeline contains every screencast.* action above. + await expect(page).toHaveTitle(/Unicorns/); + + await page.screencast.stop(); + }); + +}); diff --git a/tests/delete-api.spec.js b/tests/delete-api.spec.js old mode 100644 new mode 100755 diff --git a/tests/get-users.spec.js b/tests/get-users.spec.js old mode 100644 new mode 100755 diff --git a/tests/login.spec.js b/tests/login.spec.js old mode 100644 new mode 100755 diff --git a/tests/navigation.spec.js b/tests/navigation.spec.js old mode 100644 new mode 100755 diff --git a/tests/orders.spec.js b/tests/orders.spec.js old mode 100644 new mode 100755 diff --git a/tests/post-api.spec.js b/tests/post-api.spec.js old mode 100644 new mode 100755 diff --git a/tests/product.spec.js b/tests/product.spec.js old mode 100644 new mode 100755 diff --git a/tests/updateUser.spec.js b/tests/updateUser.spec.js old mode 100644 new mode 100755 diff --git a/tests/visual.spec.js b/tests/visual.spec.js old mode 100644 new mode 100755 diff --git a/tests/visual.spec.js-snapshots/github-login-changed-chromium-darwin.png b/tests/visual.spec.js-snapshots/github-login-changed-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/tests/visual.spec.js-snapshots/github-login-chromium-darwin.png b/tests/visual.spec.js-snapshots/github-login-chromium-darwin.png old mode 100644 new mode 100755 diff --git a/vendor/testdino-playwright-2.0.0.tgz b/vendor/testdino-playwright-2.0.0.tgz new file mode 100644 index 0000000..009ecd9 Binary files /dev/null and b/vendor/testdino-playwright-2.0.0.tgz differ