From b9460ec6c24f7e33ad11e092c7b8a2837e57ab6f Mon Sep 17 00:00:00 2001 From: legendecas Date: Fri, 27 Oct 2023 01:17:38 +0800 Subject: [PATCH 1/5] test,tools: update wpt weekly --- .github/workflows/update-wpt.yml | 67 ++++++++++++++++++ Makefile | 7 ++ test/common/wpt.js | 116 ++++++++++++++++++++++++++----- tools/dep_updaters/update-wpt.sh | 9 +++ 4 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/update-wpt.yml create mode 100755 tools/dep_updaters/update-wpt.sh diff --git a/.github/workflows/update-wpt.yml b/.github/workflows/update-wpt.yml new file mode 100644 index 00000000000..933edc0b722 --- /dev/null +++ b/.github/workflows/update-wpt.yml @@ -0,0 +1,67 @@ +# This workflow runs every night and tests various releases of Node.js +# (latest nightly, current, and two latest LTS release lines) against the +# `epochs/weekly` branch of WPT. + +name: Weekly WPT roller + +on: + workflow_dispatch: + schedule: + # This is 20 minutes after `epochs/weekly` branch is triggered to be created + # in WPT repo, every Monday. + # https://github.com/web-platform-tests/wpt/blob/master/.github/workflows/epochs.yml + - cron: 30 0 * * 1 + +env: + PYTHON_VERSION: '3.11' + NODE_VERSION: lts/* + +permissions: + contents: read + +jobs: + update-wpt: + if: github.repository == 'nodejs/node' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install Node.js + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install @node-core/utils + run: npm install -g @node-core/utils + + - name: Environment Information + run: npx envinfo + + - name: Set env.WPT_REVISION + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: echo "WPT_REVISION=$(gh api /repos/web-platform-tests/wpt/branches/epochs/weekly --jq '.commit.sha')" >> $GITHUB_ENV + - name: Rolling update wpt fixtures + run: ./tools/dep_updaters/update-wpt.sh + + - name: Build + run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn" + - name: Update wpt status.json + run: make test-wpt-status-update + + - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 + # Creates a PR or update the Action's existing PR, or + # no-op if the base branch is already up-to-date. + env: + GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} + with: + author: Node.js GitHub Bot + body: This is an automated patch update of wpt to ${{ env.WPT_REVISION }}. + branch: actions/update-wpt # Custom branch *just* for this Action. + labels: test + title: 'deps: update wpt to ${{ env.WPT_REVISION }}' + update-pull-request-title-and-body: true diff --git a/Makefile b/Makefile index b7871bf2185..dcb18e48682 100644 --- a/Makefile +++ b/Makefile @@ -595,6 +595,13 @@ test-wpt-report: -WPT_REPORT=1 $(PYTHON) tools/test.py --shell $(NODE) $(PARALLEL_ARGS) wpt $(NODE) "$$PWD/tools/merge-wpt-reports.mjs" +.PHONY: test-wpt-status-update +test-wpt-status-update: + $(RM) -r out/wpt + mkdir -p out/wpt + -WPT_UPDATE_STATUS=1 $(PYTHON) tools/test.py --shell $(NODE) $(PARALLEL_ARGS) wpt + $(NODE) "$$PWD/tools/merge-wpt-reports.mjs" + .PHONY: test-internet test-internet: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) internet diff --git a/test/common/wpt.js b/test/common/wpt.js index 34436639dc3..287a207e957 100644 --- a/test/common/wpt.js +++ b/test/common/wpt.js @@ -59,10 +59,16 @@ function codeUnitStr(char) { } class ReportResult { - constructor(name) { + /** + * Construct a ReportResult. + * @param {string} name test name shown in wpt.fyi, unique for every variants. + * @param {WPTTestSpec} spec + */ + constructor(name, spec) { this.test = name; this.status = 'OK'; this.subtests = []; + this.spec = spec; } addSubtest(name, status, message) { @@ -82,14 +88,18 @@ class ReportResult { finish(status) { this.status = status ?? 'OK'; } + + toJSON() { + return { + test: this.test, + status: this.status, + subtests: this.subtests, + }; + } } -// Generates a report that can be uploaded to wpt.fyi. -// Checkout https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation -// for more details. -class WPTReport { - constructor(path) { - this.filename = `report-${path.replaceAll('/', '-')}.json`; +class Report { + constructor() { /** @type {Map} */ this.results = new Map(); this.time_start = Date.now(); @@ -104,10 +114,21 @@ class WPTReport { if (this.results.has(name)) { return this.results.get(name); } - const result = new ReportResult(name); + const result = new ReportResult(name, spec); this.results.set(name, result); return result; } +} + +// Generates a report that can be uploaded to wpt.fyi. +// Checkout https://github.com/web-platform-tests/wpt.fyi/tree/main/api#results-creation +// for more details. +class WPTReport extends Report { + constructor(path) { + super(); + this.filename = `report-${path.replaceAll('/', '-')}.json`; + this.time_start = Date.now(); + } write() { this.time_end = Date.now(); @@ -139,6 +160,42 @@ class WPTReport { } } +class WPTStatusUpdater extends Report { + constructor(testPath) { + super(); + this.filepath = path.join('test/wpt/status', `${testPath}.json`); + this.statusFile = JSON.parse(fs.readFileSync(this.filepath, 'utf8')); + } + + write() { + for (const result of this.results.values()) { + if (result.status !== 'OK') { + this.statusFile[result.spec.filename] ??= { + skip: 'WPT test auto rolling', + }; + continue; + } + const failedSubtests = result.subtests.filter(it => it.status !== 'PASS'); + if (failedSubtests.length === 0) { + continue; + } + const expectations = new Set(this.statusFile[result.spec.filename]?.fail?.expected); + failedSubtests.forEach((subtest) => { + expectations.add(subtest.name); + }); + this.statusFile[result.spec.filename] = { + ...(this.statusFile[result.spec.filename] ?? {}), + fail: { + note: this.statusFile[result.spec.filename]?.fail?.note ?? 'WPT test auto rolling', + expected: [...expectations].sort(), + }, + }; + } + + fs.writeFileSync(this.filepath, JSON.stringify(this.statusFile, null, 2) + '\n'); + } +} + // https://github.com/web-platform-tests/wpt/blob/HEAD/resources/testharness.js // TODO: get rid of this half-baked harness in favor of the one // pulled from WPT @@ -513,6 +570,8 @@ class WPTRunner { if (process.env.WPT_REPORT != null) { this.report = new WPTReport(path); + } else if (process.env.WPT_UPDATE_STATUS != null) { + this.report = new WPTStatusUpdater(path); } } @@ -624,6 +683,7 @@ class WPTRunner { const run = limit(this.concurrency); for (const spec of queue) { + const reportResult = this.report?.getResult(spec); const content = spec.getContent(); const meta = spec.getMeta(content); @@ -632,14 +692,33 @@ class WPTRunner { const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js'); // Scripts specified with the `// META: script=` header - const scriptsToRun = meta.script?.map((script) => { - const obj = { - filename: this.resource.toRealFilePath(relativePath, script), - code: this.resource.read(relativePath, script), - }; - this.scriptsModifier?.(obj); - return obj; - }) ?? []; + let scriptsToRun + try { + scriptsToRun = meta.script?.map((script) => { + const obj = { + filename: this.resource.toRealFilePath(relativePath, script), + code: this.resource.read(relativePath, script), + }; + this.scriptsModifier?.(obj); + return obj; + }) ?? []; + } catch (err) { + // Generate a subtest failure for visibility. + // No need to record this synthetic failure with wpt.fyi. + this.fail( + spec, + { + status: NODE_UNCAUGHT, + name: 'Resource not found', + message: err.message, + stack: inspect(err), + }, + kUncaught, + ); + // Mark the whole test as failed in wpt.fyi report. + reportResult?.finish('ERROR'); + continue; + } // The actual test const obj = { code: content, @@ -667,7 +746,6 @@ class WPTRunner { this.inProgress.add(spec); this.workers.set(spec, worker); - const reportResult = this.report?.getResult(spec); worker.on('message', (message) => { switch (message.type) { case 'result': @@ -776,6 +854,10 @@ class WPTRunner { `${passed} passed, ${expectedFailures} expected failures,`, `${failures.length} unexpected failures,`, `${unexpectedPasses.length} unexpected passes`); + if (process.env.WPT_UPDATE_STATUS) { + // Exit the process normally if we are updating the status file. + return; + } if (failures.length > 0) { const file = path.join('test', 'wpt', 'status', `${this.path}.json`); throw new Error( diff --git a/tools/dep_updaters/update-wpt.sh b/tools/dep_updaters/update-wpt.sh new file mode 100755 index 00000000000..11b4b28824f --- /dev/null +++ b/tools/dep_updaters/update-wpt.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +# Shell script to update wpt test fixtures in the source tree to the most recent version. + +BASE_DIR=$(cd "$(dirname "$0")/../.." && pwd) + +cd "$BASE_DIR" +jq -r 'keys[]' "$BASE_DIR/test/fixtures/wpt/versions.json" | \ + xargs -L 1 git node wpt --commit "$WPT_REVISION" From 47700fdb6d0d97242eb640b1d39ce7d876ce86cd Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 6 Nov 2023 00:03:23 +0800 Subject: [PATCH 2/5] fixup! speedup --- .github/workflows/auto-start-ci.yml | 72 ---- .github/workflows/build-tarball.yml | 97 ------ .github/workflows/build-windows.yml | 53 --- .../close-stale-feature-requests.yml | 54 --- .../workflows/close-stale-pull-requests.yml | 59 ---- .github/workflows/close-stalled.yml | 38 --- .github/workflows/comment-labeled.yml | 55 --- .../commit-lint-problem-matcher.json | 13 - .github/workflows/commit-lint.yml | 32 -- .github/workflows/commit-queue.yml | 98 ------ .../workflows/coverage-linux-without-intl.yml | 73 ---- .github/workflows/coverage-linux.yml | 73 ---- .github/workflows/coverage-windows.yml | 72 ---- .github/workflows/daily-wpt-fyi.yml | 156 --------- .github/workflows/daily.yml | 33 -- .github/workflows/doc.yml | 43 --- .../workflows/find-inactive-collaborators.yml | 50 --- .github/workflows/find-inactive-tsc.yml | 62 ---- .github/workflows/label-flaky-test-issue.yml | 53 --- .github/workflows/label-pr.yml | 18 - .github/workflows/license-builder.yml | 38 --- .github/workflows/linters.yml | 181 ---------- .github/workflows/notify-on-push.yml | 70 ---- .../remark-lint-problem-matcher.json | 22 -- .github/workflows/scorecard.yml | 78 ----- .github/workflows/test-asan.yml | 62 ---- .github/workflows/test-internet.yml | 55 --- .github/workflows/test-linux.yml | 49 --- .github/workflows/test-macos.yml | 63 ---- .github/workflows/timezone-update.yml | 62 ---- .github/workflows/tools.yml | 318 ------------------ .github/workflows/update-openssl.yml | 109 ------ .github/workflows/update-v8.yml | 55 --- .github/workflows/update-wpt.yml | 7 +- 34 files changed, 5 insertions(+), 2368 deletions(-) delete mode 100644 .github/workflows/auto-start-ci.yml delete mode 100644 .github/workflows/build-tarball.yml delete mode 100644 .github/workflows/build-windows.yml delete mode 100644 .github/workflows/close-stale-feature-requests.yml delete mode 100644 .github/workflows/close-stale-pull-requests.yml delete mode 100644 .github/workflows/close-stalled.yml delete mode 100644 .github/workflows/comment-labeled.yml delete mode 100644 .github/workflows/commit-lint-problem-matcher.json delete mode 100644 .github/workflows/commit-lint.yml delete mode 100644 .github/workflows/commit-queue.yml delete mode 100644 .github/workflows/coverage-linux-without-intl.yml delete mode 100644 .github/workflows/coverage-linux.yml delete mode 100644 .github/workflows/coverage-windows.yml delete mode 100644 .github/workflows/daily-wpt-fyi.yml delete mode 100644 .github/workflows/daily.yml delete mode 100644 .github/workflows/doc.yml delete mode 100644 .github/workflows/find-inactive-collaborators.yml delete mode 100644 .github/workflows/find-inactive-tsc.yml delete mode 100644 .github/workflows/label-flaky-test-issue.yml delete mode 100644 .github/workflows/label-pr.yml delete mode 100644 .github/workflows/license-builder.yml delete mode 100644 .github/workflows/linters.yml delete mode 100644 .github/workflows/notify-on-push.yml delete mode 100644 .github/workflows/remark-lint-problem-matcher.json delete mode 100644 .github/workflows/scorecard.yml delete mode 100644 .github/workflows/test-asan.yml delete mode 100644 .github/workflows/test-internet.yml delete mode 100644 .github/workflows/test-linux.yml delete mode 100644 .github/workflows/test-macos.yml delete mode 100644 .github/workflows/timezone-update.yml delete mode 100644 .github/workflows/tools.yml delete mode 100644 .github/workflows/update-openssl.yml delete mode 100644 .github/workflows/update-v8.yml diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml deleted file mode 100644 index c1a9ac0ad05..00000000000 --- a/.github/workflows/auto-start-ci.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Auto Start CI - -on: - schedule: - # Runs every five minutes (fastest the scheduler can run). Five minutes is - # optimistic, it can take longer to run. - # To understand why `schedule` is used instead of other events, refer to - # ./doc/contributing/commit-queue.md - - cron: '*/5 * * * *' - -concurrency: ${{ github.workflow }} - -# todo (node-fetch not working on 18, waiting for node-core-utils to fix) -env: - NODE_VERSION: 16 - -permissions: - contents: read - -jobs: - get-prs-for-ci: - permissions: - pull-requests: read - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - outputs: - numbers: ${{ steps.get_prs_for_ci.outputs.numbers }} - steps: - - name: Get Pull Requests - id: get_prs_for_ci - run: > - numbers=$(gh pr list \ - --repo ${{ github.repository }} \ - --label 'request-ci' \ - --json 'number' \ - -t '{{ range . }}{{ .number }} {{ end }}' \ - --limit 5) - echo "numbers=$numbers" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - start-ci: - permissions: - contents: read - pull-requests: write - needs: get-prs-for-ci - if: needs.get-prs-for-ci.outputs.numbers != '' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - - name: Install Node.js - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Install @node-core/utils - run: npm install -g @node-core/utils - - - name: Setup @node-core/utils - run: | - ncu-config set username ${{ secrets.JENKINS_USER }} - ncu-config set token "${{ secrets.GH_USER_TOKEN }}" - ncu-config set jenkins_token ${{ secrets.JENKINS_TOKEN }} - ncu-config set owner "${{ github.repository_owner }}" - ncu-config set repo "$(echo ${{ github.repository }} | cut -d/ -f2)" - - - name: Start the CI - run: ./tools/actions/start-ci.sh ${{ needs.get-prs-for-ci.outputs.numbers }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml deleted file mode 100644 index ea6df99e2c1..00000000000 --- a/.github/workflows/build-tarball.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Build from tarball - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/build-tarball.yml' - push: - branches: - - main - - v[0-9]+.x-staging - - v[0-9]+.x - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/build-tarball.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - build-tarball: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Make tarball - run: | - export DISTTYPE=nightly - export DATESTRING=`date "+%Y-%m-%d"` - export COMMIT=$(git rev-parse --short=10 "$GITHUB_SHA") - ./configure && make tar -j8 SKIP_XZ=1 - mkdir tarballs - mv *.tar.gz tarballs - - name: Upload tarball artifact - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: tarballs - path: tarballs - test-tarball-linux: - needs: build-tarball - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Download tarball - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - with: - name: tarballs - path: tarballs - - name: Extract tarball - run: | - tar xzf tarballs/*.tar.gz -C $RUNNER_TEMP - echo "TAR_DIR=$RUNNER_TEMP/`basename tarballs/*.tar.gz .tar.gz`" >> $GITHUB_ENV - - name: Copy directories needed for testing - run: | - cp -r tools/node_modules $TAR_DIR/tools - cp -r tools/eslint-rules $TAR_DIR/tools - - name: Build - run: | - cd $TAR_DIR - make build-ci -j2 V=1 - - name: Test - run: | - cd $TAR_DIR - make run-ci -j2 V=1 TEST_CI_ARGS="-p dots --node-args='--test-reporter=spec' --measure-flakiness 9" diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml deleted file mode 100644 index 3dcbf7e7b72..00000000000 --- a/.github/workflows/build-windows.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Build Windows - -on: - pull_request: - paths-ignore: - - README.md - - .github/** - - '!.github/workflows/build-windows.yml' - types: [opened, synchronize, reopened, ready_for_review] - push: - branches: - - main - - canary - - v[0-9]+.x-staging - - v[0-9]+.x - paths-ignore: - - README.md - - .github/** - - '!.github/workflows/build-windows.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - build-windows: - if: github.event.pull_request.draft == false - strategy: - matrix: - windows: [windows-2022] - fail-fast: false - runs-on: ${{ matrix.windows }} - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Install deps - run: choco install nasm - - name: Environment Information - run: npx envinfo - - name: Build - run: ./vcbuild.bat diff --git a/.github/workflows/close-stale-feature-requests.yml b/.github/workflows/close-stale-feature-requests.yml deleted file mode 100644 index ca2bd3a0d86..00000000000 --- a/.github/workflows/close-stale-feature-requests.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Close stale feature requests -on: - workflow_dispatch: - schedule: - # Run every day at 1:00 AM UTC. - - cron: 0 1 * * * - -# yamllint disable rule:empty-lines -env: - CLOSE_MESSAGE: > - There has been no activity on this feature request - and it is being closed. If you feel closing this issue is not the - right thing to do, please leave a comment. - - - For more information on how the project manages - feature requests, please consult the - [feature request management document](https://github.com/nodejs/node/blob/HEAD/doc/contributing/feature-request-management.md). - - WARN_MESSAGE: > - There has been no activity on this feature request for - 5 months and it is unlikely to be implemented. - It will be closed 6 months after the last non-automated comment. - - - For more information on how the project manages - feature requests, please consult the - [feature request management document](https://github.com/nodejs/node/blob/HEAD/doc/contributing/feature-request-management.md). -# yamllint enable - -permissions: - contents: read - -jobs: - stale: - permissions: - issues: write # for actions/stale to close stale issues - pull-requests: write # for actions/stale to close stale PRs - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 180 - days-before-close: 30 - stale-issue-label: stale - close-issue-message: ${{ env.CLOSE_MESSAGE }} - stale-issue-message: ${{ env.WARN_MESSAGE }} - only-labels: feature request - exempt-issue-labels: never-stale - # max requests it will send per run to the GitHub API before it deliberately exits to avoid hitting API rate limits - operations-per-run: 500 - remove-stale-when-updated: true diff --git a/.github/workflows/close-stale-pull-requests.yml b/.github/workflows/close-stale-pull-requests.yml deleted file mode 100644 index b18cd5c37e6..00000000000 --- a/.github/workflows/close-stale-pull-requests.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Close stale pull requests -on: - workflow_dispatch: - inputs: - endDate: - description: stop processing PRs after this date - required: false - type: string - -# yamllint disable rule:empty-lines -env: - CLOSE_MESSAGE: > - This pull request was opened more than a year ago and there has - been no activity in the last 6 months. We value your contribution - but since it has not progressed in the last 6 months it is being - closed. If you feel closing this pull request is not the right thing - to do, please leave a comment. - - WARN_MESSAGE: > - This pull request was opened more than a year ago and there has - been no activity in the last 5 months. We value your contribution - but since it has not progressed in the last 5 months it is being - marked stale and will be closed if there is no progress in the - next month. If you feel that is not the right thing to do please - comment on the pull request. -# yamllint enable - -permissions: - contents: read - -jobs: - stale: - permissions: - pull-requests: write # for actions/stale to close stale PRs - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - name: Set default end date which is 1 year ago - run: echo "END_DATE=$(date --date='525600 minutes ago' --rfc-2822)" >> "$GITHUB_ENV" - - name: if date set in event override the default end date - env: - END_DATE_INPUT_VALUE: ${{ github.event.inputs.endDate }} - if: ${{ github.event.inputs.endDate != '' }} - run: echo "END_DATE=$END_DATE_INPUT_VALUE" >> "$GITHUB_ENV" - - uses: mhdawson/stale@453d6581568dc43dbe345757f24408d7b451c651 # PR to add support for endDate - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - end-date: ${{ env.END_DATE }} - days-before-issue-stale: -1 - days-before-issue-close: -1 - days-before-stale: 150 - days-before-close: 30 - stale-issue-label: stale - close-issue-message: ${{ env.CLOSE_MESSAGE }} - stale-issue-message: ${{ env.WARN_MESSAGE }} - exempt-pr-labels: never-stale - # max requests it will send per run to the GitHub API before it deliberately exits to avoid hitting API rate limits - operations-per-run: 500 - remove-stale-when-updated: true diff --git a/.github/workflows/close-stalled.yml b/.github/workflows/close-stalled.yml deleted file mode 100644 index 8fec9f1d6c4..00000000000 --- a/.github/workflows/close-stalled.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Close stalled issues and PRs -on: - schedule: - - cron: 0 0 * * * - -env: - CLOSE_MESSAGE: > - Closing this because it has stalled. Feel free to reopen if this issue/PR - is still relevant, or to ping the collaborator who labelled it stalled if - you have any questions. - -permissions: - contents: read - -jobs: - stale: - permissions: - issues: write # for actions/stale to close stale issues - pull-requests: write # for actions/stale to close stale PRs - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-close: 30 - stale-pr-label: stalled - stale-issue-label: stalled - close-issue-message: ${{ env.CLOSE_MESSAGE }} - close-pr-message: ${{ env.CLOSE_MESSAGE }} - # used to filter issues to check whether or not should be closed, avoids hitting maximum operations allowed if needing to paginate through all open issues - only-labels: stalled - # max requests it will send per run to the GitHub API before it deliberately exits to avoid hitting API rate limits - operations-per-run: 500 - # deactivates automatic removal of stalled label if issue gets any activity - remove-stale-when-updated: false - # deactivates automatic stale labelling as we prefer to do that manually - days-before-stale: -1 diff --git a/.github/workflows/comment-labeled.yml b/.github/workflows/comment-labeled.yml deleted file mode 100644 index 7e3a19c6afd..00000000000 --- a/.github/workflows/comment-labeled.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Comment on issues and PRs when labeled -on: - issues: - types: [labeled] - pull_request_target: - types: [labeled] - -env: - STALE_MESSAGE: > - This issue/PR was marked as stalled, it will be automatically closed in 30 days. - If it should remain open, please leave a comment explaining why it should remain open. - FAST_TRACK_MESSAGE: Fast-track has been requested by @${{ github.actor }}. Please 👍 to approve. - NOTABLE_CHANGE_MESSAGE: | - The https://github.com/nodejs/node/labels/notable-change label has been added by @${{ github.actor }}. - - Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the _Other Notable Changes_ section. - -permissions: - contents: read - -jobs: - stale-comment: - permissions: - issues: write - pull-requests: write - if: github.repository == 'nodejs/node' && github.event.label.name == 'stalled' - runs-on: ubuntu-latest - steps: - - name: Post stalled comment - env: - NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh issue comment "$NUMBER" --repo ${{ github.repository }} --body "$STALE_MESSAGE" - - fast-track: - permissions: - pull-requests: write - if: github.repository == 'nodejs/node' && github.event_name == 'pull_request_target' && github.event.label.name == 'fast-track' - runs-on: ubuntu-latest - steps: - - name: Request Fast-Track - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$FAST_TRACK_MESSAGE" - - notable-change: - permissions: - pull-requests: write - if: github.repository == 'nodejs/node' && github.event_name == 'pull_request_target' && github.event.label.name == 'notable-change' - runs-on: ubuntu-latest - steps: - - name: Add notable change description - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$NOTABLE_CHANGE_MESSAGE" diff --git a/.github/workflows/commit-lint-problem-matcher.json b/.github/workflows/commit-lint-problem-matcher.json deleted file mode 100644 index 72dd13b9e09..00000000000 --- a/.github/workflows/commit-lint-problem-matcher.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "core-validate-commit", - "pattern": [ - { - "regexp": "^not ok \\d+ (.*)$", - "message": 1 - } - ] - } - ] -} diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml deleted file mode 100644 index f5d59079aab..00000000000 --- a/.github/workflows/commit-lint.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: First commit message adheres to guidelines - -on: [pull_request] - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - lint-commit-message: - runs-on: ubuntu-latest - steps: - - name: Compute number of commits in the PR - id: nb-of-commits - run: | - echo "plusOne=$((${{ github.event.pull_request.commits }} + 1))" >> $GITHUB_OUTPUT - echo "minusOne=$((${{ github.event.pull_request.commits }} - 1))" >> $GITHUB_OUTPUT - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: ${{ steps.nb-of-commits.outputs.plusOne }} - persist-credentials: false - - run: git reset HEAD^2 - - name: Install Node.js - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Validate commit message - run: | - echo "::add-matcher::.github/workflows/commit-lint-problem-matcher.json" - git rev-parse HEAD~${{ steps.nb-of-commits.outputs.minusOne }} | xargs npx -q core-validate-commit --no-validate-metadata --tap diff --git a/.github/workflows/commit-queue.yml b/.github/workflows/commit-queue.yml deleted file mode 100644 index cd5bbb83007..00000000000 --- a/.github/workflows/commit-queue.yml +++ /dev/null @@ -1,98 +0,0 @@ -# This action requires the following secrets to be set on the repository: -# GH_USER_NAME: GitHub user whose Jenkins and GitHub token are defined below -# GH_USER_TOKEN: GitHub user token, to be used by ncu and to push changes -# JENKINS_TOKEN: Jenkins token, to be used to check CI status - -name: Commit Queue - -on: - # `schedule` event is used instead of `pull_request` because when a - # `pull_request` event is triggered on a PR from a fork, GITHUB_TOKEN will - # be read-only, and the Action won't have access to any other repository - # secrets, which it needs to access Jenkins API. - schedule: - - cron: '*/5 * * * *' - -concurrency: ${{ github.workflow }} - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - get_mergeable_prs: - permissions: - pull-requests: read - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - outputs: - numbers: ${{ steps.get_mergeable_prs.outputs.numbers }} - steps: - - name: Get Pull Requests - id: get_mergeable_prs - run: | - prs=$(gh pr list \ - --repo ${{ github.repository }} \ - --base ${{ github.ref_name }} \ - --label 'commit-queue' \ - --json 'number' \ - --search "created:<=$(date --date="2 days ago" +"%Y-%m-%dT%H:%M:%S%z")" \ - -t '{{ range . }}{{ .number }} {{ end }}' \ - --limit 100) - fast_track_prs=$(gh pr list \ - --repo ${{ github.repository }} \ - --base ${{ github.ref_name }} \ - --label 'commit-queue' \ - --label 'fast-track' \ - --json 'number' \ - -t '{{ range . }}{{ .number }} {{ end }}' \ - --limit 100) - numbers=$(echo $prs' '$fast_track_prs | jq -r -s 'unique | join(" ")') - echo "numbers=$numbers" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - commitQueue: - needs: get_mergeable_prs - if: needs.get_mergeable_prs.outputs.numbers != '' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - # Needs the whole git history for ncu to work - # See https://github.com/nodejs/node-core-utils/pull/486 - fetch-depth: 0 - # A personal token is required because pushing with GITHUB_TOKEN will - # prevent commits from running CI after they land. It needs - # to be set here because `checkout` configures GitHub authentication - # for push as well. - token: ${{ secrets.GH_USER_TOKEN }} - - # Install dependencies - - name: Install Node.js - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Install @node-core/utils - run: npm install -g @node-core/utils - - - name: Set variables - run: | - echo "REPOSITORY=$(echo ${{ github.repository }} | cut -d/ -f2)" >> $GITHUB_ENV - echo "OWNER=${{ github.repository_owner }}" >> $GITHUB_ENV - - - name: Configure @node-core/utils - run: | - ncu-config set branch ${GITHUB_REF_NAME} - ncu-config set upstream origin - ncu-config set username "${{ secrets.GH_USER_NAME }}" - ncu-config set token "${{ secrets.GH_USER_TOKEN }}" - ncu-config set jenkins_token "${{ secrets.JENKINS_TOKEN }}" - ncu-config set repo "${REPOSITORY}" - ncu-config set owner "${OWNER}" - - - name: Start the Commit Queue - run: ./tools/actions/commit-queue.sh ${{ env.OWNER }} ${{ env.REPOSITORY }} ${{ needs.get_mergeable_prs.outputs.numbers }} - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml deleted file mode 100644 index c29ca32c1a7..00000000000 --- a/.github/workflows/coverage-linux-without-intl.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Coverage Linux (without intl) - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-linux-without-intl.yml - push: - branches: - - main - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-linux-without-intl.yml - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - coverage-linux-without-intl: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Install gcovr - run: pip install gcovr==4.2 - - name: Build - run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn --coverage --without-intl" - # TODO(bcoe): fix the couple tests that fail with the inspector enabled. - # The cause is most likely coverage's use of the inspector. - - name: Test - run: NODE_V8_COVERAGE=coverage/tmp make test-cov -j2 V=1 TEST_CI_ARGS="-p dots --node-args='--test-reporter=spec' --measure-flakiness 9" || exit 0 - - name: Report JS - run: npx c8 report --check-coverage - env: - NODE_OPTIONS: --max-old-space-size=8192 - - name: Report C++ - run: cd out && gcovr --gcov-exclude='.*\b(deps|usr|out|obj|cctest|embedding)\b' -v -r Release/obj.target --xml -o ../coverage/coverage-cxx.xml --root=$(cd ../ && pwd) - # Clean temporary output from gcov and c8, so that it's not uploaded: - - name: Clean tmp - run: rm -rf coverage/tmp && rm -rf out - - name: Upload - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 - with: - directory: ./coverage diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml deleted file mode 100644 index 557ede95d4d..00000000000 --- a/.github/workflows/coverage-linux.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Coverage Linux - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-linux.yml - push: - branches: - - main - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-linux.yml - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - coverage-linux: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Install gcovr - run: pip install gcovr==4.2 - - name: Build - run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn --coverage" - # TODO(bcoe): fix the couple tests that fail with the inspector enabled. - # The cause is most likely coverage's use of the inspector. - - name: Test - run: NODE_V8_COVERAGE=coverage/tmp make test-cov -j2 V=1 TEST_CI_ARGS="-p dots --node-args='--test-reporter=spec' --measure-flakiness 9" || exit 0 - - name: Report JS - run: npx c8 report --check-coverage - env: - NODE_OPTIONS: --max-old-space-size=8192 - - name: Report C++ - run: cd out && gcovr --gcov-exclude='.*\b(deps|usr|out|obj|cctest|embedding)\b' -v -r Release/obj.target --xml -o ../coverage/coverage-cxx.xml --root=$(cd ../ && pwd) - # Clean temporary output from gcov and c8, so that it's not uploaded: - - name: Clean tmp - run: rm -rf coverage/tmp && rm -rf out - - name: Upload - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 - with: - directory: ./coverage diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml deleted file mode 100644 index 994b30c29e7..00000000000 --- a/.github/workflows/coverage-windows.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Coverage Windows - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-windows.yml - push: - branches: - - main - paths: - - lib/**/*.js - - Makefile - - src/**/*.cc - - src/**/*.h - - test/** - - tools/gyp/** - - tools/test.py - - .github/workflows/coverage-windows.yml - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - coverage-windows: - if: github.event.pull_request.draft == false - runs-on: windows-2022 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Install deps - run: choco install nasm - - name: Environment Information - run: npx envinfo - - name: Build - run: ./vcbuild.bat - # TODO(bcoe): investigate tests that fail with coverage enabled - # on Windows. - - name: Test - run: ./vcbuild.bat test-ci-js; node -e 'process.exit(0)' - env: - NODE_V8_COVERAGE: ./coverage/tmp - - name: Report - run: npx c8 report - env: - NODE_OPTIONS: --max-old-space-size=8192 - - name: Clean tmp - run: npx rimraf ./coverage/tmp - - name: Upload - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 - with: - directory: ./coverage diff --git a/.github/workflows/daily-wpt-fyi.yml b/.github/workflows/daily-wpt-fyi.yml deleted file mode 100644 index 0b007702583..00000000000 --- a/.github/workflows/daily-wpt-fyi.yml +++ /dev/null @@ -1,156 +0,0 @@ -# This workflow runs every night and tests various releases of Node.js -# (latest nightly, current, and two latest LTS release lines) against the -# `epochs/daily` branch of WPT. - -name: Daily WPT report - -on: - workflow_dispatch: - inputs: - node-versions: - description: Node.js versions (as supported by actions/setup-node) to test as JSON array - required: false - default: '["current", "lts/*", "lts/-1"]' - schedule: - # This is 20 minutes after `epochs/daily` branch is triggered to be created - # in WPT repo. - # https://github.com/web-platform-tests/wpt/blob/master/.github/workflows/epochs.yml - - cron: 30 0 * * * - -env: - PYTHON_VERSION: '3.11' - -permissions: - contents: read - -jobs: - report: - if: github.repository == 'nodejs/node' || github.event_name == 'workflow_dispatch' - strategy: - matrix: - node-version: ${{ fromJSON(github.event.inputs.node-versions || '["latest-nightly", "current", "lts/*", "lts/-1"]') }} - fail-fast: false - runs-on: ubuntu-latest - steps: - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - # install a version and checkout - - name: Get latest nightly - if: matrix.node-version == 'latest-nightly' - run: echo "NIGHTLY=$(curl -s https://nodejs.org/download/nightly/index.json | jq -r '[.[] | select(.files[] | contains("linux-x64"))][0].version')" >> $GITHUB_ENV - - name: Install Node.js - id: setup-node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NIGHTLY || matrix.node-version }} - check-latest: true - - name: Get nightly ref - if: contains(matrix.node-version, 'nightly') - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - SHORT_SHA=$(node -p 'process.version.split(/-nightly\d{8}/)[1]') - echo "NIGHTLY_REF=$(gh api /repos/nodejs/node/commits/$SHORT_SHA --jq '.sha')" >> $GITHUB_ENV - - name: Checkout ${{ steps.setup-node.outputs.node-version }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - ref: ${{ env.NIGHTLY_REF || steps.setup-node.outputs.node-version }} - - name: Set env.NODE - run: echo "NODE=$(which node)" >> $GITHUB_ENV - - name: Set env.WPT_REVISION - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: echo "WPT_REVISION=$(gh api /repos/web-platform-tests/wpt/branches/epochs/daily --jq '.commit.sha')" >> $GITHUB_ENV - - # replace checked out WPT with the synchronized branch - - name: Remove stale WPT - run: rm -rf wpt - working-directory: test/fixtures - - name: Checkout epochs/daily WPT - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - repository: web-platform-tests/wpt - persist-credentials: false - path: test/fixtures/wpt - clean: false - ref: ${{ env.WPT_REVISION }} - - # Node.js WPT Runner - - name: Run WPT and generate report - run: | - make test-wpt-report || true - if [ -e out/wpt/wptreport.json ]; then - echo "WPT_REPORT=$(pwd)/out/wpt/wptreport.json" >> $GITHUB_ENV - fi - - # undici WPT Runner - - name: Set env.UNDICI_VERSION - if: ${{ env.WPT_REPORT != '' }} - run: echo "UNDICI_VERSION=v$(jq -r '.version' < deps/undici/src/package.json)" >> $GITHUB_ENV - - name: Remove deps/undici - if: ${{ env.WPT_REPORT != '' }} - run: rm -rf deps/undici - - name: Checkout undici - if: ${{ env.WPT_REPORT != '' }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - repository: nodejs/undici - persist-credentials: false - path: deps/undici - clean: false - ref: ${{ env.UNDICI_VERSION }} - - name: Add undici WPTs to the report - if: ${{ env.WPT_REPORT != '' }} - run: | - rm -rf test/wpt/tests - mv ../../test/fixtures/wpt/ test/wpt/tests/ - npm install - npm run test:wpt || true - working-directory: deps/undici - - # Upload artifacts - - name: Clone report for upload - if: ${{ env.WPT_REPORT != '' }} - working-directory: out/wpt - run: cp wptreport.json wptreport-${{ steps.setup-node.outputs.node-version }}.json - - name: Upload GitHub Actions artifact - if: ${{ env.WPT_REPORT != '' }} - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - path: out/wpt/wptreport-*.json - name: WPT Reports - if-no-files-found: error - - name: Upload WPT Report to wpt.fyi API - if: ${{ env.WPT_REPORT != '' }} - env: - WPT_FYI_USERNAME: ${{ vars.WPT_FYI_USERNAME }} - WPT_FYI_PASSWORD: ${{ secrets.WPT_FYI_PASSWORD }} - working-directory: out/wpt - run: | - gzip wptreport.json - echo "## Node.js ${{ steps.setup-node.outputs.node-version }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "WPT Revision: [\`${WPT_REVISION:0:7}\`](https://github.com/web-platform-tests/wpt/commits/$WPT_REVISION)" >> $GITHUB_STEP_SUMMARY - for WPT_FYI_ENDPOINT in "https://wpt.fyi/api/results/upload" "https://staging.wpt.fyi/api/results/upload" - do - response=$(curl -sS \ - -u "$WPT_FYI_USERNAME:$WPT_FYI_PASSWORD" \ - -F "result_file=@wptreport.json.gz" \ - -F "labels=master" \ - $WPT_FYI_ENDPOINT) - - if [[ $response =~ Task\ ([0-9]+)\ added\ to\ queue ]]; then - run_id=${BASH_REMATCH[1]} - origin=${WPT_FYI_ENDPOINT%/api/results/upload} - - echo "" >> $GITHUB_STEP_SUMMARY - echo "Run ID [\`$run_id\`]($origin/api/runs/$run_id) added to the processor queue at ${origin:8}" >> $GITHUB_STEP_SUMMARY - echo "- [View on the ${origin:8} dashboard]($origin/results?run_id=$run_id)" >> $GITHUB_STEP_SUMMARY - fi - done diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml deleted file mode 100644 index aff2f1ccb67..00000000000 --- a/.github/workflows/daily.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Node.js daily job - -on: - workflow_dispatch: - schedule: - - cron: 0 0 * * * - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - build-lto: - runs-on: ubuntu-latest - # not working on gcc-8 and gcc-9 see https://github.com/nodejs/node/issues/38570 - container: gcc:11 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Build lto - run: | - apt-get update && apt-get install ninja-build python-is-python3 -y - ./configure --enable-lto --ninja - ninja -C out/Release diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml deleted file mode 100644 index ffb21dc8540..00000000000 --- a/.github/workflows/doc.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Test and upload documentation to artifacts - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - push: - branches: - - main - - v[0-9]+.x-staging - - v[0-9]+.x - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - build-docs: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Build - run: NODE=$(command -v node) make doc-only - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: docs - path: out/doc - - name: Test - run: NODE=$(command -v node) make test-doc-ci TEST_CI_ARGS="-p actions --node-args='--test-reporter=spec' --node-args='--test-reporter-destination=stdout' --measure-flakiness 9" diff --git a/.github/workflows/find-inactive-collaborators.yml b/.github/workflows/find-inactive-collaborators.yml deleted file mode 100644 index 8376927156c..00000000000 --- a/.github/workflows/find-inactive-collaborators.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Find inactive collaborators - -on: - schedule: - # Run every Monday at 4:05 AM UTC. - - cron: 5 4 * * 1 - - workflow_dispatch: - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - find: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Find inactive collaborators - run: tools/find-inactive-collaborators.mjs - - - name: Open pull request - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - # Creates a PR or update the Action's existing PR, or - # no-op if the base branch is already up-to-date. - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - branch: actions/inactive-collaborators - body: | - This PR was generated by tools/find-inactive-collaborators.yml. - - @nodejs/tsc Please follow up with the [offboarding tasks](https://github.com/nodejs/node/blob/main/doc/contributing/offboarding.md). - commit-message: 'meta: move one or more collaborators to emeritus' - labels: meta - title: 'meta: move one or more collaborators to emeritus' diff --git a/.github/workflows/find-inactive-tsc.yml b/.github/workflows/find-inactive-tsc.yml deleted file mode 100644 index 2fe7c15fea9..00000000000 --- a/.github/workflows/find-inactive-tsc.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Find inactive TSC voting members - -on: - schedule: - # Run every Tuesday 12:05 AM UTC. - - cron: 5 0 * * 2 - - workflow_dispatch: - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - find: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Clone nodejs/TSC repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - path: .tmp - persist-credentials: false - repository: nodejs/TSC - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Find inactive TSC voting members - run: tools/find-inactive-tsc.mjs >> $GITHUB_ENV - - - name: Open pull request - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - # Creates a PR or update the Action's existing PR, or - # no-op if the base branch is already up-to-date. - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - branch: actions/inactive-tsc - body: | - This PR was generated by tools/find-inactive-tsc.yml. - - @nodejs/tsc ${{ env.INACTIVE_TSC_HANDLES }} - - ${{ env.DETAILS_FOR_COMMIT_BODY }} - commit-message: 'meta: move TSC voting member(s) to regular member(s)' - labels: meta - title: 'meta: move TSC voting member(s) to regular member(s)' - update-pull-request-title-and-body: true diff --git a/.github/workflows/label-flaky-test-issue.yml b/.github/workflows/label-flaky-test-issue.yml deleted file mode 100644 index 82e2a10ab2b..00000000000 --- a/.github/workflows/label-flaky-test-issue.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Label Flaky Test Issues - -on: - issues: - types: [opened, labeled] - -permissions: - contents: read - -jobs: - label: - if: github.event.label.name == 'flaky-test' - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Extract labels - id: extract-labels - env: - BODY: ${{ github.event.issue.body }} - run: | - BODY="${BODY//$'\n'/'\n'}" - - declare -A platform2label - - platform2label["AIX"]="aix"; - platform2label["FreeBSD"]="freebsd"; - platform2label["Linux ARM64"]="linux"; - platform2label["Linux ARMv7"]="arm"; - platform2label["Linux PPC64LE"]="ppc"; - platform2label["Linux s390x"]="s390"; - platform2label["Linux x64"]="linux"; - platform2label["macOS ARM64"]="macos"; - platform2label["macOS x64"]="macos"; - platform2label["SmartOS"]="smartos"; - platform2label["Windows"]="windows"; - - # sed is cleaning up the edges - PLATFORMS=$(echo $BODY | sed 's/^.*Platform\\n\\n//' | sed 's/\(, Other\)\?\\n\\n.*$//') 2> /dev/null - readarray -d , -t list <<< "$PLATFORMS" - labels= - for row in "${list[@]}"; do \ - platform=$(echo $row | xargs); \ - labels="${labels}${platform2label[$platform]},"; \ - done; - - echo "LABELS=${labels::-1}" >> $GITHUB_OUTPUT - - - name: Add labels - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NUMBER: ${{ github.event.issue.number }} - run: gh issue edit "$NUMBER" --repo ${{ github.repository }} --add-label "${{ steps.extract-labels.outputs.LABELS }}" diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml deleted file mode 100644 index 95fdd42a4c7..00000000000 --- a/.github/workflows/label-pr.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Label PRs - -on: - pull_request_target: - types: [opened] - -permissions: - contents: read - -jobs: - label: - runs-on: ubuntu-latest - - steps: - - uses: nodejs/node-pr-labeler@d4cf1b8b9f23189c37917000e5e17e796c770a6b # v1 - with: - repo-token: ${{ secrets.GH_USER_TOKEN }} - configuration-path: .github/label-pr-config.yml diff --git a/.github/workflows/license-builder.yml b/.github/workflows/license-builder.yml deleted file mode 100644 index c1cbfafc1ac..00000000000 --- a/.github/workflows/license-builder.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: License update -on: - schedule: - # 00:00:00 every Monday - # https://crontab.guru/#0_0_*_*_1 - - cron: 0 0 * * 1 - workflow_dispatch: - -permissions: - contents: read - -jobs: - update_license: - permissions: - contents: write # for gr2m/create-or-update-pull-request-action to push local changes - pull-requests: write # for gr2m/create-or-update-pull-request-action to create a PR - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - run: ./tools/license-builder.sh # Run the license builder tool - - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - # Creates a PR or update the Action's existing PR, or - # no-op if the base branch is already up-to-date. - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - author: Node.js GitHub Bot - branch: actions/license-builder - title: 'doc: run license-builder' - body: > - License is likely out of date. This is an automatically generated PR by - the `license-builder.yml` GitHub Action, which runs `license-builder.sh` - and submits a new PR or updates an existing PR. - commit-message: 'doc: run license-builder' - labels: meta diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml deleted file mode 100644 index a7446bff522..00000000000 --- a/.github/workflows/linters.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Linters - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - push: - branches: - - main - - v[0-9]+.x-staging - - v[0-9]+.x - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - lint-addon-docs: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Lint addon docs - run: NODE=$(command -v node) make lint-addon-docs - lint-cpp: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Lint C/C++ files - run: make lint-cpp - format-cpp: - if: ${{ github.event.pull_request && github.event.pull_request.draft == false && github.base_ref == github.event.repository.default_branch }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Format C/C++ files - run: | - make format-cpp-build - # The `make format-cpp` error code is intentionally ignored here - # because it is irrelevant. We already check if the formatter produced - # a diff in the next line. - # Refs: https://github.com/nodejs/node/pull/42764 - CLANG_FORMAT_START="$(git merge-base HEAD refs/remotes/origin/$GITHUB_BASE_REF)" \ - make format-cpp || true - git --no-pager diff --exit-code && EXIT_CODE="$?" || EXIT_CODE="$?" - if [ "$EXIT_CODE" != "0" ] - then - echo - echo 'ERROR: Please run:' - echo - echo " CLANG_FORMAT_START="$\(git merge-base HEAD ${GITHUB_BASE_REF}\)" make format-cpp" - echo - echo 'to format the commits in your branch.' - exit "$EXIT_CODE" - fi - lint-js-and-md: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Lint JavaScript files - run: NODE=$(command -v node) make lint-js - - name: Get release version numbers - if: ${{ github.event.pull_request && github.event.pull_request.base.ref == github.event.pull_request.base.repo.default_branch }} - id: get-released-versions - run: ./tools/lint-md/list-released-versions-from-changelogs.mjs >> $GITHUB_OUTPUT - - name: Lint markdown files - run: | - echo "::add-matcher::.github/workflows/remark-lint-problem-matcher.json" - NODE=$(command -v node) make lint-md - env: - NODE_RELEASED_VERSIONS: ${{ steps.get-released-versions.outputs.NODE_RELEASED_VERSIONS }} - lint-py: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Lint Python - run: | - make lint-py-build - make lint-py - lint-yaml: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Use Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Lint YAML - run: | - make lint-yaml-build || true - make lint-yaml - - lint-sh: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - run: shellcheck -V - - name: Lint Shell scripts - run: tools/lint-sh.mjs . - lint-codeowners: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - uses: mszostok/codeowners-validator@7f3f5e28c6d7b8dfae5731e54ce2272ca384592f - with: - checks: files,duppatterns - lint-pr-url: - if: ${{ github.event.pull_request }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 2 - persist-credentials: false - # GH Actions squashes all PR commits, HEAD^ refers to the base branch. - - run: git diff HEAD^ HEAD -G"pr-url:" -- "*.md" | ./tools/lint-pr-url.mjs ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/notify-on-push.yml b/.github/workflows/notify-on-push.yml deleted file mode 100644 index 364e6610d43..00000000000 --- a/.github/workflows/notify-on-push.yml +++ /dev/null @@ -1,70 +0,0 @@ -on: - push: - branches: - - main - -name: Notify on Push -permissions: - contents: read - -jobs: - notifyOnForcePush: - name: Notify on Force Push on `main` - if: github.repository == 'nodejs/node' && github.event.forced - runs-on: ubuntu-latest - steps: - - name: Slack Notification - uses: rtCamp/action-slack-notify@b24d75fe0e728a4bf9fc42ee217caa686d141ee8 # 2.2.1 - env: - SLACK_COLOR: '#DE512A' - SLACK_ICON: https://github.com/nodejs.png?size=48 - SLACK_TITLE: ${{ github.actor }} force-pushed to ${{ github.ref }} - SLACK_MESSAGE: | - A commit was force-pushed to by - - Before: - After: - SLACK_USERNAME: nodejs-bot - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - - notifyOnMissingMetadata: - name: Notify on Push on `main` that lacks metadata - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Check commit message - run: npx -q core-validate-commit ${{ github.event.after }} || echo "INVALID_COMMIT_MESSAGE=1" >> $GITHUB_ENV - - name: Retrieve PR number if possible - if: env.INVALID_COMMIT_MESSAGE - run: | - COMMIT_TITLE=$(git --no-pager log --oneline -1 --no-color) node <<'EOF' >> $GITHUB_ENV || true - const invalidCommitMessageMatch = /\s\(\#(\d+)\)$/.exec(process.env.COMMIT_TITLE); - if (invalidCommitMessageMatch == null) process.exit(1) - console.log(`PR_ID=${invalidCommitMessageMatch[1]}`) - EOF - - name: Comment on the Pull Request - if: ${{ env.PR_ID }} - run: | - gh pr comment ${{ env.PR_ID }} --repo "${{ github.repository }}" \ - --body "A commit referencing this Pull Request was pushed to `${{ github.ref_name }}` by @${{ github.actor }} with an invalid commit message." - env: - GH_TOKEN: ${{ github.token }} - - name: Slack Notification - if: ${{ env.INVALID_COMMIT_MESSAGE }} - uses: rtCamp/action-slack-notify@b24d75fe0e728a4bf9fc42ee217caa686d141ee8 # 2.2.1 - env: - SLACK_COLOR: '#DE512A' - SLACK_ICON: https://github.com/nodejs.png?size=48 - SLACK_TITLE: Invalid commit was pushed to ${{ github.repository.default_branch }} - SLACK_MESSAGE: | - A commit with an invalid message was pushed to by . - - Before: - After: - SLACK_USERNAME: nodejs-bot - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/remark-lint-problem-matcher.json b/.github/workflows/remark-lint-problem-matcher.json deleted file mode 100644 index cfb281310a9..00000000000 --- a/.github/workflows/remark-lint-problem-matcher.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "remark-lint", - "pattern": [ - { - "regexp": "^(?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)*$", - "file": 1 - }, - { - "regexp": "^\\s+(?:\\d+:\\d+-)?(\\d+):(\\d+)\\s+\\S*(error|warning|info)\\S*\\s+(.+)\\s+(\\S+)\\s+(?:\\S+)$", - "line": 1, - "column": 2, - "severity": 3, - "message": 4, - "code": 5, - "loop": true - } - ] - } - ] -} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml deleted file mode 100644 index 9cd389da746..00000000000 --- a/.github/workflows/scorecard.yml +++ /dev/null @@ -1,78 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. They are provided -# by a third-party and are governed by separate terms of service, privacy -# policy, and support documentation. - -name: Scorecard supply-chain security -on: - # For Branch-Protection check. Only the default branch is supported. See - # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection - branch_protection_rule: - # To guarantee Maintained check is occasionally updated. See - # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained - schedule: - - cron: 16 21 * * 1 - push: - branches: [main] - workflow_dispatch: - -# Declare default permissions as read only. -permissions: read-all - -jobs: - analysis: - name: Scorecard analysis - runs-on: ubuntu-latest - permissions: - # Needed to upload the results to code-scanning dashboard. - security-events: write - # Needed to publish results and get a badge (see publish_results below). - id-token: write - # Uncomment the permissions below if installing in a private repository. - # contents: read - # actions: read - - steps: - - name: Harden Runner - uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - - name: Run analysis - uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0 - with: - results_file: results.sarif - results_format: sarif - # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: - # - you want to enable the Branch-Protection check on a *public* repository, or - # - you are installing Scorecard on a *private* repository - # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. - # repo_token: ${{ secrets.SCORECARD_TOKEN }} - - # Public repositories: - # - Publish results to OpenSSF REST API for easy access by consumers - # - Allows the repository to include the Scorecard badge. - # - See https://github.com/ossf/scorecard-action#publishing-results. - # For private repositories: - # - `publish_results` will always be set to `false`, regardless - # of the value entered here. - publish_results: true - - # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF - # format to the repository Actions tab. - - name: Upload artifact - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: SARIF file - path: results.sarif - retention-days: 5 - - # Upload the results to GitHub's code scanning dashboard. - - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 - with: - sarif_file: results.sarif diff --git a/.github/workflows/test-asan.yml b/.github/workflows/test-asan.yml deleted file mode 100644 index 55448d5ed4f..00000000000 --- a/.github/workflows/test-asan.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Test ASan - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/test-asan.yml' - push: - branches: - - main - - canary - - v[0-9]+.x-staging - - v[0-9]+.x - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/test-asan.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - ASAN_OPTIONS: intercept_tls_get_addr=0 - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - test-asan: - if: github.event.pull_request.draft == false - runs-on: ubuntu-20.04 - env: - CC: clang - CXX: clang++ - LINK: clang++ - CONFIG_FLAGS: --enable-asan - ASAN: true - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Build - run: make build-ci -j2 V=1 - - name: Test - run: make run-ci -j2 V=1 TEST_CI_ARGS="-p actions --node-args='--test-reporter=spec' --node-args='--test-reporter-destination=stdout' -t 300 --measure-flakiness 9" diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml deleted file mode 100644 index dc35ba41750..00000000000 --- a/.github/workflows/test-internet.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Test internet - -on: - workflow_dispatch: - schedule: - - cron: 5 0 * * * - - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - test/internet/** - - internal/dns/** - - lib/dns.js - - lib/net.js - push: - branches: - - main - - canary - - v[0-9]+.x-staging - - v[0-9]+.x - paths: - - test/internet/** - - internal/dns/** - - lib/dns.js - - lib/net.js - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - test-internet: - if: github.repository == 'nodejs/node' || github.event_name != 'schedule' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Build - run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn" - - name: Test Internet - run: make test-internet -j2 V=1; diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml deleted file mode 100644 index ca4f9ed9257..00000000000 --- a/.github/workflows/test-linux.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Test Linux - -on: - pull_request: - paths-ignore: - - README.md - - .github/** - - '!.github/workflows/test-linux.yml' - types: [opened, synchronize, reopened, ready_for_review] - push: - branches: - - main - - canary - - v[0-9]+.x-staging - - v[0-9]+.x - paths-ignore: - - README.md - - .github/** - - '!.github/workflows/test-linux.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - test-linux: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - - name: Build - run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn" - - name: Test - run: make run-ci -j2 V=1 TEST_CI_ARGS="-p actions --node-args='--test-reporter=spec' --node-args='--test-reporter-destination=stdout' --measure-flakiness 9" diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml deleted file mode 100644 index 35d47f16beb..00000000000 --- a/.github/workflows/test-macos.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Test macOS - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/test-macos.yml' - push: - branches: - - main - - canary - - v[0-9]+.x-staging - - v[0-9]+.x - paths-ignore: - - .mailmap - - '**.md' - - AUTHORS - - doc/** - - .github/** - - '!.github/workflows/test-macos.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - PYTHON_VERSION: '3.11' - FLAKY_TESTS: keep_retrying - -permissions: - contents: read - -jobs: - test-macOS: - if: github.event.pull_request.draft == false - runs-on: macos-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Environment Information - run: npx envinfo - # The `npm ci` for this step fails a lot as part of the Test step. Run it - # now so that we don't have to wait 2 hours for the Build step to pass - # first before that failure happens. (And if there's something about - # `make run-ci -j3` that is causing the failure and the failure doesn't - # happen anymore running this step here first, that's also useful - # information.) - - name: tools/doc/node_modules workaround - run: make tools/doc/node_modules - - name: Build - run: make build-ci -j$(getconf _NPROCESSORS_ONLN) V=1 CONFIG_FLAGS="--error-on-warn" - - name: Test - run: make run-ci -j$(getconf _NPROCESSORS_ONLN) V=1 TEST_CI_ARGS="-p actions --node-args='--test-reporter=spec' --node-args='--test-reporter-destination=stdout' --measure-flakiness 9" diff --git a/.github/workflows/timezone-update.yml b/.github/workflows/timezone-update.yml deleted file mode 100644 index 12b93abceed..00000000000 --- a/.github/workflows/timezone-update.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Timezone update -on: - schedule: - # Run once a week at 00:05 AM UTC on Sunday. - - cron: 5 0 * * 0 - - workflow_dispatch: - -permissions: - contents: read - -jobs: - timezone_update: - permissions: - contents: write # to push local changes (gr2m/create-or-update-pull-request-action) - pull-requests: write # to create a PR (gr2m/create-or-update-pull-request-action) - - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - - steps: - - name: Checkout nodejs/node - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - - name: Checkout unicode-org/icu-data - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - path: icu-data - persist-credentials: false - repository: unicode-org/icu-data - - - name: Record new version - run: echo "new_version=$(ls icu-data/tzdata/icunew | tail -1)" >> $GITHUB_ENV - - - run: ./tools/update-timezone.mjs - - - name: Update the expected timezone version in test - run: echo "${{ env.new_version }}" > test/fixtures/tz-version.txt - - - name: Open Pull Request - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 # Create a PR or update the Action's existing PR - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - body: | - This PR was generated by tools/timezone-update.yml. - - Updates the ICU files as per the instructions present in https://github.com/nodejs/node/blob/main/doc/contributing/maintaining/maintaining-icu.md#time-zone-data - - To test, build node off this branch & log the version of tz using - ```js - console.log(process.versions.tz) - ``` - branch: actions/timezone-update - commit-message: 'deps: update timezone to ${{ env.new_version }}' - labels: dependencies - title: 'deps: update timezone to ${{ env.new_version }}' - reviewers: \@nodejs/i18n-api - update-pull-request-title-and-body: true diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml deleted file mode 100644 index d252e445d48..00000000000 --- a/.github/workflows/tools.yml +++ /dev/null @@ -1,318 +0,0 @@ -name: Tools and deps update -on: - schedule: - # Run once a week at 00:05 AM UTC on Sunday. - - cron: 5 0 * * 0 - - workflow_dispatch: - inputs: - id: - description: The ID of the job to run - required: true - default: all - type: choice - options: - - all - - acorn - - acorn-walk - - ada - - base64 - - brotli - - c-ares - - cjs-module-lexer - - corepack - - doc - - eslint - - github_reporter - - googletest - - histogram - - icu - - libuv - - lint-md-dependencies - - llhttp - - minimatch - - nghttp2 - - nghttp3 - - ngtcp2 - - postject - - root-certificates - - simdutf - - undici - - uvwasi - - zlib - -env: - PYTHON_VERSION: '3.11' - -permissions: - contents: read - -jobs: - tools-deps-update: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - strategy: - fail-fast: false # Prevent other jobs from aborting if one fails - matrix: - include: - - id: acorn - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-acorn.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: acorn-walk - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-acorn-walk.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: ada - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-ada.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: base64 - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-base64.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: brotli - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-brotli.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: c-ares - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-c-ares.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: cjs-module-lexer - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-cjs-module-lexer.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: corepack - subsystem: deps - label: dependencies - run: | - make corepack-update - echo "NEW_VERSION=$(node deps/corepack/dist/corepack.js --version)" >> $GITHUB_ENV - - id: doc - subsystem: tools - label: tools - run: | - cd tools/doc - npm ci - NEW_VERSION=$(npm outdated --parseable | cut -d: -f4 | xargs) - if [ "$NEW_VERSION" != "" ]; then - echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV - rm -rf package-lock.json node_modules - # Include $NEW_VERSION to explicitly update the package.json - # entry for the dependency and also so that semver-major updates - # are not skipped. - npm install --ignore-scripts $NEW_VERSION - npm install --ignore-scripts - fi - - id: eslint - subsystem: tools - label: tools - run: | - ./tools/dep_updaters/update-eslint.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: github_reporter - subsystem: tools - label: tools - run: | - ./tools/dep_updaters/update-github-reporter.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: googletest - subsystem: deps - label: dependencies, test - run: | - ./tools/dep_updaters/update-googletest.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: histogram - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-histogram.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: icu - subsystem: deps - label: dependencies, test - run: | - ./tools/dep_updaters/update-icu.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: libuv - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-libuv.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: lint-md-dependencies - subsystem: tools - label: tools - run: | - cd tools/lint-md - npm ci - NEW_VERSION=$(npm outdated --parseable | cut -d: -f4 | xargs) - if [ "$NEW_VERSION" != "" ]; then - echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV - rm -rf package-lock.json node_modules - # Include $NEW_VERSION to explicitly update the package.json - # entry for the dependency and also so that semver-major updates - # are not skipped. - npm install --ignore-scripts $NEW_VERSION - npm install --ignore-scripts - cd ../.. - make lint-md-rollup - fi - - id: llhttp - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-llhttp.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: minimatch - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-minimatch.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: nghttp2 - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-nghttp2.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: nghttp3 - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-nghttp3.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: ngtcp2 - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-ngtcp2.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: postject - subsystem: deps,test - label: test - run: | - ./tools/dep_updaters/update-postject.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: root-certificates - subsystem: crypto - label: crypto, notable-change - run: | - node ./tools/dep_updaters/update-root-certs.mjs -v -f "$GITHUB_ENV" - - id: simdutf - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-simdutf.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: undici - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-undici.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: uvwasi - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-uvwasi.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - id: zlib - subsystem: deps - label: dependencies - run: | - ./tools/dep_updaters/update-zlib.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - if: github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id - with: - persist-credentials: false - - name: Set up Python ${{ env.PYTHON_VERSION }} - if: matrix.id == 'icu' && (github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id) - uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - run: ${{ matrix.run }} - if: github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - - name: Generate commit message if not set - if: env.COMMIT_MSG == '' && (github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id) - run: | - echo "COMMIT_MSG=${{ matrix.subsystem }}: update ${{ matrix.id }} to ${{ env.NEW_VERSION }}" >> "$GITHUB_ENV" - - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - if: github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id - # Creates a PR or update the Action's existing PR, or - # no-op if the base branch is already up-to-date. - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - body: This is an automated update of ${{ matrix.id }} to ${{ env.NEW_VERSION }}. - branch: actions/tools-update-${{ matrix.id }} # Custom branch *just* for this Action. - commit-message: ${{ env.COMMIT_MSG }} - labels: ${{ matrix.label }} - title: '${{ matrix.subsystem }}: update ${{ matrix.id }} to ${{ env.NEW_VERSION }}' - update-pull-request-title-and-body: true diff --git a/.github/workflows/update-openssl.yml b/.github/workflows/update-openssl.yml deleted file mode 100644 index 95802feaee3..00000000000 --- a/.github/workflows/update-openssl.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: OpenSSL update -on: - schedule: - # Run once a week at 00:05 AM UTC on Sunday. - - cron: 5 0 * * 0 - - workflow_dispatch: - -permissions: - contents: read - -jobs: - openssl-v3-update: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Check and download new OpenSSL version - run: | - ./tools/dep_updaters/update-openssl.sh download_v3 > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - - name: Create PR with first commit - if: env.NEW_VERSION - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - # Creates a PR with the new OpenSSL source code committed - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - body: This is an automated update of OpenSSL to ${{ env.NEW_VERSION }}. - branch: actions/tools-update-openssl # Custom branch *just* for this Action. - commit-message: 'deps: upgrade openssl sources to quictls/openssl-${{ env.NEW_VERSION }}' - labels: dependencies - title: 'deps: update OpenSSL to ${{ env.NEW_VERSION }}' - path: deps/openssl - update-pull-request-title-and-body: true - - name: Regenerate platform specific files - if: env.NEW_VERSION - run: | - sudo apt install -y nasm libtext-template-perl - ./tools/dep_updaters/update-openssl.sh regenerate - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - - name: Add second commit - # Adds a second commit to the PR with the generated platform-dependent files - if: env.NEW_VERSION - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - branch: actions/tools-update-openssl # Custom branch *just* for this Action. - commit-message: 'deps: update archs files for openssl-${{ env.NEW_VERSION }}' - path: deps/openssl - openssl-v1-update: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - ref: v16.x-staging - - name: Check and download new OpenSSL version - run: | - ./tools/dep_updaters/update-openssl.sh download_v1 > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - - name: Create PR with first commit - if: env.NEW_VERSION - uses: gr2m/create-or-update-pull-request-action@df20b2c073090271599a08c55ae26e0c3522b329 # v1.9.2 - # Creates a PR with the new OpenSSL source code committed - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - body: This is an automated update of OpenSSL to ${{ env.NEW_VERSION }}. - branch: actions/tools-update-openssl-v1 # Custom branch *just* for this Action. - commit-message: 'deps: upgrade openssl sources to quictls/openssl-${{ env.NEW_VERSION }}' - labels: dependencies - title: '[v16.x] deps: update OpenSSL to ${{ env.NEW_VERSION }}' - path: deps/openssl - update-pull-request-title-and-body: true - - name: Regenerate platform specific files - if: env.NEW_VERSION - run: | - sudo apt install -y nasm libtext-template-perl - ./tools/dep_updaters/update-openssl.sh regenerate - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - - name: Add second commit - # Adds a second commit to the PR with the generated platform-dependent files - if: env.NEW_VERSION - uses: gr2m/create-or-update-pull-request-action@df20b2c073090271599a08c55ae26e0c3522b329 # v1.9.2 - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - branch: actions/tools-update-openssl-v1 # Custom branch *just* for this Action. - commit-message: 'deps: update archs files for openssl-${{ env.NEW_VERSION }}' - path: deps/openssl diff --git a/.github/workflows/update-v8.yml b/.github/workflows/update-v8.yml deleted file mode 100644 index a22ff2f0138..00000000000 --- a/.github/workflows/update-v8.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: V8 patch update -on: - schedule: - # Run once a week at 00:05 AM UTC on Sunday. - - cron: 5 0 * * 0 - workflow_dispatch: - -env: - NODE_VERSION: lts/* - -permissions: - contents: read - -jobs: - v8-update: - if: github.repository == 'nodejs/node' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - name: Cache node modules and update-v8 - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 - id: cache-v8-npm - env: - cache-name: cache-v8-npm - with: - path: | - ~/.update-v8 - ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }} - - name: Install Node.js - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Install @node-core/utils - run: npm install -g @node-core/utils - - name: Check and download new V8 version - run: | - ./tools/dep_updaters/update-v8-patch.sh > temp-output - cat temp-output - tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true - rm temp-output - - uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 - # Creates a PR or update the Action's existing PR, or - # no-op if the base branch is already up-to-date. - env: - GITHUB_TOKEN: ${{ secrets.GH_USER_TOKEN }} - with: - author: Node.js GitHub Bot - body: This is an automated patch update of V8 to ${{ env.NEW_VERSION }}. - branch: actions/update-v8-patch # Custom branch *just* for this Action. - labels: v8 engine - title: 'deps: patch V8 to ${{ env.NEW_VERSION }}' - update-pull-request-title-and-body: true diff --git a/.github/workflows/update-wpt.yml b/.github/workflows/update-wpt.yml index 933edc0b722..884c25c1e81 100644 --- a/.github/workflows/update-wpt.yml +++ b/.github/workflows/update-wpt.yml @@ -48,8 +48,11 @@ jobs: - name: Rolling update wpt fixtures run: ./tools/dep_updaters/update-wpt.sh - - name: Build - run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn" + # - name: Build + # run: make build-ci -j2 V=1 CONFIG_FLAGS="--error-on-warn" + - name: Set env.NODE + run: echo "NODE=$(which node)" >> $GITHUB_ENV + - name: Update wpt status.json run: make test-wpt-status-update From 480cc1710c6fbb96dd9e6816ec76deecec9313e5 Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 6 Nov 2023 00:09:10 +0800 Subject: [PATCH 3/5] fixup! --- .github/workflows/update-wpt.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/update-wpt.yml b/.github/workflows/update-wpt.yml index 884c25c1e81..d15b651538b 100644 --- a/.github/workflows/update-wpt.yml +++ b/.github/workflows/update-wpt.yml @@ -37,6 +37,18 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Install @node-core/utils run: npm install -g @node-core/utils + - name: Set variables + run: | + echo "REPOSITORY=$(echo ${{ github.repository }} | cut -d/ -f2)" >> $GITHUB_ENV + echo "OWNER=${{ github.repository_owner }}" >> $GITHUB_ENV + - name: Configure @node-core/utils + run: | + ncu-config set branch ${GITHUB_REF_NAME} + ncu-config set upstream origin + ncu-config set username "${{ secrets.GH_USER_NAME }}" + ncu-config set token "${{ secrets.GH_USER_TOKEN }}" + ncu-config set repo "${REPOSITORY}" + ncu-config set owner "${OWNER}" - name: Environment Information run: npx envinfo @@ -65,6 +77,7 @@ jobs: author: Node.js GitHub Bot body: This is an automated patch update of wpt to ${{ env.WPT_REVISION }}. branch: actions/update-wpt # Custom branch *just* for this Action. + commit-message: 'deps: update wpt to ${{ env.WPT_REVISION }}' labels: test title: 'deps: update wpt to ${{ env.WPT_REVISION }}' update-pull-request-title-and-body: true From 60a025ffb8bde2351c50fec43c66a7c6bb6f2b95 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Sun, 5 Nov 2023 16:25:08 +0000 Subject: [PATCH 4/5] deps: update wpt to 708e132acaee153316bf9356b0b2ba64c40a2965 --- test/fixtures/wpt/FileAPI/META.yml | 2 +- test/fixtures/wpt/README.md | 48 +- test/fixtures/wpt/common/META.yml | 1 - test/fixtures/wpt/common/dummy.json | 1 + test/fixtures/wpt/common/media.js | 20 +- test/fixtures/wpt/common/top-layer.js | 29 ++ .../wpt/dom/events/Event-dispatch-click.html | 56 ++ .../Event-dispatch-on-disabled-elements.html | 2 +- ...t-dispatch-single-activation-behavior.html | 164 ++++++ ...entDefault-during-activation-behavior.html | 53 ++ .../wpt/dom/events/remove-all-listeners.html | 95 ++++ .../events/scrolling/overscroll-deltas.html | 208 +++++--- .../dom/events/scrolling/scroll_support.js | 125 ++++- ...d-after-sequence-of-scrolls.tentative.html | 76 ++- ...d-for-mandatory-snap-point-after-load.html | 87 ++++ .../scrollend-event-fired-to-document.html | 142 ++++-- ...d-to-element-with-overscroll-behavior.html | 233 ++++++--- ...llend-event-fired-to-scrolled-element.html | 68 --- .../scrollend-event-fired-to-window.html | 90 ++-- ...end-event-fires-to-iframe-inner-frame.html | 30 ++ ...crollend-event-fires-to-iframe-window.html | 88 ++++ .../scrollend-event-for-user-scroll.html | 149 +----- ...crollend-event-not-fired-on-no-scroll.html | 114 +++++ .../scrolling/scrollend-user-scroll-common.js | 145 ++++++ ...ollend-with-snap-on-fractional-offset.html | 85 ++++ test/fixtures/wpt/encoding/api-basics.any.js | 1 + .../wpt/encoding/api-surrogates-utf8.any.js | 1 + .../wpt/encoding/iso-2022-jp-decoder.any.js | 2 + .../gb18030/gb18030-decoder.any.js | 38 ++ .../gb18030/gb18030-encoder.html | 38 ++ .../wpt/encoding/streams/backpressure.any.js | 2 +- .../encoding/streams/decode-attributes.any.js | 2 +- .../encoding/streams/decode-bad-chunks.any.js | 2 +- .../encoding/streams/decode-non-utf8.any.js | 2 +- .../readable-writable-properties.any.js | 2 +- .../wpt/encoding/textdecoder-arguments.any.js | 1 + .../textdecoder-byte-order-marks.any.js | 1 + .../textdecoder-fatal-streaming.any.js | 1 + .../wpt/encoding/textdecoder-fatal.any.js | 1 + .../wpt/encoding/textdecoder-ignorebom.any.js | 1 + .../textdecoder-utf16-surrogates.any.js | 1 + .../textencoder-utf16-surrogates.any.js | 1 + .../wpt/hr-time/raf-coarsened-time.https.html | 33 ++ .../raf-coarsened-time.https.html.headers | 2 + ...cross-realm-callback-report-exception.html | 28 + ...ructured-clone-battery-of-tests-harness.js | 5 +- ...one-battery-of-tests-with-transferables.js | 147 ++++++ .../structured-clone-battery-of-tests.js | 257 +++++++--- .../structured-clone-cross-realm-method.html | 20 + ...tructured-clone-detached-window-crash.html | 11 + .../structured-clone/structured-clone.any.js | 7 +- .../timers/clearinterval-from-callback.any.js | 19 + .../timers/evil-spec-example.any.js | 12 + .../webappapis/timers/evil-spec-example.html | 23 - ...cross-realm-callback-report-exception.html | 32 ++ ...cross-realm-callback-report-exception.html | 28 + test/fixtures/wpt/interfaces/dom.idl | 3 +- test/fixtures/wpt/interfaces/encoding.idl | 2 +- test/fixtures/wpt/interfaces/hr-time.idl | 2 +- test/fixtures/wpt/interfaces/html.idl | 264 ++++++++-- .../wpt/interfaces/performance-timeline.idl | 8 +- .../wpt/interfaces/resource-timing.idl | 12 +- test/fixtures/wpt/interfaces/streams.idl | 2 + test/fixtures/wpt/interfaces/url.idl | 8 +- test/fixtures/wpt/interfaces/user-timing.idl | 4 +- test/fixtures/wpt/interfaces/webidl.idl | 5 +- ...k-forward-cache-restoration.tentative.html | 95 ++++ .../droppedentriescount.any.js | 81 +++ .../idlharness-shadowrealm.window.js | 2 + ...avigation-id-detached-frame.tentative.html | 30 ++ ...avigation-id-element-timing.tentative.html | 14 + .../navigation-id-initial-load.tentative.html | 49 ++ ...-long-task-task-attribution.tentative.html | 14 + .../navigation-id-mark-measure.tentative.html | 14 + .../navigation-id-reset.tentative.html | 53 ++ ...vigation-id-resource-timing.tentative.html | 14 + .../navigation-id-worker-created-entries.html | 27 + .../navigation-id.helper.js | 144 ++++++ ...tion-timing-attributes.tentative.window.js | 57 +++ ...g-bfcache-reasons-stay.tentative.window.js | 49 ++ ...igation-timing-bfcache.tentative.window.js | 28 + ...g-cross-origin-bfcache.tentative.window.js | 63 +++ ...avigation-timing-fetch.tentative.window.js | 41 ++ ...tion-timing-lock.https.tentative.window.js | 32 ++ ...ing-navigation-failure.tentative.window.js | 26 + ...on-timing-not-bfcached.tentative.window.js | 37 ++ ...ng-redirect-on-history.tentative.window.js | 53 ++ ...vigation-timing-reload.tentative.window.js | 51 ++ ...ng-same-origin-bfcache.tentative.window.js | 64 +++ ...ng-same-origin-replace.tentative.window.js | 44 ++ .../not-restored-reasons/test-helper.js | 46 ++ .../resources/child-frame.html | 7 + .../performance-timeline/resources/empty.html | 0 .../resources/include-frames-helper.js | 60 +++ .../resources/include-frames-subframe.html | 43 ++ .../resources/json_resource.json | 4 + .../resources/make_long_task.js | 4 + .../navigation-id-detached-frame-page.html | 21 + .../resources/worker-navigation-id.js | 6 + ...upportedEntryTypes-cross-realm-access.html | 18 + .../tentative/detached-frame.html | 27 + .../tentative/include-frames-originA-A-A.html | 93 ++++ .../tentative/include-frames-originA-A.html | 76 +++ .../tentative/include-frames-originA-AA.html | 51 ++ .../tentative/include-frames-originA-AB.html | 53 ++ .../tentative/include-frames-originA-B-A.html | 91 ++++ .../tentative/include-frames-originA-B-B.html | 57 +++ .../tentative/include-frames-originA-B.html | 50 ++ ...erformance-entry-source-deleted-frame.html | 39 ++ .../tentative/performance-entry-source.html | 37 ++ .../with-filter-options-originA.html | 26 + .../timing-removed-iframe.html | 16 + test/fixtures/wpt/resource-timing/META.yml | 1 - .../body-size-cross-origin.https.html | 63 +++ .../resource-timing/content-type-parsing.html | 76 +++ .../wpt/resource-timing/content-type.html | 117 +++++ ...-origin-start-end-time-with-redirects.html | 20 +- .../delivery-type.tentative.any.js | 90 ++++ .../entries-for-network-errors.sub.https.html | 16 + .../fetch-cross-origin-redirect.https.html | 2 +- .../resource-timing/iframe-failed-commit.html | 34 +- .../iframe-sequence-of-events.html | 16 +- .../resource-timing/initiator-type/link.html | 57 +-- .../interim-response-times.h2.html | 74 +++ .../interim-response-times.html | 72 +++ .../nested-nav-fallback-timing.html | 33 ++ ...s-origin-css-fetched-memory-cache.sub.html | 53 ++ ...not-found-after-cross-origin-redirect.html | 25 +- .../queue-entry-regardless-buffer-size.html | 38 ++ ...ing-failed-fetch-web-bundle.tentative.html | 53 ++ .../resource-timing-failed-fetch.html | 34 ++ .../resource-timing/resource-timing-level1.js | 41 -- .../resource-timing/resources/delay-load.html | 4 + .../resources/entry-invariants.js | 43 +- .../resource-timing/resources/frame-timing.js | 97 ++-- .../resources/get-resourceID.js | 30 ++ .../resources/loadingResources.js | 21 + .../resources/nested-contexts.js | 37 +- ...n-css-fetched-memory-cache-iframe.sub.html | 8 + .../resources/resource-loaders.js | 77 ++- .../resources/test-initiator.js | 16 + .../resource-timing/response-status-code.html | 165 ++++++ .../resource-timing/sizes-redirect-img.html | 8 +- .../tentative/document-initiated.html | 78 +++ .../tentative/script-initiated.html | 24 + .../tentative/stylesheet-initiated.html | 23 + test/fixtures/wpt/resource-timing/tojson.html | 4 +- .../declarative-shadow-dom-polyfill.js | 3 +- test/fixtures/wpt/resources/idlharness.js | 7 +- test/fixtures/wpt/resources/testdriver.js | 480 ++++++++++++++++-- test/fixtures/wpt/resources/testharness.js | 36 +- test/fixtures/wpt/streams/piping/abort.any.js | 2 +- .../piping/close-propagation-backward.any.js | 2 +- .../piping/close-propagation-forward.any.js | 2 +- .../piping/crashtests/cross-piping.html | 12 + .../piping/error-propagation-backward.any.js | 2 +- .../piping/error-propagation-forward.any.js | 2 +- .../wpt/streams/piping/flow-control.any.js | 2 +- .../streams/piping/general-addition.any.js | 2 +- .../wpt/streams/piping/general.any.js | 2 +- .../piping/multiple-propagation.any.js | 2 +- .../wpt/streams/piping/pipe-through.any.js | 2 +- .../streams/piping/then-interception.any.js | 2 +- .../streams/piping/throwing-options.any.js | 2 +- .../streams/piping/transform-streams.any.js | 2 +- .../wpt/streams/queuing-strategies.any.js | 2 +- .../bad-buffers-and-views.any.js | 2 +- .../construct-byob-request.any.js | 2 +- .../enqueue-with-detached-buffer.any.js | 2 +- .../readable-byte-streams/general.any.js | 2 +- .../non-transferable-buffers.any.js | 2 +- .../respond-after-enqueue.any.js | 2 +- .../streams/readable-byte-streams/tee.any.js | 2 +- .../readable-streams/async-iterator.any.js | 2 +- .../readable-streams/bad-strategies.any.js | 43 +- .../bad-underlying-sources.any.js | 2 +- .../streams/readable-streams/cancel.any.js | 2 +- .../readable-streams/constructor.any.js | 2 +- .../count-queuing-strategy-integration.any.js | 2 +- .../readable-streams/default-reader.any.js | 2 +- .../floating-point-total-queue-size.any.js | 2 +- .../wpt/streams/readable-streams/from.any.js | 2 +- .../garbage-collection.any.js | 2 +- .../streams/readable-streams/general.any.js | 2 +- .../owning-type-message-port.any.js | 2 +- .../owning-type-video-frame.any.js | 2 +- .../readable-streams/owning-type.any.js | 2 +- .../readable-streams/patched-global.any.js | 2 +- .../reentrant-strategies.any.js | 2 +- .../wpt/streams/readable-streams/tee.any.js | 2 +- .../streams/readable-streams/templated.any.js | 2 +- .../transform-stream-members.any.js | 2 + .../transform-streams/backpressure.any.js | 2 +- .../streams/transform-streams/cancel.any.js | 115 +++++ .../streams/transform-streams/errors.any.js | 45 +- .../streams/transform-streams/flush.any.js | 17 +- .../streams/transform-streams/general.any.js | 21 +- .../streams/transform-streams/lipfuzz.any.js | 2 +- .../transform-streams/patched-global.any.js | 2 +- .../transform-streams/properties.any.js | 2 +- .../reentrant-strategies.any.js | 6 +- .../transform-streams/strategies.any.js | 2 +- .../transform-streams/terminate.any.js | 2 +- .../streams/writable-streams/aborting.any.js | 2 +- .../writable-streams/bad-strategies.any.js | 2 +- .../bad-underlying-sinks.any.js | 2 +- .../byte-length-queuing-strategy.any.js | 2 +- .../wpt/streams/writable-streams/close.any.js | 2 +- .../writable-streams/constructor.any.js | 2 +- .../count-queuing-strategy.any.js | 2 +- .../wpt/streams/writable-streams/error.any.js | 2 +- .../floating-point-total-queue-size.any.js | 2 +- .../streams/writable-streams/general.any.js | 2 +- .../writable-streams/properties.any.js | 2 +- .../reentrant-strategy.any.js | 2 +- .../wpt/streams/writable-streams/start.any.js | 2 +- .../wpt/streams/writable-streams/write.any.js | 2 +- test/fixtures/wpt/versions.json | 48 +- test/fixtures/wpt/wasm/jsapi/assertions.js | 5 + test/fixtures/wpt/wasm/jsapi/bad-imports.js | 1 + .../wpt/wasm/jsapi/constructor/compile.any.js | 2 +- .../instantiate-bad-imports.any.js | 2 +- .../wasm/jsapi/constructor/instantiate.any.js | 2 +- .../wasm/jsapi/constructor/multi-value.any.js | 2 +- .../wasm/jsapi/constructor/toStringTag.any.js | 2 +- .../wasm/jsapi/constructor/validate.any.js | 2 +- .../jsapi/exception/basic.tentative.any.js | 11 +- .../exception/constructor.tentative.any.js | 2 +- .../jsapi/exception/getArg.tentative.any.js | 2 +- .../jsapi/exception/identity.tentative.any.js | 2 +- .../wasm/jsapi/exception/is.tentative.any.js | 2 +- .../jsapi/exception/toString.tentative.any.js | 2 +- .../wasm/jsapi/function/call.tentative.any.js | 2 +- .../function/constructor.tentative.any.js | 2 +- .../jsapi/function/table.tentative.any.js | 2 +- .../wasm/jsapi/function/type.tentative.any.js | 2 +- .../wpt/wasm/jsapi/gc/casts.tentative.any.js | 332 ++++++++++++ .../jsapi/gc/exported-object.tentative.any.js | 190 +++++++ .../wpt/wasm/jsapi/gc/i31.tentative.any.js | 98 ++++ .../wpt/wasm/jsapi/global/constructor.any.js | 2 +- .../wpt/wasm/jsapi/global/toString.any.js | 2 +- .../wasm/jsapi/global/type.tentative.any.js | 2 +- .../wasm/jsapi/global/value-get-set.any.js | 2 +- .../wpt/wasm/jsapi/global/valueOf.any.js | 2 +- .../instance/constructor-bad-imports.any.js | 2 +- .../jsapi/instance/constructor-caching.any.js | 2 +- .../wasm/jsapi/instance/constructor.any.js | 2 +- .../wpt/wasm/jsapi/instance/exports.any.js | 2 +- .../wpt/wasm/jsapi/instance/toString.any.js | 2 +- .../wpt/wasm/jsapi/instanceTestFactory.js | 8 +- test/fixtures/wpt/wasm/jsapi/interface.any.js | 2 +- .../constructor-shared.tentative.any.js | 2 +- .../memory/constructor-types.tentative.any.js | 4 +- .../wpt/wasm/jsapi/memory/constructor.any.js | 2 +- .../wpt/wasm/jsapi/memory/grow.any.js | 2 +- .../wasm/jsapi/memory/type.tentative.any.js | 4 +- .../wpt/wasm/jsapi/module/constructor.any.js | 2 +- .../wasm/jsapi/module/customSections.any.js | 2 +- .../wpt/wasm/jsapi/module/exports.any.js | 8 +- .../wpt/wasm/jsapi/module/imports.any.js | 2 +- .../wpt/wasm/jsapi/module/toString.any.js | 2 +- .../fixtures/wpt/wasm/jsapi/prototypes.any.js | 2 +- .../table/constructor-types.tentative.any.js | 4 +- .../wpt/wasm/jsapi/table/constructor.any.js | 2 +- .../wpt/wasm/jsapi/table/get-set.any.js | 2 +- .../fixtures/wpt/wasm/jsapi/table/grow.any.js | 2 +- .../wpt/wasm/jsapi/table/length.any.js | 2 +- .../wpt/wasm/jsapi/table/toString.any.js | 2 +- .../wasm/jsapi/table/type.tentative.any.js | 2 +- .../jsapi/tag/constructor.tentative.any.js | 2 +- .../wasm/jsapi/tag/toString.tentative.any.js | 2 +- .../wpt/wasm/jsapi/tag/type.tentative.any.js | 2 +- .../wpt/wasm/jsapi/wasm-module-builder.js | 352 ++++++++++--- .../esm-integration/worker.tentative.html | 3 + .../broadcastchannel/basics.any.js | 8 + test/wpt/status/FileAPI/blob.json | 44 +- test/wpt/status/dom/events.json | 6 +- test/wpt/status/encoding.json | 89 +++- test/wpt/status/hr-time.json | 1 + test/wpt/status/html/webappapis/atob.json | 3 +- .../html/webappapis/structured-clone.json | 10 +- test/wpt/status/html/webappapis/timers.json | 3 + test/wpt/status/performance-timeline.json | 42 ++ test/wpt/status/resource-timing.json | 21 + test/wpt/status/streams.json | 54 +- test/wpt/status/url.json | 2 + .../status/webmessaging/broadcastchannel.json | 10 +- 287 files changed, 7710 insertions(+), 1239 deletions(-) create mode 100644 test/fixtures/wpt/common/dummy.json create mode 100644 test/fixtures/wpt/common/top-layer.js create mode 100644 test/fixtures/wpt/dom/events/Event-dispatch-single-activation-behavior.html create mode 100644 test/fixtures/wpt/dom/events/preventDefault-during-activation-behavior.html create mode 100644 test/fixtures/wpt/dom/events/remove-all-listeners.html create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-for-mandatory-snap-point-after-load.html delete mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-inner-frame.html create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-window.html create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-event-not-fired-on-no-scroll.html create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-user-scroll-common.js create mode 100644 test/fixtures/wpt/dom/events/scrolling/scrollend-with-snap-on-fractional-offset.html create mode 100644 test/fixtures/wpt/hr-time/raf-coarsened-time.https.html create mode 100644 test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers create mode 100644 test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html create mode 100644 test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html create mode 100644 test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html create mode 100644 test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js create mode 100644 test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js delete mode 100644 test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html create mode 100644 test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html create mode 100644 test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html create mode 100644 test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/droppedentriescount.any.js create mode 100644 test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html create mode 100644 test/fixtures/wpt/performance-timeline/navigation-id.helper.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js create mode 100644 test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js create mode 100644 test/fixtures/wpt/performance-timeline/resources/child-frame.html create mode 100644 test/fixtures/wpt/performance-timeline/resources/empty.html create mode 100644 test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js create mode 100644 test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html create mode 100644 test/fixtures/wpt/performance-timeline/resources/json_resource.json create mode 100644 test/fixtures/wpt/performance-timeline/resources/make_long_task.js create mode 100644 test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html create mode 100644 test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js create mode 100644 test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/detached-frame.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/performance-entry-source-deleted-frame.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html create mode 100644 test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html create mode 100644 test/fixtures/wpt/performance-timeline/timing-removed-iframe.html create mode 100644 test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html create mode 100644 test/fixtures/wpt/resource-timing/content-type-parsing.html create mode 100644 test/fixtures/wpt/resource-timing/content-type.html create mode 100644 test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js create mode 100644 test/fixtures/wpt/resource-timing/interim-response-times.h2.html create mode 100644 test/fixtures/wpt/resource-timing/interim-response-times.html create mode 100644 test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html create mode 100644 test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html create mode 100644 test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html create mode 100644 test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html create mode 100644 test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html create mode 100644 test/fixtures/wpt/resource-timing/resources/delay-load.html create mode 100644 test/fixtures/wpt/resource-timing/resources/get-resourceID.js create mode 100644 test/fixtures/wpt/resource-timing/resources/loadingResources.js create mode 100644 test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html create mode 100644 test/fixtures/wpt/resource-timing/resources/test-initiator.js create mode 100644 test/fixtures/wpt/resource-timing/response-status-code.html create mode 100644 test/fixtures/wpt/resource-timing/tentative/document-initiated.html create mode 100644 test/fixtures/wpt/resource-timing/tentative/script-initiated.html create mode 100644 test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html create mode 100644 test/fixtures/wpt/streams/piping/crashtests/cross-piping.html create mode 100644 test/fixtures/wpt/streams/transform-streams/cancel.any.js create mode 100644 test/fixtures/wpt/wasm/jsapi/gc/casts.tentative.any.js create mode 100644 test/fixtures/wpt/wasm/jsapi/gc/exported-object.tentative.any.js create mode 100644 test/fixtures/wpt/wasm/jsapi/gc/i31.tentative.any.js diff --git a/test/fixtures/wpt/FileAPI/META.yml b/test/fixtures/wpt/FileAPI/META.yml index 506a59fec1e..66227c8224b 100644 --- a/test/fixtures/wpt/FileAPI/META.yml +++ b/test/fixtures/wpt/FileAPI/META.yml @@ -1,6 +1,6 @@ spec: https://w3c.github.io/FileAPI/ suggested_reviewers: - inexorabletash - - zqzhang - jdm - mkruisselbrink + - annevk diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index 6404571a498..4a2bedecc8b 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -10,30 +10,30 @@ See [test/wpt](../../wpt/README.md) for information on how these tests are run. Last update: -- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common -- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console -- dom/abort: https://github.com/web-platform-tests/wpt/tree/d1f1ecbd52/dom/abort -- dom/events: https://github.com/web-platform-tests/wpt/tree/ab8999891c/dom/events -- encoding: https://github.com/web-platform-tests/wpt/tree/a58bbf6d8c/encoding -- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources -- FileAPI: https://github.com/web-platform-tests/wpt/tree/e36dbb6f00/FileAPI -- hr-time: https://github.com/web-platform-tests/wpt/tree/34cafd797e/hr-time -- html/webappapis/atob: https://github.com/web-platform-tests/wpt/tree/f267e1dca6/html/webappapis/atob -- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing -- html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/47d3fb280c/html/webappapis/structured-clone -- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/5873f2d8f1/html/webappapis/timers -- interfaces: https://github.com/web-platform-tests/wpt/tree/df731dab88/interfaces -- performance-timeline: https://github.com/web-platform-tests/wpt/tree/17ebc3aea0/performance-timeline -- resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing -- resources: https://github.com/web-platform-tests/wpt/tree/919874f84f/resources -- streams: https://github.com/web-platform-tests/wpt/tree/517e945bbf/streams -- url: https://github.com/web-platform-tests/wpt/tree/c2d7e70b52/url -- user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing -- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi -- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi -- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/d4e14d714c/WebCryptoAPI -- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions -- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/e97fac4791/webmessaging/broadcastchannel +- common: https://github.com/web-platform-tests/wpt/tree/708e132aca/common +- console: https://github.com/web-platform-tests/wpt/tree/708e132aca/console +- dom/abort: https://github.com/web-platform-tests/wpt/tree/708e132aca/dom/abort +- dom/events: https://github.com/web-platform-tests/wpt/tree/708e132aca/dom/events +- encoding: https://github.com/web-platform-tests/wpt/tree/708e132aca/encoding +- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/708e132aca/fetch/data-urls/resources +- FileAPI: https://github.com/web-platform-tests/wpt/tree/708e132aca/FileAPI +- hr-time: https://github.com/web-platform-tests/wpt/tree/708e132aca/hr-time +- html/webappapis/atob: https://github.com/web-platform-tests/wpt/tree/708e132aca/html/webappapis/atob +- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/708e132aca/html/webappapis/microtask-queuing +- html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/708e132aca/html/webappapis/structured-clone +- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/708e132aca/html/webappapis/timers +- interfaces: https://github.com/web-platform-tests/wpt/tree/708e132aca/interfaces +- performance-timeline: https://github.com/web-platform-tests/wpt/tree/708e132aca/performance-timeline +- resource-timing: https://github.com/web-platform-tests/wpt/tree/708e132aca/resource-timing +- resources: https://github.com/web-platform-tests/wpt/tree/708e132aca/resources +- streams: https://github.com/web-platform-tests/wpt/tree/708e132aca/streams +- url: https://github.com/web-platform-tests/wpt/tree/708e132aca/url +- user-timing: https://github.com/web-platform-tests/wpt/tree/708e132aca/user-timing +- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/708e132aca/wasm/jsapi +- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/708e132aca/wasm/webapi +- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/708e132aca/WebCryptoAPI +- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/708e132aca/webidl/ecmascript-binding/es-exceptions +- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/708e132aca/webmessaging/broadcastchannel [Web Platform Tests]: https://github.com/web-platform-tests/wpt [`git node wpt`]: https://github.com/nodejs/node-core-utils/blob/main/docs/git-node.md#git-node-wpt diff --git a/test/fixtures/wpt/common/META.yml b/test/fixtures/wpt/common/META.yml index ca4d2e523c0..963dff9d1f1 100644 --- a/test/fixtures/wpt/common/META.yml +++ b/test/fixtures/wpt/common/META.yml @@ -1,3 +1,2 @@ suggested_reviewers: - - zqzhang - deniak diff --git a/test/fixtures/wpt/common/dummy.json b/test/fixtures/wpt/common/dummy.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/test/fixtures/wpt/common/dummy.json @@ -0,0 +1 @@ +{} diff --git a/test/fixtures/wpt/common/media.js b/test/fixtures/wpt/common/media.js index f2dc8612660..800593f5343 100644 --- a/test/fixtures/wpt/common/media.js +++ b/test/fixtures/wpt/common/media.js @@ -9,10 +9,15 @@ function getVideoURI(base) var videotag = document.createElement("video"); - if ( videotag.canPlayType && - videotag.canPlayType('video/ogg; codecs="theora, vorbis"') ) + if ( videotag.canPlayType ) { - extension = '.ogv'; + if (videotag.canPlayType('video/webm; codecs="vp9, opus"') ) + { + extension = '.webm'; + } else if ( videotag.canPlayType('video/ogg; codecs="theora, vorbis"') ) + { + extension = '.ogv'; + } } return base + extension; @@ -46,10 +51,11 @@ function getAudioURI(base) function getMediaContentType(url) { var extension = new URL(url, location).pathname.split(".").pop(); var map = { - "mp4": "video/mp4", - "ogv": "application/ogg", - "mp3": "audio/mp3", - "oga": "application/ogg", + "mp4" : "video/mp4", + "ogv" : "application/ogg", + "webm": "video/webm", + "mp3" : "audio/mp3", + "oga" : "application/ogg", }; return map[extension]; } diff --git a/test/fixtures/wpt/common/top-layer.js b/test/fixtures/wpt/common/top-layer.js new file mode 100644 index 00000000000..2dc8ce3893a --- /dev/null +++ b/test/fixtures/wpt/common/top-layer.js @@ -0,0 +1,29 @@ +// This function is a version of test_driver.bless which works while there are +// elements in the top layer: +// https://github.com/web-platform-tests/wpt/issues/41218. +// Pass it the element at the top of the top layer stack. +window.blessTopLayer = async (topLayerElement) => { + const button = document.createElement('button'); + topLayerElement.append(button); + let wait_click = new Promise(resolve => button.addEventListener("click", resolve, {once: true})); + await test_driver.click(button); + await wait_click; + button.remove(); +}; + +window.isTopLayer = (el) => { + // A bit of a hack. Just test a few properties of the ::backdrop pseudo + // element that change when in the top layer. + const properties = ['right','background']; + const testEl = document.createElement('div'); + document.body.appendChild(testEl); + const computedStyle = getComputedStyle(testEl, '::backdrop'); + const nonTopLayerValues = properties.map(p => computedStyle[p]); + testEl.remove(); + for(let i=0;i") +async_test(function(t) { + var input = document.createElement("input") + input.type = "radio" + dump.appendChild(input) + input.onclick = t.step_func(function() { + assert_false(input.checked, "input pre-click must not be triggered") + }) + var child = input.appendChild(document.createElement("input")) + child.type = "radio" + child.onclick = t.step_func(function() { + assert_true(child.checked, "child pre-click must be triggered") + }) + child.dispatchEvent(new MouseEvent("click", {bubbles:true})) + t.done() +}, "pick the first with activation behavior ") + async_test(function(t) { var input = document.createElement("input") input.type = "checkbox" @@ -173,6 +189,46 @@ t.done() }, "disabled checkbox still has activation behavior, part 2") +async_test(function(t) { + var state = "start" + + var form = document.createElement("form") + form.onsubmit = t.step_func(() => { + if(state == "start" || state == "radio") { + state = "failure" + } else if(state == "form") { + state = "done" + } + return false + }) + dump.appendChild(form) + var button = form.appendChild(document.createElement("button")) + button.type = "submit" + var radio = button.appendChild(document.createElement("input")) + radio.type = "radio" + radio.onclick = t.step_func(() => { + if(state == "start") { + assert_unreached() + } else if(state == "radio") { + assert_true(radio.checked) + } + }) + radio.disabled = true + radio.click() + assert_equals(state, "start") + + state = "radio" + radio.disabled = false + radio.click() + assert_equals(state, "radio") + + state = "form" + button.click() + assert_equals(state, "done") + + t.done() +}, "disabled radio still has activation behavior") + async_test(function(t) { var input = document.createElement("input") input.type = "checkbox" diff --git a/test/fixtures/wpt/dom/events/Event-dispatch-on-disabled-elements.html b/test/fixtures/wpt/dom/events/Event-dispatch-on-disabled-elements.html index 361006a7240..e7d6b455bbc 100644 --- a/test/fixtures/wpt/dom/events/Event-dispatch-on-disabled-elements.html +++ b/test/fixtures/wpt/dom/events/Event-dispatch-on-disabled-elements.html @@ -19,7 +19,7 @@ + +
+ +
+ + + + + diff --git a/test/fixtures/wpt/dom/events/preventDefault-during-activation-behavior.html b/test/fixtures/wpt/dom/events/preventDefault-during-activation-behavior.html new file mode 100644 index 00000000000..92874031347 --- /dev/null +++ b/test/fixtures/wpt/dom/events/preventDefault-during-activation-behavior.html @@ -0,0 +1,53 @@ + +preventDefault during activation behavior + + + + + + + + + +
+ +
+ + diff --git a/test/fixtures/wpt/dom/events/remove-all-listeners.html b/test/fixtures/wpt/dom/events/remove-all-listeners.html new file mode 100644 index 00000000000..3a2a751a146 --- /dev/null +++ b/test/fixtures/wpt/dom/events/remove-all-listeners.html @@ -0,0 +1,95 @@ + +Various edge cases where listeners are removed during iteration + + +
+ diff --git a/test/fixtures/wpt/dom/events/scrolling/overscroll-deltas.html b/test/fixtures/wpt/dom/events/scrolling/overscroll-deltas.html index 6f0b77f22ed..e13e9f1cce5 100644 --- a/test/fixtures/wpt/dom/events/scrolling/overscroll-deltas.html +++ b/test/fixtures/wpt/dom/events/scrolling/overscroll-deltas.html @@ -6,80 +6,152 @@ - -
-
+ +
+
+
+
+
diff --git a/test/fixtures/wpt/dom/events/scrolling/scroll_support.js b/test/fixtures/wpt/dom/events/scrolling/scroll_support.js index 169393e4c3e..f05251ce21a 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scroll_support.js +++ b/test/fixtures/wpt/dom/events/scrolling/scroll_support.js @@ -1,15 +1,85 @@ -async function waitForScrollendEvent(test, target, timeoutMs = 500) { +async function waitForEvent(eventName, test, target, timeoutMs = 500) { return new Promise((resolve, reject) => { const timeoutCallback = test.step_timeout(() => { - reject(`No Scrollend event received for target ${target}`); + reject(`No ${eventName} event received for target ${target}`); }, timeoutMs); - target.addEventListener('scrollend', (evt) => { + target.addEventListener(eventName, (evt) => { clearTimeout(timeoutCallback); resolve(evt); }, { once: true }); }); } +async function waitForScrollendEvent(test, target, timeoutMs = 500) { + return waitForEvent("scrollend", test, target, timeoutMs); +} + +async function waitForScrollendEventNoTimeout(target) { + return new Promise((resolve) => { + target.addEventListener("scrollend", resolve); + }); +} + +async function waitForPointercancelEvent(test, target, timeoutMs = 500) { + return waitForEvent("pointercancel", test, target, timeoutMs); +} + +// Resets the scroll position to (0,0). If a scroll is required, then the +// promise is not resolved until the scrollend event is received. +async function waitForScrollReset(test, scroller, timeoutMs = 500) { + return new Promise(resolve => { + if (scroller.scrollTop == 0 && + scroller.scrollLeft == 0) { + resolve(); + } else { + const eventTarget = + scroller == document.scrollingElement ? document : scroller; + scroller.scrollTop = 0; + scroller.scrollLeft = 0; + waitForScrollendEvent(test, eventTarget, timeoutMs).then(resolve); + } + }); +} + +async function createScrollendPromiseForTarget(test, + target_div, + timeoutMs = 500) { + return waitForScrollendEvent(test, target_div, timeoutMs).then(evt => { + assert_false(evt.cancelable, 'Event is not cancelable'); + assert_false(evt.bubbles, 'Event targeting element does not bubble'); + }); +} + +function verifyNoScrollendOnDocument(test) { + const callback = + test.unreached_func("window got unexpected scrollend event."); + window.addEventListener('scrollend', callback); + test.add_cleanup(() => { + window.removeEventListener('scrollend', callback); + }); +} + +async function verifyScrollStopped(test, target_div) { + const unscaled_pause_time_in_ms = 100; + const x = target_div.scrollLeft; + const y = target_div.scrollTop; + return new Promise(resolve => { + test.step_timeout(() => { + assert_equals(target_div.scrollLeft, x); + assert_equals(target_div.scrollTop, y); + resolve(); + }, unscaled_pause_time_in_ms); + }); +} + +async function resetTargetScrollState(test, target_div) { + if (target_div.scrollTop != 0 || target_div.scrollLeft != 0) { + target_div.scrollTop = 0; + target_div.scrollLeft = 0; + return waitForScrollendEvent(test, target_div); + } +} + const MAX_FRAME = 700; const MAX_UNCHANGED_FRAMES = 20; @@ -45,6 +115,29 @@ function waitForCompositorCommit() { }); } +// Please don't remove this. This is necessary for chromium-based browsers. +// This shouldn't be necessary if the test harness deferred running the tests +// until after paint holding. This can be a no-op on user-agents that do not +// have a separate compositor thread. +async function waitForCompositorReady() { + const animation = + document.body.animate({ opacity: [ 1, 1 ] }, {duration: 1 }); + return animation.finished; +} + +function waitForNextFrame() { + const startTime = performance.now(); + return new Promise(resolve => { + window.requestAnimationFrame((frameTime) => { + if (frameTime < startTime) { + window.requestAnimationFrame(resolve); + } else { + resolve(); + } + }); + }); +} + // TODO(crbug.com/1400399): Deprecate as frame rates may vary greatly in // different test environments. function waitForAnimationEnd(getValue) { @@ -70,6 +163,10 @@ function waitForAnimationEnd(getValue) { } // Scrolls in target according to move_path with pauses in between +// The move_path should contains coordinates that are within target boundaries. +// Keep in mind that 0,0 is the center of the target element and is also +// the pointerDown position. +// pointerUp() is fired after sequence of moves. function touchScrollInTargetSequentiallyWithPause(target, move_path, pause_time_in_ms = 100) { const test_driver_actions = new test_driver.Actions() .addPointer("pointer1", "touch") @@ -88,7 +185,7 @@ function touchScrollInTargetSequentiallyWithPause(target, move_path, pause_time_ y += step_y; test_driver_actions.pointerMove(x, y, {origin: target}); } - test_driver_actions.pause(pause_time_in_ms); + test_driver_actions.pause(pause_time_in_ms); // To prevent inertial scroll } return test_driver_actions.pointerUp().send(); @@ -161,3 +258,23 @@ function conditionHolds(condition, error_message = 'Condition is not true anymor tick(0); }); } + +function scrollElementDown(element, scroll_amount) { + let x = 0; + let y = 0; + let delta_x = 0; + let delta_y = scroll_amount; + let actions = new test_driver.Actions() + .scroll(x, y, delta_x, delta_y, {origin: element}); + return actions.send(); +} + +function scrollElementLeft(element, scroll_amount) { + let x = 0; + let y = 0; + let delta_x = scroll_amount; + let delta_y = 0; + let actions = new test_driver.Actions() + .scroll(x, y, delta_x, delta_y, {origin: element}); + return actions.send(); +} diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html index 77bf029ced5..dab6dcc9bd8 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html @@ -14,7 +14,7 @@ } #innerDiv { - width: 500px; + width: 4000px; height: 4000px; } @@ -28,36 +28,64 @@ diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-for-mandatory-snap-point-after-load.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-for-mandatory-snap-point-after-load.html new file mode 100644 index 00000000000..f3791134204 --- /dev/null +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-for-mandatory-snap-point-after-load.html @@ -0,0 +1,87 @@ + + + + + + + + + + + + scrollend + mandatory scroll snap test + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html index 30904553883..797c2eb53da 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html @@ -7,64 +7,100 @@ -
-
+
+
-
+
+
diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html index acad168e56c..edda88e7cb2 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html @@ -7,96 +7,167 @@ -
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+ +
+
+
+
+
+
diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html deleted file mode 100644 index 73433969422..00000000000 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - -
-
-
-
- - - diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html index ef72f56d2ba..faacf7e572c 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html @@ -7,49 +7,63 @@ -
-
+
+
-
+
diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-inner-frame.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-inner-frame.html new file mode 100644 index 00000000000..115e583c067 --- /dev/null +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-inner-frame.html @@ -0,0 +1,30 @@ + + + + +
+
+
+
+ + diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-window.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-window.html new file mode 100644 index 00000000000..4e531580870 --- /dev/null +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-fires-to-iframe-window.html @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-for-user-scroll.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-for-user-scroll.html index 5146c5f719a..a06843a35e7 100644 --- a/test/fixtures/wpt/dom/events/scrolling/scrollend-event-for-user-scroll.html +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-event-for-user-scroll.html @@ -8,6 +8,7 @@ + + + +
+ + +
+
+ +
+ + + diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-user-scroll-common.js b/test/fixtures/wpt/dom/events/scrolling/scrollend-user-scroll-common.js new file mode 100644 index 00000000000..5c278784d83 --- /dev/null +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-user-scroll-common.js @@ -0,0 +1,145 @@ + +async function test_scrollend_on_touch_drag(t, target_div) { + // Skip the test on a Mac as they do not support touch screens. + const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + if (isMac) + return; + + await resetTargetScrollState(t, target_div); + await waitForCompositorReady(); + + const targetScrollendPromise = waitForScrollendEventNoTimeout(target_div); + verifyNoScrollendOnDocument(t); + + let scrollend_count = 0; + const scrollend_listener = () => { + scrollend_count += 1; + }; + target_div.addEventListener("scrollend", scrollend_listener); + t.add_cleanup(() => { + target_div.removeEventListener('scrollend', scrollend_listener); + }); + + // Perform a touch drag on target div and wait for target_div to get + // a scrollend event. + await new test_driver.Actions() + .addPointer('TestPointer', 'touch') + .pointerMove(0, 0, { origin: target_div }) // 0, 0 is center of element. + .pointerDown() + .addTick() + .pointerMove(0, -40, { origin: target_div }) // Drag up to move down. + .addTick() + .pause(200) // Prevent inertial scroll. + .pointerMove(0, -60, { origin: target_div }) + .addTick() + .pause(200) // Prevent inertial scroll. + .pointerUp() + .send(); + + await targetScrollendPromise; + + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t, target_div); + assert_equals(scrollend_count, 1); +} + +async function test_scrollend_on_scrollbar_gutter_click(t, target_div) { + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = target_div.offsetWidth - target_div.clientWidth; + if (scrollbar_width == 0) + return; + + await resetTargetScrollState(t, target_div); + await waitForCompositorReady(); + + const targetScrollendPromise = waitForScrollendEventNoTimeout(target_div); + verifyNoScrollendOnDocument(t); + + const bounds = target_div.getBoundingClientRect(); + // Some versions of webdriver have been known to frown at non-int arguments + // to pointerMove. + const x = bounds.right - Math.round(scrollbar_width / 2); + const y = bounds.bottom - 20; + await new test_driver.Actions() + .addPointer('TestPointer', 'mouse') + .pointerMove(x, y, { origin: 'viewport' }) + .pointerDown() + .addTick() + .pointerUp() + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t, target_div); +} + +// Same issue as previous test. +async function test_scrollend_on_scrollbar_thumb_drag(t, target_div) { + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = target_div.offsetWidth - target_div.clientWidth; + if (scrollbar_width == 0) + return; + + await resetTargetScrollState(t, target_div); + await waitForCompositorReady(); + + const targetScrollendPromise = waitForScrollendEventNoTimeout(target_div); + verifyNoScrollendOnDocument(t); + + const bounds = target_div.getBoundingClientRect(); + // Some versions of webdriver have been known to frown at non-int arguments + // to pointerMove. + const x = bounds.right - Math.round(scrollbar_width / 2); + const y = bounds.top + 30; + const dy = 30; + await new test_driver.Actions() + .addPointer('TestPointer', 'mouse') + .pointerMove(x, y, { origin: 'viewport' }) + .pointerDown() + .pointerMove(x, y + dy, { origin: 'viewport' }) + .addTick() + .pointerUp() + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t, target_div); +} + +async function test_scrollend_on_mousewheel_scroll(t, target_div) { + await resetTargetScrollState(t, target_div); + await waitForCompositorReady(); + + const targetScrollendPromise = waitForScrollendEventNoTimeout(target_div); + verifyNoScrollendOnDocument(t); + + const x = 0; + const y = 0; + const dx = 0; + const dy = 40; + const duration_ms = 10; + await new test_driver.Actions() + .scroll(x, y, dx, dy, { origin: target_div }, duration_ms) + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t, target_div); +} + +async function test_scrollend_on_keyboard_scroll(t, target_div) { + await resetTargetScrollState(t, target_div); + await waitForCompositorReady(); + + verifyNoScrollendOnDocument(t); + const targetScrollendPromise = waitForScrollendEventNoTimeout(target_div); + + target_div.focus(); + window.test_driver.send_keys(target_div, '\ue015'); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t, target_div); +} diff --git a/test/fixtures/wpt/dom/events/scrolling/scrollend-with-snap-on-fractional-offset.html b/test/fixtures/wpt/dom/events/scrolling/scrollend-with-snap-on-fractional-offset.html new file mode 100644 index 00000000000..d1f50304add --- /dev/null +++ b/test/fixtures/wpt/dom/events/scrolling/scrollend-with-snap-on-fractional-offset.html @@ -0,0 +1,85 @@ + + + + + + + +
+
1
+
2
+
3
+
+ + + \ No newline at end of file diff --git a/test/fixtures/wpt/encoding/api-basics.any.js b/test/fixtures/wpt/encoding/api-basics.any.js index 941b878738c..768f8159313 100644 --- a/test/fixtures/wpt/encoding/api-basics.any.js +++ b/test/fixtures/wpt/encoding/api-basics.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: Basics test(function() { diff --git a/test/fixtures/wpt/encoding/api-surrogates-utf8.any.js b/test/fixtures/wpt/encoding/api-surrogates-utf8.any.js index a4ced03d428..52d29731494 100644 --- a/test/fixtures/wpt/encoding/api-surrogates-utf8.any.js +++ b/test/fixtures/wpt/encoding/api-surrogates-utf8.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: Invalid UTF-16 surrogates with UTF-8 encoding var badStrings = [ diff --git a/test/fixtures/wpt/encoding/iso-2022-jp-decoder.any.js b/test/fixtures/wpt/encoding/iso-2022-jp-decoder.any.js index b02259b9600..f9915a2fcf6 100644 --- a/test/fixtures/wpt/encoding/iso-2022-jp-decoder.any.js +++ b/test/fixtures/wpt/encoding/iso-2022-jp-decoder.any.js @@ -1,3 +1,5 @@ +// META: global=window,dedicatedworker,shadowrealm +// function decode(input, output, desc) { test(function() { var d = new TextDecoder("iso-2022-jp"), diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js index 99a0253ba6b..fca68358623 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-decoder.any.js @@ -47,6 +47,44 @@ decode([0x83, 0x36, 0xC8, 0x30], "\uE7C8", "legacy ICU special case 1"); decode([0xA1, 0xAD], "\u2026", "legacy ICU special case 2"); decode([0xA1, 0xAB], "\uFF5E", "legacy ICU special case 3"); +// GB18030-2022 +decode([0xA6, 0xD9], "\uFE10", "GB18030-2022 1"); +decode([0xA6, 0xDA], "\uFE12", "GB18030-2022 2"); +decode([0xA6, 0xDB], "\uFE11", "GB18030-2022 3"); +decode([0xA6, 0xDC], "\uFE13", "GB18030-2022 4"); +decode([0xA6, 0xDD], "\uFE14", "GB18030-2022 5"); +decode([0xA6, 0xDE], "\uFE15", "GB18030-2022 6"); +decode([0xA6, 0xDF], "\uFE16", "GB18030-2022 7"); +decode([0xA6, 0xEC], "\uFE17", "GB18030-2022 8"); +decode([0xA6, 0xED], "\uFE18", "GB18030-2022 9"); +decode([0xA6, 0xF3], "\uFE19", "GB18030-2022 10"); +decode([0xFE, 0x59], "\u9FB4", "GB18030-2022 11"); +decode([0xFE, 0x61], "\u9FB5", "GB18030-2022 12"); +decode([0xFE, 0x66], "\u9FB6", "GB18030-2022 13"); +decode([0xFE, 0x67], "\u9FB7", "GB18030-2022 14"); +decode([0xFE, 0x6D], "\u9FB8", "GB18030-2022 15"); +decode([0xFE, 0x7E], "\u9FB9", "GB18030-2022 16"); +decode([0xFE, 0x90], "\u9FBA", "GB18030-2022 17"); +decode([0xFE, 0xA0], "\u9FBB", "GB18030-2022 18"); +decode([0x82, 0x35, 0x90, 0x37], "\uE81E", "GB18030-2022 19"); +decode([0x82, 0x35, 0x90, 0x38], "\uE826", "GB18030-2022 20"); +decode([0x82, 0x35, 0x90, 0x39], "\uE82B", "GB18030-2022 21"); +decode([0x82, 0x35, 0x91, 0x30], "\uE82C", "GB18030-2022 22"); +decode([0x82, 0x35, 0x91, 0x31], "\uE832", "GB18030-2022 23"); +decode([0x82, 0x35, 0x91, 0x32], "\uE843", "GB18030-2022 24"); +decode([0x82, 0x35, 0x91, 0x33], "\uE854", "GB18030-2022 25"); +decode([0x82, 0x35, 0x91, 0x34], "\uE864", "GB18030-2022 26"); +decode([0x84, 0x31, 0x82, 0x36], "\uE78D", "GB18030-2022 27"); +decode([0x84, 0x31, 0x82, 0x37], "\uE78F", "GB18030-2022 28"); +decode([0x84, 0x31, 0x82, 0x38], "\uE78E", "GB18030-2022 29"); +decode([0x84, 0x31, 0x82, 0x39], "\uE790", "GB18030-2022 30"); +decode([0x84, 0x31, 0x83, 0x30], "\uE791", "GB18030-2022 31"); +decode([0x84, 0x31, 0x83, 0x31], "\uE792", "GB18030-2022 32"); +decode([0x84, 0x31, 0x83, 0x32], "\uE793", "GB18030-2022 33"); +decode([0x84, 0x31, 0x83, 0x33], "\uE794", "GB18030-2022 34"); +decode([0x84, 0x31, 0x83, 0x34], "\uE795", "GB18030-2022 35"); +decode([0x84, 0x31, 0x83, 0x35], "\uE796", "GB18030-2022 36"); + let i = 0; for (const range of ranges) { const pointer = range[0]; diff --git a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html index a6570c8d2b8..531d26084e2 100644 --- a/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html +++ b/test/fixtures/wpt/encoding/legacy-mb-schinese/gb18030/gb18030-encoder.html @@ -24,6 +24,44 @@ encode("\u2026", "%A1%AD", "legacy ICU special case 2"); encode("\uFF5E", "%A1%AB", "legacy ICU special case 3"); + // GB18030-2022 + encode("\uFE10", "%A6%D9", "GB18030-2022 1"); + encode("\uFE12", "%A6%DA", "GB18030-2022 2"); + encode("\uFE11", "%A6%DB", "GB18030-2022 3"); + encode("\uFE13", "%A6%DC", "GB18030-2022 4"); + encode("\uFE14", "%A6%DD", "GB18030-2022 5"); + encode("\uFE15", "%A6%DE", "GB18030-2022 6"); + encode("\uFE16", "%A6%DF", "GB18030-2022 7"); + encode("\uFE17", "%A6%EC", "GB18030-2022 8"); + encode("\uFE18", "%A6%ED", "GB18030-2022 9"); + encode("\uFE19", "%A6%F3", "GB18030-2022 10"); + encode("\u9FB4", "%FEY", "GB18030-2022 11"); + encode("\u9FB5", "%FEa", "GB18030-2022 12"); + encode("\u9FB6", "%FEf", "GB18030-2022 13"); + encode("\u9FB7", "%FEg", "GB18030-2022 14"); + encode("\u9FB8", "%FEm", "GB18030-2022 15"); + encode("\u9FB9", "%FE~", "GB18030-2022 16"); + encode("\u9FBA", "%FE%90", "GB18030-2022 17"); + encode("\u9FBB", "%FE%A0", "GB18030-2022 18"); + encode("\uE78D", "%841%826", "GB18030-2022 19"); + encode("\uE78E", "%841%828", "GB18030-2022 20"); + encode("\uE78F", "%841%827", "GB18030-2022 21"); + encode("\uE790", "%841%829", "GB18030-2022 22"); + encode("\uE791", "%841%830", "GB18030-2022 23"); + encode("\uE792", "%841%831", "GB18030-2022 24"); + encode("\uE793", "%841%832", "GB18030-2022 25"); + encode("\uE794", "%841%833", "GB18030-2022 26"); + encode("\uE795", "%841%834", "GB18030-2022 27"); + encode("\uE796", "%841%835", "GB18030-2022 28"); + encode("\uE81E", "%825%907", "GB18030-2022 29"); + encode("\uE826", "%825%908", "GB18030-2022 30"); + encode("\uE82B", "%825%909", "GB18030-2022 31"); + encode("\uE82C", "%825%910", "GB18030-2022 32"); + encode("\uE832", "%825%911", "GB18030-2022 33"); + encode("\uE843", "%825%912", "GB18030-2022 34"); + encode("\uE854", "%825%913", "GB18030-2022 35"); + encode("\uE864", "%825%914", "GB18030-2022 36"); + const upperCaseNibble = x => { return Math.floor(x).toString(16).toUpperCase(); } diff --git a/test/fixtures/wpt/encoding/streams/backpressure.any.js b/test/fixtures/wpt/encoding/streams/backpressure.any.js index 22f7f0aa2bc..0f67e335841 100644 --- a/test/fixtures/wpt/encoding/streams/backpressure.any.js +++ b/test/fixtures/wpt/encoding/streams/backpressure.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/encoding/streams/decode-attributes.any.js b/test/fixtures/wpt/encoding/streams/decode-attributes.any.js index 0843cc665fd..f64f45b56ac 100644 --- a/test/fixtures/wpt/encoding/streams/decode-attributes.any.js +++ b/test/fixtures/wpt/encoding/streams/decode-attributes.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/encoding/streams/decode-bad-chunks.any.js b/test/fixtures/wpt/encoding/streams/decode-bad-chunks.any.js index b7b2dd58459..21d61427a2b 100644 --- a/test/fixtures/wpt/encoding/streams/decode-bad-chunks.any.js +++ b/test/fixtures/wpt/encoding/streams/decode-bad-chunks.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/encoding/streams/decode-non-utf8.any.js b/test/fixtures/wpt/encoding/streams/decode-non-utf8.any.js index 2950a9e58ed..effdee3b430 100644 --- a/test/fixtures/wpt/encoding/streams/decode-non-utf8.any.js +++ b/test/fixtures/wpt/encoding/streams/decode-non-utf8.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/encoding/streams/readable-writable-properties.any.js b/test/fixtures/wpt/encoding/streams/readable-writable-properties.any.js index 234649209cf..8084cb99421 100644 --- a/test/fixtures/wpt/encoding/streams/readable-writable-properties.any.js +++ b/test/fixtures/wpt/encoding/streams/readable-writable-properties.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // This just tests that the "readable" and "writable" properties pass the brand // checks. All other relevant attributes are covered by the IDL tests. diff --git a/test/fixtures/wpt/encoding/textdecoder-arguments.any.js b/test/fixtures/wpt/encoding/textdecoder-arguments.any.js index f469dcd30ea..2d137b7aa37 100644 --- a/test/fixtures/wpt/encoding/textdecoder-arguments.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-arguments.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: TextDecoder decode() optional arguments test(t => { diff --git a/test/fixtures/wpt/encoding/textdecoder-byte-order-marks.any.js b/test/fixtures/wpt/encoding/textdecoder-byte-order-marks.any.js index 9ef0d73141a..31350fdf689 100644 --- a/test/fixtures/wpt/encoding/textdecoder-byte-order-marks.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-byte-order-marks.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: Byte-order marks var testCases = [ diff --git a/test/fixtures/wpt/encoding/textdecoder-fatal-streaming.any.js b/test/fixtures/wpt/encoding/textdecoder-fatal-streaming.any.js index 0d58b2e1d7d..9043b43eae2 100644 --- a/test/fixtures/wpt/encoding/textdecoder-fatal-streaming.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-fatal-streaming.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: End-of-file test(function() { diff --git a/test/fixtures/wpt/encoding/textdecoder-fatal.any.js b/test/fixtures/wpt/encoding/textdecoder-fatal.any.js index f9ccb2dfa76..054b35f21f4 100644 --- a/test/fixtures/wpt/encoding/textdecoder-fatal.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-fatal.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: Fatal flag var bad = [ diff --git a/test/fixtures/wpt/encoding/textdecoder-ignorebom.any.js b/test/fixtures/wpt/encoding/textdecoder-ignorebom.any.js index 81f210eec89..e825698ba40 100644 --- a/test/fixtures/wpt/encoding/textdecoder-ignorebom.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-ignorebom.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: TextDecoder ignoreBOM option var cases = [ diff --git a/test/fixtures/wpt/encoding/textdecoder-utf16-surrogates.any.js b/test/fixtures/wpt/encoding/textdecoder-utf16-surrogates.any.js index b08ea56cee3..7e8322cd19c 100644 --- a/test/fixtures/wpt/encoding/textdecoder-utf16-surrogates.any.js +++ b/test/fixtures/wpt/encoding/textdecoder-utf16-surrogates.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: UTF-16 surrogate handling var bad = [ diff --git a/test/fixtures/wpt/encoding/textencoder-utf16-surrogates.any.js b/test/fixtures/wpt/encoding/textencoder-utf16-surrogates.any.js index 014a0ebb12d..31657516455 100644 --- a/test/fixtures/wpt/encoding/textencoder-utf16-surrogates.any.js +++ b/test/fixtures/wpt/encoding/textencoder-utf16-surrogates.any.js @@ -1,3 +1,4 @@ +// META: global=window,dedicatedworker,shadowrealm // META: title=Encoding API: USVString surrogate handling when encoding var bad = [ diff --git a/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html new file mode 100644 index 00000000000..c7cc723da6f --- /dev/null +++ b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers new file mode 100644 index 00000000000..5f8621ef836 --- /dev/null +++ b/test/fixtures/wpt/hr-time/raf-coarsened-time.https.html.headers @@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin diff --git a/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000..fa153f8f965 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/microtask-queuing/queue-microtask-cross-realm-callback-report-exception.html @@ -0,0 +1,28 @@ + + +queueMicrotask() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js index 660477dca4c..00a86fa74b9 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js @@ -9,6 +9,7 @@ * - `postTest()`: An optional, async function run after a test is done * - `structuredClone(obj, transferList)`: Required function that somehow * structurally clones an object. + * Must return a promise. * - `hasDocument`: When true, disables tests that require a document. True by default. */ @@ -30,11 +31,11 @@ function runStructuredCloneBatteryOfTests(runner) { } return new Promise(resolve => { - promise_test(async _ => { + promise_test(async t => { test = await test; await setupPromise; await runner.preTest(test); - await test.f(runner) + await test.f(runner, t) await runner.postTest(test); resolve(); }, test.description); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js index 744f1168196..23cf4f651ac 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js @@ -20,3 +20,150 @@ structuredCloneBatteryOfTests.push({ }); // TODO: ImageBitmap + +structuredCloneBatteryOfTests.push({ + description: 'A detached ArrayBuffer cannot be transferred', + async f(runner, t) { + const buffer = new ArrayBuffer(); + await runner.structuredClone(buffer, [buffer]); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(buffer, [buffer]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'A detached platform object cannot be transferred', + async f(runner, t) { + const {port1} = new MessageChannel(); + await runner.structuredClone(port1, [port1]); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(port1, [port1]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring a non-transferable platform object fails', + async f(runner, t) { + const blob = new Blob(); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(blob, [blob]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'An object whose interface is deleted from the global object must still be received', + async f(runner) { + const {port1} = new MessageChannel(); + const messagePortInterface = globalThis.MessagePort; + delete globalThis.MessagePort; + try { + const transfer = await runner.structuredClone(port1, [port1]); + assert_true(transfer instanceof messagePortInterface); + } finally { + globalThis.MessagePort = messagePortInterface; + } + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'A subclass instance will be received as its closest transferable superclass', + async f(runner) { + // MessagePort doesn't have a constructor, so we must use something else. + + // Make sure that ReadableStream is transferable before we test its subclasses. + try { + const stream = new ReadableStream(); + await runner.structuredClone(stream, [stream]); + } catch(err) { + if (err instanceof DOMException && err.code === DOMException.DATA_CLONE_ERR) { + throw new OptionalFeatureUnsupportedError("ReadableStream isn't transferable"); + } else { + throw err; + } + } + + class ReadableStreamSubclass extends ReadableStream {} + const original = new ReadableStreamSubclass(); + const transfer = await runner.structuredClone(original, [original]); + assert_equals(Object.getPrototypeOf(transfer), ReadableStream.prototype); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Resizable ArrayBuffer is transferable', + async f(runner) { + const buffer = new ArrayBuffer(16, { maxByteLength: 1024 }); + const copy = await runner.structuredClone(buffer, [buffer]); + assert_equals(buffer.byteLength, 0); + assert_equals(copy.byteLength, 16); + assert_equals(copy.maxByteLength, 1024); + assert_true(copy.resizable); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Length-tracking TypedArray is transferable', + async f(runner) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab); + const copy = await runner.structuredClone(ta, [ab]); + assert_equals(ab.byteLength, 0); + assert_equals(copy.buffer.byteLength, 16); + assert_equals(copy.buffer.maxByteLength, 1024); + assert_true(copy.buffer.resizable); + copy.buffer.resize(32); + assert_equals(copy.byteLength, 32); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Length-tracking DataView is transferable', + async f(runner) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab); + const copy = await runner.structuredClone(dv, [ab]); + assert_equals(ab.byteLength, 0); + assert_equals(copy.buffer.byteLength, 16); + assert_equals(copy.buffer.maxByteLength, 1024); + assert_true(copy.buffer.resizable); + copy.buffer.resize(32); + assert_equals(copy.byteLength, 32); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring OOB TypedArray throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(ta, [ab]) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Transferring OOB DataView throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(dv, [ab]) + ); + } +}); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js index 0c96ded2088..923ac9dc164 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-battery-of-tests.js @@ -3,11 +3,6 @@ structuredCloneBatteryOfTests = []; function check(description, input, callback, requiresDocument = false) { - testObjMock = { - done() {}, - step_func(f) {return _ => f()}, - }; - structuredCloneBatteryOfTests.push({ description, async f(runner) { @@ -16,47 +11,41 @@ function check(description, input, callback, requiresDocument = false) { newInput = input(); } const copy = await runner.structuredClone(newInput); - await callback(copy, newInput, testObjMock); + await callback(copy, newInput); }, requiresDocument }); } -function compare_primitive(actual, input, test_obj) { +function compare_primitive(actual, input) { assert_equals(actual, input); - if (test_obj) - test_obj.done(); } -function compare_Array(callback, callback_is_async) { - return function(actual, input, test_obj) { +function compare_Array(callback) { + return async function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Array, 'instanceof Array'); assert_not_equals(actual, input); assert_equals(actual.length, input.length, 'length'); - callback(actual, input); - if (test_obj && !callback_is_async) - test_obj.done(); + await callback(actual, input); } } -function compare_Object(callback, callback_is_async) { - return function(actual, input, test_obj) { +function compare_Object(callback) { + return async function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Object, 'instanceof Object'); assert_false(actual instanceof Array, 'instanceof Array'); assert_not_equals(actual, input); - callback(actual, input); - if (test_obj && !callback_is_async) - test_obj.done(); + await callback(actual, input); } } -function enumerate_props(compare_func, test_obj) { - return function(actual, input) { +function enumerate_props(compare_func) { + return async function(actual, input) { for (const x in input) { - compare_func(actual[x], input[x], test_obj); + await compare_func(actual[x], input[x]); } }; } @@ -127,14 +116,12 @@ check('Object primitives', {'undefined':undefined, '9007199254740994':9007199254740994, '-9007199254740994':-9007199254740994}, compare_Object(enumerate_props(compare_primitive))); -function compare_Boolean(actual, input, test_obj) { +function compare_Boolean(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Boolean, 'instanceof Boolean'); assert_equals(String(actual), String(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } check('Boolean true', new Boolean(true), compare_Boolean); check('Boolean false', new Boolean(false), compare_Boolean); @@ -143,14 +130,12 @@ check('Object Boolean objects', {'true':new Boolean(true), 'false':new Boolean(f function compare_obj(what) { const Type = self[what]; - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Type, 'instanceof '+what); assert_equals(Type(actual), Type(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); }; } check('String empty string', new String(''), compare_obj('String')); @@ -203,14 +188,12 @@ check('Object Number objects', {'0.2':new Number(0.2), '9007199254740994':new Number(9007199254740994), '-9007199254740994':new Number(-9007199254740994)}, compare_Object(enumerate_props(compare_obj('Number')))); -function compare_Date(actual, input, test_obj) { +function compare_Date(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Date, 'instanceof Date'); assert_equals(Number(actual), Number(input), 'converted to primitive'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } check('Date 0', new Date(0), compare_Date); check('Date -0', new Date(-0), compare_Date); @@ -227,7 +210,7 @@ check('Object Date objects', {'0':new Date(0), function compare_RegExp(expected_source) { // XXX ES6 spec doesn't define exact serialization for `source` (it allows several ways to escape) - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof RegExp, 'instanceof RegExp'); @@ -239,8 +222,6 @@ function compare_RegExp(expected_source) { assert_equals(actual.unicode, input.unicode, 'unicode'); assert_equals(actual.lastIndex, 0, 'lastIndex'); assert_not_equals(actual, input); - if (test_obj) - test_obj.done(); } } function func_RegExp_flags_lastIndex() { @@ -273,7 +254,28 @@ check('Object RegExp object, RegExp empty', {'x':new RegExp('')}, compare_Object check('Object RegExp object, RegExp slash', {'x':new RegExp('/')}, compare_Object(enumerate_props(compare_RegExp('\\/')))); check('Object RegExp object, RegExp new line', {'x':new RegExp('\n')}, compare_Object(enumerate_props(compare_RegExp('\\n')))); -async function compare_Blob(actual, input, test_obj, expect_File) { +function compare_Error(actual, input) { + assert_true(actual instanceof Error, "Checking instanceof"); + assert_equals(actual.constructor, input.constructor, "Checking constructor"); + assert_equals(actual.name, input.name, "Checking name"); + assert_equals(actual.hasOwnProperty("message"), input.hasOwnProperty("message"), "Checking message existence"); + assert_equals(actual.message, input.message, "Checking message"); + assert_equals(actual.foo, undefined, "Checking for absence of custom property"); +} + +check('Empty Error object', new Error, compare_Error); + +const errorConstructors = [Error, EvalError, RangeError, ReferenceError, + SyntaxError, TypeError, URIError]; +for (const constructor of errorConstructors) { + check(`${constructor.name} object`, () => { + let error = new constructor("Error message here"); + error.foo = "testing"; + return error; + }, compare_Error); +} + +async function compare_Blob(actual, input, expect_File) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Blob, 'instanceof Blob'); @@ -333,33 +335,33 @@ function func_Blob_NUL() { } check('Blob NUL', func_Blob_NUL, compare_Blob); -check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob), true)); -check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true)); - -check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])() }, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob), true)); -check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob), true)); - -function compare_File(actual, input, test_obj) { +check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob))); +check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob))); + +check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])() }, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob))); +check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob))); + +async function compare_File(actual, input) { assert_true(actual instanceof File, 'instanceof File'); assert_equals(actual.name, input.name, 'name'); assert_equals(actual.lastModified, input.lastModified, 'lastModified'); - compare_Blob(actual, input, test_obj, true); + await compare_Blob(actual, input, true); } function func_File_basic() { return new File(['foo'], 'bar', {type:'text/x-bar', lastModified:42}); } check('File basic', func_File_basic, compare_File); -function compare_FileList(actual, input, test_obj) { +function compare_FileList(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof FileList, 'instanceof FileList'); @@ -367,8 +369,6 @@ function compare_FileList(actual, input, test_obj) { assert_not_equals(actual, input); // XXX when there's a way to populate or construct a FileList, // check the items in the FileList - if (test_obj) - test_obj.done(); } function func_FileList_empty() { const input = document.createElement('input'); @@ -379,30 +379,36 @@ check('FileList empty', func_FileList_empty, compare_FileList, true); check('Array FileList object, FileList empty', () => ([func_FileList_empty()]), compare_Array(enumerate_props(compare_FileList)), true); check('Object FileList object, FileList empty', () => ({'x':func_FileList_empty()}), compare_Object(enumerate_props(compare_FileList)), true); +function compare_ArrayBuffer(actual, input) { + assert_true(actual instanceof ArrayBuffer, 'instanceof ArrayBuffer'); + assert_equals(actual.byteLength, input.byteLength, 'byteLength'); + assert_equals(actual.maxByteLength, input.maxByteLength, 'maxByteLength'); + assert_equals(actual.resizable, input.resizable, 'resizable'); + assert_equals(actual.growable, input.growable, 'growable'); +} + function compare_ArrayBufferView(view) { const Type = self[view]; - return function(actual, input, test_obj) { + return function(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_true(actual instanceof Type, 'instanceof '+view); assert_equals(actual.length, input.length, 'length'); + assert_equals(actual.byteLength, input.byteLength, 'byteLength'); + assert_equals(actual.byteOffset, input.byteOffset, 'byteOffset'); assert_not_equals(actual.buffer, input.buffer, 'buffer'); for (let i = 0; i < actual.length; ++i) { assert_equals(actual[i], input[i], 'actual['+i+']'); } - if (test_obj) - test_obj.done(); }; } -function compare_ImageData(actual, input, test_obj) { +function compare_ImageData(actual, input) { if (typeof actual === 'string') assert_unreached(actual); assert_equals(actual.width, input.width, 'width'); assert_equals(actual.height, input.height, 'height'); assert_not_equals(actual.data, input.data, 'data'); compare_ArrayBufferView('Uint8ClampedArray')(actual.data, input.data, null); - if (test_obj) - test_obj.done(); } function func_ImageData_1x1_transparent_black() { const canvas = document.createElement('canvas'); @@ -506,6 +512,23 @@ check('Object with non-configurable property', function() { return rv; }, compare_Object(check_configurable_property('foo'))); +structuredCloneBatteryOfTests.push({ + description: 'Object with a getter that throws', + async f(runner, t) { + const exception = new Error(); + const testObject = { + get testProperty() { + throw exception; + } + }; + await promise_rejects_exactly( + t, + exception, + runner.structuredClone(testObject) + ); + } +}); + /* The tests below are inspired by @zcorpan’s work but got some more substantial changed due to their previous async setup */ @@ -616,3 +639,115 @@ check('ObjectPrototype must lose its exotic-ness when cloned', assert_equals(Object.getPrototypeOf(copy), newProto); } ); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing a non-serializable platform object fails', + async f(runner, t) { + const request = new Response(); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(request) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'An object whose interface is deleted from the global must still deserialize', + async f(runner) { + const blob = new Blob(); + const blobInterface = globalThis.Blob; + delete globalThis.Blob; + try { + const copy = await runner.structuredClone(blob); + assert_true(copy instanceof blobInterface); + } finally { + globalThis.Blob = blobInterface; + } + } +}); + +check( + 'A subclass instance will deserialize as its closest serializable superclass', + () => { + class FileSubclass extends File {} + return new FileSubclass([], ""); + }, + (copy) => { + assert_equals(Object.getPrototypeOf(copy), File.prototype); + } +); + +check( + 'Resizable ArrayBuffer', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return ab; + }, + compare_ArrayBuffer); + +structuredCloneBatteryOfTests.push({ + description: 'Growable SharedArrayBuffer', + async f(runner) { + const sab = createBuffer('SharedArrayBuffer', 16, { maxByteLength: 1024 }); + assert_true(sab.growable); + try { + const copy = await runner.structuredClone(sab); + compare_ArrayBuffer(sab, copy); + } catch (e) { + // If we're cross-origin isolated, cloning SABs should not fail. + if (e instanceof DOMException && e.code === DOMException.DATA_CLONE_ERR) { + assert_false(self.crossOriginIsolated); + } else { + throw e; + } + } + } +}); + +check( + 'Length-tracking TypedArray', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return new Uint8Array(ab); + }, + compare_ArrayBufferView('Uint8Array')); + +check( + 'Length-tracking DataView', + () => { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + assert_true(ab.resizable); + return new DataView(ab); + }, + compare_ArrayBufferView('DataView')); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing OOB TypedArray throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const ta = new Uint8Array(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(ta) + ); + } +}); + +structuredCloneBatteryOfTests.push({ + description: 'Serializing OOB DataView throws', + async f(runner, t) { + const ab = new ArrayBuffer(16, { maxByteLength: 1024 }); + const dv = new DataView(ab, 8); + ab.resize(0); + await promise_rejects_dom( + t, + "DataCloneError", + runner.structuredClone(dv) + ); + } +}); diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html new file mode 100644 index 00000000000..d80010e0df7 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-cross-realm-method.html @@ -0,0 +1,20 @@ + +self.structuredClone() uses this's relevant Realm for deserialization + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html new file mode 100644 index 00000000000..75971023d2d --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone-detached-window-crash.html @@ -0,0 +1,11 @@ + +window.structuredClone() doesn't crash when window is detached + + + diff --git a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js index 34f96f33fdf..1358a71fc03 100644 --- a/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js +++ b/test/fixtures/wpt/html/webappapis/structured-clone/structured-clone.any.js @@ -1,9 +1,14 @@ // META: title=structuredClone() tests +// META: script=/common/sab.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js // META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js runStructuredCloneBatteryOfTests({ - structuredClone: (obj, transfer) => self.structuredClone(obj, { transfer }), + structuredClone: (obj, transfer) => { + return new Promise(resolve => { + resolve(self.structuredClone(obj, { transfer })); + }); + }, hasDocument: typeof document !== "undefined", }); diff --git a/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js b/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js new file mode 100644 index 00000000000..bf4eb7cf5ac --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/clearinterval-from-callback.any.js @@ -0,0 +1,19 @@ +async_test((t) => { + let wasPreviouslyCalled = false; + + const handle = setInterval( + t.step_func(() => { + if (!wasPreviouslyCalled) { + wasPreviouslyCalled = true; + + clearInterval(handle); + + // Make the test succeed after the callback would've run next. + setInterval(t.step_func_done(), 750); + } else { + assert_unreached(); + } + }), + 500 + ); +}, "Clearing an interval from the callback should still clear it."); diff --git a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js new file mode 100644 index 00000000000..17215e218a9 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.any.js @@ -0,0 +1,12 @@ +var t = async_test("Interaction of setTimeout and WebIDL") +function finishTest() { + assert_equals(log, "ONE TWO ") + t.done() +} +var log = ''; +function logger(s) { log += s + ' '; } + +setTimeout({ toString: function () { + setTimeout("logger('ONE')", 100); + return "logger('TWO'); t.step(finishTest)"; +} }, 100); diff --git a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html b/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html deleted file mode 100644 index 77a8746908d..00000000000 --- a/test/fixtures/wpt/html/webappapis/timers/evil-spec-example.html +++ /dev/null @@ -1,23 +0,0 @@ - -Interaction of setTimeout and WebIDL - - - - - - -
- diff --git a/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000..4a780fc9329 --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/setinterval-cross-realm-callback-report-exception.html @@ -0,0 +1,32 @@ + + +window.setInterval() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html b/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html new file mode 100644 index 00000000000..b4860151a6c --- /dev/null +++ b/test/fixtures/wpt/html/webappapis/timers/settimeout-cross-realm-callback-report-exception.html @@ -0,0 +1,28 @@ + + +window.setTimeout() reports the exception from its callback in the callback's global object + + + + + + diff --git a/test/fixtures/wpt/interfaces/dom.idl b/test/fixtures/wpt/interfaces/dom.idl index 96acfc6a717..c2def872fa2 100644 --- a/test/fixtures/wpt/interfaces/dom.idl +++ b/test/fixtures/wpt/interfaces/dom.idl @@ -95,6 +95,7 @@ interface AbortController { interface AbortSignal : EventTarget { [NewObject] static AbortSignal abort(optional any reason); [Exposed=(Window,Worker), NewObject] static AbortSignal timeout([EnforceRange] unsigned long long milliseconds); + [NewObject] static AbortSignal _any(sequence signals); readonly attribute boolean aborted; readonly attribute any reason; @@ -618,7 +619,7 @@ callback interface XPathNSResolver { interface mixin XPathEvaluatorBase { [NewObject] XPathExpression createExpression(DOMString expression, optional XPathNSResolver? resolver = null); - XPathNSResolver createNSResolver(Node nodeResolver); + Node createNSResolver(Node nodeResolver); // legacy // XPathResult.ANY_TYPE = 0 XPathResult evaluate(DOMString expression, Node contextNode, optional XPathNSResolver? resolver = null, optional unsigned short type = 0, optional XPathResult? result = null); }; diff --git a/test/fixtures/wpt/interfaces/encoding.idl b/test/fixtures/wpt/interfaces/encoding.idl index a8cbe4431a2..a9499f62378 100644 --- a/test/fixtures/wpt/interfaces/encoding.idl +++ b/test/fixtures/wpt/interfaces/encoding.idl @@ -22,7 +22,7 @@ dictionary TextDecodeOptions { interface TextDecoder { constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options = {}); - USVString decode(optional [AllowShared] BufferSource input, optional TextDecodeOptions options = {}); + USVString decode(optional AllowSharedBufferSource input, optional TextDecodeOptions options = {}); }; TextDecoder includes TextDecoderCommon; diff --git a/test/fixtures/wpt/interfaces/hr-time.idl b/test/fixtures/wpt/interfaces/hr-time.idl index 13aa109b6c7..835ee8a65c8 100644 --- a/test/fixtures/wpt/interfaces/hr-time.idl +++ b/test/fixtures/wpt/interfaces/hr-time.idl @@ -7,7 +7,7 @@ typedef double DOMHighResTimeStamp; typedef unsigned long long EpochTimeStamp; -[Exposed=*] +[Exposed=(Window,Worker)] interface Performance : EventTarget { DOMHighResTimeStamp now(); readonly attribute DOMHighResTimeStamp timeOrigin; diff --git a/test/fixtures/wpt/interfaces/html.idl b/test/fixtures/wpt/interfaces/html.idl index d9068b4ad1e..c7f744ccbe6 100644 --- a/test/fixtures/wpt/interfaces/html.idl +++ b/test/fixtures/wpt/interfaces/html.idl @@ -98,7 +98,6 @@ partial interface Document { // also has obsolete members }; Document includes GlobalEventHandlers; -Document includes DocumentAndElementEventHandlers; partial interface mixin DocumentOrShadowRoot { readonly attribute Element? activeElement; @@ -128,10 +127,15 @@ interface HTMLElement : Element { [CEReactions] attribute [LegacyNullToEmptyString] DOMString outerText; ElementInternals attachInternals(); + + // The popover API + undefined showPopover(); + undefined hidePopover(); + boolean togglePopover(optional boolean force); + [CEReactions] attribute DOMString? popover; }; HTMLElement includes GlobalEventHandlers; -HTMLElement includes DocumentAndElementEventHandlers; HTMLElement includes ElementContentEditable; HTMLElement includes HTMLOrSVGElement; @@ -204,6 +208,7 @@ interface HTMLLinkElement : HTMLElement { [CEReactions] attribute DOMString referrerPolicy; [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking; [CEReactions] attribute boolean disabled; + [CEReactions] attribute DOMString fetchPriority; // also has obsolete members }; @@ -432,6 +437,7 @@ interface HTMLImageElement : HTMLElement { [CEReactions] attribute DOMString referrerPolicy; [CEReactions] attribute DOMString decoding; [CEReactions] attribute DOMString loading; + [CEReactions] attribute DOMString fetchPriority; Promise decode(); @@ -886,7 +892,7 @@ interface HTMLInputElement : HTMLElement { [CEReactions] attribute DOMString formTarget; [CEReactions] attribute unsigned long height; attribute boolean indeterminate; - readonly attribute HTMLElement? list; + readonly attribute HTMLDataListElement? list; [CEReactions] attribute DOMString max; [CEReactions] attribute long maxLength; [CEReactions] attribute DOMString min; @@ -931,6 +937,7 @@ interface HTMLInputElement : HTMLElement { // also has obsolete members }; +HTMLInputElement includes PopoverInvokerElement; [Exposed=Window] interface HTMLButtonElement : HTMLElement { @@ -956,6 +963,7 @@ interface HTMLButtonElement : HTMLElement { readonly attribute NodeList labels; }; +HTMLButtonElement includes PopoverInvokerElement; [Exposed=Window] interface HTMLSelectElement : HTMLElement { @@ -1216,6 +1224,7 @@ interface HTMLScriptElement : HTMLElement { [CEReactions] attribute DOMString integrity; [CEReactions] attribute DOMString referrerPolicy; [SameObject, PutForwards=value] readonly attribute DOMTokenList blocking; + [CEReactions] attribute DOMString fetchPriority; static boolean supports(DOMString type); @@ -1364,14 +1373,7 @@ interface mixin CanvasShadowStyles { interface mixin CanvasFilters { // filters - attribute (DOMString or CanvasFilter) filter; // (default "none") -}; - -typedef record CanvasFilterInput; - -[Exposed=(Window,Worker,PaintWorklet)] -interface CanvasFilter { - constructor(optional (CanvasFilterInput or sequence) filters); + attribute DOMString filter; // (default "none") }; interface mixin CanvasRect { @@ -1592,6 +1594,7 @@ OffscreenCanvasRenderingContext2D includes CanvasPath; interface CustomElementRegistry { [CEReactions] undefined define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {}); (CustomElementConstructor or undefined) get(DOMString name); + DOMString? getName(CustomElementConstructor constructor); Promise whenDefined(DOMString name); [CEReactions] undefined upgrade(Node root); }; @@ -1641,8 +1644,39 @@ dictionary ValidityStateFlags { boolean customError = false; }; +[Exposed=(Window)] +interface VisibilityStateEntry : PerformanceEntry { + readonly attribute DOMString name; // shadows inherited name + readonly attribute DOMString entryType; // shadows inherited entryType + readonly attribute DOMHighResTimeStamp startTime; // shadows inherited startTime + readonly attribute unsigned long duration; // shadows inherited duration +}; + +[Exposed=Window] +interface UserActivation { + readonly attribute boolean hasBeenActive; + readonly attribute boolean isActive; +}; + +partial interface Navigator { + [SameObject] readonly attribute UserActivation userActivation; +}; + +[Exposed=Window] +interface ToggleEvent : Event { + constructor(DOMString type, optional ToggleEventInit eventInitDict = {}); + readonly attribute DOMString oldState; + readonly attribute DOMString newState; +}; + +dictionary ToggleEventInit : EventInit { + DOMString oldState = ""; + DOMString newState = ""; +}; + dictionary FocusOptions { boolean preventScroll = false; + boolean focusVisible; }; interface mixin ElementContentEditable { @@ -1702,6 +1736,11 @@ dictionary DragEventInit : MouseEventInit { DataTransfer? dataTransfer = null; }; +interface mixin PopoverInvokerElement { + [CEReactions] attribute Element? popoverTargetElement; + [CEReactions] attribute DOMString popoverTargetAction; +}; + [Global=Window, Exposed=Window, LegacyUnenumerableNamedProperties] @@ -1713,6 +1752,7 @@ interface Window : EventTarget { attribute DOMString name; [PutForwards=href, LegacyUnforgeable] readonly attribute Location location; readonly attribute History history; + readonly attribute Navigation navigation; readonly attribute CustomElementRegistry customElements; [Replaceable] readonly attribute BarProp locationbar; [Replaceable] readonly attribute BarProp menubar; @@ -1735,14 +1775,15 @@ interface Window : EventTarget { [Replaceable] readonly attribute WindowProxy? parent; readonly attribute Element? frameElement; WindowProxy? open(optional USVString url = "", optional DOMString target = "_blank", optional [LegacyNullToEmptyString] DOMString features = ""); - getter object (DOMString name); + // Since this is the global object, the IDL named getter adds a NamedPropertiesObject exotic // object on the prototype chain. Indeed, this does not make the global object an exotic object. // Indexed access is taken care of by the WindowProxy exotic object. + getter object (DOMString name); // the user agent readonly attribute Navigator navigator; - readonly attribute Navigator clientInformation; // legacy alias of .navigator + [Replaceable] readonly attribute Navigator clientInformation; // legacy alias of .navigator readonly attribute boolean originAgentCluster; // user prompts @@ -1769,20 +1810,6 @@ interface BarProp { readonly attribute boolean visible; }; -enum ScrollRestoration { "auto", "manual" }; - -[Exposed=Window] -interface History { - readonly attribute unsigned long length; - attribute ScrollRestoration scrollRestoration; - readonly attribute any state; - undefined go(optional long delta = 0); - undefined back(); - undefined forward(); - undefined pushState(any data, DOMString unused, optional USVString? url = null); - undefined replaceState(any data, DOMString unused, optional USVString? url = null); -}; - [Exposed=Window] interface Location { // but see also additional creation steps and overridden internal methods [LegacyUnforgeable] stringifier attribute USVString href; @@ -1802,15 +1829,183 @@ interface Location { // but see also additional creation steps and overridden in [LegacyUnforgeable, SameObject] readonly attribute DOMStringList ancestorOrigins; }; +enum ScrollRestoration { "auto", "manual" }; + +[Exposed=Window] +interface History { + readonly attribute unsigned long length; + attribute ScrollRestoration scrollRestoration; + readonly attribute any state; + undefined go(optional long delta = 0); + undefined back(); + undefined forward(); + undefined pushState(any data, DOMString unused, optional USVString? url = null); + undefined replaceState(any data, DOMString unused, optional USVString? url = null); +}; + +[Exposed=Window] +interface Navigation : EventTarget { + sequence entries(); + readonly attribute NavigationHistoryEntry? currentEntry; + undefined updateCurrentEntry(NavigationUpdateCurrentEntryOptions options); + readonly attribute NavigationTransition? transition; + + readonly attribute boolean canGoBack; + readonly attribute boolean canGoForward; + + NavigationResult navigate(USVString url, optional NavigationNavigateOptions options = {}); + NavigationResult reload(optional NavigationReloadOptions options = {}); + + NavigationResult traverseTo(DOMString key, optional NavigationOptions options = {}); + NavigationResult back(optional NavigationOptions options = {}); + NavigationResult forward(optional NavigationOptions options = {}); + + attribute EventHandler onnavigate; + attribute EventHandler onnavigatesuccess; + attribute EventHandler onnavigateerror; + attribute EventHandler oncurrententrychange; +}; + +dictionary NavigationUpdateCurrentEntryOptions { + required any state; +}; + +dictionary NavigationOptions { + any info; +}; + +dictionary NavigationNavigateOptions : NavigationOptions { + any state; + NavigationHistoryBehavior history = "auto"; +}; + +dictionary NavigationReloadOptions : NavigationOptions { + any state; +}; + +dictionary NavigationResult { + Promise committed; + Promise finished; +}; + +enum NavigationHistoryBehavior { + "auto", + "push", + "replace" +}; + +enum NavigationType { + "push", + "replace", + "reload", + "traverse" +}; + +[Exposed=Window] +interface NavigationHistoryEntry : EventTarget { + readonly attribute USVString? url; + readonly attribute DOMString key; + readonly attribute DOMString id; + readonly attribute long long index; + readonly attribute boolean sameDocument; + + any getState(); + + attribute EventHandler ondispose; +}; + +[Exposed=Window] +interface NavigationTransition { + readonly attribute NavigationType navigationType; + readonly attribute NavigationHistoryEntry from; + readonly attribute Promise finished; +}; + +[Exposed=Window] +interface NavigateEvent : Event { + constructor(DOMString type, NavigateEventInit eventInitDict); + + readonly attribute NavigationType navigationType; + readonly attribute NavigationDestination destination; + readonly attribute boolean canIntercept; + readonly attribute boolean userInitiated; + readonly attribute boolean hashChange; + readonly attribute AbortSignal signal; + readonly attribute FormData? formData; + readonly attribute DOMString? downloadRequest; + readonly attribute any info; + readonly attribute boolean hasUAVisualTransition; + + undefined intercept(optional NavigationInterceptOptions options = {}); + undefined scroll(); +}; + +dictionary NavigateEventInit : EventInit { + NavigationType navigationType = "push"; + required NavigationDestination destination; + boolean canIntercept = false; + boolean userInitiated = false; + boolean hashChange = false; + required AbortSignal signal; + FormData? formData = null; + DOMString? downloadRequest = null; + any info; + boolean hasUAVisualTransition = false; +}; + +dictionary NavigationInterceptOptions { + NavigationInterceptHandler handler; + NavigationFocusReset focusReset; + NavigationScrollBehavior scroll; +}; + +enum NavigationFocusReset { + "after-transition", + "manual" +}; + +enum NavigationScrollBehavior { + "after-transition", + "manual" +}; + +callback NavigationInterceptHandler = Promise (); + +[Exposed=Window] +interface NavigationDestination { + readonly attribute USVString url; + readonly attribute DOMString key; + readonly attribute DOMString id; + readonly attribute long long index; + readonly attribute boolean sameDocument; + + any getState(); +}; + +[Exposed=Window] +interface NavigationCurrentEntryChangeEvent : Event { + constructor(DOMString type, NavigationCurrentEntryChangeEventInit eventInitDict); + + readonly attribute NavigationType? navigationType; + readonly attribute NavigationHistoryEntry from; +}; + +dictionary NavigationCurrentEntryChangeEventInit : EventInit { + NavigationType? navigationType = null; + required NavigationHistoryEntry from; +}; + [Exposed=Window] interface PopStateEvent : Event { constructor(DOMString type, optional PopStateEventInit eventInitDict = {}); readonly attribute any state; + readonly attribute boolean hasUAVisualTransition; }; dictionary PopStateEventInit : EventInit { any state = null; + boolean hasUAVisualTransition = false; }; [Exposed=Window] @@ -1891,6 +2086,7 @@ interface mixin GlobalEventHandlers { attribute EventHandler onauxclick; attribute EventHandler onbeforeinput; attribute EventHandler onbeforematch; + attribute EventHandler onbeforetoggle; attribute EventHandler onblur; attribute EventHandler oncancel; attribute EventHandler oncanplay; @@ -1901,7 +2097,9 @@ interface mixin GlobalEventHandlers { attribute EventHandler oncontextlost; attribute EventHandler oncontextmenu; attribute EventHandler oncontextrestored; + attribute EventHandler oncopy; attribute EventHandler oncuechange; + attribute EventHandler oncut; attribute EventHandler ondblclick; attribute EventHandler ondrag; attribute EventHandler ondragend; @@ -1932,6 +2130,7 @@ interface mixin GlobalEventHandlers { attribute EventHandler onmouseout; attribute EventHandler onmouseover; attribute EventHandler onmouseup; + attribute EventHandler onpaste; attribute EventHandler onpause; attribute EventHandler onplay; attribute EventHandler onplaying; @@ -1940,6 +2139,7 @@ interface mixin GlobalEventHandlers { attribute EventHandler onreset; attribute EventHandler onresize; attribute EventHandler onscroll; + attribute EventHandler onscrollend; attribute EventHandler onsecuritypolicyviolation; attribute EventHandler onseeked; attribute EventHandler onseeking; @@ -1978,12 +2178,6 @@ interface mixin WindowEventHandlers { attribute EventHandler onunload; }; -interface mixin DocumentAndElementEventHandlers { - attribute EventHandler oncopy; - attribute EventHandler oncut; - attribute EventHandler onpaste; -}; - typedef (DOMString or Function) TimerHandler; interface mixin WindowOrWorkerGlobalScope { @@ -2132,13 +2326,13 @@ typedef (CanvasImageSource or Blob or ImageData) ImageBitmapSource; -enum ImageOrientation { "none", "flipY" }; +enum ImageOrientation { "from-image", "flipY" }; enum PremultiplyAlpha { "none", "premultiply", "default" }; enum ColorSpaceConversion { "none", "default" }; enum ResizeQuality { "pixelated", "low", "medium", "high" }; dictionary ImageBitmapOptions { - ImageOrientation imageOrientation = "none"; + ImageOrientation imageOrientation = "from-image"; PremultiplyAlpha premultiplyAlpha = "default"; ColorSpaceConversion colorSpaceConversion = "default"; [EnforceRange] unsigned long resizeWidth; diff --git a/test/fixtures/wpt/interfaces/performance-timeline.idl b/test/fixtures/wpt/interfaces/performance-timeline.idl index 9f6cc5e2e90..cdd8fafd8c6 100644 --- a/test/fixtures/wpt/interfaces/performance-timeline.idl +++ b/test/fixtures/wpt/interfaces/performance-timeline.idl @@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: Performance Timeline Level 2 (https://w3c.github.io/performance-timeline/) +// Source: Performance Timeline (https://w3c.github.io/performance-timeline/) partial interface Performance { PerformanceEntryList getEntries (); @@ -10,7 +10,7 @@ partial interface Performance { }; typedef sequence PerformanceEntryList; -[Exposed=*] +[Exposed=(Window,Worker)] interface PerformanceEntry { readonly attribute DOMString name; readonly attribute DOMString entryType; @@ -22,7 +22,7 @@ interface PerformanceEntry { callback PerformanceObserverCallback = undefined (PerformanceObserverEntryList entries, PerformanceObserver observer, optional PerformanceObserverCallbackOptions options = {}); -[Exposed=*] +[Exposed=(Window,Worker)] interface PerformanceObserver { constructor(PerformanceObserverCallback callback); undefined observe (optional PerformanceObserverInit options = {}); @@ -41,7 +41,7 @@ dictionary PerformanceObserverInit { boolean buffered; }; -[Exposed=*] +[Exposed=(Window,Worker)] interface PerformanceObserverEntryList { PerformanceEntryList getEntries(); PerformanceEntryList getEntriesByType (DOMString type); diff --git a/test/fixtures/wpt/interfaces/resource-timing.idl b/test/fixtures/wpt/interfaces/resource-timing.idl index 235963b804b..33fed05b756 100644 --- a/test/fixtures/wpt/interfaces/resource-timing.idl +++ b/test/fixtures/wpt/interfaces/resource-timing.idl @@ -1,11 +1,12 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: Resource Timing Level 2 (https://w3c.github.io/resource-timing/) +// Source: Resource Timing (https://w3c.github.io/resource-timing/) [Exposed=(Window,Worker)] interface PerformanceResourceTiming : PerformanceEntry { readonly attribute DOMString initiatorType; + readonly attribute DOMString deliveryType; readonly attribute ByteString nextHopProtocol; readonly attribute DOMHighResTimeStamp workerStart; readonly attribute DOMHighResTimeStamp redirectStart; @@ -17,14 +18,23 @@ interface PerformanceResourceTiming : PerformanceEntry { readonly attribute DOMHighResTimeStamp connectEnd; readonly attribute DOMHighResTimeStamp secureConnectionStart; readonly attribute DOMHighResTimeStamp requestStart; + readonly attribute DOMHighResTimeStamp firstInterimResponseStart; readonly attribute DOMHighResTimeStamp responseStart; readonly attribute DOMHighResTimeStamp responseEnd; readonly attribute unsigned long long transferSize; readonly attribute unsigned long long encodedBodySize; readonly attribute unsigned long long decodedBodySize; + readonly attribute unsigned short responseStatus; + readonly attribute RenderBlockingStatusType renderBlockingStatus; + readonly attribute DOMString contentType; [Default] object toJSON(); }; +enum RenderBlockingStatusType { + "blocking", + "non-blocking" +}; + partial interface Performance { undefined clearResourceTimings (); undefined setResourceTimingBufferSize (unsigned long maxSize); diff --git a/test/fixtures/wpt/interfaces/streams.idl b/test/fixtures/wpt/interfaces/streams.idl index fd5420f16a0..838bf39c6d6 100644 --- a/test/fixtures/wpt/interfaces/streams.idl +++ b/test/fixtures/wpt/interfaces/streams.idl @@ -7,6 +7,8 @@ interface ReadableStream { constructor(optional object underlyingSource, optional QueuingStrategy strategy = {}); + static ReadableStream from(any asyncIterable); + readonly attribute boolean locked; Promise cancel(optional any reason); diff --git a/test/fixtures/wpt/interfaces/url.idl b/test/fixtures/wpt/interfaces/url.idl index 360c9adcfa1..a5e4d1eb492 100644 --- a/test/fixtures/wpt/interfaces/url.idl +++ b/test/fixtures/wpt/interfaces/url.idl @@ -8,6 +8,8 @@ interface URL { constructor(USVString url, optional USVString base); + static boolean canParse(USVString url, optional USVString base); + stringifier attribute USVString href; readonly attribute USVString origin; attribute USVString protocol; @@ -28,11 +30,13 @@ interface URL { interface URLSearchParams { constructor(optional (sequence> or record or USVString) init = ""); + readonly attribute unsigned long size; + undefined append(USVString name, USVString value); - undefined delete(USVString name); + undefined delete(USVString name, optional USVString value); USVString? get(USVString name); sequence getAll(USVString name); - boolean has(USVString name); + boolean has(USVString name, optional USVString value); undefined set(USVString name, USVString value); undefined sort(); diff --git a/test/fixtures/wpt/interfaces/user-timing.idl b/test/fixtures/wpt/interfaces/user-timing.idl index a0b8f94710e..28ee8aac2b1 100644 --- a/test/fixtures/wpt/interfaces/user-timing.idl +++ b/test/fixtures/wpt/interfaces/user-timing.idl @@ -22,13 +22,13 @@ partial interface Performance { undefined clearMeasures(optional DOMString measureName); }; -[Exposed=*] +[Exposed=(Window,Worker)] interface PerformanceMark : PerformanceEntry { constructor(DOMString markName, optional PerformanceMarkOptions markOptions = {}); readonly attribute any detail; }; -[Exposed=*] +[Exposed=(Window,Worker)] interface PerformanceMeasure : PerformanceEntry { readonly attribute any detail; }; diff --git a/test/fixtures/wpt/interfaces/webidl.idl b/test/fixtures/wpt/interfaces/webidl.idl index 43748c5ac4c..4d0dfaa1062 100644 --- a/test/fixtures/wpt/interfaces/webidl.idl +++ b/test/fixtures/wpt/interfaces/webidl.idl @@ -9,7 +9,8 @@ typedef (Int8Array or Int16Array or Int32Array or Float32Array or Float64Array or DataView) ArrayBufferView; typedef (ArrayBufferView or ArrayBuffer) BufferSource; -[Exposed=(Window,Worker), +typedef (ArrayBuffer or SharedArrayBuffer or [AllowShared] ArrayBufferView) AllowSharedBufferSource; +[Exposed=*, Serializable] interface DOMException { // but see below note about ECMAScript binding constructor(optional DOMString message = "", optional DOMString name = "Error"); @@ -46,5 +47,3 @@ interface DOMException { // but see below note about ECMAScript binding callback Function = any (any... arguments); callback VoidFunction = undefined (); - -typedef unsigned long long DOMTimeStamp; diff --git a/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html b/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html new file mode 100644 index 00000000000..c673e09cb46 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/back-forward-cache-restoration.tentative.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js b/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js new file mode 100644 index 00000000000..4de816bdc42 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/droppedentriescount.any.js @@ -0,0 +1,81 @@ +promise_test(t => { + // This setup is required for later tests as well. + // Await for a dropped entry. + return new Promise(res => { + // Set a buffer size of 0 so that new resource entries count as dropped. + performance.setResourceTimingBufferSize(0); + // Use an observer to make sure the promise is resolved only when the + // new entry has been created. + new PerformanceObserver(res).observe({type: 'resource'}); + fetch('resources/square.png?id=1'); + }).then(() => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 0); + resolve(); + })).observe({type: 'mark'}); + performance.mark('test'); + })}); +}, 'Dropped entries count is 0 when there are no dropped entries of relevant type.'); + +promise_test(async t => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 1); + resolve(); + })).observe({entryTypes: ['mark', 'resource']}); + performance.mark('meow'); + }); +}, 'Dropped entries correctly counted with multiple types.'); + +promise_test(t => { + return new Promise(resolve => { + new PerformanceObserver(t.step_func((entries, obs, options) => { + assert_equals(options['droppedEntriesCount'], 1, + 'There should have been some dropped resource timing entries at this point'); + resolve(); + })).observe({type: 'resource', buffered: true}); + }); +}, 'Dropped entries counted even if observer was not registered at the time.'); + +promise_test(t => { + return new Promise(resolve => { + let callback_ran = false; + new PerformanceObserver(t.step_func((entries, obs, options) => { + if (!callback_ran) { + assert_equals(options['droppedEntriesCount'], 2, + 'There should be two dropped entries right now.'); + fetch('resources/square.png?id=3'); + callback_ran = true; + } else { + assert_equals(options['droppedEntriesCount'], undefined, + 'droppedEntriesCount should be unset after the first callback!'); + resolve(); + } + })).observe({type: 'resource'}); + fetch('resources/square.png?id=2'); + }); +}, 'Dropped entries only surfaced on the first callback.'); + + +promise_test(t => { + return new Promise(resolve => { + let callback_ran = false; + let droppedEntriesCount = -1; + new PerformanceObserver(t.step_func((entries, obs, options) => { + if (!callback_ran) { + assert_greater_than(options['droppedEntriesCount'], 0, + 'There should be several dropped entries right now.'); + droppedEntriesCount = options['droppedEntriesCount']; + callback_ran = true; + obs.observe({type: 'mark'}); + performance.mark('woof'); + } else { + assert_equals(options['droppedEntriesCount'], droppedEntriesCount, + 'There should be droppedEntriesCount due to the new observe().'); + resolve(); + } + })).observe({type: 'resource'}); + fetch('resources/square.png?id=4'); + }); +}, 'Dropped entries surfaced after an observe() call!'); diff --git a/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js b/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js new file mode 100644 index 00000000000..6caaa330613 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/idlharness-shadowrealm.window.js @@ -0,0 +1,2 @@ +// META: script=/resources/idlharness-shadowrealm.js +idl_test_shadowrealm(["performance-timeline"], ["hr-time", "dom"]); diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html new file mode 100644 index 00000000000..add11255af4 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-detached-frame.tentative.html @@ -0,0 +1,30 @@ + + + + + + The navigation_id Detached iframe Parent Page. + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html new file mode 100644 index 00000000000..7ff415530bc --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-element-timing.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html new file mode 100644 index 00000000000..93ddcff062e --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-initial-load.tentative.html @@ -0,0 +1,49 @@ + + + + + + + +

This text is to trigger a LCP entry emission.

+ + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html new file mode 100644 index 00000000000..e1da9100aee --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-long-task-task-attribution.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html new file mode 100644 index 00000000000..30613ebb980 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-mark-measure.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html new file mode 100644 index 00000000000..f5a2428e5f5 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-reset.tentative.html @@ -0,0 +1,53 @@ + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html b/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html new file mode 100644 index 00000000000..6d0614a6e23 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-resource-timing.tentative.html @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html b/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html new file mode 100644 index 00000000000..96fc57be1d4 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id-worker-created-entries.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/navigation-id.helper.js b/test/fixtures/wpt/performance-timeline/navigation-id.helper.js new file mode 100644 index 00000000000..1b72fe9908d --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/navigation-id.helper.js @@ -0,0 +1,144 @@ +// The test functions called in the navigation-counter test. They rely on +// artifacts defined in +// '/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js' +// which should be included before this file to use these functions. + +// This function is to obtain navigation ids of all performance entries to +// verify. +let testInitial = () => { + return window.performance.getEntries().map(e => e.navigationId); +} + +let testMarkMeasure = (markId, markName, MeasureName) => { + const markName1 = 'test-mark'; + const markName2 = 'test-mark' + markId; + const measureName = 'test-measure' + markId; + + window.performance.mark(markName1); + window.performance.mark(markName2); + window.performance.measure(measureName, markName1, markName2); + return window.performance.getEntriesByName(markName2).concat( + window.performance.getEntriesByName(measureName)).map(e => e.navigationId); +} + +let testResourceTiming = async (resourceTimingEntryId) => { + let navigationId; + + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find( + e => e.name.includes('json_resource' + resourceTimingEntryId)); + if (entry) { + navigationId = entry.navigationId; + resolve(); + } + }).observe({ type: 'resource' }); + }); + + const resp = await fetch( + '/performance-timeline/resources/json_resource' + resourceTimingEntryId + '.json'); + await p; + return [navigationId]; +} + +let testElementTiming = async (elementTimingEntryId) => { + let navigationId; + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find( + e => e.entryType === 'element' && e.identifier === 'test-element-timing' + elementTimingEntryId); + if (entry) { + navigationId = entry.navigationId; + resolve(); + } + }).observe({ type: 'element' }); + }); + + let el = document.createElement('p'); + el.setAttribute('elementtiming', 'test-element-timing' + elementTimingEntryId); + el.textContent = 'test element timing text'; + document.body.appendChild(el); + await p; + return [navigationId]; +} + +let testLongTask = async () => { + let navigationIds = []; + + let p = new Promise(resolve => { + new PerformanceObserver((list) => { + const entry = list.getEntries().find(e => e.entryType === 'longtask') + if (entry) { + navigationIds.push(entry.navigationId); + navigationIds = navigationIds.concat( + entry.attribution.map(a => a.navigationId)); + resolve(); + } + }).observe({ type: 'longtask' }); + }); + + const script = document.createElement('script'); + script.src = '/performance-timeline/resources/make_long_task.js'; + document.body.appendChild(script); + await p; + document.body.removeChild(script); + return navigationIds; +} + +const testFunctionMap = { + 'mark_measure': testMarkMeasure, + 'resource_timing': testResourceTiming, + 'element_timing': testElementTiming, + 'long_task_task_attribution': testLongTask, +}; + +function runNavigationIdTest(params, description) { + const defaultParams = { + openFunc: url => window.open(url, '_blank', 'noopener'), + scripts: [], + funcBeforeNavigation: () => { }, + targetOrigin: originCrossSite, + navigationTimes: 4, + funcAfterAssertion: () => { }, + } // Apply defaults. + params = { ...defaultParams, ...params }; + + promise_test(async t => { + const pageA = new RemoteContext(token()); + const pageB = new RemoteContext(token()); + + const urlA = executorPath + pageA.context_id; + const urlB = params.targetOrigin + executorPath + pageB.context_id; + // Open url A. + params.openFunc(urlA); + await pageA.execute_script(waitForPageShow); + + // Assert navigation ids of all performance entries are the same. + let navigationIds = await pageA.execute_script(testInitial); + assert_true( + navigationIds.every(t => t === navigationIds[0]), + 'Navigation Ids should be the same as the initial load.'); + + for (i = 1; i <= params.navigationTimes; i++) { + // Navigate away to url B and back. + await navigateAndThenBack(pageA, pageB, urlB); + + // Assert new navigation ids are generated when the document is load from bfcache. + let nextNavigationIds = await pageA.execute_script( + testFunctionMap[params.testName], [i + 1]); + + // Assert navigation ids of all performance entries are the same. + assert_true( + nextNavigationIds.every(t => t === nextNavigationIds[0]), + 'All Navigation Ids should be same after bfcache navigation.'); + + // Assert navigation ids after bfcache navigation are different from those before. + assert_true( + navigationIds[0] !== nextNavigationIds[0], + params.testName + + ' Navigation Ids should be re-generated and different from the previous ones.'); + + navigationIds = nextNavigationIds; + } + }, description); +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js new file mode 100644 index 00000000000..2fabf45f351 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js @@ -0,0 +1,57 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that empty attributes are reported as empty strings and missing +// attributes are reported as null. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a cross-origin iframe. + const rc1_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {id: '', name: ''}, + ); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/[{ + 'preventedBackForwardCache': "masked", + 'url': null, + 'src': rc1_child_url, + // Id and name should be empty. + 'id': '', + 'name': '', + 'reasons': null, + 'children': null + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js new file mode 100644 index 00000000000..897a9900268 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js @@ -0,0 +1,49 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons are only updated after non BFCache navigation. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/ []); + + // This time no blocking feature is used, so the page is restored + // from BFCache. Ensure that the previous reasons stay there. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/ []); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js new file mode 100644 index 00000000000..bfb685451c3 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js @@ -0,0 +1,28 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons is empty for successful BFCache restore. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + + // Check the BFCache result and verify that no reasons are recorded + // for successful restore. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + assert_true(await rc1.executeScript(() => { + let reasons = + performance.getEntriesByType('navigation')[0].notRestoredReasons; + return reasons === null; + })); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js new file mode 100644 index 00000000000..42769cf458b --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js @@ -0,0 +1,63 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that cross-origin subtree's reasons are not exposed to +// notRestoredReasons. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a cross-origin iframe. + const rc1_child = await rc1.addIframe( + /*extraConfig=*/ { + origin: 'HTTP_REMOTE_ORIGIN', + scripts: [], + headers: [], + }, + /*attributes=*/ {id: 'test-id'}, + ); + // Use WebSocket to block BFCache. + await useWebSocket(rc1_child); + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Add a child to the iframe. + const rc1_grand_child = await rc1_child.addIframe(); + const rc1_grand_child_url = await rc1_grand_child.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "no", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[], + /*children=*/[{ + 'preventedBackForwardCache': "masked", + 'url': null, + 'src': rc1_child_url, + 'id': 'test-id', + // Iframes that are generated by addIframe have an empty name. + 'name': '', + 'reasons': null, + 'children': null + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js new file mode 100644 index 00000000000..5cd35c7ba36 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js @@ -0,0 +1,41 @@ +// META: title=Ensure that ongoing fetch upon entering bfcache blocks bfcache and recorded. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + const wavURL = new URL(get_host_info().HTTP_REMOTE_ORIGIN + '/fetch/range/resources/long-wav.py'); + await rc1.executeScript((wavURL) => { + // Register pagehide handler to create a fetch request. + addEventListener('pagehide', (wavURL) => { + fetch(wavURL, { + keepalive: true + }); + }) + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*blocked=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['fetch'], + /*children=*/[]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js new file mode 100644 index 00000000000..46d8752f20d --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js @@ -0,0 +1,32 @@ +// META: title=Ensure that if WebLock is held upon entering bfcache, it cannot enter bfcache and gets reported. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Request a WebLock. + let return_value = await rc1.executeScript(() => { + return new Promise((resolve) => { + navigator.locks.request('resource', () => { + resolve(42); + }); + }) + }); + assert_equals(return_value, 42); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, ['lock']); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js new file mode 100644 index 00000000000..4022e6e59f1 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js @@ -0,0 +1,26 @@ +// META: title=Ensure that navigation failure blocks bfcache and gets recorded. +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/404.py +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: timeout=long + +'use strict'; +const {ORIGIN} = get_host_info(); + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ {status: 404}, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, ['error-document']); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js new file mode 100644 index 00000000000..0dc1519d1bb --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js @@ -0,0 +1,37 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons is populated when not restored. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/ []); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js new file mode 100644 index 00000000000..7191456cc84 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js @@ -0,0 +1,53 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; +const {ORIGIN, REMOTE_ORIGIN} = get_host_info(); + +// Ensure that notRestoredReasons reset after the server redirect. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + // Create a remote context with the redirected URL. + let rc1_redirected = + await rcHelper.createContext(/*extraConfig=*/ { + origin: 'HTTP_ORIGIN', + scripts: [], + headers: [], + }); + + const redirectUrl = + `${ORIGIN}/common/redirect.py?location=${encodeURIComponent(rc1_redirected.url)}`; + // Replace the history state. + await rc1.executeScript((url) => { + window.history.replaceState(null, '', url); + }, [redirectUrl]); + + // Navigate away. + const newRemoteContextHelper = await rc1.navigateToNew(); + + // Go back. + await newRemoteContextHelper.historyBack(); + + const navigation_entry = await rc1_redirected.executeScript(() => { + return performance.getEntriesByType('navigation')[0]; + }); + assert_equals( + navigation_entry.redirectCount, 1, 'Expected redirectCount is 1.'); + // Becauase of the redirect, notRestoredReasons is reset. + assert_equals( + navigation_entry.notRestoredReasons, null, + 'Expected notRestoredReasons is null.'); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js new file mode 100644 index 00000000000..58584390cd3 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js @@ -0,0 +1,51 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; +const {ORIGIN, REMOTE_ORIGIN} = get_host_info(); + +// Ensure that notRestoredReasons reset after the server redirect. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/ []); + + // Reload. + await rc1.navigate(() => { + location.reload(); + }, []); + + // Becauase of the reload, notRestoredReasons is reset. + const navigation_entry = await rc1.executeScript(() => { + return performance.getEntriesByType('navigation')[0]; + }); + + assert_equals( + navigation_entry.notRestoredReasons, null, + 'Expected notRestoredReasons is null.'); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js new file mode 100644 index 00000000000..44b44a865c0 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js @@ -0,0 +1,64 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + + +'use strict'; + +// Ensure that same-origin subtree's reasons are exposed to notRestoredReasons. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + // Add a same-origin iframe and use WebSocket. + const rc1_child = await rc1.addIframe( + /*extra_config=*/ {}, /*attributes=*/ {id: 'test-id'}); + await useWebSocket(rc1_child); + + const rc1_child_url = await rc1_child.executeScript(() => { + return location.href; + }); + // Add a child to the iframe. + const rc1_grand_child = await rc1_child.addIframe(); + const rc1_grand_child_url = await rc1_grand_child.executeScript(() => { + return location.href; + }); + + // Check the BFCache result and the reported reasons. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "no", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/[], + /*children=*/[{ + 'preventedBackForwardCache': "yes", + 'url': rc1_child_url, + 'src': rc1_child_url, + 'id': 'test-id', + 'name': '', + 'reasons': ['websocket'], + 'children': [{ + 'preventedBackForwardCache': "no", + 'url': rc1_grand_child_url, + 'src': rc1_grand_child_url, + 'id': '', + 'name': '', + 'reasons': [], + 'children': [] + }] + }]); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js new file mode 100644 index 00000000000..c833db75139 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js @@ -0,0 +1,44 @@ +// META: title=RemoteContextHelper navigation using BFCache +// META: script=./test-helper.js +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: timeout=long + +'use strict'; + +// Ensure that notRestoredReasons are accessible after history replace. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ {features: 'noopener'}); + const rc1_url = await rc1.executeScript(() => { + return location.href; + }); + + // Use WebSocket to block BFCache. + await useWebSocket(rc1); + // Navigate away. + const newRemoteContextHelper = await rc1.navigateToNew(); + // Replace the history state to a same-origin site. + await newRemoteContextHelper.executeScript((destUrl) => { + window.history.replaceState(null, '', '#'); + }); + // Go back. + await newRemoteContextHelper.historyBack(); + + // Reasons are not reset for same-origin replace. + await assertNotRestoredReasonsEquals( + rc1, + /*preventedBackForwardCache=*/ "yes", + /*url=*/ rc1_url, + /*src=*/ null, + /*id=*/ null, + /*name=*/ null, + /*reasons=*/['websocket'], + /*children=*/ []); +}); diff --git a/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js b/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js new file mode 100644 index 00000000000..a172546512a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-restored-reasons/test-helper.js @@ -0,0 +1,46 @@ +// META: script=../../html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js + +async function assertNotRestoredReasonsEquals( + remoteContextHelper, blocked, url, src, id, name, reasons, children) { + let result = await remoteContextHelper.executeScript(() => { + return performance.getEntriesByType('navigation')[0].notRestoredReasons; + }); + assertReasonsStructEquals( + result, blocked, url, src, id, name, reasons, children); +} + +function assertReasonsStructEquals( + result, blocked, url, src, id, name, reasons, children) { + assert_equals(result.preventedBackForwardCache, blocked); + assert_equals(result.url, url); + assert_equals(result.src, src); + assert_equals(result.id, id); + assert_equals(result.name, name); + // Reasons should match. + matchReasons(new Set(reasons), new Set(result.reasons)); + + // Children should match. + if (children == null) { + assert_equals(result.children, children); + } else { + for (let j = 0; j < children.length; j++) { + assertReasonsStructEquals( + result.children[0], children[0].preventedBackForwardCache, children[0].url, + children[0].src, children[0].id, children[0].name, children[0].reasons, + children[0].children); + } + } +} + +// Requires: +// - /websockets/constants.sub.js in the test file and pass the domainPort +// constant here. +async function useWebSocket(remoteContextHelper) { + let return_value = await remoteContextHelper.executeScript((domain) => { + return new Promise((resolve) => { + var webSocketInNotRestoredReasonsTests = new WebSocket(domain + '/echo'); + webSocketInNotRestoredReasonsTests.onopen = () => { resolve(42); }; + }); + }, [SCHEME_DOMAIN_PORT]); + assert_equals(return_value, 42); +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/child-frame.html b/test/fixtures/wpt/performance-timeline/resources/child-frame.html new file mode 100644 index 00000000000..40c8f726885 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/child-frame.html @@ -0,0 +1,7 @@ + + + + + diff --git a/test/fixtures/wpt/performance-timeline/resources/empty.html b/test/fixtures/wpt/performance-timeline/resources/empty.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js b/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js new file mode 100644 index 00000000000..a56489baaf4 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/include-frames-helper.js @@ -0,0 +1,60 @@ +const verifyEntries = (entries, filterOptions) => { + for (const filterOption of filterOptions) { + let countBeforeFiltering = entries.length; + + // Using negate of the condition so that the next filtering is applied on less entries. + entries = entries.filter( + e => !(e.entryType == filterOption['entryType'] && e.name.includes(filterOption['name']))); + + assert_equals( + countBeforeFiltering - entries.length, filterOption['expectedCount'], filterOption['failureMsg']); + } +} + +const createFilterOption = (name, entryType, expectedCount, msgPrefix, description = '') => { + if (description) { + description = ' ' + description; + } + + let failureMsg = + `${msgPrefix} should have ${expectedCount} ${entryType} entries for name ${name}` + description; + + return { + name: name, + entryType: entryType, + expectedCount: expectedCount, + failureMsg: failureMsg + }; +} + +const loadChildFrame = (src) => { + return new Promise(resolve => { + + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", resolve); + + childFrame.src = src; + + document.body.appendChild(childFrame); + }); +} + +const loadChildFrameAndGrandchildFrame = (src) => { + return new Promise(resolve => { + + const crossOriginChildFrame = document.createElement('iframe'); + + // Wait for the child frame to send a message. The child frame would send a message + // when it loads its child frame. + window.addEventListener('message', e => { + if (e.data == 'Load completed') { + resolve(); + } + }); + + crossOriginChildFrame.src = src; + + document.body.appendChild(crossOriginChildFrame) + }); +} diff --git a/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html b/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html new file mode 100644 index 00000000000..0d43f418a09 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/include-frames-subframe.html @@ -0,0 +1,43 @@ + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/resources/json_resource.json b/test/fixtures/wpt/performance-timeline/resources/json_resource.json new file mode 100644 index 00000000000..68b6ac1d56f --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/json_resource.json @@ -0,0 +1,4 @@ +{ + "name": "nav_id_test", + "target": "resource_timing" +} \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/make_long_task.js b/test/fixtures/wpt/performance-timeline/resources/make_long_task.js new file mode 100644 index 00000000000..a52d6d83929 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/make_long_task.js @@ -0,0 +1,4 @@ +(function () { + let now = window.performance.now(); + while (window.performance.now() < now + 60); +}()); \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html b/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html new file mode 100644 index 00000000000..02aafbb5c78 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/navigation-id-detached-frame-page.html @@ -0,0 +1,21 @@ + + + + + + The navigation_id Detached iframe Page. + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js b/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js new file mode 100644 index 00000000000..3a2740d0675 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/worker-navigation-id.js @@ -0,0 +1,6 @@ +self.onmessage = () => { + const mark_name = 'user_timig_mark'; + performance.mark(mark_name); + postMessage(performance.getEntriesByName(mark_name)[0].navigationId); + self.close(); +} diff --git a/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html b/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html new file mode 100644 index 00000000000..8b86a6398bf --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/supportedEntryTypes-cross-realm-access.html @@ -0,0 +1,18 @@ + + +Cross-realm access of supportedEntryTypes returns Array of another realm + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html b/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html new file mode 100644 index 00000000000..70019223a64 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/detached-frame.html @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html new file mode 100644 index 00000000000..57623e5b33b --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A-A.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html new file mode 100644 index 00000000000..bcb9a81657f --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-A.html @@ -0,0 +1,76 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html new file mode 100644 index 00000000000..cccbf4100dd --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AA.html @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html new file mode 100644 index 00000000000..d630665b652 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-AB.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html new file mode 100644 index 00000000000..58cad40faba --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-A.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html new file mode 100644 index 00000000000..2368a8e881a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B-B.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html new file mode 100644 index 00000000000..b823d6edaa3 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/include-frames-originA-B.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source-deleted-frame.html b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source-deleted-frame.html new file mode 100644 index 00000000000..81970606707 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source-deleted-frame.html @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html new file mode 100644 index 00000000000..d10d3c5ed51 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/performance-entry-source.html @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html b/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html new file mode 100644 index 00000000000..6c6643df75c --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/tentative/with-filter-options-originA.html @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html b/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html new file mode 100644 index 00000000000..43988b21fbb --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/timing-removed-iframe.html @@ -0,0 +1,16 @@ + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/META.yml b/test/fixtures/wpt/resource-timing/META.yml index 662c42cb664..153654eae8b 100644 --- a/test/fixtures/wpt/resource-timing/META.yml +++ b/test/fixtures/wpt/resource-timing/META.yml @@ -1,6 +1,5 @@ spec: https://w3c.github.io/resource-timing/ suggested_reviewers: - plehegar - - zqzhang - igrigorik - yoavweiss diff --git a/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html b/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html new file mode 100644 index 00000000000..b0340139bf7 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/body-size-cross-origin.https.html @@ -0,0 +1,63 @@ + + + + +Verify that encodedBodySize/decodedBodySize are CORS-protected rather than TAO-protected + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/content-type-parsing.html b/test/fixtures/wpt/resource-timing/content-type-parsing.html new file mode 100644 index 00000000000..c0081eb4137 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/content-type-parsing.html @@ -0,0 +1,76 @@ + + + +This test validates the parsing of content-type of resources. + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/content-type.html b/test/fixtures/wpt/resource-timing/content-type.html new file mode 100644 index 00000000000..f6b1db7d9f8 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/content-type.html @@ -0,0 +1,117 @@ + + + +This test validates the content-type of resources. + + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html b/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html index 1b107d3aef7..8e368d13807 100644 --- a/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html +++ b/test/fixtures/wpt/resource-timing/cross-origin-start-end-time-with-redirects.html @@ -19,13 +19,19 @@ const blank_page = `/resource-timing/resources/blank_page_green.htm`; const destUrl = `/common/slow-redirect.py?delay=${delay}&location=${REMOTE_ORIGIN}/${blank_page}`; -const timeBefore = performance.now() -attribute_test(load.iframe, destUrl, entry => { - assert_equals(entry.startTime, entry.fetchStart, 'startTime and fetchStart should be equal'); - assert_greater_than(entry.startTime, timeBefore, 'startTime and fetchStart should be greater than the time before fetching'); - // See https://github.com/w3c/resource-timing/issues/264 - assert_less_than(Math.round(entry.startTime - timeBefore), delay * 1000, 'startTime should not expose redirect delays'); -}, "Verify that cross-origin resources don't implicitly expose their redirect timings") +const timeBefore = performance.now(); +(async () => { + // Wait 10 ms, to ensure the difference between startTime and timeBefore is + // larger than 1 ms, to avoid flakiness in browsers that clamp timestamps to + // 1 ms. + await new Promise(r => step_timeout(r, 10)); + attribute_test(load.iframe, destUrl, entry => { + assert_equals(entry.startTime, entry.fetchStart, 'startTime and fetchStart should be equal'); + assert_greater_than(entry.startTime, timeBefore, 'startTime and fetchStart should be greater than the time before fetching'); + // See https://github.com/w3c/resource-timing/issues/264 + assert_less_than(Math.round(entry.startTime - timeBefore), delay * 1000, 'startTime should not expose redirect delays'); + }, "Verify that cross-origin resources don't implicitly expose their redirect timings") +})(); diff --git a/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js b/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js new file mode 100644 index 00000000000..e2b408fdd74 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/delivery-type.tentative.any.js @@ -0,0 +1,90 @@ +// META: global=window,worker +// META: script=/common/get-host-info.sub.js +// META: script=/resource-timing/resources/resource-loaders.js + +// TODO(crbug/1358591): Rename this file from "tentative" once +// `w3c/resource-timing#343` is merged. + +const {REMOTE_ORIGIN, ORIGIN} = get_host_info(); + +const redirectBase = new URL( + '/resource-timing/resources/redirect-cors.py', REMOTE_ORIGIN).href; +const cacheAndValidatedBase = new URL( + '/resource-timing/resources/cacheable-and-validated.py?content=content', + ORIGIN).href; + +const mustRevalidate = {headers: {'Cache-Control': 'max-age=0'}}; + +const fetchAndEatBody = (url, fetchOption) => { + return fetch(url, fetchOption).then(response => response.arrayBuffer()); +}; + +const accumulateEntries = () => { + return new Promise(resolve => { + const po = new PerformanceObserver(list => { + resolve(list); + }); + po.observe({type: "resource", buffered: true}); + }); +}; + +const checkDeliveryTypeBase = + (list, lookupURL, deliveryTypeForCachedResources) => { + const entries = list.getEntriesByName(lookupURL); + assert_equals(entries.length, 3, 'Wrong number of entries'); + + // 200 response (`cacheMode` is an empty string) + assert_equals(entries[0].deliveryType, "", + "Expect empty deliveryType for 200 response."); + // Cached response (`cacheMode` is "local") or 304 response (`cacheMode` is + // "validated"). + assert_equals(entries[1].deliveryType, deliveryTypeForCachedResources, + `Expect "${deliveryTypeForCachedResources}" deliveryType for a + cached response.`); + assert_equals(entries[2].deliveryType, deliveryTypeForCachedResources, + `Expect "${deliveryTypeForCachedResources}" deliveryType for a + revalidated response.`); +}; + +promise_test(() => { + // Use a different URL every time so that the cache behaviour does not depend + // on execution order. + const initialURL = load.cache_bust(cacheAndValidatedBase); + const checkDeliveryType = + list => checkDeliveryTypeBase(list, initialURL, "cache"); + return fetchAndEatBody(initialURL, {}) // 200. + .then(() => fetchAndEatBody(initialURL, {})) // Cached. + .then(() => fetchAndEatBody(initialURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, same origin.'); + +promise_test(() => { + const cacheAndValidatedURL = load.cache_bust( + cacheAndValidatedBase + '&timing_allow_origin=*'); + const redirectURL = redirectBase + + "?timing_allow_origin=*" + + `&allow_origin=${encodeURIComponent(ORIGIN)}` + + `&location=${encodeURIComponent(cacheAndValidatedURL)}`; + const checkDeliveryType = + list => checkDeliveryTypeBase(list, redirectURL, "cache"); + return fetchAndEatBody(redirectURL, {}) // 200. + .then(() => fetchAndEatBody(redirectURL, {})) // Cached. + .then(() => fetchAndEatBody(redirectURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, cross origin, TAO passes.'); + +promise_test(() => { + const cacheAndValidatedURL = load.cache_bust(cacheAndValidatedBase); + const redirectURL = redirectBase + + `?allow_origin=${encodeURIComponent(ORIGIN)}` + + `&location=${encodeURIComponent(cacheAndValidatedURL)}`; + const checkDeliveryType = + list => checkDeliveryTypeBase(list, redirectURL, ""); + return fetchAndEatBody(redirectURL, {}) // 200. + .then(() => fetchAndEatBody(redirectURL, {})) // Cached. + .then(() => fetchAndEatBody(redirectURL, mustRevalidate)) // 304. + .then(accumulateEntries) + .then(checkDeliveryType); +}, 'PerformanceResourceTiming deliveryType test, cross origin, TAO fails.'); diff --git a/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html b/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html index 95849d28262..ebc2247babc 100644 --- a/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html +++ b/test/fixtures/wpt/resource-timing/entries-for-network-errors.sub.https.html @@ -30,6 +30,22 @@ network_error_entry_test( `/element-timing/resources/multiple-redirects.py?redirect_count=22&final_resource=${validXmlUrl}`, null, "too many redirects"); + +// ORB (https://github.com/whatwg/fetch/pull/1442) will return network errors +// for certain cross-origin fetches. This tests that the same rules apply to +// these fetches. Since ORB (at least as presently implemented) doesn't return +// network errors for fetches, we have to load this case using an element. +// +// This emulates a case previously tested in service-workers/service-worker/resource-timing.sub.https.html +const orb_loader = (url, _) => new Promise(resolve => { + const img = document.createElement("img"); + img.src = url; + img.onerror = resolve; + document.body.appendChild(img); +} ); +network_error_entry_test( + '//{{hosts[alt][]}}:{{ports[https][0]}}/service-workers/service-worker/resources/missing.jpg', + null, "network error for ORB-blocked response", orb_loader); diff --git a/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html b/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html index 4193422653a..1605e224ab4 100644 --- a/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html +++ b/test/fixtures/wpt/resource-timing/fetch-cross-origin-redirect.https.html @@ -12,7 +12,7 @@ const {REMOTE_ORIGIN, ORIGIN} = get_host_info(); const redirect = "/common/redirect.py?" + - "location=/resource-timing/resources/green.html"; + "location=/resource-timing/resources/empty_script.js"; const cross_origin_redirect = REMOTE_ORIGIN + redirect; const same_origin_redirect = ORIGIN + redirect; diff --git a/test/fixtures/wpt/resource-timing/iframe-failed-commit.html b/test/fixtures/wpt/resource-timing/iframe-failed-commit.html index 1da207d2fbe..d3b5cce59ec 100644 --- a/test/fixtures/wpt/resource-timing/iframe-failed-commit.html +++ b/test/fixtures/wpt/resource-timing/iframe-failed-commit.html @@ -3,6 +3,7 @@ Resource Timing - test that unsuccessful iframes create entries + @@ -20,6 +21,10 @@ return load.iframe_with_attrs(path, {"csp": "default-src 'none'"}); }; +const load_iframe_with_csp_no_navigation = async path => { + return load.iframe_with_attrs(path, {"csp": "default-src 'none'"}, () => {}, true); +} + // Runs a test (labeled by the given label) to verify that loading an iframe // with the given URL generates a PerformanceResourceTiming entry and that the // entry does not expose sensitive timing attributes. @@ -46,12 +51,12 @@ }; // Runs a test (labeled by the given label) to verify that loading an iframe -// with the given URL, an empty response body and under a "default-src 'none' -// Content-Security-Policy generates a PerformanceResourceTiming entry and that -// the entry does expose sensitive timing attributes. -const empty_unmasked_entry_with_csp_test = (url, label) => { - return attribute_test(load_iframe_with_csp, url, - invariants.assert_tao_pass_no_redirect_http_empty, label); +// with the given URL under a "default-src 'none' Content-Security-Policy +// generates a PerformanceResourceTiming entry and that the entry does not +// expose sensitive timing attributes. +const non_navigating_masked_entry_with_csp_test = (url, label) => { + return attribute_test(load_iframe_with_csp_no_navigation, url, + invariants.assert_tao_failure_resource, label); }; const {REMOTE_ORIGIN, ORIGINAL_HOST, HTTPS_PORT} = get_host_info(); @@ -68,7 +73,8 @@ unmasked_entry_with_csp_test("/resource-timing/resources/csp-default-none.html", "Same-origin iframe that complies with CSP attribute gets reported"); -unmasked_entry_with_csp_test("/resource-timing/resources/green-frame.html", +// masked because this will load an error page which is cross-origin. +masked_entry_with_csp_test("/resource-timing/resources/green-frame.html", "Same-origin iframe that doesn't comply with CSP attribute gets reported"); masked_entry_with_csp_test( @@ -79,7 +85,7 @@ new URL("/resource-timing/resources/green-frame.html", REMOTE_ORIGIN), "Cross-origin iframe that doesn't comply with CSP attribute gets reported"); -empty_unmasked_entry_with_csp_test( +masked_entry_with_csp_test( "/resource-timing/resources/200_empty.asis", "Same-origin empty iframe with a 200 status gets reported"); @@ -87,19 +93,19 @@ new URL("/resource-timing/resources/200_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 200 status gets reported"); -unmasked_entry_with_csp_test( - new URL("/resource-timing/resources/204_empty.asis"), +non_navigating_masked_entry_with_csp_test( + new URL("/resource-timing/resources/204_empty.asis", location.origin), "Same-origin empty iframe with a 204 status gets reported"); -unmasked_entry_with_csp_test( - new URL("/resource-timing/resources/205_empty.asis"), +non_navigating_masked_entry_with_csp_test( + new URL("/resource-timing/resources/205_empty.asis", location.origin), "Same-origin empty iframe with a 205 status gets reported"); -masked_entry_with_csp_test( +non_navigating_masked_entry_with_csp_test( new URL("/resource-timing/resources/204_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 204 status gets reported"); -masked_entry_with_csp_test( +non_navigating_masked_entry_with_csp_test( new URL("/resource-timing/resources/205_empty.asis", REMOTE_ORIGIN), "Cross-origin empty iframe with a 205 status gets reported"); diff --git a/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html b/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html index 5f99a5cab2d..02d1c362c9d 100644 --- a/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html +++ b/test/fixtures/wpt/resource-timing/iframe-sequence-of-events.html @@ -4,9 +4,21 @@ + + - \ No newline at end of file + diff --git a/test/fixtures/wpt/resource-timing/initiator-type/link.html b/test/fixtures/wpt/resource-timing/initiator-type/link.html index c49576a8e65..43367ac3d50 100644 --- a/test/fixtures/wpt/resource-timing/initiator-type/link.html +++ b/test/fixtures/wpt/resource-timing/initiator-type/link.html @@ -1,38 +1,35 @@ + - -Resource Timing initiator type: link - - - - - - + + Resource Timing initiator type: link + + + + + + + + + + + + - - - - - - - -
    This content forces a font to get fetched
+ // Verify there are enries for each of nested.css' nested resources. + initiator_type_test("resource_timing_test0.css?id=n1", "css", "css resources embedded in css"); + initiator_type_test("fonts/Ahem.ttf?id=n1", "css", "font resources embedded in css"); + initiator_type_test("blue.png?id=n1", "css", "image resources embedded in css"); + initiator_type_test("resource_timing_test0.css?id=prefetch", "link", ""); + initiator_type_test("resource_timing_test0.css?id=preload", "link", ""); + initiator_type_test("manifest.json", "link", ""); + initiator_type_test("resources/empty.js?id=modulePreload", "other", "module preload"); + +
    This content forces a font to get fetched
diff --git a/test/fixtures/wpt/resource-timing/interim-response-times.h2.html b/test/fixtures/wpt/resource-timing/interim-response-times.h2.html new file mode 100644 index 00000000000..4b1ca93ff7b --- /dev/null +++ b/test/fixtures/wpt/resource-timing/interim-response-times.h2.html @@ -0,0 +1,74 @@ + + + + + +Resource Timing: PerformanceResourceTiming interim resource times + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/interim-response-times.html b/test/fixtures/wpt/resource-timing/interim-response-times.html new file mode 100644 index 00000000000..a4d03f599ee --- /dev/null +++ b/test/fixtures/wpt/resource-timing/interim-response-times.html @@ -0,0 +1,72 @@ + + + + + +Resource Timing: PerformanceResourceTiming interim resource times + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html b/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html new file mode 100644 index 00000000000..b8bba5614d0 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/nested-nav-fallback-timing.html @@ -0,0 +1,33 @@ + + +Test ResourceTiming reporting for cross-origin iframe. + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html b/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html new file mode 100644 index 00000000000..6b60305ded2 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html @@ -0,0 +1,53 @@ + + +Make sure that resources fetched by cross origin CSS are not in the timeline. + + + + + + + +
    Some content
+ diff --git a/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html b/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html index 278c78e320e..6990c6c0608 100644 --- a/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html +++ b/test/fixtures/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html @@ -4,6 +4,7 @@ This test validates the values in resource timing for cross-origin redirects. + @@ -15,20 +16,26 @@ diff --git a/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html b/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html new file mode 100644 index 00000000000..ea47ae3a795 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/queue-entry-regardless-buffer-size.html @@ -0,0 +1,38 @@ + + + + + +This test validates that resource timing entires should always be queued regardless the size of the buffer. + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html new file mode 100644 index 00000000000..b99183a49cd --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch-web-bundle.tentative.html @@ -0,0 +1,53 @@ + + + + Resource timing attributes are consistent for the same-origin subresources. + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html new file mode 100644 index 00000000000..5bab39e2760 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resource-timing-failed-fetch.html @@ -0,0 +1,34 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/resource-timing-level1.js b/test/fixtures/wpt/resource-timing/resource-timing-level1.js index 95b5cdfb1ed..6167777fe68 100644 --- a/test/fixtures/wpt/resource-timing/resource-timing-level1.js +++ b/test/fixtures/wpt/resource-timing/resource-timing-level1.js @@ -235,47 +235,6 @@ window.onload = }); }); - // Test that responseStart uses the timing of 1XX responses by - // synthesizing a delay between a 100 and 200 status, and verifying that - // this delay is included before responseEnd. If the delay is not - // included, this implies that the 200 status line was (incorrectly) used - // for responseStart timing, despite the 100 response arriving earlier. - // - // Source: "In the case where more than one response is available for a - // request, due to an Informational 1xx response, the reported - // responseStart value is that of the first response to the last - // request." - [ - { initiator: "iframe", response: "(done)", mime: mimeHtml }, - { initiator: "xmlhttprequest", response: "(done)", mime: mimeText }, - { initiator: "script", response: '"";', mime: mimeScript }, - { initiator: "link", response: ".unused{}", mime: mimeCss }, - ] - .forEach(function (template) { - testCases.push({ - description: "'" + template.initiator + " responseStart uses 1XX (first) response timings'", - test: function (test) { - initiateFetch( - test, - template.initiator, - getSyntheticUrl("status:100" - + "&flush" - + "&" + serverStepDelay + "ms" - + "&status:200" - + "&mime:" + template.mime - + "&send:" + encodeURIComponent(template.response)), - function (initiator, entry) { - assert_greater_than_equal( - entry.responseEnd, - entry.responseStart + serverStepDelay, - "HTTP/1.1 1XX (first) response should determine 'responseStart' timing."); - - test.done(); - }); - } - }); - }); - // Function to run the next case in the queue. var currentTestIndex = -1; function runNextCase() { diff --git a/test/fixtures/wpt/resource-timing/resources/delay-load.html b/test/fixtures/wpt/resource-timing/resources/delay-load.html new file mode 100644 index 00000000000..4898c1be8eb --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/delay-load.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/fixtures/wpt/resource-timing/resources/entry-invariants.js b/test/fixtures/wpt/resource-timing/resources/entry-invariants.js index 4bef9496103..78d43d1b01e 100644 --- a/test/fixtures/wpt/resource-timing/resources/entry-invariants.js +++ b/test/fixtures/wpt/resource-timing/resources/entry-invariants.js @@ -1,3 +1,19 @@ +const await_with_timeout = async (delay, message, promise, cleanup = ()=>{}) => { + let timeout_id; + const timeout = new Promise((_, reject) => { + timeout_id = step_timeout(() => + reject(new DOMException(message, "TimeoutError")), delay) + }); + let result = null; + try { + result = await Promise.race([promise, timeout]); + clearTimeout(timeout_id); + } finally { + cleanup(); + } + return result; +}; + // Asserts that the given attributes are present in 'entry' and hold equal // values. const assert_all_equal_ = (entry, attributes) => { @@ -75,8 +91,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -98,8 +112,6 @@ const invariants = { "secureConnectionStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -139,8 +151,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -172,8 +182,6 @@ const invariants = { assert_positive_(entry, [ "fetchStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); }, @@ -196,8 +204,6 @@ const invariants = { "secureConnectionStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -229,8 +235,6 @@ const invariants = { "workerStart", "redirectStart", "redirectEnd", - "encodedBodySize", - "decodedBodySize", ]); assert_not_negative_(entry, [ @@ -405,8 +409,6 @@ const invariants = { "requestStart", "responseStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); assert_ordered_(entry, [ @@ -440,8 +442,6 @@ const invariants = { "requestStart", "responseStart", "transferSize", - "encodedBodySize", - "decodedBodySize", ]); } @@ -467,7 +467,10 @@ const attribute_test_internal = (loader, path, validator, run_test, test_label) }); await loader(path, validator); - const entry = await(loaded_entry); + const entry = await await_with_timeout(2000, + "Timeout was reached before entry fired", + loaded_entry); + assert_not_equals(entry, null, 'No entry was received'); run_test(entry); }, test_label); }; @@ -485,11 +488,13 @@ const attribute_test_with_validator = (loader, path, validator, run_test, test_l attribute_test_internal(loader, path, validator, run_test, test_label); }; -const network_error_entry_test = (originalURL, args, label) => { +const network_error_entry_test = (originalURL, args, label, loader) => { const url = new URL(originalURL, location.href); const search = new URLSearchParams(url.search.substr(1)); const timeBefore = performance.now(); - loader = () => new Promise(resolve => fetch(url, args).catch(resolve)); + + // Load using `fetch()`, unless we're given a specific loader for this test. + loader ??= () => new Promise(resolve => fetch(url, args).catch(resolve)); attribute_test( loader, url, diff --git a/test/fixtures/wpt/resource-timing/resources/frame-timing.js b/test/fixtures/wpt/resource-timing/resources/frame-timing.js index e0c364e9b2c..019bd424b55 100644 --- a/test/fixtures/wpt/resource-timing/resources/frame-timing.js +++ b/test/fixtures/wpt/resource-timing/resources/frame-timing.js @@ -1,48 +1,63 @@ function test_frame_timing_before_load_event(type) { - promise_test(async t => { - const {document, performance} = type === 'frame' ? window.parent : window; - const delay = 500; - const frame = document.createElement(type); - t.add_cleanup(() => frame.remove()); - await new Promise(resolve => { - frame.addEventListener('load', resolve); - frame.src = `resources/iframe-with-delay.sub.html?delay=${delay}`; - (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); - }); + promise_test(async t => { + const {document, performance} = type === 'frame' ? window.parent : window; + const delay = 500; + const frame = document.createElement(type); + t.add_cleanup(() => frame.remove()); + await new Promise(resolve => { + frame.addEventListener('load', resolve); + frame.src = `/resource-timing/resources/iframe-with-delay.sub.html?delay=${delay}`; + (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); + }); - const entries = performance.getEntriesByName(frame.src); - const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; - assert_equals(entries.length, 1); - assert_equals(entries[0].initiatorType, type); - assert_greater_than(performance.now(), entries[0].responseEnd + delay); - const domContentLoadedEventAbsoluteTime = navigationEntry.domContentLoadedEventStart + frame.contentWindow.performance.timeOrigin; - const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; - assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); - }, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); + const entries = performance.getEntriesByName(frame.src); + const navigationEntry = frame.contentWindow.performance.getEntriesByType('navigation')[0]; + assert_equals(entries.length, 1); + assert_equals(entries[0].initiatorType, type); + assert_greater_than(performance.now(), entries[0].responseEnd + delay); + const domContentLoadedEventAbsoluteTime = + navigationEntry.domContentLoadedEventStart + + frame.contentWindow.performance.timeOrigin; + const frameResponseEndAbsoluteTime = entries[0].responseEnd + performance.timeOrigin; + assert_greater_than(domContentLoadedEventAbsoluteTime, frameResponseEndAbsoluteTime); + }, `A ${type} should report its RT entry when the response is done and before it is completely loaded`); } -function test_frame_timing_change_src(type) { - promise_test(async t => { - const {document, performance} = type === 'frame' ? window.parent : window; - const frame = document.createElement(type); - t.add_cleanup(() => frame.remove()); - await new Promise(resolve => { - const done = () => { - resolve(); - frame.removeEventListener('load', done); - } - frame.addEventListener('load', done); - frame.src = 'resources/green.html?1'; - (type === 'frame' ? document.querySelector('frameset') : document.body).appendChild(frame); - }); +function test_frame_timing_change_src(type, + origin1 = document.origin, + origin2 = document.origin, + tao = false, label = '') { + const uid = token(); + promise_test(async t => { + const {document, performance} = type === 'frame' ? window.parent : window; + const frame = document.createElement(type); + t.add_cleanup(() => frame.remove()); + function createURL(origin) { + const url = new URL(`${origin}/resource-timing/resources/green.html`, location.href); + url.searchParams.set("uid", uid); + if (tao) + url.searchParams.set("pipe", "header(Timing-Allow-Origin, *)"); + return url.toString(); + } - await new Promise(resolve => { - frame.addEventListener('load', resolve); - frame.src = 'resources/green.html?2'; - }); + await new Promise(resolve => { + const done = () => { + resolve(); + frame.removeEventListener('load', done); + } + frame.addEventListener('load', done); + frame.src = createURL(origin1); + const root = type === 'frame' ? document.querySelector('frameset') : document.body; + root.appendChild(frame); + }); - const entries = performance.getEntries().filter(e => e.name.includes('green.html')); - assert_equals(entries.length, 2); - }, `A ${type} should report separate RT entries if its src changed from the outside`); -} \ No newline at end of file + await new Promise(resolve => { + frame.addEventListener('load', resolve); + frame.src = createURL(origin2); + }); + + const entries = performance.getEntries().filter(e => e.name.includes(uid)); + assert_equals(entries.length, 2); + }, label || `A ${type} should report separate RT entries if its src changed from the outside`); +} diff --git a/test/fixtures/wpt/resource-timing/resources/get-resourceID.js b/test/fixtures/wpt/resource-timing/resources/get-resourceID.js new file mode 100644 index 00000000000..3fe499226a4 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/get-resourceID.js @@ -0,0 +1,30 @@ +function getResourceID(resourceName) { + return new Promise((resolve) => { + const observer = new PerformanceObserver((list) => { + const entries = list.getEntriesByType("resource"); + for (const entry of entries) { + if (entry.name.endsWith(resourceName)) { + observer.disconnect(); + resolve(`${entry.name}/${entry.startTime}`); + return; + } + } + }); + observer.observe({ entryTypes: ["resource"] }); + }); +} + +function getDocumentResourceID() { + return new Promise((resolve) => { + const observer = new PerformanceObserver((list) => { + const entries = list.getEntriesByType("navigation"); + if (entries.length > 0) { + observer.disconnect(); + const [entry] = entries; + const { name, startTime } = entry; + resolve(`${name}/${startTime}`); + } + }); + observer.observe({ entryTypes: ["navigation"] }); + }); +} diff --git a/test/fixtures/wpt/resource-timing/resources/loadingResources.js b/test/fixtures/wpt/resource-timing/resources/loadingResources.js new file mode 100644 index 00000000000..e5d5d71982a --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/loadingResources.js @@ -0,0 +1,21 @@ +//Fetching the Stylesheet +var link = document.createElement("link"); +link.rel = "stylesheet"; +link.href = "../resources/empty_style.css"; +document.head.appendChild(link); + +// Fetching an image +var img = document.createElement("img"); +img.src = "/images/blue.png"; +img.alt = "Sample Image for testing initiator Attribute"; +document.body.appendChild(img); + +//Inserting a html document in an iframe +var iframe = document.createElement("iframe"); +iframe.src = "../resources/green.html"; +document.body.appendChild(iframe); + +// Inserting a script element +var script = document.createElement("script"); +script.src = "../resources/empty.js"; +document.body.appendChild(script); diff --git a/test/fixtures/wpt/resource-timing/resources/nested-contexts.js b/test/fixtures/wpt/resource-timing/resources/nested-contexts.js index c0822943e86..31337ae5da2 100644 --- a/test/fixtures/wpt/resource-timing/resources/nested-contexts.js +++ b/test/fixtures/wpt/resource-timing/resources/nested-contexts.js @@ -22,22 +22,12 @@ const post_refresh_url = const setup_navigate_or_refresh = (type, pre, post) => { const verify_document_navigate_not_observable = () => { - const entries = performance.getEntriesByType("resource"); - let found_first_document = false; - for (entry of entries) { - if (entry.name == pre) { - found_first_document = true; - } - if (entry.name == post) { - opener.postMessage(`FAIL - ${type} document should not be observable`, - `*`); - return; - } - } - if (!found_first_document) { - opener.postMessage("FAIL - initial document should be observable", "*"); - return; + if (performance.getEntriesByName(post).length) { + opener.postMessage(`FAIL - ${type} document should not be observable`, + `*`); + } + opener.postMessage("PASS", "*"); } window.addEventListener("message", e => { @@ -57,21 +47,8 @@ const setup_refresh_test = () => { const setup_back_navigation = pushed_url => { const verify_document_navigate_not_observable = navigated_back => { - const entries = performance.getEntriesByType("resource"); - let found_first_document = false; - for (entry of entries) { - if (entry.name == pre_navigate_url) { - found_first_document = true; - } - if (entry.name == post_navigate_url) { - opener.postMessage("FAIL - navigated document exposed", "*"); - return; - } - } - if (!found_first_document) { - opener.postMessage(`FAIL - first document not exposed. navigated_back ` + - `is ${navigated_back}`, "*"); - return; + if (performance.getEntriesByName(post_navigate_url).length) { + opener.postMessage("FAIL - navigated document exposed", "*"); } if (navigated_back) { opener.postMessage("PASS", "*"); diff --git a/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html b/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html new file mode 100644 index 00000000000..f47913468b6 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/no-entries-for-cross-origin-css-fetched-memory-cache-iframe.sub.html @@ -0,0 +1,8 @@ + + + + + + +
    Some content
+ diff --git a/test/fixtures/wpt/resource-timing/resources/resource-loaders.js b/test/fixtures/wpt/resource-timing/resources/resource-loaders.js index 99a2c28d2b3..37fea16b175 100644 --- a/test/fixtures/wpt/resource-timing/resources/resource-loaders.js +++ b/test/fixtures/wpt/resource-timing/resources/resource-loaders.js @@ -1,23 +1,38 @@ const load = { - _cache_bust_value: Math.random().toString().substr(2), cache_bust: path => { let url = new URL(path, location.origin); url.href += (url.href.includes("?")) ? '&' : '?'; - url.href += "unique=" + load._cache_bust_value++ + // The `Number` type in Javascript, when interpreted as an integer, can only + // safely represent [-2^53 + 1, 2^53 - 1] without the loss of precision [1]. + // We do not generate a global value and increment from it, as the increment + // might not have enough precision to be reflected. + // + // [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number + url.href += "unique=" + Math.random().toString().substring(2); return url.href; }, - // Returns a promise that settles once the given path has been fetched as an - // image resource. - image: path => { + image_with_attrs: async (path, attribute_map) => { return new Promise(resolve => { const img = new Image(); + for (const key in attribute_map) + img[key] = attribute_map[key]; img.onload = img.onerror = resolve; img.src = load.cache_bust(path); }); }, + // Returns a promise that settles once the given path has been fetched as an + // image resource. + image: path => { + return load.image_with_attrs(path, undefined); + }, + + // Returns a promise that settles once the given path has been fetched as an + // image resource. + image_cors: path => load.image_with_attrs(path, {crossOrigin: "anonymous"}), + // Returns a promise that settles once the given path has been fetched as a // font resource. font: path => { @@ -37,10 +52,13 @@ const load = { }); }, - // Returns a promise that settles once the given path has been fetched as a - // stylesheet resource. - stylesheet: async path => { + stylesheet_with_attrs: async (path, attribute_map) => { const link = document.createElement("link"); + if (attribute_map instanceof Object) { + for (const [key, value] of Object.entries(attribute_map)) { + link[key] = value; + } + } link.rel = "stylesheet"; link.type = "text/css"; link.href = load.cache_bust(path); @@ -54,7 +72,13 @@ const load = { document.head.removeChild(link); }, - iframe_with_attrs: async (path, attribute_map, validator) => { + // Returns a promise that settles once the given path has been fetched as a + // stylesheet resource. + stylesheet: async path => { + return load.stylesheet_with_attrs(path, undefined); + }, + + iframe_with_attrs: async (path, attribute_map, validator, skip_wait_for_navigation) => { const frame = document.createElement("iframe"); if (attribute_map instanceof Object) { for (const [key, value] of Object.entries(attribute_map)) { @@ -66,11 +90,17 @@ const load = { }); frame.src = load.cache_bust(path); document.body.appendChild(frame); - await loaded; + if ( !skip_wait_for_navigation ) { + await loaded; + } if (validator instanceof Function) { validator(frame); } - document.body.removeChild(frame); + // since we skipped the wait for load animation, we cannot + // remove the iframe here since the request could get cancelled + if ( !skip_wait_for_navigation ) { + document.body.removeChild(frame); + } }, // Returns a promise that settles once the given path has been fetched as an @@ -79,10 +109,13 @@ const load = { return load.iframe_with_attrs(path, undefined, validator); }, - // Returns a promise that settles once the given path has been fetched as a - // script. - script: async path => { + script_with_attrs: async (path, attribute_map) => { const script = document.createElement("script"); + if (attribute_map instanceof Object) { + for (const [key, value] of Object.entries(attribute_map)) { + script[key] = value; + } + } const loaded = new Promise(resolve => { script.onload = script.onerror = resolve; }); @@ -92,21 +125,29 @@ const load = { document.body.removeChild(script); }, + // Returns a promise that settles once the given path has been fetched as a + // script. + script: async path => { + return load.script_with_attrs(path, undefined); + }, + // Returns a promise that settles once the given path has been fetched as an // object. object: async (path, type) => { const object = document.createElement("object"); - const loaded = new Promise(resolve => { + const object_load_settled = new Promise(resolve => { object.onload = object.onerror = resolve; }); object.data = load.cache_bust(path); if (type) { object.type = type; } - object.style = "width: 0px; height: 0px"; document.body.appendChild(object); - await loaded; - document.body.removeChild(object); + await await_with_timeout(2000, + "Timeout was reached before load or error events fired", + object_load_settled, + () => { document.body.removeChild(object) } + ); }, // Returns a promise that settles once the given path has been fetched diff --git a/test/fixtures/wpt/resource-timing/resources/test-initiator.js b/test/fixtures/wpt/resource-timing/resources/test-initiator.js new file mode 100644 index 00000000000..f839b463c56 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/resources/test-initiator.js @@ -0,0 +1,16 @@ +function testResourceInitiator(resourceName, expectedInitiator) { + return new Promise(resolve => { + const observer = new PerformanceObserver(list => { + const entries = list.getEntriesByType('resource'); + for (const entry of entries) { + if (entry.name.endsWith(resourceName)) { + observer.disconnect(); + assert_equals(entry.initiator, expectedInitiator, `Test ${resourceName} initiator`); + resolve(); + return; + } + } + }); + observer.observe({entryTypes: ['resource']}); + }); +} \ No newline at end of file diff --git a/test/fixtures/wpt/resource-timing/response-status-code.html b/test/fixtures/wpt/resource-timing/response-status-code.html new file mode 100644 index 00000000000..3a184c6f016 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/response-status-code.html @@ -0,0 +1,165 @@ + + + + +This test validates the response status of resources. + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/sizes-redirect-img.html b/test/fixtures/wpt/resource-timing/sizes-redirect-img.html index 786018d0c46..e440029782b 100644 --- a/test/fixtures/wpt/resource-timing/sizes-redirect-img.html +++ b/test/fixtures/wpt/resource-timing/sizes-redirect-img.html @@ -18,7 +18,7 @@ const redirectUrl = (redirectSourceOrigin, targetUrl) => { return redirectSourceOrigin + - '/resource-timing/resources/redirect-cors.py?timing_allow_origin=*' + + '/resource-timing/resources/redirect-cors.py?allow_origin=*&timing_allow_origin=*' + '&location=' + encodeURIComponent(targetUrl); }; @@ -35,18 +35,18 @@ verify_entry, "PerformanceResourceTiming sizes redirect image - same origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, baseUrl), verify_entry, "PerformanceResourceTiming sizes redirect image - cross origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, redirectUrl(hostInfo.HTTP_ORIGIN, baseUrl)), verify_entry, "PerformanceResourceTiming sizes redirect image - cross origin to same origin redirect"); -attribute_test(load.image, +attribute_test(load.image_cors, redirectUrl(hostInfo.HTTP_ORIGIN, redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, redirectUrl(hostInfo.HTTP_ORIGIN, diff --git a/test/fixtures/wpt/resource-timing/tentative/document-initiated.html b/test/fixtures/wpt/resource-timing/tentative/document-initiated.html new file mode 100644 index 00000000000..eea2bb2761d --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/document-initiated.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample Image for testing initiator Attribute + + + + + diff --git a/test/fixtures/wpt/resource-timing/tentative/script-initiated.html b/test/fixtures/wpt/resource-timing/tentative/script-initiated.html new file mode 100644 index 00000000000..d6f3d1a3203 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/script-initiated.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html b/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html new file mode 100644 index 00000000000..d12e3d193d0 --- /dev/null +++ b/test/fixtures/wpt/resource-timing/tentative/stylesheet-initiated.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/test/fixtures/wpt/resource-timing/tojson.html b/test/fixtures/wpt/resource-timing/tojson.html index 7a6187d3d55..2564b855dff 100644 --- a/test/fixtures/wpt/resource-timing/tojson.html +++ b/test/fixtures/wpt/resource-timing/tojson.html @@ -47,7 +47,9 @@ 'transferSize', 'encodedBodySize', 'decodedBodySize', - 'renderBlockingStatus' + 'renderBlockingStatus', + 'responseStatus', + 'contentType', ]; for (const key of performanceResourceTimingKeys) { try { diff --git a/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js b/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js index 8ab08b0294c..99a3e911eb6 100644 --- a/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js +++ b/test/fixtures/wpt/resources/declarative-shadow-dom-polyfill.js @@ -16,7 +16,8 @@ function polyfill_declarative_shadow_dom(root) { return; root.querySelectorAll("template[shadowrootmode]").forEach(template => { const mode = template.getAttribute("shadowrootmode"); - const shadowRoot = template.parentNode.attachShadow({ mode }); + const delegatesFocus = template.hasAttribute("shadowrootdelegatesfocus"); + const shadowRoot = template.parentNode.attachShadow({ mode, delegatesFocus }); shadowRoot.appendChild(template.content); template.remove(); polyfill_declarative_shadow_dom(shadowRoot); diff --git a/test/fixtures/wpt/resources/idlharness.js b/test/fixtures/wpt/resources/idlharness.js index 46aa11e5ca1..8f741b09b26 100644 --- a/test/fixtures/wpt/resources/idlharness.js +++ b/test/fixtures/wpt/resources/idlharness.js @@ -2357,12 +2357,13 @@ IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject assert_equals(typeof memberHolderObject[member.name], "function", "property must be a function"); - const ctors = this.members.filter(function(m) { - return m.type == "operation" && m.name == member.name; + const operationOverloads = this.members.filter(function(m) { + return m.type == "operation" && m.name == member.name && + (m.special === "static") === (member.special === "static"); }); assert_equals( memberHolderObject[member.name].length, - minOverloadLength(ctors), + minOverloadLength(operationOverloads), "property has wrong .length"); assert_equals( memberHolderObject[member.name].name, diff --git a/test/fixtures/wpt/resources/testdriver.js b/test/fixtures/wpt/resources/testdriver.js index 76ae2834fdf..0327e1759a9 100644 --- a/test/fixtures/wpt/resources/testdriver.js +++ b/test/fixtures/wpt/resources/testdriver.js @@ -220,6 +220,40 @@ return cookie; }, + /** + * Get Computed Label for an element. + * + * This matches the behaviour of the + * `Get Computed Label + * `_ + * WebDriver command. + * + * @param {Element} element + * @returns {Promise} fulfilled after the computed label is returned, or + * rejected in the cases the WebDriver command errors + */ + get_computed_label: async function(element) { + let label = await window.test_driver_internal.get_computed_label(element); + return label; + }, + + /** + * Get Computed Role for an element. + * + * This matches the behaviour of the + * `Get Computed Label + * `_ + * WebDriver command. + * + * @param {Element} element + * @returns {Promise} fulfilled after the computed role is returned, or + * rejected in the cases the WebDriver command errors + */ + get_computed_role: async function(element) { + let role = await window.test_driver_internal.get_computed_role(element); + return role; + }, + /** * Send keys to an element. * @@ -228,7 +262,9 @@ * occurs. * * If ``element`` is from a different browsing context, the - * command will be run in that context. + * command will be run in that context. The test must not depend + * on the ``window.name`` property being unset on the target + * window. * * To send special keys, send the respective key's codepoint, * as defined by `WebDriver @@ -262,12 +298,6 @@ inline: "nearest"}); } - var pointerInteractablePaintTree = getPointerInteractablePaintTree(element); - if (pointerInteractablePaintTree.length === 0 || - !element.contains(pointerInteractablePaintTree[0])) { - return Promise.reject(new Error("element send_keys intercepted error")); - } - return window.test_driver_internal.send_keys(element, keys); }, @@ -300,9 +330,9 @@ * to run the call, or null for the current * browsing context. * - * @returns {Promise} fulfilled with the previous {@link - * https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect} - * value, after the window is minimized. + * @returns {Promise} fulfilled with the previous `WindowRect + * `_ + * value, after the window is minimized. */ minimize_window: function(context=null) { return window.test_driver_internal.minimize_window(context); @@ -315,8 +345,8 @@ * `_ * WebDriver command * - * @param {Object} rect - A {@link - * https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect} + * @param {Object} rect - A `WindowRect + * `_ * @param {WindowProxy} context - Browsing context in which * to run the call, or null for the current * browsing context. @@ -389,8 +419,9 @@ /** * Sets the state of a permission * - * This function simulates a user setting a permission into a - * particular state. + * This function causes permission requests and queries for the status + * of a certain permission type (e.g. "push", or "background-fetch") to + * always return ``state``. * * Matches the `Set Permission * `_ @@ -402,8 +433,10 @@ * * @param {PermissionDescriptor} descriptor - a `PermissionDescriptor * `_ - * dictionary. - * @param {String} state - the state of the permission + * or derived object. + * @param {PermissionState} state - a `PermissionState + * `_ + * value. * @param {WindowProxy} context - Browsing context in which * to run the call, or null for the current * browsing context. @@ -646,6 +679,295 @@ set_spc_transaction_mode: function(mode, context=null) { return window.test_driver_internal.set_spc_transaction_mode(mode, context); }, + + /** + * Cancels the Federated Credential Management dialog + * + * Matches the `Cancel dialog + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the dialog is canceled, or rejected + * in case the WebDriver command errors + */ + cancel_fedcm_dialog: function(context=null) { + return window.test_driver_internal.cancel_fedcm_dialog(context); + }, + + /** + * Accepts a FedCM "Confirm IDP login" dialog. + * + * Matches the `Confirm IDP Login + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the IDP login has started, + * or rejected in case the WebDriver command errors + */ + confirm_idp_login: function(context=null) { + return window.test_driver_internal.confirm_idp_login(context); + }, + + /** + * Selects an account from the Federated Credential Management dialog + * + * Matches the `Select account + * `_ + * WebDriver command. + * + * @param {number} account_index - Index of the account to select. + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the account is selected, + * or rejected in case the WebDriver command errors + */ + select_fedcm_account: function(account_index, context=null) { + return window.test_driver_internal.select_fedcm_account(account_index, context); + }, + + /** + * Gets the account list from the Federated Credential Management dialog + * + * Matches the `Account list + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} fulfilled after the account list is returned, or + * rejected in case the WebDriver command errors + */ + get_fedcm_account_list: function(context=null) { + return window.test_driver_internal.get_fedcm_account_list(context); + }, + + /** + * Gets the title of the Federated Credential Management dialog + * + * Matches the `Get title + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the title is returned, or rejected + * in case the WebDriver command errors + */ + get_fedcm_dialog_title: function(context=null) { + return window.test_driver_internal.get_fedcm_dialog_title(context); + }, + + /** + * Gets the type of the Federated Credential Management dialog + * + * Matches the `Get dialog type + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the dialog type is returned, or + * rejected in case the WebDriver command errors + */ + get_fedcm_dialog_type: function(context=null) { + return window.test_driver_internal.get_fedcm_dialog_type(context); + }, + + /** + * Sets whether promise rejection delay is enabled for the Federated Credential Management dialog + * + * Matches the `Set delay enabled + * `_ + * WebDriver command. + * + * @param {boolean} enabled - Whether to delay FedCM promise rejection. + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the delay has been enabled or disabled, + * or rejected in case the WebDriver command errors + */ + set_fedcm_delay_enabled: function(enabled, context=null) { + return window.test_driver_internal.set_fedcm_delay_enabled(enabled, context); + }, + + /** + * Resets the Federated Credential Management dialog's cooldown + * + * Matches the `Reset cooldown + * `_ + * WebDriver command. + * + * @param {WindowProxy} context - Browsing context in which + * to run the call, or null for the current + * browsing context. + * + * @returns {Promise} Fulfilled after the cooldown has been reset, + * or rejected in case the WebDriver command errors + */ + reset_fedcm_cooldown: function(context=null) { + return window.test_driver_internal.reset_fedcm_cooldown(context); + }, + + /** + * Creates a virtual sensor for use with the Generic Sensors APIs. + * + * Matches the `Create Virtual Sensor + * `_ + * WebDriver command. + * + * Once created, a virtual sensor is available to all navigables under + * the same top-level traversable (i.e. all frames in the same page, + * regardless of origin). + * + * @param {String} sensor_type - A `virtual sensor type + * `_ + * such as "accelerometer". + * @param {Object} [sensor_params={}] - Optional parameters described + * in `Create Virtual Sensor + * `_. + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled when virtual sensor is created. + * Rejected in case the WebDriver command errors out + * (including if a virtual sensor of the same type + * already exists). + */ + create_virtual_sensor: function(sensor_type, sensor_params={}, context=null) { + return window.test_driver_internal.create_virtual_sensor(sensor_type, sensor_params, context); + }, + + /** + * Causes a virtual sensor to report a new reading to any connected + * platform sensor. + * + * Matches the `Update Virtual Sensor Reading + * `_ + * WebDriver command. + * + * Note: The ``Promise`` it returns may fulfill before or after a + * "reading" event is fired. When using + * :js:func:`EventWatcher.wait_for`, it is necessary to take this into + * account: + * + * Note: New values may also be discarded due to the checks in `update + * latest reading + * `_. + * + * @example + * // Avoid races between EventWatcher and update_virtual_sensor(). + * // This assumes you are sure this reading will be processed (see + * // the example below otherwise). + * const reading = { x: 1, y: 2, z: 3 }; + * await Promise.all([ + * test_driver.update_virtual_sensor('gyroscope', reading), + * watcher.wait_for('reading') + * ]); + * + * @example + * // Do not wait forever if you are not sure the reading will be + * // processed. + * const readingPromise = watcher.wait_for('reading'); + * const timeoutPromise = new Promise(resolve => { + * t.step_timeout(() => resolve('TIMEOUT', 3000)) + * }); + * + * const reading = { x: 1, y: 2, z: 3 }; + * await test_driver.update_virtual_sensor('gyroscope', 'reading'); + * + * const value = + * await Promise.race([timeoutPromise, readingPromise]); + * if (value !== 'TIMEOUT') { + * // Do something. The "reading" event was fired. + * } + * + * @param {String} sensor_type - A `virtual sensor type + * `_ + * such as "accelerometer". + * @param {Object} reading - An Object describing a reading in a format + * dependent on ``sensor_type`` (e.g. ``{x: + * 1, y: 2, z: 3}`` or ``{ illuminance: 42 + * }``). + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled after the reading update reaches the + * virtual sensor. Rejected in case the WebDriver + * command errors out (including if a virtual sensor + * of the given type does not exist). + */ + update_virtual_sensor: function(sensor_type, reading, context=null) { + return window.test_driver_internal.update_virtual_sensor(sensor_type, reading, context); + }, + + /** + * Triggers the removal of a virtual sensor if it exists. + * + * Matches the `Delete Virtual Sensor + * `_ + * WebDriver command. + * + * @param {String} sensor_type - A `virtual sensor type + * `_ + * such as "accelerometer". + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled after the virtual sensor has been + * removed or if a sensor of the given type does not + * exist. Rejected in case the WebDriver command + * errors out. + + */ + remove_virtual_sensor: function(sensor_type, context=null) { + return window.test_driver_internal.remove_virtual_sensor(sensor_type, context); + }, + + /** + * Returns information about a virtual sensor. + * + * Matches the `Get Virtual Sensor Information + * `_ + * WebDriver command. + * + * @param {String} sensor_type - A `virtual sensor type + * `_ + * such as "accelerometer". + * @param {WindowProxy} [context=null] - Browsing context in which to + * run the call, or null for the + * current browsing context. + * + * @returns {Promise} Fulfilled with an Object with the properties + * described in `Get Virtual Sensor Information + * `_. + * Rejected in case the WebDriver command errors out + * (including if a virtual sensor of the given type + * does not exist). + */ + get_virtual_sensor_information: function(sensor_type, context=null) { + return window.test_driver_internal.get_virtual_sensor_information(sensor_type, context); + } }; window.test_driver_internal = { @@ -657,9 +979,9 @@ */ in_automation: false, - click: function(element, coords) { + async click(element, coords) { if (this.in_automation) { - return Promise.reject(new Error('Not implemented')); + throw new Error("click() is not implemented by testdriver-vendor.js"); } return new Promise(function(resolve, reject) { @@ -667,21 +989,21 @@ }); }, - delete_all_cookies: function(context=null) { - return Promise.reject(new Error("unimplemented")); + async delete_all_cookies(context=null) { + throw new Error("delete_all_cookies() is not implemented by testdriver-vendor.js"); }, - get_all_cookies: function(context=null) { - return Promise.reject(new Error("unimplemented")); + async get_all_cookies(context=null) { + throw new Error("get_all_cookies() is not implemented by testdriver-vendor.js"); }, - get_named_cookie: function(name, context=null) { - return Promise.reject(new Error("unimplemented")); + async get_named_cookie(name, context=null) { + throw new Error("get_named_cookie() is not implemented by testdriver-vendor.js"); }, - send_keys: function(element, keys) { + async send_keys(element, keys) { if (this.in_automation) { - return Promise.reject(new Error('Not implemented')); + throw new Error("send_keys() is not implemented by testdriver-vendor.js"); } return new Promise(function(resolve, reject) { @@ -711,66 +1033,112 @@ }); }, - freeze: function(context=null) { - return Promise.reject(new Error("unimplemented")); + async freeze(context=null) { + throw new Error("freeze() is not implemented by testdriver-vendor.js"); }, - minimize_window: function(context=null) { - return Promise.reject(new Error("unimplemented")); + async minimize_window(context=null) { + throw new Error("minimize_window() is not implemented by testdriver-vendor.js"); }, - set_window_rect: function(rect, context=null) { - return Promise.reject(new Error("unimplemented")); + async set_window_rect(rect, context=null) { + throw new Error("set_window_rect() is not implemented by testdriver-vendor.js"); }, - action_sequence: function(actions, context=null) { - return Promise.reject(new Error("unimplemented")); + async action_sequence(actions, context=null) { + throw new Error("action_sequence() is not implemented by testdriver-vendor.js"); }, - generate_test_report: function(message, context=null) { - return Promise.reject(new Error("unimplemented")); + async generate_test_report(message, context=null) { + throw new Error("generate_test_report() is not implemented by testdriver-vendor.js"); }, + async set_permission(permission_params, context=null) { + throw new Error("set_permission() is not implemented by testdriver-vendor.js"); + }, - set_permission: function(permission_params, context=null) { - return Promise.reject(new Error("unimplemented")); + async add_virtual_authenticator(config, context=null) { + throw new Error("add_virtual_authenticator() is not implemented by testdriver-vendor.js"); }, - add_virtual_authenticator: function(config, context=null) { - return Promise.reject(new Error("unimplemented")); + async remove_virtual_authenticator(authenticator_id, context=null) { + throw new Error("remove_virtual_authenticator() is not implemented by testdriver-vendor.js"); }, - remove_virtual_authenticator: function(authenticator_id, context=null) { - return Promise.reject(new Error("unimplemented")); + async add_credential(authenticator_id, credential, context=null) { + throw new Error("add_credential() is not implemented by testdriver-vendor.js"); }, - add_credential: function(authenticator_id, credential, context=null) { - return Promise.reject(new Error("unimplemented")); + async get_credentials(authenticator_id, context=null) { + throw new Error("get_credentials() is not implemented by testdriver-vendor.js"); }, - get_credentials: function(authenticator_id, context=null) { - return Promise.reject(new Error("unimplemented")); + async remove_credential(authenticator_id, credential_id, context=null) { + throw new Error("remove_credential() is not implemented by testdriver-vendor.js"); }, - remove_credential: function(authenticator_id, credential_id, context=null) { - return Promise.reject(new Error("unimplemented")); + async remove_all_credentials(authenticator_id, context=null) { + throw new Error("remove_all_credentials() is not implemented by testdriver-vendor.js"); }, - remove_all_credentials: function(authenticator_id, context=null) { - return Promise.reject(new Error("unimplemented")); + async set_user_verified(authenticator_id, uv, context=null) { + throw new Error("set_user_verified() is not implemented by testdriver-vendor.js"); }, - set_user_verified: function(authenticator_id, uv, context=null) { - return Promise.reject(new Error("unimplemented")); + async set_storage_access(origin, embedding_origin, blocked, context=null) { + throw new Error("set_storage_access() is not implemented by testdriver-vendor.js"); }, - set_storage_access: function(origin, embedding_origin, blocked, context=null) { - return Promise.reject(new Error("unimplemented")); + async set_spc_transaction_mode(mode, context=null) { + throw new Error("set_spc_transaction_mode() is not implemented by testdriver-vendor.js"); }, - set_spc_transaction_mode: function(mode, context=null) { - return Promise.reject(new Error("unimplemented")); + async cancel_fedcm_dialog(context=null) { + throw new Error("cancel_fedcm_dialog() is not implemented by testdriver-vendor.js"); + }, + + async confirm_idp_login(context=null) { + throw new Error("confirm_idp_login() is not implemented by testdriver-vendor.js"); + }, + + async select_fedcm_account(account_index, context=null) { + throw new Error("select_fedcm_account() is not implemented by testdriver-vendor.js"); + }, + + async get_fedcm_account_list(context=null) { + throw new Error("get_fedcm_account_list() is not implemented by testdriver-vendor.js"); + }, + + async get_fedcm_dialog_title(context=null) { + throw new Error("get_fedcm_dialog_title() is not implemented by testdriver-vendor.js"); + }, + + async get_fedcm_dialog_type(context=null) { + throw new Error("get_fedcm_dialog_type() is not implemented by testdriver-vendor.js"); }, + async set_fedcm_delay_enabled(enabled, context=null) { + throw new Error("set_fedcm_delay_enabled() is not implemented by testdriver-vendor.js"); + }, + + async reset_fedcm_cooldown(context=null) { + throw new Error("reset_fedcm_cooldown() is not implemented by testdriver-vendor.js"); + }, + + async create_virtual_sensor(sensor_type, sensor_params, context=null) { + throw new Error("create_virtual_sensor() is not implemented by testdriver-vendor.js"); + }, + + async update_virtual_sensor(sensor_type, reading, context=null) { + throw new Error("update_virtual_sensor() is not implemented by testdriver-vendor.js"); + }, + + async remove_virtual_sensor(sensor_type, context=null) { + throw new Error("remove_virtual_sensor() is not implemented by testdriver-vendor.js"); + }, + + async get_virtual_sensor_information(sensor_type, context=null) { + throw new Error("get_virtual_sensor_information() is not implemented by testdriver-vendor.js"); + } }; })(); diff --git a/test/fixtures/wpt/resources/testharness.js b/test/fixtures/wpt/resources/testharness.js index 112790bb1ee..497ae23f0e8 100644 --- a/test/fixtures/wpt/resources/testharness.js +++ b/test/fixtures/wpt/resources/testharness.js @@ -1426,12 +1426,16 @@ function assert_wrapper(...args) { let status = Test.statuses.TIMEOUT; let stack = null; + let new_assert_index = null; try { if (settings.debug) { console.debug("ASSERT", name, tests.current_test && tests.current_test.name, args); } if (tests.output) { tests.set_assert(name, args); + // Remember the newly pushed assert's index, because `apply` + // below might push new asserts. + new_assert_index = tests.asserts_run.length - 1; } const rv = f.apply(undefined, args); status = Test.statuses.PASS; @@ -1445,7 +1449,7 @@ stack = get_stack(); } if (tests.output) { - tests.set_assert_status(status, stack); + tests.set_assert_status(new_assert_index, status, stack); } } } @@ -1493,7 +1497,7 @@ /** * Assert that ``actual`` is the same value as ``expected``. * - * For objects this compares by cobject identity; for primitives + * For objects this compares by object identity; for primitives * this distinguishes between 0 and -0, and has correct handling * of NaN. * @@ -2725,8 +2729,9 @@ * speed when the condition is quickly met. * * @param {Function} cond A function taking no arguments and - * returning a boolean. The callback is called - * when this function returns true. + * returning a boolean or a Promise. The callback is + * called when this function returns true, or the + * returned Promise is resolved with true. * @param {Function} func A function taking no arguments to call once * the condition is met. * @param {string} [description] Error message to add to assert in case of @@ -2742,11 +2747,11 @@ var remaining = Math.ceil(timeout_full / interval); var test_this = this; - var wait_for_inner = test_this.step_func(() => { - if (cond()) { + const step = test_this.step_func((result) => { + if (result) { func(); } else { - if(remaining === 0) { + if (remaining === 0) { assert(false, "step_wait_func", description, "Timed out waiting on condition"); } @@ -2755,6 +2760,12 @@ } }); + var wait_for_inner = test_this.step_func(() => { + Promise.resolve(cond()).then( + step, + test_this.unreached_func("step_wait_func")); + }); + wait_for_inner(); }; @@ -2780,8 +2791,9 @@ * }, "Navigating a popup to about:blank"); * * @param {Function} cond A function taking no arguments and - * returning a boolean. The callback is called - * when this function returns true. + * returning a boolean or a Promise. The callback is + * called when this function returns true, or the + * returned Promise is resolved with true. * @param {Function} func A function taking no arguments to call once * the condition is met. * @param {string} [description] Error message to add to assert in case of @@ -2817,7 +2829,7 @@ * }, ""); * * @param {Function} cond A function taking no arguments and - * returning a boolean. + * returning a boolean or a Promise. * @param {string} [description] Error message to add to assert in case of * failure. * @param {number} timeout Timeout in ms. This is multiplied by the global @@ -3673,8 +3685,8 @@ this.asserts_run.push(new AssertRecord(this.current_test, assert_name, args)) } - Tests.prototype.set_assert_status = function(status, stack) { - let assert_record = this.asserts_run[this.asserts_run.length - 1]; + Tests.prototype.set_assert_status = function(index, status, stack) { + let assert_record = this.asserts_run[index]; assert_record.status = status; assert_record.stack = stack; } diff --git a/test/fixtures/wpt/streams/piping/abort.any.js b/test/fixtures/wpt/streams/piping/abort.any.js index 503de9dcaf0..c9929df91cf 100644 --- a/test/fixtures/wpt/streams/piping/abort.any.js +++ b/test/fixtures/wpt/streams/piping/abort.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/close-propagation-backward.any.js b/test/fixtures/wpt/streams/piping/close-propagation-backward.any.js index 5ea47ab85c0..25bd475ed13 100644 --- a/test/fixtures/wpt/streams/piping/close-propagation-backward.any.js +++ b/test/fixtures/wpt/streams/piping/close-propagation-backward.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/close-propagation-forward.any.js b/test/fixtures/wpt/streams/piping/close-propagation-forward.any.js index 71b6e262840..0ec94f80abf 100644 --- a/test/fixtures/wpt/streams/piping/close-propagation-forward.any.js +++ b/test/fixtures/wpt/streams/piping/close-propagation-forward.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/crashtests/cross-piping.html b/test/fixtures/wpt/streams/piping/crashtests/cross-piping.html new file mode 100644 index 00000000000..712d5ecebef --- /dev/null +++ b/test/fixtures/wpt/streams/piping/crashtests/cross-piping.html @@ -0,0 +1,12 @@ + + diff --git a/test/fixtures/wpt/streams/piping/error-propagation-backward.any.js b/test/fixtures/wpt/streams/piping/error-propagation-backward.any.js index ec74592f86e..f786469d6c1 100644 --- a/test/fixtures/wpt/streams/piping/error-propagation-backward.any.js +++ b/test/fixtures/wpt/streams/piping/error-propagation-backward.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/error-propagation-forward.any.js b/test/fixtures/wpt/streams/piping/error-propagation-forward.any.js index 482da2f8a88..e9260f9ea22 100644 --- a/test/fixtures/wpt/streams/piping/error-propagation-forward.any.js +++ b/test/fixtures/wpt/streams/piping/error-propagation-forward.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/flow-control.any.js b/test/fixtures/wpt/streams/piping/flow-control.any.js index 09c4420f872..e2318da375a 100644 --- a/test/fixtures/wpt/streams/piping/flow-control.any.js +++ b/test/fixtures/wpt/streams/piping/flow-control.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js // META: script=../resources/recording-streams.js diff --git a/test/fixtures/wpt/streams/piping/general-addition.any.js b/test/fixtures/wpt/streams/piping/general-addition.any.js index 2562b706433..cf4aa9bea6a 100644 --- a/test/fixtures/wpt/streams/piping/general-addition.any.js +++ b/test/fixtures/wpt/streams/piping/general-addition.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; promise_test(async t => { diff --git a/test/fixtures/wpt/streams/piping/general.any.js b/test/fixtures/wpt/streams/piping/general.any.js index bec3480f653..09e01536325 100644 --- a/test/fixtures/wpt/streams/piping/general.any.js +++ b/test/fixtures/wpt/streams/piping/general.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/multiple-propagation.any.js b/test/fixtures/wpt/streams/piping/multiple-propagation.any.js index a78652fc067..9be828a2326 100644 --- a/test/fixtures/wpt/streams/piping/multiple-propagation.any.js +++ b/test/fixtures/wpt/streams/piping/multiple-propagation.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/pipe-through.any.js b/test/fixtures/wpt/streams/piping/pipe-through.any.js index 26b1cd26a3c..339cee19993 100644 --- a/test/fixtures/wpt/streams/piping/pipe-through.any.js +++ b/test/fixtures/wpt/streams/piping/pipe-through.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js diff --git a/test/fixtures/wpt/streams/piping/then-interception.any.js b/test/fixtures/wpt/streams/piping/then-interception.any.js index 543f916d940..fc48c368311 100644 --- a/test/fixtures/wpt/streams/piping/then-interception.any.js +++ b/test/fixtures/wpt/streams/piping/then-interception.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/piping/throwing-options.any.js b/test/fixtures/wpt/streams/piping/throwing-options.any.js index b9f906778f6..186f8ded196 100644 --- a/test/fixtures/wpt/streams/piping/throwing-options.any.js +++ b/test/fixtures/wpt/streams/piping/throwing-options.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; class ThrowingOptions { diff --git a/test/fixtures/wpt/streams/piping/transform-streams.any.js b/test/fixtures/wpt/streams/piping/transform-streams.any.js index caae9fbad88..e079bb637ca 100644 --- a/test/fixtures/wpt/streams/piping/transform-streams.any.js +++ b/test/fixtures/wpt/streams/piping/transform-streams.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; promise_test(() => { diff --git a/test/fixtures/wpt/streams/queuing-strategies.any.js b/test/fixtures/wpt/streams/queuing-strategies.any.js index fa959ebba28..9efc4570cf2 100644 --- a/test/fixtures/wpt/streams/queuing-strategies.any.js +++ b/test/fixtures/wpt/streams/queuing-strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const highWaterMarkConversions = new Map([ diff --git a/test/fixtures/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js b/test/fixtures/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js index 3322116b191..afcc61e6800 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/bad-buffers-and-views.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; promise_test(() => { diff --git a/test/fixtures/wpt/streams/readable-byte-streams/construct-byob-request.any.js b/test/fixtures/wpt/streams/readable-byte-streams/construct-byob-request.any.js index 8d460a1c81b..a26f949ee29 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/construct-byob-request.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/construct-byob-request.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js b/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js index d2b37f00a9d..92bd0a26a0e 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/enqueue-with-detached-buffer.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm promise_test(async t => { const error = new Error('cannot proceed'); diff --git a/test/fixtures/wpt/streams/readable-byte-streams/general.any.js b/test/fixtures/wpt/streams/readable-byte-streams/general.any.js index dd4fdc85578..cdce2244c3c 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/general.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/general.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-byte-streams/non-transferable-buffers.any.js b/test/fixtures/wpt/streams/readable-byte-streams/non-transferable-buffers.any.js index e8ea3c4f966..47d7b2e653e 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/non-transferable-buffers.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/non-transferable-buffers.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; promise_test(async t => { diff --git a/test/fixtures/wpt/streams/readable-byte-streams/respond-after-enqueue.any.js b/test/fixtures/wpt/streams/readable-byte-streams/respond-after-enqueue.any.js index b93cec97391..e51efa061a6 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/respond-after-enqueue.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/respond-after-enqueue.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js index 85844669cd9..7dd5ba3f3fb 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js diff --git a/test/fixtures/wpt/streams/readable-streams/async-iterator.any.js b/test/fixtures/wpt/streams/readable-streams/async-iterator.any.js index 3ccaca17bc1..4b674bea843 100644 --- a/test/fixtures/wpt/streams/readable-streams/async-iterator.any.js +++ b/test/fixtures/wpt/streams/readable-streams/async-iterator.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js diff --git a/test/fixtures/wpt/streams/readable-streams/bad-strategies.any.js b/test/fixtures/wpt/streams/readable-streams/bad-strategies.any.js index 521fbffe3ab..49fa4bdbece 100644 --- a/test/fixtures/wpt/streams/readable-streams/bad-strategies.any.js +++ b/test/fixtures/wpt/streams/readable-streams/bad-strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; test(() => { @@ -149,7 +149,9 @@ promise_test(() => { } ); - promises.push(rs.getReader().closed.catch(e => { + promises.push(rs.getReader().closed.then(() => { + assert_unreached('closed didn\'t throw'); + }, e => { assert_equals(e, theError, 'closed should reject with the error for ' + size); })); } @@ -157,3 +159,40 @@ promise_test(() => { return Promise.all(promises); }, 'Readable stream: invalid strategy.size return value'); + +promise_test(() => { + + const promises = []; + for (const size of [NaN, -Infinity, Infinity, -1]) { + let theError; + const rs = new ReadableStream( + { + pull(c) { + try { + c.enqueue('hi'); + assert_unreached('enqueue didn\'t throw'); + } catch (error) { + assert_equals(error.name, 'RangeError', 'enqueue should throw a RangeError for ' + size); + theError = error; + } + } + }, + { + size() { + return size; + }, + highWaterMark: 5 + } + ); + + promises.push(rs.getReader().closed.then(() => { + assert_unreached('closed didn\'t throw'); + }, e => { + assert_equals(e, theError, 'closed should reject with the error for ' + size); + })); + } + + return Promise.all(promises); + +}, 'Readable stream: invalid strategy.size return value when pulling'); + diff --git a/test/fixtures/wpt/streams/readable-streams/bad-underlying-sources.any.js b/test/fixtures/wpt/streams/readable-streams/bad-underlying-sources.any.js index e9cf4c92493..3d77b923d17 100644 --- a/test/fixtures/wpt/streams/readable-streams/bad-underlying-sources.any.js +++ b/test/fixtures/wpt/streams/readable-streams/bad-underlying-sources.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/cancel.any.js b/test/fixtures/wpt/streams/readable-streams/cancel.any.js index 800bd994417..9915c1fb633 100644 --- a/test/fixtures/wpt/streams/readable-streams/cancel.any.js +++ b/test/fixtures/wpt/streams/readable-streams/cancel.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/constructor.any.js b/test/fixtures/wpt/streams/readable-streams/constructor.any.js index 608dc48cfa3..0b995f0cb16 100644 --- a/test/fixtures/wpt/streams/readable-streams/constructor.any.js +++ b/test/fixtures/wpt/streams/readable-streams/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const error1 = new Error('error1'); diff --git a/test/fixtures/wpt/streams/readable-streams/count-queuing-strategy-integration.any.js b/test/fixtures/wpt/streams/readable-streams/count-queuing-strategy-integration.any.js index 02ac5bae5c2..a8c1b91d006 100644 --- a/test/fixtures/wpt/streams/readable-streams/count-queuing-strategy-integration.any.js +++ b/test/fixtures/wpt/streams/readable-streams/count-queuing-strategy-integration.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; test(() => { diff --git a/test/fixtures/wpt/streams/readable-streams/default-reader.any.js b/test/fixtures/wpt/streams/readable-streams/default-reader.any.js index 59d7ab2f74d..f92862719e4 100644 --- a/test/fixtures/wpt/streams/readable-streams/default-reader.any.js +++ b/test/fixtures/wpt/streams/readable-streams/default-reader.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/floating-point-total-queue-size.any.js b/test/fixtures/wpt/streams/readable-streams/floating-point-total-queue-size.any.js index 50cca3d951a..8b88c21d7f0 100644 --- a/test/fixtures/wpt/streams/readable-streams/floating-point-total-queue-size.any.js +++ b/test/fixtures/wpt/streams/readable-streams/floating-point-total-queue-size.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; // Due to the limitations of floating-point precision, the calculation of desiredSize sometimes gives different answers diff --git a/test/fixtures/wpt/streams/readable-streams/from.any.js b/test/fixtures/wpt/streams/readable-streams/from.any.js index 04a03545ad5..58ad4d4add1 100644 --- a/test/fixtures/wpt/streams/readable-streams/from.any.js +++ b/test/fixtures/wpt/streams/readable-streams/from.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker,jsshell +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js b/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js index e578176777a..13bd1fb3437 100644 --- a/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js +++ b/test/fixtures/wpt/streams/readable-streams/garbage-collection.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=/common/gc.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/general.any.js b/test/fixtures/wpt/streams/readable-streams/general.any.js index 2a32b27943c..eee3f62215e 100644 --- a/test/fixtures/wpt/streams/readable-streams/general.any.js +++ b/test/fixtures/wpt/streams/readable-streams/general.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/owning-type-message-port.any.js b/test/fixtures/wpt/streams/readable-streams/owning-type-message-port.any.js index e9961ce0422..282c1f41148 100644 --- a/test/fixtures/wpt/streams/readable-streams/owning-type-message-port.any.js +++ b/test/fixtures/wpt/streams/readable-streams/owning-type-message-port.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js b/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js index ec01fda0b3c..b652f9c5fcb 100644 --- a/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js +++ b/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/owning-type.any.js b/test/fixtures/wpt/streams/readable-streams/owning-type.any.js index 27a3dda894e..34c2a55d513 100644 --- a/test/fixtures/wpt/streams/readable-streams/owning-type.any.js +++ b/test/fixtures/wpt/streams/readable-streams/owning-type.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/readable-streams/patched-global.any.js b/test/fixtures/wpt/streams/readable-streams/patched-global.any.js index a64a054a97f..c208824c864 100644 --- a/test/fixtures/wpt/streams/readable-streams/patched-global.any.js +++ b/test/fixtures/wpt/streams/readable-streams/patched-global.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; // Tests which patch the global environment are kept separate to avoid diff --git a/test/fixtures/wpt/streams/readable-streams/reentrant-strategies.any.js b/test/fixtures/wpt/streams/readable-streams/reentrant-strategies.any.js index b4988bc2433..8ae7b98e8d5 100644 --- a/test/fixtures/wpt/streams/readable-streams/reentrant-strategies.any.js +++ b/test/fixtures/wpt/streams/readable-streams/reentrant-strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js diff --git a/test/fixtures/wpt/streams/readable-streams/tee.any.js b/test/fixtures/wpt/streams/readable-streams/tee.any.js index 00397932f4b..c2c2e482307 100644 --- a/test/fixtures/wpt/streams/readable-streams/tee.any.js +++ b/test/fixtures/wpt/streams/readable-streams/tee.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js diff --git a/test/fixtures/wpt/streams/readable-streams/templated.any.js b/test/fixtures/wpt/streams/readable-streams/templated.any.js index ecae3f4d8b1..dc75b805a10 100644 --- a/test/fixtures/wpt/streams/readable-streams/templated.any.js +++ b/test/fixtures/wpt/streams/readable-streams/templated.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-test-templates.js 'use strict'; diff --git a/test/fixtures/wpt/streams/transferable/transform-stream-members.any.js b/test/fixtures/wpt/streams/transferable/transform-stream-members.any.js index fca060b0c05..05914e12ccb 100644 --- a/test/fixtures/wpt/streams/transferable/transform-stream-members.any.js +++ b/test/fixtures/wpt/streams/transferable/transform-stream-members.any.js @@ -1,3 +1,5 @@ +// META: global=window,dedicatedworker,shadowrealm + const combinations = [ (t => [t, t.readable])(new TransformStream()), (t => [t.readable, t])(new TransformStream()), diff --git a/test/fixtures/wpt/streams/transform-streams/backpressure.any.js b/test/fixtures/wpt/streams/transform-streams/backpressure.any.js index 6befba41b79..47a21fb7e71 100644 --- a/test/fixtures/wpt/streams/transform-streams/backpressure.any.js +++ b/test/fixtures/wpt/streams/transform-streams/backpressure.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/transform-streams/cancel.any.js b/test/fixtures/wpt/streams/transform-streams/cancel.any.js new file mode 100644 index 00000000000..5c7fc4eae5d --- /dev/null +++ b/test/fixtures/wpt/streams/transform-streams/cancel.any.js @@ -0,0 +1,115 @@ +// META: global=window,worker,shadowrealm +// META: script=../resources/test-utils.js +'use strict'; + +const thrownError = new Error('bad things are happening!'); +thrownError.name = 'error1'; + +const originalReason = new Error('original reason'); +originalReason.name = 'error2'; + +promise_test(async t => { + let cancelled = undefined; + const ts = new TransformStream({ + cancel(reason) { + cancelled = reason; + } + }); + const res = await ts.readable.cancel(thrownError); + assert_equals(res, undefined, 'readable.cancel() should return undefined'); + assert_equals(cancelled, thrownError, 'transformer.cancel() should be called with the passed reason'); +}, 'cancelling the readable side should call transformer.cancel()'); + +promise_test(async t => { + const ts = new TransformStream({ + cancel(reason) { + assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); + throw thrownError; + } + }); + const writer = ts.writable.getWriter(); + const cancelPromise = ts.readable.cancel(originalReason); + await promise_rejects_exactly(t, thrownError, cancelPromise, 'readable.cancel() should reject with thrownError'); + await promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject with thrownError'); +}, 'cancelling the readable side should reject if transformer.cancel() throws'); + +promise_test(async t => { + let aborted = undefined; + const ts = new TransformStream({ + cancel(reason) { + aborted = reason; + }, + flush: t.unreached_func('flush should not be called') + }); + const res = await ts.writable.abort(thrownError); + assert_equals(res, undefined, 'writable.abort() should return undefined'); + assert_equals(aborted, thrownError, 'transformer.abort() should be called with the passed reason'); +}, 'aborting the writable side should call transformer.abort()'); + +promise_test(async t => { + const ts = new TransformStream({ + cancel(reason) { + assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); + throw thrownError; + }, + flush: t.unreached_func('flush should not be called') + }); + const reader = ts.readable.getReader(); + const abortPromise = ts.writable.abort(originalReason); + await promise_rejects_exactly(t, thrownError, abortPromise, 'writable.abort() should reject with thrownError'); + await promise_rejects_exactly(t, thrownError, reader.closed, 'reader.closed should reject with thrownError'); +}, 'aborting the writable side should reject if transformer.cancel() throws'); + +promise_test(async t => { + const ts = new TransformStream({ + async cancel(reason) { + assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); + throw thrownError; + }, + flush: t.unreached_func('flush should not be called') + }); + const cancelPromise = ts.readable.cancel(originalReason); + const closePromise = ts.writable.close(); + await Promise.all([ + promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), + promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), + ]); +}, 'closing the writable side should reject if a parallel transformer.cancel() throws'); + +promise_test(async t => { + let controller; + const ts = new TransformStream({ + start(c) { + controller = c; + }, + async cancel(reason) { + assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); + controller.error(thrownError); + }, + flush: t.unreached_func('flush should not be called') + }); + const cancelPromise = ts.readable.cancel(originalReason); + const closePromise = ts.writable.close(); + await Promise.all([ + promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), + promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), + ]); +}, 'readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()'); + +promise_test(async t => { + let controller; + const ts = new TransformStream({ + start(c) { + controller = c; + }, + async cancel(reason) { + assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); + controller.error(thrownError); + }, + flush: t.unreached_func('flush should not be called') + }); + const cancelPromise = ts.writable.abort(originalReason); + await promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'); + const closePromise = ts.readable.cancel(1); + await promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'); +}, 'writable.abort() and readable.cancel() should reject if a transformer.cancel() calls controller.error()'); diff --git a/test/fixtures/wpt/streams/transform-streams/errors.any.js b/test/fixtures/wpt/streams/transform-streams/errors.any.js index 0cca4c75479..bea060b6590 100644 --- a/test/fixtures/wpt/streams/transform-streams/errors.any.js +++ b/test/fixtures/wpt/streams/transform-streams/errors.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js 'use strict'; @@ -9,7 +9,8 @@ promise_test(t => { const ts = new TransformStream({ transform() { throw thrownError; - } + }, + cancel: t.unreached_func('cancel should not be called') }); const reader = ts.readable.getReader(); @@ -34,7 +35,8 @@ promise_test(t => { }, flush() { throw thrownError; - } + }, + cancel: t.unreached_func('cancel should not be called') }); const reader = ts.readable.getReader(); @@ -54,13 +56,14 @@ promise_test(t => { ]); }, 'TransformStream errors thrown in flush put the writable and readable in an errored state'); -test(() => { +test(t => { new TransformStream({ start(c) { c.enqueue('a'); c.error(new Error('generic error')); assert_throws_js(TypeError, () => c.enqueue('b'), 'enqueue() should throw'); - } + }, + cancel: t.unreached_func('cancel should not be called') }); }, 'errored TransformStream should not enqueue new chunks'); @@ -72,7 +75,8 @@ promise_test(t => { }); }, transform: t.unreached_func('transform should not be called'), - flush: t.unreached_func('flush should not be called') + flush: t.unreached_func('flush should not be called'), + cancel: t.unreached_func('cancel should not be called') }); const writer = ts.writable.getWriter(); @@ -96,7 +100,8 @@ promise_test(t => { }); }, transform: t.unreached_func('transform should never be called if start() fails'), - flush: t.unreached_func('flush should never be called if start() fails') + flush: t.unreached_func('flush should never be called if start() fails'), + cancel: t.unreached_func('cancel should never be called if start() fails') }); const writer = ts.writable.getWriter(); @@ -202,9 +207,10 @@ promise_test(t => { return Promise.all([ abortPromise, cancelPromise, - promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject with thrownError')]); -}, 'abort should set the close reason for the writable when it happens before cancel during start, but cancel should ' + - 'still succeed'); + promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject'), + ]); +}, 'abort should set the close reason for the writable when it happens before cancel during start, and cancel should ' + + 'reject'); promise_test(t => { let resolveTransform; @@ -251,13 +257,26 @@ promise_test(t => { controller = c; } }); - const cancelPromise = ts.readable.cancel(thrownError); - controller.error(ignoredError); + const cancelPromise = ts.readable.cancel(ignoredError); + controller.error(thrownError); return Promise.all([ cancelPromise, promise_rejects_exactly(t, thrownError, ts.writable.getWriter().closed, 'closed should reject with thrownError') ]); -}, 'controller.error() should do nothing after readable.cancel()'); +}, 'controller.error() should close writable immediately after readable.cancel()'); + +promise_test(t => { + let controller; + const ts = new TransformStream({ + start(c) { + controller = c; + } + }); + return ts.readable.cancel(thrownError).then(() => { + controller.error(ignoredError); + return promise_rejects_exactly(t, thrownError, ts.writable.getWriter().closed, 'closed should reject with thrownError'); + }); +}, 'controller.error() should do nothing after readable.cancel() resolves'); promise_test(t => { let controller; diff --git a/test/fixtures/wpt/streams/transform-streams/flush.any.js b/test/fixtures/wpt/streams/transform-streams/flush.any.js index 9287f6f5eb7..c95d8ae1186 100644 --- a/test/fixtures/wpt/streams/transform-streams/flush.any.js +++ b/test/fixtures/wpt/streams/transform-streams/flush.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js 'use strict'; @@ -129,3 +129,18 @@ promise_test(t => { }); return promise_rejects_exactly(t, error1, ts.writable.getWriter().close(), 'close() should reject'); }, 'error() during flush should cause writer.close() to reject'); + +promise_test(async t => { + let flushed = false; + const ts = new TransformStream({ + flush() { + flushed = true; + }, + cancel: t.unreached_func('cancel should not be called') + }); + const closePromise = ts.writable.close(); + await delay(0); + const cancelPromise = ts.readable.cancel(error1); + await Promise.all([closePromise, cancelPromise]); + assert_equals(flushed, true, 'transformer.flush() should be called'); +}, 'closing the writable side should call transformer.flush() and a parallel readable.cancel() should not reject'); diff --git a/test/fixtures/wpt/streams/transform-streams/general.any.js b/test/fixtures/wpt/streams/transform-streams/general.any.js index c95691f7bf4..a40ef30843e 100644 --- a/test/fixtures/wpt/streams/transform-streams/general.any.js +++ b/test/fixtures/wpt/streams/transform-streams/general.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; @@ -388,9 +388,24 @@ promise_test(t => { controller.terminate(); return Promise.all([ cancelPromise, - promise_rejects_exactly(t, cancelReason, ts.writable.getWriter().closed, 'closed should reject with cancelReason') + promise_rejects_js(t, TypeError, ts.writable.getWriter().closed, 'closed should reject with TypeError') ]); -}, 'terminate() should do nothing after readable.cancel()'); +}, 'terminate() should abort writable immediately after readable.cancel()'); + +promise_test(t => { + let controller; + const ts = new TransformStream({ + start(c) { + controller = c; + } + }); + const cancelReason = { name: 'cancelReason' }; + return ts.readable.cancel(cancelReason).then(() => { + controller.terminate(); + return promise_rejects_exactly(t, cancelReason, ts.writable.getWriter().closed, 'closed should reject with TypeError'); + }) +}, 'terminate() should do nothing after readable.cancel() resolves'); + promise_test(() => { let calls = 0; diff --git a/test/fixtures/wpt/streams/transform-streams/lipfuzz.any.js b/test/fixtures/wpt/streams/transform-streams/lipfuzz.any.js index f9f148aaf1c..e334705db44 100644 --- a/test/fixtures/wpt/streams/transform-streams/lipfuzz.any.js +++ b/test/fixtures/wpt/streams/transform-streams/lipfuzz.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; class LipFuzzTransformer { diff --git a/test/fixtures/wpt/streams/transform-streams/patched-global.any.js b/test/fixtures/wpt/streams/transform-streams/patched-global.any.js index 2d04e3b948b..cc111eda452 100644 --- a/test/fixtures/wpt/streams/transform-streams/patched-global.any.js +++ b/test/fixtures/wpt/streams/transform-streams/patched-global.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; // Tests which patch the global environment are kept separate to avoid diff --git a/test/fixtures/wpt/streams/transform-streams/properties.any.js b/test/fixtures/wpt/streams/transform-streams/properties.any.js index 02981b8bc76..dbfd1aa372b 100644 --- a/test/fixtures/wpt/streams/transform-streams/properties.any.js +++ b/test/fixtures/wpt/streams/transform-streams/properties.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const transformerMethods = { diff --git a/test/fixtures/wpt/streams/transform-streams/reentrant-strategies.any.js b/test/fixtures/wpt/streams/transform-streams/reentrant-strategies.any.js index fc2f9188665..a6d45965585 100644 --- a/test/fixtures/wpt/streams/transform-streams/reentrant-strategies.any.js +++ b/test/fixtures/wpt/streams/transform-streams/reentrant-strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/rs-utils.js // META: script=../resources/test-utils.js @@ -314,6 +314,10 @@ promise_test(t => { // call to TransformStreamDefaultSink. return delay(0).then(() => { controller.enqueue('a'); + return reader.read(); + }).then(({ value, done }) => { + assert_false(done, 'done should be false'); + assert_equals(value, 'a', 'value should be correct'); return Promise.all([promise_rejects_exactly(t, error1, reader.read(), 'read() should reject'), abortPromise]); }); }, 'writer.abort() inside size() should work'); diff --git a/test/fixtures/wpt/streams/transform-streams/strategies.any.js b/test/fixtures/wpt/streams/transform-streams/strategies.any.js index 94055ad99dc..57e113e668c 100644 --- a/test/fixtures/wpt/streams/transform-streams/strategies.any.js +++ b/test/fixtures/wpt/streams/transform-streams/strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/transform-streams/terminate.any.js b/test/fixtures/wpt/streams/transform-streams/terminate.any.js index 670006366db..a959e70fe69 100644 --- a/test/fixtures/wpt/streams/transform-streams/terminate.any.js +++ b/test/fixtures/wpt/streams/transform-streams/terminate.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/recording-streams.js // META: script=../resources/test-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/aborting.any.js b/test/fixtures/wpt/streams/writable-streams/aborting.any.js index e016cd191b8..9171dbe158f 100644 --- a/test/fixtures/wpt/streams/writable-streams/aborting.any.js +++ b/test/fixtures/wpt/streams/writable-streams/aborting.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/bad-strategies.any.js b/test/fixtures/wpt/streams/writable-streams/bad-strategies.any.js index 63fa443065e..a1ef0791168 100644 --- a/test/fixtures/wpt/streams/writable-streams/bad-strategies.any.js +++ b/test/fixtures/wpt/streams/writable-streams/bad-strategies.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const error1 = new Error('a unique string'); diff --git a/test/fixtures/wpt/streams/writable-streams/bad-underlying-sinks.any.js b/test/fixtures/wpt/streams/writable-streams/bad-underlying-sinks.any.js index d0b3467978e..3c434ffe60c 100644 --- a/test/fixtures/wpt/streams/writable-streams/bad-underlying-sinks.any.js +++ b/test/fixtures/wpt/streams/writable-streams/bad-underlying-sinks.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/byte-length-queuing-strategy.any.js b/test/fixtures/wpt/streams/writable-streams/byte-length-queuing-strategy.any.js index ce1962e8917..eed86ee7004 100644 --- a/test/fixtures/wpt/streams/writable-streams/byte-length-queuing-strategy.any.js +++ b/test/fixtures/wpt/streams/writable-streams/byte-length-queuing-strategy.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; promise_test(t => { diff --git a/test/fixtures/wpt/streams/writable-streams/close.any.js b/test/fixtures/wpt/streams/writable-streams/close.any.js index 88855a92efd..45261e7ca7e 100644 --- a/test/fixtures/wpt/streams/writable-streams/close.any.js +++ b/test/fixtures/wpt/streams/writable-streams/close.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/constructor.any.js b/test/fixtures/wpt/streams/writable-streams/constructor.any.js index eaac90e48b8..0abc7ef545e 100644 --- a/test/fixtures/wpt/streams/writable-streams/constructor.any.js +++ b/test/fixtures/wpt/streams/writable-streams/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const error1 = new Error('error1'); diff --git a/test/fixtures/wpt/streams/writable-streams/count-queuing-strategy.any.js b/test/fixtures/wpt/streams/writable-streams/count-queuing-strategy.any.js index 064e16e8150..8211757530d 100644 --- a/test/fixtures/wpt/streams/writable-streams/count-queuing-strategy.any.js +++ b/test/fixtures/wpt/streams/writable-streams/count-queuing-strategy.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; test(() => { diff --git a/test/fixtures/wpt/streams/writable-streams/error.any.js b/test/fixtures/wpt/streams/writable-streams/error.any.js index faf3fdd9521..d08c8a54863 100644 --- a/test/fixtures/wpt/streams/writable-streams/error.any.js +++ b/test/fixtures/wpt/streams/writable-streams/error.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const error1 = new Error('error1'); diff --git a/test/fixtures/wpt/streams/writable-streams/floating-point-total-queue-size.any.js b/test/fixtures/wpt/streams/writable-streams/floating-point-total-queue-size.any.js index bd34cc53a69..20a14fc19a5 100644 --- a/test/fixtures/wpt/streams/writable-streams/floating-point-total-queue-size.any.js +++ b/test/fixtures/wpt/streams/writable-streams/floating-point-total-queue-size.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; // Due to the limitations of floating-point precision, the calculation of desiredSize sometimes gives different answers diff --git a/test/fixtures/wpt/streams/writable-streams/general.any.js b/test/fixtures/wpt/streams/writable-streams/general.any.js index cede7fd0845..48f8eeb89e4 100644 --- a/test/fixtures/wpt/streams/writable-streams/general.any.js +++ b/test/fixtures/wpt/streams/writable-streams/general.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; test(() => { diff --git a/test/fixtures/wpt/streams/writable-streams/properties.any.js b/test/fixtures/wpt/streams/writable-streams/properties.any.js index c95bd7d0c08..ae0549f0871 100644 --- a/test/fixtures/wpt/streams/writable-streams/properties.any.js +++ b/test/fixtures/wpt/streams/writable-streams/properties.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm 'use strict'; const sinkMethods = { diff --git a/test/fixtures/wpt/streams/writable-streams/reentrant-strategy.any.js b/test/fixtures/wpt/streams/writable-streams/reentrant-strategy.any.js index eb05cc06804..18ce9e84759 100644 --- a/test/fixtures/wpt/streams/writable-streams/reentrant-strategy.any.js +++ b/test/fixtures/wpt/streams/writable-streams/reentrant-strategy.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/start.any.js b/test/fixtures/wpt/streams/writable-streams/start.any.js index 82d869430dd..17972b568ce 100644 --- a/test/fixtures/wpt/streams/writable-streams/start.any.js +++ b/test/fixtures/wpt/streams/writable-streams/start.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/streams/writable-streams/write.any.js b/test/fixtures/wpt/streams/writable-streams/write.any.js index f0246f6cad3..20a2885bf35 100644 --- a/test/fixtures/wpt/streams/writable-streams/write.any.js +++ b/test/fixtures/wpt/streams/writable-streams/write.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm // META: script=../resources/test-utils.js // META: script=../resources/recording-streams.js 'use strict'; diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 4b28c06e6c4..cb8e81853cc 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -1,98 +1,98 @@ { "common": { - "commit": "dbd648158d337580885e70a54f929daf215211a0", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "common" }, "console": { - "commit": "767ae354642bee1e4d90b28df4480475b9260e14", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "console" }, "dom/abort": { - "commit": "d1f1ecbd52f2eab3b7fe5dc1b20b41174f1341ce", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "dom/abort" }, "dom/events": { - "commit": "ab8999891c6225bef1741c2960033aad620481a8", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "dom/events" }, "encoding": { - "commit": "a58bbf6d8c0db1f1fd5352e846acb0754ee55567", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "encoding" }, "fetch/data-urls/resources": { - "commit": "7c79d998ff42e52de90290cb847d1b515b3b58f7", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "fetch/data-urls/resources" }, "FileAPI": { - "commit": "e36dbb6f00fb59f9fc792f509194432e9e6d0b6d", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "FileAPI" }, "hr-time": { - "commit": "34cafd797e58dad280d20040eee012d49ccfa91f", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "hr-time" }, "html/webappapis/atob": { - "commit": "f267e1dca6f57a9f4d69f32a6920adfdb3268656", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "html/webappapis/atob" }, "html/webappapis/microtask-queuing": { - "commit": "2c5c3c4c27d27a419c1fdba3e9879c2d22037074", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "html/webappapis/microtask-queuing" }, "html/webappapis/structured-clone": { - "commit": "47d3fb280c9c632e684dee3b78ae1f4c5d5ba640", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "html/webappapis/structured-clone" }, "html/webappapis/timers": { - "commit": "5873f2d8f1f7bbb9c64689e52d04498614632906", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "html/webappapis/timers" }, "interfaces": { - "commit": "df731dab88a1a25c04eb7e6238c11dc28fda0801", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "interfaces" }, "performance-timeline": { - "commit": "17ebc3aea0d6321e69554067c39ab5855e6fb67e", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "performance-timeline" }, "resource-timing": { - "commit": "22d38586d04c1d22b64db36f439c6bb84f03db7d", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "resource-timing" }, "resources": { - "commit": "919874f84ff3703365063e749161a34af38c3d2a", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "resources" }, "streams": { - "commit": "517e945bbfaf903f37a35c11700eb96662efbdd3", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "streams" }, "url": { - "commit": "c2d7e70b52cbd9a5b938aa32f37078d7a71e0b21", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "url" }, "user-timing": { - "commit": "5ae85bf8267ac617833dc013dee9774c9e2a18b7", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "user-timing" }, "wasm/jsapi": { - "commit": "cde25e7e3c3b9d2280eb088a3fb9da988793d255", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "wasm/jsapi" }, "wasm/webapi": { - "commit": "fd1b23eeaaf9a01555d4fa29cf79ed11a4c44a50", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "wasm/webapi" }, "WebCryptoAPI": { - "commit": "d4e14d714c5242e174ba9aec43caf5eb514d0f09", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "WebCryptoAPI" }, "webidl/ecmascript-binding/es-exceptions": { - "commit": "a370aad338d6ed743abb4d2c6ae84a7f1058558c", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "webidl/ecmascript-binding/es-exceptions" }, "webmessaging/broadcastchannel": { - "commit": "e97fac4791931fb7455ba3fad759d362c7108b09", + "commit": "708e132acaee153316bf9356b0b2ba64c40a2965", "path": "webmessaging/broadcastchannel" } } diff --git a/test/fixtures/wpt/wasm/jsapi/assertions.js b/test/fixtures/wpt/wasm/jsapi/assertions.js index 162f5a9a6b8..3b370190682 100644 --- a/test/fixtures/wpt/wasm/jsapi/assertions.js +++ b/test/fixtures/wpt/wasm/jsapi/assertions.js @@ -6,6 +6,7 @@ function assert_function_name(fn, name, description) { assert_true(propdesc.configurable, "configurable", `${description} name should be configurable`); assert_equals(propdesc.value, name, `${description} name should be ${name}`); } +globalThis.assert_function_name = assert_function_name; function assert_function_length(fn, length, description) { const propdesc = Object.getOwnPropertyDescriptor(fn, "length"); @@ -15,6 +16,7 @@ function assert_function_length(fn, length, description) { assert_true(propdesc.configurable, "configurable", `${description} length should be configurable`); assert_equals(propdesc.value, length, `${description} length should be ${length}`); } +globalThis.assert_function_length = assert_function_length; function assert_exported_function(fn, { name, length }, description) { if (WebAssembly.Function === undefined) { @@ -28,6 +30,7 @@ function assert_exported_function(fn, { name, length }, description) { assert_function_name(fn, name, description); assert_function_length(fn, length, description); } +globalThis.assert_exported_function = assert_exported_function; function assert_Instance(instance, expected_exports) { assert_equals(Object.getPrototypeOf(instance), WebAssembly.Instance.prototype, @@ -77,6 +80,7 @@ function assert_Instance(instance, expected_exports) { } } } +globalThis.assert_Instance = assert_Instance; function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) { assert_equals(Object.getPrototypeOf(actual), Object.prototype, @@ -98,3 +102,4 @@ function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) { assert_true(instance.configurable, "instance: configurable"); assert_Instance(instance.value, expected_exports); } +globalThis.assert_WebAssemblyInstantiatedSource = assert_WebAssemblyInstantiatedSource; diff --git a/test/fixtures/wpt/wasm/jsapi/bad-imports.js b/test/fixtures/wpt/wasm/jsapi/bad-imports.js index 786fc650e32..c7c9c6b6cdd 100644 --- a/test/fixtures/wpt/wasm/jsapi/bad-imports.js +++ b/test/fixtures/wpt/wasm/jsapi/bad-imports.js @@ -183,3 +183,4 @@ function test_bad_imports(t) { }); } } +globalThis.test_bad_imports = test_bad_imports; diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/compile.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/compile.any.js index e94ce117173..f822aa30e69 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/compile.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/compile.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function assert_Module(module) { diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js index 30252bd6eeb..e4926c8d70a 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/instantiate-bad-imports.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/bad-imports.js diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/instantiate.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/instantiate.any.js index 8152f3a56f3..34e005c4700 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/instantiate.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/instantiate.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/instanceTestFactory.js diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/multi-value.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/multi-value.any.js index 4b06d1da3c4..8786f9b953b 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/multi-value.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/multi-value.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/toStringTag.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/toStringTag.any.js index c6d2cdaf662..5fae8304f8c 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/toStringTag.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/toStringTag.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm "use strict"; // https://webidl.spec.whatwg.org/#es-namespaces diff --git a/test/fixtures/wpt/wasm/jsapi/constructor/validate.any.js b/test/fixtures/wpt/wasm/jsapi/constructor/validate.any.js index 8b4f4582ab2..fce43d1e175 100644 --- a/test/fixtures/wpt/wasm/jsapi/constructor/validate.any.js +++ b/test/fixtures/wpt/wasm/jsapi/constructor/validate.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; diff --git a/test/fixtures/wpt/wasm/jsapi/exception/basic.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/basic.tentative.any.js index acf644f904f..cacce99d9cb 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/basic.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/basic.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker,jsshell +// META: global=window,worker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function assert_throws_wasm(fn, message) { @@ -11,8 +11,7 @@ function assert_throws_wasm(fn, message) { } promise_test(async () => { - const kWasmAnyRef = 0x6f; - const kSig_v_r = makeSig([kWasmAnyRef], []); + const kSig_v_r = makeSig([kWasmExternRef], []); const builder = new WasmModuleBuilder(); const tagIndex = builder.addTag(kSig_v_r); builder.addFunction("throw_param", kSig_v_r) @@ -48,7 +47,7 @@ promise_test(async () => { const tagIndex = builder.addTag(kSig_v_a); builder.addFunction("throw_null", kSig_v_v) .addBody([ - kExprRefNull, kWasmAnyFunc, + kExprRefNull, kAnyFuncCode, kExprThrow, tagIndex, ]) .exportFunc(); @@ -82,7 +81,7 @@ promise_test(async () => { kExprCatch, tagIndex, kExprReturn, kExprEnd, - kExprRefNull, kWasmAnyRef, + kExprRefNull, kExternRefCode, ]) .exportFunc(); @@ -106,7 +105,7 @@ promise_test(async () => { kExprCatchAll, kExprRethrow, 0x00, kExprEnd, - kExprRefNull, kWasmAnyRef, + kExprRefNull, kExternRefCode, ]) .exportFunc(); diff --git a/test/fixtures/wpt/wasm/jsapi/exception/constructor.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/constructor.tentative.any.js index 7ad08e1883b..a46d1816c35 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/constructor.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/constructor.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/exception/getArg.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/getArg.tentative.any.js index f0a568a857f..87719c7ebdf 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/getArg.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/getArg.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/memory/assertions.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/exception/identity.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/identity.tentative.any.js index 65787c107e3..2675668ec73 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/identity.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/identity.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/wasm-module-builder.js diff --git a/test/fixtures/wpt/wasm/jsapi/exception/is.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/is.tentative.any.js index e28a88a3c5f..840d00bf0d4 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/is.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/is.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/memory/assertions.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/exception/toString.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/exception/toString.tentative.any.js index 00e801a6fc1..6885cf0deb6 100644 --- a/test/fixtures/wpt/wasm/jsapi/exception/toString.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/exception/toString.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { parameters: [] }; diff --git a/test/fixtures/wpt/wasm/jsapi/function/call.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/function/call.tentative.any.js index 626cd13c9f0..2e63d5fa103 100644 --- a/test/fixtures/wpt/wasm/jsapi/function/call.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/function/call.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function addxy(x, y) { diff --git a/test/fixtures/wpt/wasm/jsapi/function/constructor.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/function/constructor.tentative.any.js index 636aeca4dc1..fc92fcfaf0c 100644 --- a/test/fixtures/wpt/wasm/jsapi/function/constructor.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/function/constructor.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function addxy(x, y) { diff --git a/test/fixtures/wpt/wasm/jsapi/function/table.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/function/table.tentative.any.js index d7d0d86e3b6..f0dd6ea6f85 100644 --- a/test/fixtures/wpt/wasm/jsapi/function/table.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/function/table.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function testfunc(n) {} diff --git a/test/fixtures/wpt/wasm/jsapi/function/type.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/function/type.tentative.any.js index e01a23a9e43..72a7f1bfbe5 100644 --- a/test/fixtures/wpt/wasm/jsapi/function/type.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/function/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function addNumbers(x, y, z) { diff --git a/test/fixtures/wpt/wasm/jsapi/gc/casts.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/gc/casts.tentative.any.js new file mode 100644 index 00000000000..cce06224fd4 --- /dev/null +++ b/test/fixtures/wpt/wasm/jsapi/gc/casts.tentative.any.js @@ -0,0 +1,332 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/wasm-module-builder.js + +let exports = {}; +setup(() => { + const builder = new WasmModuleBuilder(); + const structIndex = builder.addStruct([makeField(kWasmI32, true)]); + const arrayIndex = builder.addArray(kWasmI32, true); + const structIndex2 = builder.addStruct([makeField(kWasmF32, true)]); + const arrayIndex2 = builder.addArray(kWasmF32, true); + const funcIndex = builder.addType({ params: [], results: [] }); + const funcIndex2 = builder.addType({ params: [], results: [kWasmI32] }); + + const argFunctions = [ + { name: "any", code: kWasmAnyRef }, + { name: "eq", code: kWasmEqRef }, + { name: "struct", code: kWasmStructRef }, + { name: "array", code: kWasmArrayRef }, + { name: "i31", code: kWasmI31Ref }, + { name: "func", code: kWasmFuncRef }, + { name: "extern", code: kWasmExternRef }, + { name: "none", code: kWasmNullRef }, + { name: "nofunc", code: kWasmNullFuncRef }, + { name: "noextern", code: kWasmNullExternRef }, + { name: "concreteStruct", code: structIndex }, + { name: "concreteArray", code: arrayIndex }, + { name: "concreteFunc", code: funcIndex }, + ]; + + for (const desc of argFunctions) { + builder + .addFunction(desc.name + "Arg", makeSig_v_x(wasmRefType(desc.code))) + .addBody([]) + .exportFunc(); + + builder + .addFunction(desc.name + "NullableArg", makeSig_v_x(wasmRefNullType(desc.code))) + .addBody([]) + .exportFunc(); + } + + builder + .addFunction("makeStruct", makeSig_r_v(wasmRefType(structIndex))) + .addBody([...wasmI32Const(42), + ...GCInstr(kExprStructNew), structIndex]) + .exportFunc(); + + builder + .addFunction("makeArray", makeSig_r_v(wasmRefType(arrayIndex))) + .addBody([...wasmI32Const(5), ...wasmI32Const(42), + ...GCInstr(kExprArrayNew), arrayIndex]) + .exportFunc(); + + builder + .addFunction("makeStruct2", makeSig_r_v(wasmRefType(structIndex2))) + .addBody([...wasmF32Const(42), + ...GCInstr(kExprStructNew), structIndex2]) + .exportFunc(); + + builder + .addFunction("makeArray2", makeSig_r_v(wasmRefType(arrayIndex2))) + .addBody([...wasmF32Const(42), ...wasmI32Const(5), + ...GCInstr(kExprArrayNew), arrayIndex2]) + .exportFunc(); + + builder + .addFunction("testFunc", funcIndex) + .addBody([]) + .exportFunc(); + + builder + .addFunction("testFunc2", funcIndex2) + .addBody([...wasmI32Const(42)]) + .exportFunc(); + + const buffer = builder.toBuffer(); + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module, {}); + exports = instance.exports; +}); + +test(() => { + exports.anyArg(exports.makeStruct()); + exports.anyArg(exports.makeArray()); + exports.anyArg(42); + exports.anyArg(42n); + exports.anyArg("foo"); + exports.anyArg({}); + exports.anyArg(() => {}); + exports.anyArg(exports.testFunc); + assert_throws_js(TypeError, () => exports.anyArg(null)); + + exports.anyNullableArg(null); + exports.anyNullableArg(exports.makeStruct()); + exports.anyNullableArg(exports.makeArray()); + exports.anyNullableArg(42); + exports.anyNullableArg(42n); + exports.anyNullableArg("foo"); + exports.anyNullableArg({}); + exports.anyNullableArg(() => {}); + exports.anyNullableArg(exports.testFunc); +}, "anyref casts"); + +test(() => { + exports.eqArg(exports.makeStruct()); + exports.eqArg(exports.makeArray()); + exports.eqArg(42); + assert_throws_js(TypeError, () => exports.eqArg(42n)); + assert_throws_js(TypeError, () => exports.eqArg("foo")); + assert_throws_js(TypeError, () => exports.eqArg({})); + assert_throws_js(TypeError, () => exports.eqArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.eqArg(() => {})); + assert_throws_js(TypeError, () => exports.eqArg(null)); + + exports.eqNullableArg(null); + exports.eqNullableArg(exports.makeStruct()); + exports.eqNullableArg(exports.makeArray()); + exports.eqNullableArg(42); + assert_throws_js(TypeError, () => exports.eqNullableArg(42n)); + assert_throws_js(TypeError, () => exports.eqNullableArg("foo")); + assert_throws_js(TypeError, () => exports.eqNullableArg({})); + assert_throws_js(TypeError, () => exports.eqNullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.eqNullableArg(() => {})); +}, "eqref casts"); + +test(() => { + exports.structArg(exports.makeStruct()); + assert_throws_js(TypeError, () => exports.structArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.structArg(42)); + assert_throws_js(TypeError, () => exports.structArg(42n)); + assert_throws_js(TypeError, () => exports.structArg("foo")); + assert_throws_js(TypeError, () => exports.structArg({})); + assert_throws_js(TypeError, () => exports.structArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.structArg(() => {})); + assert_throws_js(TypeError, () => exports.structArg(null)); + + exports.structNullableArg(null); + exports.structNullableArg(exports.makeStruct()); + assert_throws_js(TypeError, () => exports.structNullableArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.structNullableArg(42)); + assert_throws_js(TypeError, () => exports.structNullableArg(42n)); + assert_throws_js(TypeError, () => exports.structNullableArg("foo")); + assert_throws_js(TypeError, () => exports.structNullableArg({})); + assert_throws_js(TypeError, () => exports.structNullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.structNullableArg(() => {})); +}, "structref casts"); + +test(() => { + exports.arrayArg(exports.makeArray()); + assert_throws_js(TypeError, () => exports.arrayArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.arrayArg(42)); + assert_throws_js(TypeError, () => exports.arrayArg(42n)); + assert_throws_js(TypeError, () => exports.arrayArg("foo")); + assert_throws_js(TypeError, () => exports.arrayArg({})); + assert_throws_js(TypeError, () => exports.arrayArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.arrayArg(() => {})); + assert_throws_js(TypeError, () => exports.arrayArg(null)); + + exports.arrayNullableArg(null); + exports.arrayNullableArg(exports.makeArray()); + assert_throws_js(TypeError, () => exports.arrayNullableArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.arrayNullableArg(42)); + assert_throws_js(TypeError, () => exports.arrayNullableArg(42n)); + assert_throws_js(TypeError, () => exports.arrayNullableArg("foo")); + assert_throws_js(TypeError, () => exports.arrayNullableArg({})); + assert_throws_js(TypeError, () => exports.arrayNullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.arrayNullableArg(() => {})); +}, "arrayref casts"); + +test(() => { + exports.i31Arg(42); + assert_throws_js(TypeError, () => exports.i31Arg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.i31Arg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.i31Arg(42n)); + assert_throws_js(TypeError, () => exports.i31Arg("foo")); + assert_throws_js(TypeError, () => exports.i31Arg({})); + assert_throws_js(TypeError, () => exports.i31Arg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.i31Arg(() => {})); + assert_throws_js(TypeError, () => exports.i31Arg(null)); + + exports.i31NullableArg(null); + exports.i31NullableArg(42); + assert_throws_js(TypeError, () => exports.i31NullableArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.i31NullableArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.i31NullableArg(42n)); + assert_throws_js(TypeError, () => exports.i31NullableArg("foo")); + assert_throws_js(TypeError, () => exports.i31NullableArg({})); + assert_throws_js(TypeError, () => exports.i31NullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.i31NullableArg(() => {})); +}, "i31ref casts"); + +test(() => { + exports.funcArg(exports.testFunc); + assert_throws_js(TypeError, () => exports.funcArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.funcArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.funcArg(42)); + assert_throws_js(TypeError, () => exports.funcArg(42n)); + assert_throws_js(TypeError, () => exports.funcArg("foo")); + assert_throws_js(TypeError, () => exports.funcArg({})); + assert_throws_js(TypeError, () => exports.funcArg(() => {})); + assert_throws_js(TypeError, () => exports.funcArg(null)); + + exports.funcNullableArg(null); + exports.funcNullableArg(exports.testFunc); + assert_throws_js(TypeError, () => exports.funcNullableArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.funcNullableArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.funcNullableArg(42)); + assert_throws_js(TypeError, () => exports.funcNullableArg(42n)); + assert_throws_js(TypeError, () => exports.funcNullableArg("foo")); + assert_throws_js(TypeError, () => exports.funcNullableArg({})); + assert_throws_js(TypeError, () => exports.funcNullableArg(() => {})); +}, "funcref casts"); + +test(() => { + exports.externArg(exports.makeArray()); + exports.externArg(exports.makeStruct()); + exports.externArg(42); + exports.externArg(42n); + exports.externArg("foo"); + exports.externArg({}); + exports.externArg(exports.testFunc); + exports.externArg(() => {}); + assert_throws_js(TypeError, () => exports.externArg(null)); + + exports.externNullableArg(null); + exports.externNullableArg(exports.makeArray()); + exports.externNullableArg(exports.makeStruct()); + exports.externNullableArg(42); + exports.externNullableArg(42n); + exports.externNullableArg("foo"); + exports.externNullableArg({}); + exports.externNullableArg(exports.testFunc); + exports.externNullableArg(() => {}); +}, "externref casts"); + +test(() => { + for (const nullfunc of [exports.noneArg, exports.nofuncArg, exports.noexternArg]) { + assert_throws_js(TypeError, () => nullfunc(exports.makeStruct())); + assert_throws_js(TypeError, () => nullfunc(exports.makeArray())); + assert_throws_js(TypeError, () => nullfunc(42)); + assert_throws_js(TypeError, () => nullfunc(42n)); + assert_throws_js(TypeError, () => nullfunc("foo")); + assert_throws_js(TypeError, () => nullfunc({})); + assert_throws_js(TypeError, () => nullfunc(exports.testFunc)); + assert_throws_js(TypeError, () => nullfunc(() => {})); + assert_throws_js(TypeError, () => nullfunc(null)); + } + + for (const nullfunc of [exports.noneNullableArg, exports.nofuncNullableArg, exports.noexternNullableArg]) { + nullfunc(null); + assert_throws_js(TypeError, () => nullfunc(exports.makeStruct())); + assert_throws_js(TypeError, () => nullfunc(exports.makeArray())); + assert_throws_js(TypeError, () => nullfunc(42)); + assert_throws_js(TypeError, () => nullfunc(42n)); + assert_throws_js(TypeError, () => nullfunc("foo")); + assert_throws_js(TypeError, () => nullfunc({})); + assert_throws_js(TypeError, () => nullfunc(exports.testFunc)); + assert_throws_js(TypeError, () => nullfunc(() => {})); + } +}, "null casts"); + +test(() => { + exports.concreteStructArg(exports.makeStruct()); + assert_throws_js(TypeError, () => exports.concreteStructArg(exports.makeStruct2())); + assert_throws_js(TypeError, () => exports.concreteStructArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.concreteStructArg(42)); + assert_throws_js(TypeError, () => exports.concreteStructArg(42n)); + assert_throws_js(TypeError, () => exports.concreteStructArg("foo")); + assert_throws_js(TypeError, () => exports.concreteStructArg({})); + assert_throws_js(TypeError, () => exports.concreteStructArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.concreteStructArg(() => {})); + assert_throws_js(TypeError, () => exports.concreteStructArg(null)); + + exports.concreteStructNullableArg(null); + exports.concreteStructNullableArg(exports.makeStruct()); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(exports.makeStruct2())); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(42)); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(42n)); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg("foo")); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg({})); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.concreteStructNullableArg(() => {})); +}, "concrete struct casts"); + +test(() => { + exports.concreteArrayArg(exports.makeArray()); + assert_throws_js(TypeError, () => exports.concreteArrayArg(exports.makeArray2())); + assert_throws_js(TypeError, () => exports.concreteArrayArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.concreteArrayArg(42)); + assert_throws_js(TypeError, () => exports.concreteArrayArg(42n)); + assert_throws_js(TypeError, () => exports.concreteArrayArg("foo")); + assert_throws_js(TypeError, () => exports.concreteArrayArg({})); + assert_throws_js(TypeError, () => exports.concreteArrayArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.concreteArrayArg(() => {})); + assert_throws_js(TypeError, () => exports.concreteArrayArg(null)); + + exports.concreteArrayNullableArg(null); + exports.concreteArrayNullableArg(exports.makeArray()); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(exports.makeArray2())); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(42)); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(42n)); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg("foo")); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg({})); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(exports.testFunc)); + assert_throws_js(TypeError, () => exports.concreteArrayNullableArg(() => {})); +}, "concrete array casts"); + +test(() => { + exports.concreteFuncArg(exports.testFunc); + assert_throws_js(TypeError, () => exports.concreteFuncArg(exports.testFunc2)); + assert_throws_js(TypeError, () => exports.concreteFuncArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.concreteFuncArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.concreteFuncArg(42)); + assert_throws_js(TypeError, () => exports.concreteFuncArg(42n)); + assert_throws_js(TypeError, () => exports.concreteFuncArg("foo")); + assert_throws_js(TypeError, () => exports.concreteFuncArg({})); + assert_throws_js(TypeError, () => exports.concreteFuncArg(() => {})); + assert_throws_js(TypeError, () => exports.concreteFuncArg(null)); + + exports.concreteFuncNullableArg(null); + exports.concreteFuncNullableArg(exports.testFunc); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(exports.testFunc2)); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(exports.makeArray())); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(exports.makeStruct())); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(42)); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(42n)); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg("foo")); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg({})); + assert_throws_js(TypeError, () => exports.concreteFuncNullableArg(() => {})); +}, "concrete func casts"); diff --git a/test/fixtures/wpt/wasm/jsapi/gc/exported-object.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/gc/exported-object.tentative.any.js new file mode 100644 index 00000000000..b572f140067 --- /dev/null +++ b/test/fixtures/wpt/wasm/jsapi/gc/exported-object.tentative.any.js @@ -0,0 +1,190 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/wasm-module-builder.js + +let functions = {}; +setup(() => { + const builder = new WasmModuleBuilder(); + + const structIndex = builder.addStruct([makeField(kWasmI32, true)]); + const arrayIndex = builder.addArray(kWasmI32, true); + const structRef = wasmRefType(structIndex); + const arrayRef = wasmRefType(arrayIndex); + + builder + .addFunction("makeStruct", makeSig_r_v(structRef)) + .addBody([...wasmI32Const(42), + ...GCInstr(kExprStructNew), structIndex]) + .exportFunc(); + + builder + .addFunction("makeArray", makeSig_r_v(arrayRef)) + .addBody([...wasmI32Const(5), ...wasmI32Const(42), + ...GCInstr(kExprArrayNew), arrayIndex]) + .exportFunc(); + + const buffer = builder.toBuffer(); + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module, {}); + functions = instance.exports; +}); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_equals(struct.foo, undefined); + assert_equals(struct[0], undefined); + assert_equals(array.foo, undefined); + assert_equals(array[0], undefined); +}, "property access"); + +test(() => { + "use strict"; + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => { struct.foo = 5; }); + assert_throws_js(TypeError, () => { array.foo = 5; }); + assert_throws_js(TypeError, () => { struct[0] = 5; }); + assert_throws_js(TypeError, () => { array[0] = 5; }); +}, "property assignment (strict mode)"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => { struct.foo = 5; }); + assert_throws_js(TypeError, () => { array.foo = 5; }); + assert_throws_js(TypeError, () => { struct[0] = 5; }); + assert_throws_js(TypeError, () => { array[0] = 5; }); +}, "property assignment (non-strict mode)"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_equals(Object.getOwnPropertyNames(struct).length, 0); + assert_equals(Object.getOwnPropertyNames(array).length, 0); +}, "ownPropertyNames"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => Object.defineProperty(struct, "foo", { value: 1 })); + assert_throws_js(TypeError, () => Object.defineProperty(array, "foo", { value: 1 })); +}, "defineProperty"); + +test(() => { + "use strict"; + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => delete struct.foo); + assert_throws_js(TypeError, () => delete struct[0]); + assert_throws_js(TypeError, () => delete array.foo); + assert_throws_js(TypeError, () => delete array[0]); +}, "delete (strict mode)"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => delete struct.foo); + assert_throws_js(TypeError, () => delete struct[0]); + assert_throws_js(TypeError, () => delete array.foo); + assert_throws_js(TypeError, () => delete array[0]); +}, "delete (non-strict mode)"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_equals(Object.getPrototypeOf(struct), null); + assert_equals(Object.getPrototypeOf(array), null); +}, "getPrototypeOf"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => Object.setPrototypeOf(struct, {})); + assert_throws_js(TypeError, () => Object.setPrototypeOf(array, {})); +}, "setPrototypeOf"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_false(Object.isExtensible(struct)); + assert_false(Object.isExtensible(array)); +}, "isExtensible"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => Object.preventExtensions(struct)); + assert_throws_js(TypeError, () => Object.preventExtensions(array)); +}, "preventExtensions"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => Object.seal(struct)); + assert_throws_js(TypeError, () => Object.seal(array)); +}, "sealing"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_equals(typeof struct, "object"); + assert_equals(typeof array, "object"); +}, "typeof"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => struct.toString()); + assert_equals(Object.prototype.toString.call(struct), "[object Object]"); + assert_throws_js(TypeError, () => array.toString()); + assert_equals(Object.prototype.toString.call(array), "[object Object]"); +}, "toString"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + assert_throws_js(TypeError, () => struct.valueOf()); + assert_equals(Object.prototype.valueOf.call(struct), struct); + assert_throws_js(TypeError, () => array.valueOf()); + assert_equals(Object.prototype.valueOf.call(array), array); +}, "valueOf"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + const map = new Map(); + map.set(struct, "struct"); + map.set(array, "array"); + assert_equals(map.get(struct), "struct"); + assert_equals(map.get(array), "array"); +}, "GC objects as map keys"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + const set = new Set(); + set.add(struct); + set.add(array); + assert_true(set.has(struct)); + assert_true(set.has(array)); +}, "GC objects as set element"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + const map = new WeakMap(); + map.set(struct, "struct"); + map.set(array, "array"); + assert_equals(map.get(struct), "struct"); + assert_equals(map.get(array), "array"); +}, "GC objects as weak map keys"); + +test(() => { + const struct = functions.makeStruct(); + const array = functions.makeArray(); + const set = new WeakSet(); + set.add(struct); + set.add(array); + assert_true(set.has(struct)); + assert_true(set.has(array)); +}, "GC objects as weak set element"); diff --git a/test/fixtures/wpt/wasm/jsapi/gc/i31.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/gc/i31.tentative.any.js new file mode 100644 index 00000000000..17fd82440cc --- /dev/null +++ b/test/fixtures/wpt/wasm/jsapi/gc/i31.tentative.any.js @@ -0,0 +1,98 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/wasm-module-builder.js + +let exports = {}; +setup(() => { + const builder = new WasmModuleBuilder(); + const i31Ref = wasmRefType(kWasmI31Ref); + const i31NullableRef = wasmRefNullType(kWasmI31Ref); + const anyRef = wasmRefType(kWasmAnyRef); + + builder + .addFunction("makeI31", makeSig_r_x(i31Ref, kWasmI32)) + .addBody([kExprLocalGet, 0, + ...GCInstr(kExprI31New)]) + .exportFunc(); + + builder + .addFunction("castI31", makeSig_r_x(kWasmI32, anyRef)) + .addBody([kExprLocalGet, 0, + ...GCInstr(kExprRefCast), kI31RefCode, + ...GCInstr(kExprI31GetU)]) + .exportFunc(); + + builder + .addFunction("getI31", makeSig_r_x(kWasmI32, i31Ref)) + .addBody([kExprLocalGet, 0, + ...GCInstr(kExprI31GetS)]) + .exportFunc(); + + builder + .addFunction("argI31", makeSig_v_x(i31NullableRef)) + .addBody([]) + .exportFunc(); + + builder + .addGlobal(i31NullableRef, true, [...wasmI32Const(0), ...GCInstr(kExprI31New)]) + builder + .addExportOfKind("i31Global", kExternalGlobal, 0); + + builder + .addTable(i31NullableRef, 10) + builder + .addExportOfKind("i31Table", kExternalTable, 0); + + const buffer = builder.toBuffer(); + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module, {}); + exports = instance.exports; +}); + +test(() => { + assert_equals(exports.makeI31(42), 42); + assert_equals(exports.makeI31(2 ** 30 - 1), 2 ** 30 - 1); + assert_equals(exports.makeI31(2 ** 30), -(2 ** 30)); + assert_equals(exports.makeI31(-(2 ** 30)), -(2 ** 30)); + assert_equals(exports.makeI31(2 ** 31 - 1), -1); + assert_equals(exports.makeI31(2 ** 31), 0); +}, "i31ref conversion to Number"); + +test(() => { + assert_equals(exports.getI31(exports.makeI31(42)), 42); + assert_equals(exports.getI31(42), 42); + assert_equals(exports.getI31(2.0 ** 30 - 1), 2 ** 30 - 1); + assert_equals(exports.getI31(-(2 ** 30)), -(2 ** 30)); +}, "Number conversion to i31ref"); + +test(() => { + exports.argI31(null); + assert_throws_js(TypeError, () => exports.argI31(2 ** 30)); + assert_throws_js(TypeError, () => exports.argI31(-(2 ** 30) - 1)); + assert_throws_js(TypeError, () => exports.argI31(2n)); + assert_throws_js(TypeError, () => exports.argI31(() => 3)); + assert_throws_js(TypeError, () => exports.argI31(exports.getI31)); +}, "Check i31ref argument type"); + +test(() => { + assert_equals(exports.castI31(42), 42); + assert_equals(exports.castI31(2 ** 30 - 1), 2 ** 30 - 1); + assert_throws_js(WebAssembly.RuntimeError, () => { exports.castI31(2 ** 30); }); + assert_throws_js(WebAssembly.RuntimeError, () => { exports.castI31(-(2 ** 30) - 1); }); + assert_throws_js(WebAssembly.RuntimeError, () => { exports.castI31(2 ** 32); }); +}, "Numbers in i31 range are i31ref, not hostref"); + +test(() => { + assert_equals(exports.i31Global.value, 0); + exports.i31Global.value = 42; + assert_throws_js(TypeError, () => exports.i31Global.value = 2 ** 30); + assert_throws_js(TypeError, () => exports.i31Global.value = -(2 ** 30) - 1); + assert_equals(exports.i31Global.value, 42); +}, "i31ref global"); + +test(() => { + assert_equals(exports.i31Table.get(0), null); + exports.i31Table.set(0, 42); + assert_throws_js(TypeError, () => exports.i31Table.set(0, 2 ** 30)); + assert_throws_js(TypeError, () => exports.i31Table.set(0, -(2 ** 30) - 1)); + assert_equals(exports.i31Table.get(0), 42); +}, "i31ref table"); diff --git a/test/fixtures/wpt/wasm/jsapi/global/constructor.any.js b/test/fixtures/wpt/wasm/jsapi/global/constructor.any.js index dade7b1f55a..f83f77a5c3e 100644 --- a/test/fixtures/wpt/wasm/jsapi/global/constructor.any.js +++ b/test/fixtures/wpt/wasm/jsapi/global/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_Global(actual, expected) { diff --git a/test/fixtures/wpt/wasm/jsapi/global/toString.any.js b/test/fixtures/wpt/wasm/jsapi/global/toString.any.js index 359c4273b5b..b308498982e 100644 --- a/test/fixtures/wpt/wasm/jsapi/global/toString.any.js +++ b/test/fixtures/wpt/wasm/jsapi/global/toString.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { "value": "i32" }; diff --git a/test/fixtures/wpt/wasm/jsapi/global/type.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/global/type.tentative.any.js index 95adc2af0f6..78d612529dd 100644 --- a/test/fixtures/wpt/wasm/jsapi/global/type.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/global/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_type(argument) { diff --git a/test/fixtures/wpt/wasm/jsapi/global/value-get-set.any.js b/test/fixtures/wpt/wasm/jsapi/global/value-get-set.any.js index f95b7ca9e3f..bee5581f418 100644 --- a/test/fixtures/wpt/wasm/jsapi/global/value-get-set.any.js +++ b/test/fixtures/wpt/wasm/jsapi/global/value-get-set.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const thisValues = [ diff --git a/test/fixtures/wpt/wasm/jsapi/global/valueOf.any.js b/test/fixtures/wpt/wasm/jsapi/global/valueOf.any.js index 0695a5a61fb..5bcb1718258 100644 --- a/test/fixtures/wpt/wasm/jsapi/global/valueOf.any.js +++ b/test/fixtures/wpt/wasm/jsapi/global/valueOf.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { "value": "i32" }; diff --git a/test/fixtures/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js b/test/fixtures/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js index e4a5abb8eb2..1ef4f8423de 100644 --- a/test/fixtures/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js +++ b/test/fixtures/wpt/wasm/jsapi/instance/constructor-bad-imports.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/bad-imports.js diff --git a/test/fixtures/wpt/wasm/jsapi/instance/constructor-caching.any.js b/test/fixtures/wpt/wasm/jsapi/instance/constructor-caching.any.js index 1aa4739b629..f969364d93f 100644 --- a/test/fixtures/wpt/wasm/jsapi/instance/constructor-caching.any.js +++ b/test/fixtures/wpt/wasm/jsapi/instance/constructor-caching.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function getExports() { diff --git a/test/fixtures/wpt/wasm/jsapi/instance/constructor.any.js b/test/fixtures/wpt/wasm/jsapi/instance/constructor.any.js index 26390ebd2cd..24bf97356c8 100644 --- a/test/fixtures/wpt/wasm/jsapi/instance/constructor.any.js +++ b/test/fixtures/wpt/wasm/jsapi/instance/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/instanceTestFactory.js diff --git a/test/fixtures/wpt/wasm/jsapi/instance/exports.any.js b/test/fixtures/wpt/wasm/jsapi/instance/exports.any.js index 6dcfbcee950..f7244923d83 100644 --- a/test/fixtures/wpt/wasm/jsapi/instance/exports.any.js +++ b/test/fixtures/wpt/wasm/jsapi/instance/exports.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; diff --git a/test/fixtures/wpt/wasm/jsapi/instance/toString.any.js b/test/fixtures/wpt/wasm/jsapi/instance/toString.any.js index 547a9ca8295..d77037d65b9 100644 --- a/test/fixtures/wpt/wasm/jsapi/instance/toString.any.js +++ b/test/fixtures/wpt/wasm/jsapi/instance/toString.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/instanceTestFactory.js b/test/fixtures/wpt/wasm/jsapi/instanceTestFactory.js index ac468947ec2..2e015af8198 100644 --- a/test/fixtures/wpt/wasm/jsapi/instanceTestFactory.js +++ b/test/fixtures/wpt/wasm/jsapi/instanceTestFactory.js @@ -237,7 +237,7 @@ const instanceTestFactory = [ builder.addGlobal(kWasmI32, true) .exportAs("") - .init = 7; + .init = wasmI32Const(7); const buffer = builder.toBuffer(); @@ -273,10 +273,10 @@ const instanceTestFactory = [ builder.addGlobal(kWasmI32, true) .exportAs("global") - .init = 7; + .init = wasmI32Const(7); builder.addGlobal(kWasmF64, true) .exportAs("global2") - .init = 1.2; + .init = wasmF64Const(1.2); builder.addMemory(4, 8, true); @@ -759,3 +759,5 @@ const instanceTestFactory = [ } ], ]; + +globalThis.instanceTestFactory = instanceTestFactory; diff --git a/test/fixtures/wpt/wasm/jsapi/interface.any.js b/test/fixtures/wpt/wasm/jsapi/interface.any.js index 19d29ead0a7..8256fc209a7 100644 --- a/test/fixtures/wpt/wasm/jsapi/interface.any.js +++ b/test/fixtures/wpt/wasm/jsapi/interface.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function test_operations(object, object_name, operations) { diff --git a/test/fixtures/wpt/wasm/jsapi/memory/constructor-shared.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/memory/constructor-shared.tentative.any.js index 216fc4ca555..0134b307749 100644 --- a/test/fixtures/wpt/wasm/jsapi/memory/constructor-shared.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/memory/constructor-shared.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/memory/assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/memory/constructor-types.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/memory/constructor-types.tentative.any.js index d5378dbe82b..4653c6686a7 100644 --- a/test/fixtures/wpt/wasm/jsapi/memory/constructor-types.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/memory/constructor-types.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/memory/assertions.js @@ -17,4 +17,4 @@ test(() => { const argument = { minimum: 4 }; const memory = new WebAssembly.Memory(argument); assert_Memory(memory, { "size": 4 }); - }, "Non-zero minimum"); \ No newline at end of file + }, "Non-zero minimum"); diff --git a/test/fixtures/wpt/wasm/jsapi/memory/constructor.any.js b/test/fixtures/wpt/wasm/jsapi/memory/constructor.any.js index 0a0be11e370..8f413c9f48a 100644 --- a/test/fixtures/wpt/wasm/jsapi/memory/constructor.any.js +++ b/test/fixtures/wpt/wasm/jsapi/memory/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/memory/assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/memory/grow.any.js b/test/fixtures/wpt/wasm/jsapi/memory/grow.any.js index c511129491f..2eafe5761ea 100644 --- a/test/fixtures/wpt/wasm/jsapi/memory/grow.any.js +++ b/test/fixtures/wpt/wasm/jsapi/memory/grow.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/memory/assertions.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/memory/type.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/memory/type.tentative.any.js index a96a3227adc..3f6531f5967 100644 --- a/test/fixtures/wpt/wasm/jsapi/memory/type.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/memory/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_type(argument) { @@ -34,4 +34,4 @@ test(() => { test(() => { assert_type({ "minimum": 0, "maximum": 10, "shared": true}); -}, "shared memory"); \ No newline at end of file +}, "shared memory"); diff --git a/test/fixtures/wpt/wasm/jsapi/module/constructor.any.js b/test/fixtures/wpt/wasm/jsapi/module/constructor.any.js index 9978f7e6ac8..95604aabe47 100644 --- a/test/fixtures/wpt/wasm/jsapi/module/constructor.any.js +++ b/test/fixtures/wpt/wasm/jsapi/module/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/module/customSections.any.js b/test/fixtures/wpt/wasm/jsapi/module/customSections.any.js index 4029877e92c..96958316e06 100644 --- a/test/fixtures/wpt/wasm/jsapi/module/customSections.any.js +++ b/test/fixtures/wpt/wasm/jsapi/module/customSections.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function assert_ArrayBuffer(buffer, expected) { diff --git a/test/fixtures/wpt/wasm/jsapi/module/exports.any.js b/test/fixtures/wpt/wasm/jsapi/module/exports.any.js index 40a3935a4a2..0c32e984a2c 100644 --- a/test/fixtures/wpt/wasm/jsapi/module/exports.any.js +++ b/test/fixtures/wpt/wasm/jsapi/module/exports.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; @@ -109,10 +109,10 @@ test(() => { builder.addGlobal(kWasmI32, true) .exportAs("global") - .init = 7; + .init = wasmI32Const(7); builder.addGlobal(kWasmF64, true) .exportAs("global2") - .init = 1.2; + .init = wasmF64Const(1.2); builder.addMemory(0, 256, true); @@ -167,7 +167,7 @@ test(() => { builder.addGlobal(kWasmI32, true) .exportAs("") - .init = 7; + .init = wasmI32Const(7); const buffer = builder.toBuffer() const module = new WebAssembly.Module(buffer); diff --git a/test/fixtures/wpt/wasm/jsapi/module/imports.any.js b/test/fixtures/wpt/wasm/jsapi/module/imports.any.js index ec550ce6c41..2ab1725359f 100644 --- a/test/fixtures/wpt/wasm/jsapi/module/imports.any.js +++ b/test/fixtures/wpt/wasm/jsapi/module/imports.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js function assert_ModuleImportDescriptor(import_, expected) { diff --git a/test/fixtures/wpt/wasm/jsapi/module/toString.any.js b/test/fixtures/wpt/wasm/jsapi/module/toString.any.js index 1c20cd6108c..10c707979d5 100644 --- a/test/fixtures/wpt/wasm/jsapi/module/toString.any.js +++ b/test/fixtures/wpt/wasm/jsapi/module/toString.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/prototypes.any.js b/test/fixtures/wpt/wasm/jsapi/prototypes.any.js index 714f4f8430e..2316f7d9b4e 100644 --- a/test/fixtures/wpt/wasm/jsapi/prototypes.any.js +++ b/test/fixtures/wpt/wasm/jsapi/prototypes.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/wasm-module-builder.js diff --git a/test/fixtures/wpt/wasm/jsapi/table/constructor-types.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/table/constructor-types.tentative.any.js index 99ca41b55a9..b4015bdc6f7 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/constructor-types.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/constructor-types.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/table/assertions.js @@ -17,4 +17,4 @@ test(() => { const argument = { "element": "anyfunc", "minimum": 5 }; const table = new WebAssembly.Table(argument); assert_Table(table, { "length": 5 }); -}, "Non-zero minimum"); \ No newline at end of file +}, "Non-zero minimum"); diff --git a/test/fixtures/wpt/wasm/jsapi/table/constructor.any.js b/test/fixtures/wpt/wasm/jsapi/table/constructor.any.js index 6d38d04e4f5..51b1070d413 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/constructor.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/table/assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/table/get-set.any.js b/test/fixtures/wpt/wasm/jsapi/table/get-set.any.js index 9301057a533..abe6fecac98 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/get-set.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/get-set.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/table/grow.any.js b/test/fixtures/wpt/wasm/jsapi/table/grow.any.js index 520d24bf4ba..4038f1e6493 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/grow.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/grow.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=assertions.js diff --git a/test/fixtures/wpt/wasm/jsapi/table/length.any.js b/test/fixtures/wpt/wasm/jsapi/table/length.any.js index a9ef095ded4..0e6de3f83e1 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/length.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/length.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const thisValues = [ diff --git a/test/fixtures/wpt/wasm/jsapi/table/toString.any.js b/test/fixtures/wpt/wasm/jsapi/table/toString.any.js index 8a09f2832c1..b5fb25b9c1e 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/toString.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/toString.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { "element": "anyfunc", "initial": 0 }; diff --git a/test/fixtures/wpt/wasm/jsapi/table/type.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/table/type.tentative.any.js index ef1ceecb17d..ef9bbc5aa4a 100644 --- a/test/fixtures/wpt/wasm/jsapi/table/type.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/table/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_type(argument) { diff --git a/test/fixtures/wpt/wasm/jsapi/tag/constructor.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/tag/constructor.tentative.any.js index de63e7bf46d..54edf8c8f59 100644 --- a/test/fixtures/wpt/wasm/jsapi/tag/constructor.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/tag/constructor.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js test(() => { diff --git a/test/fixtures/wpt/wasm/jsapi/tag/toString.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/tag/toString.tentative.any.js index ad9a4ba152f..76fff0feef0 100644 --- a/test/fixtures/wpt/wasm/jsapi/tag/toString.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/tag/toString.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm test(() => { const argument = { parameters: [] }; diff --git a/test/fixtures/wpt/wasm/jsapi/tag/type.tentative.any.js b/test/fixtures/wpt/wasm/jsapi/tag/type.tentative.any.js index 9d2f0de1a00..58c96078bfe 100644 --- a/test/fixtures/wpt/wasm/jsapi/tag/type.tentative.any.js +++ b/test/fixtures/wpt/wasm/jsapi/tag/type.tentative.any.js @@ -1,4 +1,4 @@ -// META: global=window,dedicatedworker,jsshell +// META: global=window,dedicatedworker,jsshell,shadowrealm // META: script=/wasm/jsapi/assertions.js function assert_type(argument) { diff --git a/test/fixtures/wpt/wasm/jsapi/wasm-module-builder.js b/test/fixtures/wpt/wasm/jsapi/wasm-module-builder.js index 86d836a5a37..1d8db0a6e6f 100644 --- a/test/fixtures/wpt/wasm/jsapi/wasm-module-builder.js +++ b/test/fixtures/wpt/wasm/jsapi/wasm-module-builder.js @@ -74,6 +74,13 @@ let kLocalNamesCode = 2; let kWasmFunctionTypeForm = 0x60; let kWasmAnyFunctionTypeForm = 0x70; +let kWasmStructTypeForm = 0x5f; +let kWasmArrayTypeForm = 0x5e; +let kWasmSubtypeForm = 0x50; +let kWasmSubtypeFinalForm = 0x4f; +let kWasmRecursiveTypeGroupForm = 0x4e; + +let kNoSuperType = 0xFFFFFFFF; let kHasMaximumFlag = 1; let kSharedHasMaximumFlag = 3; @@ -97,8 +104,43 @@ let kWasmI64 = 0x7e; let kWasmF32 = 0x7d; let kWasmF64 = 0x7c; let kWasmS128 = 0x7b; -let kWasmAnyRef = 0x6f; -let kWasmAnyFunc = 0x70; + +// These are defined as negative integers to distinguish them from positive type +// indices. +let kWasmNullFuncRef = -0x0d; +let kWasmNullExternRef = -0x0e; +let kWasmNullRef = -0x0f; +let kWasmFuncRef = -0x10; +let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec +let kWasmExternRef = -0x11; +let kWasmAnyRef = -0x12; +let kWasmEqRef = -0x13; +let kWasmI31Ref = -0x14; +let kWasmStructRef = -0x15; +let kWasmArrayRef = -0x16; + +// Use the positive-byte versions inside function bodies. +let kLeb128Mask = 0x7f; +let kFuncRefCode = kWasmFuncRef & kLeb128Mask; +let kAnyFuncCode = kFuncRefCode; // Alias named as in the JS API spec +let kExternRefCode = kWasmExternRef & kLeb128Mask; +let kAnyRefCode = kWasmAnyRef & kLeb128Mask; +let kEqRefCode = kWasmEqRef & kLeb128Mask; +let kI31RefCode = kWasmI31Ref & kLeb128Mask; +let kNullExternRefCode = kWasmNullExternRef & kLeb128Mask; +let kNullFuncRefCode = kWasmNullFuncRef & kLeb128Mask; +let kStructRefCode = kWasmStructRef & kLeb128Mask; +let kArrayRefCode = kWasmArrayRef & kLeb128Mask; +let kNullRefCode = kWasmNullRef & kLeb128Mask; + +let kWasmRefNull = 0x63; +let kWasmRef = 0x64; +function wasmRefNullType(heap_type) { + return {opcode: kWasmRefNull, heap_type: heap_type}; +} +function wasmRefType(heap_type) { + return {opcode: kWasmRef, heap_type: heap_type}; +} let kExternalFunction = 0; let kExternalTable = 1; @@ -146,14 +188,14 @@ let kSig_v_f = makeSig([kWasmF32], []); let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); let kSig_f_d = makeSig([kWasmF64], [kWasmF32]); let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); -let kSig_r_r = makeSig([kWasmAnyRef], [kWasmAnyRef]); +let kSig_r_r = makeSig([kWasmExternRef], [kWasmExternRef]); let kSig_a_a = makeSig([kWasmAnyFunc], [kWasmAnyFunc]); -let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]); -let kSig_v_r = makeSig([kWasmAnyRef], []); +let kSig_i_r = makeSig([kWasmExternRef], [kWasmI32]); +let kSig_v_r = makeSig([kWasmExternRef], []); let kSig_v_a = makeSig([kWasmAnyFunc], []); -let kSig_v_rr = makeSig([kWasmAnyRef, kWasmAnyRef], []); +let kSig_v_rr = makeSig([kWasmExternRef, kWasmExternRef], []); let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []); -let kSig_r_v = makeSig([], [kWasmAnyRef]); +let kSig_r_v = makeSig([], [kWasmExternRef]); let kSig_a_v = makeSig([], [kWasmAnyFunc]); let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]); @@ -374,10 +416,50 @@ let kExprRefIsNull = 0xd1; let kExprRefFunc = 0xd2; // Prefix opcodes +let kGCPrefix = 0xfb; let kNumericPrefix = 0xfc; let kSimdPrefix = 0xfd; let kAtomicPrefix = 0xfe; +// Use these for multi-byte instructions (opcode > 0x7F needing two LEB bytes): +function GCInstr(opcode) { + if (opcode <= 0x7F) return [kGCPrefix, opcode]; + return [kGCPrefix, 0x80 | (opcode & 0x7F), opcode >> 7]; +} + +// GC opcodes +let kExprStructNew = 0x00; +let kExprStructNewDefault = 0x01; +let kExprStructGet = 0x02; +let kExprStructGetS = 0x03; +let kExprStructGetU = 0x04; +let kExprStructSet = 0x05; +let kExprArrayNew = 0x06; +let kExprArrayNewDefault = 0x07; +let kExprArrayNewFixed = 0x08; +let kExprArrayNewData = 0x09; +let kExprArrayNewElem = 0x0a; +let kExprArrayGet = 0x0b; +let kExprArrayGetS = 0x0c; +let kExprArrayGetU = 0x0d; +let kExprArraySet = 0x0e; +let kExprArrayLen = 0x0f; +let kExprArrayFill = 0x10; +let kExprArrayCopy = 0x11; +let kExprArrayInitData = 0x12; +let kExprArrayInitElem = 0x13; +let kExprRefTest = 0x14; +let kExprRefTestNull = 0x15; +let kExprRefCast = 0x16; +let kExprRefCastNull = 0x17; +let kExprBrOnCast = 0x18; +let kExprBrOnCastFail = 0x19; +let kExprExternInternalize = 0x1a; +let kExprExternExternalize = 0x1b; +let kExprI31New = 0x1c; +let kExprI31GetS = 0x1d; +let kExprI31GetU = 0x1e; + // Numeric opcodes. let kExprMemoryInit = 0x08; let kExprDataDrop = 0x09; @@ -554,6 +636,25 @@ class Binary { } } + emit_heap_type(heap_type) { + this.emit_bytes(wasmSignedLeb(heap_type, kMaxVarInt32Size)); + } + + emit_type(type) { + if ((typeof type) == 'number') { + this.emit_u8(type >= 0 ? type : type & kLeb128Mask); + } else { + this.emit_u8(type.opcode); + if ('depth' in type) this.emit_u8(type.depth); + this.emit_heap_type(type.heap_type); + } + } + + emit_init_expr(expr) { + this.emit_bytes(expr); + this.emit_u8(kExprEnd); + } + emit_header() { this.emit_bytes([ kWasmH0, kWasmH1, kWasmH2, kWasmH3, kWasmV0, kWasmV1, kWasmV2, kWasmV3 @@ -644,11 +745,11 @@ class WasmFunctionBuilder { } class WasmGlobalBuilder { - constructor(module, type, mutable) { + constructor(module, type, mutable, init) { this.module = module; this.type = type; this.mutable = mutable; - this.init = 0; + this.init = init; } exportAs(name) { @@ -658,13 +759,24 @@ class WasmGlobalBuilder { } } +function checkExpr(expr) { + for (let b of expr) { + if (typeof b !== 'number' || (b & (~0xFF)) !== 0) { + throw new Error( + 'invalid body (entries must be 8 bit numbers): ' + expr); + } + } +} + class WasmTableBuilder { - constructor(module, type, initial_size, max_size) { + constructor(module, type, initial_size, max_size, init_expr) { this.module = module; this.type = type; this.initial_size = initial_size; this.has_max = max_size != undefined; this.max_size = max_size; + this.init_expr = init_expr; + this.has_init = init_expr !== undefined; } exportAs(name) { @@ -674,6 +786,35 @@ class WasmTableBuilder { } } +function makeField(type, mutability) { + if ((typeof mutability) != 'boolean') { + throw new Error('field mutability must be boolean'); + } + return {type: type, mutability: mutability}; +} + +class WasmStruct { + constructor(fields, is_final, supertype_idx) { + if (!Array.isArray(fields)) { + throw new Error('struct fields must be an array'); + } + this.fields = fields; + this.type_form = kWasmStructTypeForm; + this.is_final = is_final; + this.supertype = supertype_idx; + } +} + +class WasmArray { + constructor(type, mutability, is_final, supertype_idx) { + this.type = type; + this.mutability = mutability; + this.type_form = kWasmArrayTypeForm; + this.is_final = is_final; + this.supertype = supertype_idx; + } +} + class WasmModuleBuilder { constructor() { this.types = []; @@ -686,6 +827,7 @@ class WasmModuleBuilder { this.element_segments = []; this.data_segments = []; this.explicit = []; + this.rec_groups = []; this.num_imported_funcs = 0; this.num_imported_globals = 0; this.num_imported_tables = 0; @@ -728,25 +870,65 @@ class WasmModuleBuilder { this.explicit.push(this.createCustomSection(name, bytes)); } - addType(type) { - this.types.push(type); - var pl = type.params.length; // should have params - var rl = type.results.length; // should have results + // We use {is_final = true} so that the MVP syntax is generated for + // signatures. + addType(type, supertype_idx = kNoSuperType, is_final = true) { + var pl = type.params.length; // should have params + var rl = type.results.length; // should have results + var type_copy = {params: type.params, results: type.results, + is_final: is_final, supertype: supertype_idx}; + this.types.push(type_copy); + return this.types.length - 1; + } + + addStruct(fields, supertype_idx = kNoSuperType, is_final = false) { + this.types.push(new WasmStruct(fields, is_final, supertype_idx)); return this.types.length - 1; } - addGlobal(local_type, mutable) { - let glob = new WasmGlobalBuilder(this, local_type, mutable); + addArray(type, mutability, supertype_idx = kNoSuperType, is_final = false) { + this.types.push(new WasmArray(type, mutability, is_final, supertype_idx)); + return this.types.length - 1; + } + + static defaultFor(type) { + switch (type) { + case kWasmI32: + return wasmI32Const(0); + case kWasmI64: + return wasmI64Const(0); + case kWasmF32: + return wasmF32Const(0.0); + case kWasmF64: + return wasmF64Const(0.0); + case kWasmS128: + return [kSimdPrefix, kExprS128Const, ...(new Array(16).fill(0))]; + default: + if ((typeof type) != 'number' && type.opcode != kWasmRefNull) { + throw new Error("Non-defaultable type"); + } + let heap_type = (typeof type) == 'number' ? type : type.heap_type; + return [kExprRefNull, ...wasmSignedLeb(heap_type, kMaxVarInt32Size)]; + } + } + + addGlobal(type, mutable, init) { + if (init === undefined) init = WasmModuleBuilder.defaultFor(type); + checkExpr(init); + let glob = new WasmGlobalBuilder(this, type, mutable, init); glob.index = this.globals.length + this.num_imported_globals; this.globals.push(glob); return glob; } - addTable(type, initial_size, max_size = undefined) { - if (type != kWasmAnyRef && type != kWasmAnyFunc) { - throw new Error('Tables must be of type kWasmAnyRef or kWasmAnyFunc'); + addTable(type, initial_size, max_size = undefined, init_expr = undefined) { + if (type == kWasmI32 || type == kWasmI64 || type == kWasmF32 || + type == kWasmF64 || type == kWasmS128 || type == kWasmStmt) { + throw new Error('Tables must be of a reference type'); } - let table = new WasmTableBuilder(this, type, initial_size, max_size); + if (init_expr != undefined) checkExpr(init_expr); + let table = new WasmTableBuilder( + this, type, initial_size, max_size, init_expr); table.index = this.tables.length + this.num_imported_tables; this.tables.push(table); return table; @@ -754,9 +936,9 @@ class WasmModuleBuilder { addTag(type) { let type_index = (typeof type) == "number" ? type : this.addType(type); - let except_index = this.tags.length + this.num_imported_tags; + let tag_index = this.tags.length + this.num_imported_tags; this.tags.push(type_index); - return except_index; + return tag_index; } addFunction(name, type) { @@ -877,6 +1059,21 @@ class WasmModuleBuilder { return this; } + startRecGroup() { + this.rec_groups.push({start: this.types.length, size: 0}); + } + + endRecGroup() { + if (this.rec_groups.length == 0) { + throw new Error("Did not start a recursive group before ending one") + } + let last_element = this.rec_groups[this.rec_groups.length - 1] + if (last_element.size != 0) { + throw new Error("Did not start a recursive group before ending one") + } + last_element.size = this.types.length - last_element.start; + } + setName(name) { this.name = name; return this; @@ -891,18 +1088,55 @@ class WasmModuleBuilder { // Add type section if (wasm.types.length > 0) { - if (debug) print("emitting types @ " + binary.length); + if (debug) print('emitting types @ ' + binary.length); binary.emit_section(kTypeSectionCode, section => { - section.emit_u32v(wasm.types.length); - for (let type of wasm.types) { - section.emit_u8(kWasmFunctionTypeForm); - section.emit_u32v(type.params.length); - for (let param of type.params) { - section.emit_u8(param); + let length_with_groups = wasm.types.length; + for (let group of wasm.rec_groups) { + length_with_groups -= group.size - 1; + } + section.emit_u32v(length_with_groups); + + let rec_group_index = 0; + + for (let i = 0; i < wasm.types.length; i++) { + if (rec_group_index < wasm.rec_groups.length && + wasm.rec_groups[rec_group_index].start == i) { + section.emit_u8(kWasmRecursiveTypeGroupForm); + section.emit_u32v(wasm.rec_groups[rec_group_index].size); + rec_group_index++; } - section.emit_u32v(type.results.length); - for (let result of type.results) { - section.emit_u8(result); + + let type = wasm.types[i]; + if (type.supertype != kNoSuperType) { + section.emit_u8(type.is_final ? kWasmSubtypeFinalForm + : kWasmSubtypeForm); + section.emit_u8(1); // supertype count + section.emit_u32v(type.supertype); + } else if (!type.is_final) { + section.emit_u8(kWasmSubtypeForm); + section.emit_u8(0); // no supertypes + } + if (type instanceof WasmStruct) { + section.emit_u8(kWasmStructTypeForm); + section.emit_u32v(type.fields.length); + for (let field of type.fields) { + section.emit_type(field.type); + section.emit_u8(field.mutability ? 1 : 0); + } + } else if (type instanceof WasmArray) { + section.emit_u8(kWasmArrayTypeForm); + section.emit_type(type.type); + section.emit_u8(type.mutability ? 1 : 0); + } else { + section.emit_u8(kWasmFunctionTypeForm); + section.emit_u32v(type.params.length); + for (let param of type.params) { + section.emit_type(param); + } + section.emit_u32v(type.results.length); + for (let result of type.results) { + section.emit_type(result); + } } } }); @@ -918,9 +1152,9 @@ class WasmModuleBuilder { section.emit_string(imp.name || ''); section.emit_u8(imp.kind); if (imp.kind == kExternalFunction) { - section.emit_u32v(imp.type); + section.emit_u32v(imp.type_index); } else if (imp.kind == kExternalGlobal) { - section.emit_u32v(imp.type); + section.emit_type(imp.type); section.emit_u8(imp.mutable); } else if (imp.kind == kExternalMemory) { var has_max = (typeof imp.maximum) != "undefined"; @@ -933,7 +1167,7 @@ class WasmModuleBuilder { section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum } else if (imp.kind == kExternalTable) { - section.emit_u8(imp.type); + section.emit_type(imp.type); var has_max = (typeof imp.maximum) != "undefined"; section.emit_u8(has_max ? 1 : 0); // flags section.emit_u32v(imp.initial); // initial @@ -965,10 +1199,11 @@ class WasmModuleBuilder { binary.emit_section(kTableSectionCode, section => { section.emit_u32v(wasm.tables.length); for (let table of wasm.tables) { - section.emit_u8(table.type); + section.emit_type(table.type); section.emit_u8(table.has_max); section.emit_u32v(table.initial_size); if (table.has_max) section.emit_u32v(table.max_size); + if (table.has_init) section.emit_init_expr(table.init_expr); } }); } @@ -997,41 +1232,9 @@ class WasmModuleBuilder { binary.emit_section(kGlobalSectionCode, section => { section.emit_u32v(wasm.globals.length); for (let global of wasm.globals) { - section.emit_u8(global.type); + section.emit_type(global.type); section.emit_u8(global.mutable); - if ((typeof global.init_index) == "undefined") { - // Emit a constant initializer. - switch (global.type) { - case kWasmI32: - section.emit_u8(kExprI32Const); - section.emit_u32v(global.init); - break; - case kWasmI64: - section.emit_u8(kExprI64Const); - section.emit_u64v(global.init); - break; - case kWasmF32: - section.emit_bytes(wasmF32Const(global.init)); - break; - case kWasmF64: - section.emit_bytes(wasmF64Const(global.init)); - break; - case kWasmAnyFunc: - case kWasmAnyRef: - if (global.function_index !== undefined) { - section.emit_u8(kExprRefFunc); - section.emit_u32v(global.function_index); - } else { - section.emit_u8(kExprRefNull); - } - break; - } - } else { - // Emit a global-index initializer. - section.emit_u8(kExprGlobalGet); - section.emit_u32v(global.init_index); - } - section.emit_u8(kExprEnd); // end of init expression + section.emit_init_expr(global.init); } }); } @@ -1161,7 +1364,7 @@ class WasmModuleBuilder { local_decls.push({count: l.s128_count, type: kWasmS128}); } if (l.anyref_count > 0) { - local_decls.push({count: l.anyref_count, type: kWasmAnyRef}); + local_decls.push({count: l.anyref_count, type: kWasmExternRef}); } if (l.anyfunc_count > 0) { local_decls.push({count: l.anyfunc_count, type: kWasmAnyFunc}); @@ -1171,7 +1374,7 @@ class WasmModuleBuilder { header.emit_u32v(local_decls.length); for (let decl of local_decls) { header.emit_u32v(decl.count); - header.emit_u8(decl.type); + header.emit_type(decl.type); } section.emit_u32v(header.length + func.body.length); @@ -1284,6 +1487,7 @@ class WasmModuleBuilder { return new WebAssembly.Module(this.toBuffer(debug)); } } +globalThis.WasmModuleBuilder = WasmModuleBuilder; function wasmSignedLeb(val, max_len = 5) { let res = []; @@ -1300,10 +1504,12 @@ function wasmSignedLeb(val, max_len = 5) { throw new Error( 'Leb value <' + val + '> exceeds maximum length of ' + max_len); } +globalThis.wasmSignedLeb = wasmSignedLeb; function wasmI32Const(val) { return [kExprI32Const, ...wasmSignedLeb(val, 5)]; } +globalThis.wasmI32Const = wasmI32Const; function wasmF32Const(f) { // Write in little-endian order at offset 0. @@ -1312,6 +1518,7 @@ function wasmF32Const(f) { kExprF32Const, byte_view[0], byte_view[1], byte_view[2], byte_view[3] ]; } +globalThis.wasmI32Const = wasmI32Const; function wasmF64Const(f) { // Write in little-endian order at offset 0. @@ -1321,3 +1528,4 @@ function wasmF64Const(f) { byte_view[3], byte_view[4], byte_view[5], byte_view[6], byte_view[7] ]; } +globalThis.wasmF64Const = wasmF64Const; diff --git a/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html b/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html index 8002e07ce7f..6145dd04ff8 100644 --- a/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html +++ b/test/fixtures/wpt/wasm/webapi/esm-integration/worker.tentative.html @@ -10,4 +10,7 @@ assert_equals(msg, 42); done(); } +worker.onerror = () => { + assert_unreached("worker got an error"); +} diff --git a/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js b/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js index 68b4706028f..eec09d65a3a 100644 --- a/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js +++ b/test/fixtures/wpt/webmessaging/broadcastchannel/basics.any.js @@ -1,3 +1,11 @@ +test(function() { + assert_throws_js( + TypeError, + () => BroadcastChannel(""), + "Calling BroadcastChannel constructor without 'new' must throw" + ); +}, "BroadcastChannel constructor called as normal function"); + async_test(t => { let c1 = new BroadcastChannel('eventType'); let c2 = new BroadcastChannel('eventType'); diff --git a/test/wpt/status/FileAPI/blob.json b/test/wpt/status/FileAPI/blob.json index 8ea03bbc019..9008e825332 100644 --- a/test/wpt/status/FileAPI/blob.json +++ b/test/wpt/status/FileAPI/blob.json @@ -6,36 +6,36 @@ "fail": { "note": "Depends on File API", "expected": [ - "A plain object with @@iterator should be treated as a sequence for the blobParts argument.", - "A plain object with @@iterator and a length property should be treated as a sequence for the blobParts argument.", "A String object should be treated as a sequence for the blobParts argument.", "A Uint8Array object should be treated as a sequence for the blobParts argument.", - "Getters and value conversions should happen in order until an exception is thrown.", - "Changes to the blobParts array should be reflected in the returned Blob (pop).", - "Changes to the blobParts array should be reflected in the returned Blob (unshift).", - "ToString should be called on elements of the blobParts array.", - "ArrayBuffer elements of the blobParts array should be supported.", - "Passing typed arrays as elements of the blobParts array should work.", - "Passing a Float64Array as element of the blobParts array should work.", - "Passing BigInt typed arrays as elements of the blobParts array should work.", + "A plain object with @@iterator and a length property should be treated as a sequence for the blobParts argument.", + "A plain object with @@iterator should be treated as a sequence for the blobParts argument.", + "Arguments should be evaluated from left to right.", + "Array with mixed types", "Array with two blobs", "Array with two buffers", "Array with two bufferviews", - "Array with mixed types", - "options properties should be accessed in lexicographic order.", - "Arguments should be evaluated from left to right.", - "Passing null (index 0) for options should use the defaults.", + "ArrayBuffer elements of the blobParts array should be supported.", + "Changes to the blobParts array should be reflected in the returned Blob (pop).", + "Changes to the blobParts array should be reflected in the returned Blob (unshift).", + "Getters and value conversions should happen in order until an exception is thrown.", + "Passing BigInt typed arrays as elements of the blobParts array should work.", + "Passing a Float64Array as element of the blobParts array should work.", + "Passing function \"function() {}\" (index 5) for options should use the defaults (with newlines).", + "Passing function \"function() {}\" (index 5) for options should use the defaults.", "Passing null (index 0) for options should use the defaults (with newlines).", - "Passing undefined (index 1) for options should use the defaults.", - "Passing undefined (index 1) for options should use the defaults (with newlines).", - "Passing object \"[object Object]\" (index 2) for options should use the defaults.", + "Passing null (index 0) for options should use the defaults.", + "Passing object \"/regex/\" (index 4) for options should use the defaults (with newlines).", + "Passing object \"/regex/\" (index 4) for options should use the defaults.", "Passing object \"[object Object]\" (index 2) for options should use the defaults (with newlines).", - "Passing object \"[object Object]\" (index 3) for options should use the defaults.", + "Passing object \"[object Object]\" (index 2) for options should use the defaults.", "Passing object \"[object Object]\" (index 3) for options should use the defaults (with newlines).", - "Passing object \"/regex/\" (index 4) for options should use the defaults.", - "Passing object \"/regex/\" (index 4) for options should use the defaults (with newlines).", - "Passing function \"function() {}\" (index 5) for options should use the defaults.", - "Passing function \"function() {}\" (index 5) for options should use the defaults (with newlines)." + "Passing object \"[object Object]\" (index 3) for options should use the defaults.", + "Passing typed arrays as elements of the blobParts array should work.", + "Passing undefined (index 1) for options should use the defaults (with newlines).", + "Passing undefined (index 1) for options should use the defaults.", + "ToString should be called on elements of the blobParts array.", + "options properties should be accessed in lexicographic order." ] } }, diff --git a/test/wpt/status/dom/events.json b/test/wpt/status/dom/events.json index c0f4104c452..1b8cc3bb6cd 100644 --- a/test/wpt/status/dom/events.json +++ b/test/wpt/status/dom/events.json @@ -1,10 +1,11 @@ { "AddEventListenerOptions-passive.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ + "passive behavior of one listener should be unaffected by the presence of other listeners", "preventDefault should be ignored if-and-only-if the passive option is true", - "returnValue should be ignored if-and-only-if the passive option is true", - "passive behavior of one listener should be unaffected by the presence of other listeners" + "returnValue should be ignored if-and-only-if the passive option is true" ] } }, @@ -13,6 +14,7 @@ }, "Event-isTrusted.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "Event-isTrusted" ] diff --git a/test/wpt/status/encoding.json b/test/wpt/status/encoding.json index 09f8c2b545b..253dc7ec6ad 100644 --- a/test/wpt/status/encoding.json +++ b/test/wpt/status/encoding.json @@ -1,39 +1,61 @@ { "api-basics.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-fatal-streaming.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-fatal.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-ignorebom.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-streaming.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-utf16-surrogates.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "iso-2022-jp-decoder.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "iso-2022-jp decoder state handling bug: https://encoding.spec.whatwg.org/#iso-2022-jp-decoder" }, "textdecoder-byte-order-marks.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-fatal-single-byte.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "The iso-8859-16 encoding is not supported" }, "textdecoder-labels.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "The iso-8859-16 encoding is not supported" }, "textencoder-constructor-non-utf.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "The iso-8859-16 encoding is not supported" }, "idlharness.any.js": { @@ -49,7 +71,9 @@ "skip": "decoding-helpers.js needs XMLHttpRequest" }, "streams/decode-ignore-bom.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "streams/invalid-realm.window.js": { "skip": "document is not defined" @@ -58,46 +82,67 @@ "skip": "window is not defined" }, "streams/decode-attributes.any.js": { - "requires": ["full-icu"] + "requires": [ + "full-icu" + ] }, "streams/decode-incomplete-input.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "streams/decode-utf8.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "streams/decode-bad-chunks.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "chunk of type undefined should error the stream" ] } }, "streams/decode-non-utf8.any.js": { - "requires": ["full-icu"] + "requires": [ + "full-icu" + ] }, "encodeInto.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "textdecoder-copy.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "legacy-mb-schinese/gbk/gbk-decoder.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "The gbk encoding is not supported" }, "legacy-mb-schinese/gb18030/gb18030-decoder.any.js": { - "requires": ["full-icu"], + "requires": [ + "full-icu" + ], "skip": "The gb18030 encoding is not supported" }, "textdecoder-arguments.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "single-byte-decoder.window.js": { "skip": "document is not defined" }, "textdecoder-eof.any.js": { - "requires": ["small-icu"] + "requires": [ + "small-icu" + ] }, "unsupported-labels.window.js": { "skip": "document is not defined" diff --git a/test/wpt/status/hr-time.json b/test/wpt/status/hr-time.json index b787bcb7862..5461ada56d5 100644 --- a/test/wpt/status/hr-time.json +++ b/test/wpt/status/hr-time.json @@ -1,6 +1,7 @@ { "idlharness.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "Window interface: attribute performance" ] diff --git a/test/wpt/status/html/webappapis/atob.json b/test/wpt/status/html/webappapis/atob.json index 2c63c085104..0967ef424bc 100644 --- a/test/wpt/status/html/webappapis/atob.json +++ b/test/wpt/status/html/webappapis/atob.json @@ -1,2 +1 @@ -{ -} +{} diff --git a/test/wpt/status/html/webappapis/structured-clone.json b/test/wpt/status/html/webappapis/structured-clone.json index 873f2f9b46e..2702c3839bc 100644 --- a/test/wpt/status/html/webappapis/structured-clone.json +++ b/test/wpt/status/html/webappapis/structured-clone.json @@ -1,7 +1,15 @@ { "structured-clone.any.js": { "fail": { - "expected": ["File basic"] + "note": "WPT test auto rolling", + "expected": [ + "A detached ArrayBuffer cannot be transferred", + "A subclass instance will deserialize as its closest serializable superclass", + "File basic", + "Growable SharedArrayBuffer", + "Serializing a non-serializable platform object fails", + "Transferring a non-transferable platform object fails" + ] } } } diff --git a/test/wpt/status/html/webappapis/timers.json b/test/wpt/status/html/webappapis/timers.json index 21e77a089d5..3a624a903cd 100644 --- a/test/wpt/status/html/webappapis/timers.json +++ b/test/wpt/status/html/webappapis/timers.json @@ -1,5 +1,8 @@ { "negative-settimeout.any.js": { "skip": "unreliable in Node.js; Refs: https://github.com/nodejs/node/issues/37672" + }, + "evil-spec-example.any.js": { + "skip": "WPT test auto rolling" } } diff --git a/test/wpt/status/performance-timeline.json b/test/wpt/status/performance-timeline.json index 9a297e64143..4b04837b708 100644 --- a/test/wpt/status/performance-timeline.json +++ b/test/wpt/status/performance-timeline.json @@ -9,5 +9,47 @@ }, "webtiming-resolution.any.js": { "skip": "flaky" + }, + "droppedentriescount.any.js": { + "skip": "WPT test auto rolling" + }, + "idlharness-shadowrealm.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-bfcache.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-fetch.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-lock.https.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-navigation-failure.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-reload.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js": { + "skip": "WPT test auto rolling" + }, + "not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js": { + "skip": "WPT test auto rolling" } } diff --git a/test/wpt/status/resource-timing.json b/test/wpt/status/resource-timing.json index 22f21cfe48d..a9f3d3e7530 100644 --- a/test/wpt/status/resource-timing.json +++ b/test/wpt/status/resource-timing.json @@ -19,5 +19,26 @@ }, "buffered-flag.any.js": { "skip": "Browser-specific test" + }, + "delivery-type.tentative.any.js": { + "skip": "WPT test auto rolling" + }, + "idlharness.any.js": { + "fail": { + "note": "WPT test auto rolling", + "expected": [ + "PerformanceResourceTiming interface: attribute contentType", + "PerformanceResourceTiming interface: attribute deliveryType", + "PerformanceResourceTiming interface: attribute firstInterimResponseStart", + "PerformanceResourceTiming interface: attribute renderBlockingStatus", + "PerformanceResourceTiming interface: attribute responseStatus", + "PerformanceResourceTiming interface: default toJSON operation on resource", + "PerformanceResourceTiming interface: resource must inherit property \"contentType\" with the proper type", + "PerformanceResourceTiming interface: resource must inherit property \"deliveryType\" with the proper type", + "PerformanceResourceTiming interface: resource must inherit property \"firstInterimResponseStart\" with the proper type", + "PerformanceResourceTiming interface: resource must inherit property \"renderBlockingStatus\" with the proper type", + "PerformanceResourceTiming interface: resource must inherit property \"responseStatus\" with the proper type" + ] + } } } diff --git a/test/wpt/status/streams.json b/test/wpt/status/streams.json index 6454918110d..04b7c9909c7 100644 --- a/test/wpt/status/streams.json +++ b/test/wpt/status/streams.json @@ -1,8 +1,10 @@ { "idlharness.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ - "ReadableStream interface: async iterable" + "ReadableStream interface: async iterable", + "ReadableStream interface: operation from(any)" ] } }, @@ -11,6 +13,7 @@ }, "piping/general-addition.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "enqueue() must not synchronously call write algorithm" ] @@ -24,9 +27,10 @@ }, "readable-streams/owning-type-message-port.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ - "Transferred MessageChannel works as expected", - "Second branch of owning ReadableStream tee should end up into errors with transfer only values" + "Second branch of owning ReadableStream tee should end up into errors with transfer only values", + "Transferred MessageChannel works as expected" ] } }, @@ -35,12 +39,13 @@ }, "readable-streams/owning-type.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "ReadableStream can be constructed with owning type", "ReadableStream of type owning should call start with a ReadableStreamDefaultController", + "ReadableStream of type owning should transfer enqueued chunks", "ReadableStream should be able to call enqueue with an empty transfer list", - "ReadableStream should check transfer parameter", - "ReadableStream of type owning should transfer enqueued chunks" + "ReadableStream should check transfer parameter" ] } }, @@ -52,6 +57,7 @@ }, "transferable/transform-stream-members.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "Transferring [object TransformStream],[object ReadableStream] should fail", "Transferring [object TransformStream],[object WritableStream] should fail" @@ -63,5 +69,43 @@ }, "readable-streams/read-task-handling.window.js": { "skip": "Browser-specific test" + }, + "transform-streams/cancel.any.js": { + "fail": { + "note": "WPT test auto rolling", + "expected": [ + "aborting the writable side should call transformer.abort()", + "aborting the writable side should reject if transformer.cancel() throws", + "cancelling the readable side should call transformer.cancel()", + "cancelling the readable side should reject if transformer.cancel() throws", + "closing the writable side should reject if a parallel transformer.cancel() throws", + "readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()", + "writable.abort() and readable.cancel() should reject if a transformer.cancel() calls controller.error()" + ] + } + }, + "transform-streams/errors.any.js": { + "fail": { + "note": "WPT test auto rolling", + "expected": [ + "controller.error() should close writable immediately after readable.cancel()" + ] + } + }, + "transform-streams/general.any.js": { + "fail": { + "note": "WPT test auto rolling", + "expected": [ + "terminate() should abort writable immediately after readable.cancel()" + ] + } + }, + "transform-streams/reentrant-strategies.any.js": { + "fail": { + "note": "WPT test auto rolling", + "expected": [ + "writer.abort() inside size() should work" + ] + } } } diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json index 96dafd91b70..dc3f53a4728 100644 --- a/test/wpt/status/url.json +++ b/test/wpt/status/url.json @@ -9,6 +9,8 @@ "fail": { "note": "We are faking location with a URL object for the sake of the testharness and it has searchParams.", "expected": [ + "URL: no structured serialize/deserialize support", + "URLSearchParams: no structured serialize/deserialize support", "searchParams on location object" ] } diff --git a/test/wpt/status/webmessaging/broadcastchannel.json b/test/wpt/status/webmessaging/broadcastchannel.json index b6ee1b6e0db..80d1824f76a 100644 --- a/test/wpt/status/webmessaging/broadcastchannel.json +++ b/test/wpt/status/webmessaging/broadcastchannel.json @@ -1,17 +1,16 @@ { "basics.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ - "postMessage results in correct event", - "messages are delivered in port creation order" - ], - "flaky": [ - "Closing a channel in onmessage prevents already queued tasks from firing onmessage events" + "messages are delivered in port creation order", + "postMessage results in correct event" ] } }, "interface.any.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "postMessage after close should throw", "postMessage should throw InvalidStateError after close, even with uncloneable data" @@ -20,6 +19,7 @@ }, "origin.window.js": { "fail": { + "note": "WPT test auto rolling", "expected": [ "Serialization of BroadcastChannel origin" ] From b0f72cef05b1dacfefc47a1cf8512024493e7540 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Sun, 5 Nov 2023 16:41:10 +0000 Subject: [PATCH 5/5] deps: update wpt to 708e132aca --- test/wpt/status/html/webappapis/structured-clone.json | 6 +++--- test/wpt/status/resource-timing.json | 10 +++++----- test/wpt/status/streams.json | 4 ++-- test/wpt/status/url.json | 4 ++-- test/wpt/status/webmessaging/broadcastchannel.json | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/wpt/status/html/webappapis/structured-clone.json b/test/wpt/status/html/webappapis/structured-clone.json index 2702c3839bc..e8575da2418 100644 --- a/test/wpt/status/html/webappapis/structured-clone.json +++ b/test/wpt/status/html/webappapis/structured-clone.json @@ -3,11 +3,11 @@ "fail": { "note": "WPT test auto rolling", "expected": [ - "A detached ArrayBuffer cannot be transferred", - "A subclass instance will deserialize as its closest serializable superclass", "File basic", - "Growable SharedArrayBuffer", "Serializing a non-serializable platform object fails", + "A subclass instance will deserialize as its closest serializable superclass", + "Growable SharedArrayBuffer", + "A detached ArrayBuffer cannot be transferred", "Transferring a non-transferable platform object fails" ] } diff --git a/test/wpt/status/resource-timing.json b/test/wpt/status/resource-timing.json index a9f3d3e7530..922315261ad 100644 --- a/test/wpt/status/resource-timing.json +++ b/test/wpt/status/resource-timing.json @@ -27,17 +27,17 @@ "fail": { "note": "WPT test auto rolling", "expected": [ - "PerformanceResourceTiming interface: attribute contentType", "PerformanceResourceTiming interface: attribute deliveryType", "PerformanceResourceTiming interface: attribute firstInterimResponseStart", - "PerformanceResourceTiming interface: attribute renderBlockingStatus", "PerformanceResourceTiming interface: attribute responseStatus", - "PerformanceResourceTiming interface: default toJSON operation on resource", - "PerformanceResourceTiming interface: resource must inherit property \"contentType\" with the proper type", + "PerformanceResourceTiming interface: attribute renderBlockingStatus", + "PerformanceResourceTiming interface: attribute contentType", "PerformanceResourceTiming interface: resource must inherit property \"deliveryType\" with the proper type", "PerformanceResourceTiming interface: resource must inherit property \"firstInterimResponseStart\" with the proper type", + "PerformanceResourceTiming interface: resource must inherit property \"responseStatus\" with the proper type", "PerformanceResourceTiming interface: resource must inherit property \"renderBlockingStatus\" with the proper type", - "PerformanceResourceTiming interface: resource must inherit property \"responseStatus\" with the proper type" + "PerformanceResourceTiming interface: resource must inherit property \"contentType\" with the proper type", + "PerformanceResourceTiming interface: default toJSON operation on resource" ] } } diff --git a/test/wpt/status/streams.json b/test/wpt/status/streams.json index 04b7c9909c7..3a51ed61439 100644 --- a/test/wpt/status/streams.json +++ b/test/wpt/status/streams.json @@ -74,10 +74,10 @@ "fail": { "note": "WPT test auto rolling", "expected": [ - "aborting the writable side should call transformer.abort()", - "aborting the writable side should reject if transformer.cancel() throws", "cancelling the readable side should call transformer.cancel()", "cancelling the readable side should reject if transformer.cancel() throws", + "aborting the writable side should call transformer.abort()", + "aborting the writable side should reject if transformer.cancel() throws", "closing the writable side should reject if a parallel transformer.cancel() throws", "readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()", "writable.abort() and readable.cancel() should reject if a transformer.cancel() calls controller.error()" diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json index dc3f53a4728..3d8f277e406 100644 --- a/test/wpt/status/url.json +++ b/test/wpt/status/url.json @@ -9,9 +9,9 @@ "fail": { "note": "We are faking location with a URL object for the sake of the testharness and it has searchParams.", "expected": [ + "searchParams on location object", "URL: no structured serialize/deserialize support", - "URLSearchParams: no structured serialize/deserialize support", - "searchParams on location object" + "URLSearchParams: no structured serialize/deserialize support" ] } }, diff --git a/test/wpt/status/webmessaging/broadcastchannel.json b/test/wpt/status/webmessaging/broadcastchannel.json index 80d1824f76a..0f5db5a0da1 100644 --- a/test/wpt/status/webmessaging/broadcastchannel.json +++ b/test/wpt/status/webmessaging/broadcastchannel.json @@ -3,8 +3,8 @@ "fail": { "note": "WPT test auto rolling", "expected": [ - "messages are delivered in port creation order", - "postMessage results in correct event" + "postMessage results in correct event", + "messages are delivered in port creation order" ] } },