diff --git a/lib/fetch/response.js b/lib/fetch/response.js index 66c0e50e32b..88deb71a062 100644 --- a/lib/fetch/response.js +++ b/lib/fetch/response.js @@ -49,7 +49,7 @@ class Response { } // https://fetch.spec.whatwg.org/#dom-response-json - static json (data = undefined, init = {}) { + static json (data, init = {}) { webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' }) if (init !== null) { diff --git a/lib/fetch/util.js b/lib/fetch/util.js index 98a049dc79d..fcbba84bc9a 100644 --- a/lib/fetch/util.js +++ b/lib/fetch/util.js @@ -556,16 +556,37 @@ function bytesMatch (bytes, metadataList) { const algorithm = item.algo // 2. Let expectedValue be the val component of item. - const expectedValue = item.hash + let expectedValue = item.hash + + // See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e + // "be liberal with padding". This is annoying, and it's not even in the spec. + + if (expectedValue.endsWith('==')) { + expectedValue = expectedValue.slice(0, -2) + } // 3. Let actualValue be the result of applying algorithm to bytes. - const actualValue = crypto.createHash(algorithm).update(bytes).digest('base64') + let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64') + + if (actualValue.endsWith('==')) { + actualValue = actualValue.slice(0, -2) + } // 4. If actualValue is a case-sensitive match for expectedValue, // return true. if (actualValue === expectedValue) { return true } + + let actualBase64URL = crypto.createHash(algorithm).update(bytes).digest('base64url') + + if (actualBase64URL.endsWith('==')) { + actualBase64URL = actualBase64URL.slice(0, -2) + } + + if (actualBase64URL === expectedValue) { + return true + } } // 6. Return false. diff --git a/test/wpt/runner/runner.mjs b/test/wpt/runner/runner.mjs index 0b66f58466b..5bec326d3e1 100644 --- a/test/wpt/runner/runner.mjs +++ b/test/wpt/runner/runner.mjs @@ -312,6 +312,8 @@ export class WPTRunner extends EventEmitter { `unexpected failures: ${failed - expectedFailures}, ` + `skipped: ${skipped}` ) + + process.exit(0) } addInitScript (code) { diff --git a/test/wpt/status/fetch.status.json b/test/wpt/status/fetch.status.json index cb5949579cf..5910bf37f6f 100644 --- a/test/wpt/status/fetch.status.json +++ b/test/wpt/status/fetch.status.json @@ -2,11 +2,13 @@ "api": { "abort": { "general.any.js": { + "note": "TODO(@KhafraDev): Clone aborts with original controller can probably be fixed", "fail": [ "Already aborted signal rejects immediately", "Underlying connection is closed when aborting after receiving response - no-cors", "Stream errors once aborted. Underlying connection closed.", - "Readable stream synchronously cancels with AbortError if aborted before reading" + "Readable stream synchronously cancels with AbortError if aborted before reading", + "Clone aborts with original controller" ] }, "cache.https.any.js": { @@ -128,6 +130,10 @@ ] } }, + "fetch-later": { + "note": "this is not part of the spec, only a proposal", + "skip": true + }, "headers": { "header-setcookie.any.js": { "note": "undici doesn't filter headers", diff --git a/test/wpt/tests/.azure-pipelines.yml b/test/wpt/tests/.azure-pipelines.yml index 20d5ec0f431..75a87df90f0 100644 --- a/test/wpt/tests/.azure-pipelines.yml +++ b/test/wpt/tests/.azure-pipelines.yml @@ -21,6 +21,7 @@ trigger: - triggers/edge_canary - triggers/safari_stable - triggers/safari_preview +- triggers/wktr_preview # Set safaridriver_diagnose to true to enable safaridriver diagnostics. The # logs won't appear in `./wpt run` output but will be uploaded as an artifact. @@ -34,11 +35,11 @@ jobs: displayName: 'affected tests: Safari Technology Preview' condition: eq(variables['Build.Reason'], 'PullRequest') pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/affected_tests.yml parameters: artifactName: 'safari-preview-affected-tests' @@ -51,11 +52,11 @@ jobs: displayName: 'affected tests without changes: Safari Technology Preview' condition: eq(variables['Build.Reason'], 'PullRequest') pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/affected_tests.yml parameters: checkoutCommit: 'HEAD^1' @@ -76,7 +77,7 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - script: | set -eux -o pipefail @@ -93,17 +94,18 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_infrastructure'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml parameters: packages: virtualenv - template: tools/ci/azure/install_fonts.yml - template: tools/ci/azure/install_certs.yml + - template: tools/ci/azure/color_profile.yml - template: tools/ci/azure/install_chrome.yml - template: tools/ci/azure/install_firefox.yml - template: tools/ci/azure/install_safari.yml @@ -111,20 +113,25 @@ jobs: - template: tools/ci/azure/update_manifest.yml - script: | set -eux -o pipefail - ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --channel dev chrome infrastructure/ + ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_macos_chrome.json --channel dev chrome infrastructure/ condition: succeededOrFailed() displayName: 'Run tests (Chrome Dev)' - script: | set -eux -o pipefail - ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --channel nightly firefox infrastructure/ + ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_macos_firefox.json --channel nightly firefox infrastructure/ condition: succeededOrFailed() displayName: 'Run tests (Firefox Nightly)' - script: | set -eux -o pipefail export SYSTEM_VERSION_COMPAT=0 - ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --channel preview safari infrastructure/ + ./wpt run --yes --no-manifest-update --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-mach - --log-mach-level info --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_macos_safari.json --channel preview safari infrastructure/ condition: succeededOrFailed() displayName: 'Run tests (Safari Technology Preview)' + - task: PublishBuildArtifacts@1 + condition: succeededOrFailed() + displayName: 'Publish results' + inputs: + artifactName: 'infrastructure-results' - template: tools/ci/azure/publish_logs.yml - template: tools/ci/azure/sysdiagnose.yml @@ -133,76 +140,79 @@ jobs: dependsOn: decision condition: dependencies.decision.outputs['test_jobs.tools_unittest'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.7' + # TODO(#40525): Revert back to 3.7 once the Mac agent's Python v3.7 contains bz2 again. + versionSpec: '3.7.16' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/ toxenv: py37 -- job: tools_unittest_mac_py310 - displayName: 'tools/ unittests: macOS + Python 3.10' +- job: tools_unittest_mac_py311 + displayName: 'tools/ unittests: macOS + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.tools_unittest'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/ - toxenv: py310 + toxenv: py311 - job: wptrunner_unittest_mac_py37 displayName: 'tools/wptrunner/ unittests: macOS + Python 3.7' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_unittest'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.7' + # TODO(#40525): Revert back to 3.7 once the Mac agent's Python v3.7 contains bz2 again. + versionSpec: '3.7.16' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/wptrunner/ toxenv: py37 -- job: wptrunner_unittest_mac_py310 - displayName: 'tools/wptrunner/ unittests: macOS + Python 3.10' +- job: wptrunner_unittest_mac_py311 + displayName: 'tools/wptrunner/ unittests: macOS + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_unittest'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/wptrunner/ - toxenv: py310 + toxenv: py311 - job: wpt_integration_mac_py37 displayName: 'tools/wpt/ tests: macOS + Python 3.7' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wpt_integration'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: # full checkout required - task: UsePythonVersion@0 inputs: - versionSpec: '3.7' + # TODO(#40525): Revert back to 3.7 once the Mac agent's Python v3.7 contains bz2 again. + versionSpec: '3.7.16' - template: tools/ci/azure/install_chrome.yml - template: tools/ci/azure/install_firefox.yml - template: tools/ci/azure/update_hosts.yml @@ -212,17 +222,17 @@ jobs: directory: tools/wpt/ toxenv: py37 -- job: wpt_integration_mac_py310 - displayName: 'tools/wpt/ tests: macOS + Python 3.10' +- job: wpt_integration_mac_py311 + displayName: 'tools/wpt/ tests: macOS + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wpt_integration'] pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: # full checkout required - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/install_chrome.yml - template: tools/ci/azure/install_firefox.yml - template: tools/ci/azure/update_hosts.yml @@ -230,7 +240,7 @@ jobs: - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/wpt/ - toxenv: py310 + toxenv: py311 - job: tools_unittest_win_py37 displayName: 'tools/ unittests: Windows + Python 3.7' @@ -251,8 +261,8 @@ jobs: directory: tools/ toxenv: py37 -- job: tools_unittest_win_py310 - displayName: 'tools/ unittests: Windows + Python 3.10' +- job: tools_unittest_win_py311 + displayName: 'tools/ unittests: Windows + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.tools_unittest'] pool: @@ -260,13 +270,13 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' addToPath: false - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/ - toxenv: py310 + toxenv: py311 - job: wptrunner_unittest_win_py37 displayName: 'tools/wptrunner/ unittests: Windows + Python 3.7' @@ -285,8 +295,8 @@ jobs: directory: tools/wptrunner/ toxenv: py37 -- job: wptrunner_unittest_win_py310 - displayName: 'tools/wptrunner/ unittests: Windows + Python 3.10' +- job: wptrunner_unittest_win_py311 + displayName: 'tools/wptrunner/ unittests: Windows + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wptrunner_unittest'] pool: @@ -294,13 +304,13 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' addToPath: false - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/wptrunner/ - toxenv: py310 + toxenv: py311 - job: wpt_integration_win_py37 displayName: 'tools/wpt/ tests: Windows + Python 3.7' @@ -324,8 +334,8 @@ jobs: directory: tools/wpt/ toxenv: py37 -- job: wpt_integration_win_py310 - displayName: 'tools/wpt/ tests: Windows + Python 3.10' +- job: wpt_integration_win_py311 + displayName: 'tools/wpt/ tests: Windows + Python 3.11' dependsOn: decision condition: dependencies.decision.outputs['test_jobs.wpt_integration'] pool: @@ -334,7 +344,7 @@ jobs: # full checkout required - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' # currently just using the outdated Chrome/Firefox on the VM rather than # figuring out how to install Chrome Dev channel on Windows # - template: tools/ci/azure/install_chrome.yml @@ -344,7 +354,7 @@ jobs: - template: tools/ci/azure/tox_pytest.yml parameters: directory: tools/wpt/ - toxenv: py310 + toxenv: py311 - job: results_edge_stable displayName: 'all tests: Edge Stable' @@ -360,7 +370,7 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/system_info.yml - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml @@ -399,7 +409,7 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/system_info.yml - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml @@ -438,7 +448,7 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml parameters: @@ -472,16 +482,17 @@ jobs: parallel: 8 # chosen to make runtime ~2h timeoutInMinutes: 180 pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml parameters: packages: virtualenv - template: tools/ci/azure/install_certs.yml + - template: tools/ci/azure/color_profile.yml - template: tools/ci/azure/install_safari.yml parameters: channel: stable @@ -490,8 +501,9 @@ jobs: - script: | set -eux -o pipefail export SYSTEM_VERSION_COMPAT=0 - ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel stable --kill-safari safari + ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel stable --kill-safari --max-restarts 100 safari displayName: 'Run tests' + retryCountOnTaskFailure: 2 - task: PublishBuildArtifacts@1 displayName: 'Publish results' inputs: @@ -513,24 +525,26 @@ jobs: parallel: 8 # chosen to make runtime ~2h timeoutInMinutes: 180 pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml parameters: packages: virtualenv - template: tools/ci/azure/install_certs.yml + - template: tools/ci/azure/color_profile.yml - template: tools/ci/azure/install_safari.yml - template: tools/ci/azure/update_hosts.yml - template: tools/ci/azure/update_manifest.yml - script: | set -eux -o pipefail export SYSTEM_VERSION_COMPAT=0 - ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel preview --kill-safari safari + ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel preview --kill-safari --max-restarts 100 safari displayName: 'Run tests' + retryCountOnTaskFailure: 2 - task: PublishBuildArtifacts@1 displayName: 'Publish results' inputs: @@ -551,22 +565,23 @@ jobs: parallel: 8 # chosen to make runtime ~2h timeoutInMinutes: 180 pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.10' + versionSpec: '3.11' - template: tools/ci/azure/checkout.yml - template: tools/ci/azure/pip_install.yml parameters: packages: virtualenv - template: tools/ci/azure/install_certs.yml + - template: tools/ci/azure/color_profile.yml - template: tools/ci/azure/update_hosts.yml - template: tools/ci/azure/update_manifest.yml - script: | set -eux -o pipefail export SYSTEM_VERSION_COMPAT=0 - ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel main --install-browser wktr + ./wpt run --no-manifest-update --no-restart-on-unexpected --no-fail-on-unexpected --this-chunk=$(System.JobPositionInPhase) --total-chunks=$(System.TotalJobsInPhase) --chunk-type hash --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt --log-mach - --log-mach-level info --channel experimental --install-browser --yes wktr displayName: 'Run tests' - task: PublishBuildArtifacts@1 displayName: 'Publish results' diff --git a/test/wpt/tests/.taskcluster.yml b/test/wpt/tests/.taskcluster.yml index c80e92af204..c817999b8e6 100644 --- a/test/wpt/tests/.taskcluster.yml +++ b/test/wpt/tests/.taskcluster.yml @@ -57,7 +57,7 @@ tasks: owner: ${owner} source: ${event.repository.clone_url} payload: - image: webplatformtests/wpt:0.53 + image: webplatformtests/wpt:0.54 maxRunTime: 7200 artifacts: public/results: diff --git a/test/wpt/tests/FileAPI/reading-data-section/filereader_readAsDataURL.any.js b/test/wpt/tests/FileAPI/reading-data-section/filereader_readAsDataURL.any.js index d6812121295..4f9dbf7a754 100644 --- a/test/wpt/tests/FileAPI/reading-data-section/filereader_readAsDataURL.any.js +++ b/test/wpt/tests/FileAPI/reading-data-section/filereader_readAsDataURL.any.js @@ -39,4 +39,16 @@ async_test(function(testCase) { testCase.done(); }); reader.readAsDataURL(blob); -}, 'readAsDataURL result for Blob with unspecified MIME type'); \ No newline at end of file +}, 'readAsDataURL result for Blob with unspecified MIME type'); + +async_test(function(testCase) { + var blob = new Blob([]); + var reader = new FileReader(); + + reader.onload = this.step_func(function() { + assert_equals(reader.result, + "data:application/octet-stream;base64,"); + testCase.done(); + }); + reader.readAsDataURL(blob); +}, 'readAsDataURL result for empty Blob'); \ No newline at end of file diff --git a/test/wpt/tests/common/media.js b/test/wpt/tests/common/media.js index f2dc8612660..800593f5343 100644 --- a/test/wpt/tests/common/media.js +++ b/test/wpt/tests/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/wpt/tests/common/rendering-utils.js b/test/wpt/tests/common/rendering-utils.js index 8027cd5f848..46283bd5d07 100644 --- a/test/wpt/tests/common/rendering-utils.js +++ b/test/wpt/tests/common/rendering-utils.js @@ -7,14 +7,12 @@ */ function waitForAtLeastOneFrame() { return new Promise(resolve => { - // Different web engines work slightly different on this area but 1) waiting - // for two requestAnimationFrames() to happen one after another and 2) - // adding a step_timeout(0) to guarantee events have finished should be + // Different web engines work slightly different on this area but waiting + // for two requestAnimationFrames() to happen, one after another, should be // sufficient to ensure at least one frame has been generated anywhere. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1785615 window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { - setTimeout(resolve, 0); + resolve(); }); }); }); diff --git a/test/wpt/tests/fetch/api/abort/general.any.js b/test/wpt/tests/fetch/api/abort/general.any.js index 7bf98ba9b24..3727bb42afe 100644 --- a/test/wpt/tests/fetch/api/abort/general.any.js +++ b/test/wpt/tests/fetch/api/abort/general.any.js @@ -566,7 +566,7 @@ test(() => { controller.abort(); - assert_array_equals(log, ['clone-aborted', 'original-aborted'], "Abort events fired in correct order"); + assert_array_equals(log, ['original-aborted', 'clone-aborted'], "Abort events fired in correct order"); assert_true(request.signal.aborted, 'Signal aborted'); assert_true(clonedRequest.signal.aborted, 'Signal aborted'); }, "Clone aborts with original controller"); diff --git a/test/wpt/tests/fetch/api/basic/integrity.sub.any.js b/test/wpt/tests/fetch/api/basic/integrity.sub.any.js index 56dbd4909f6..e3cfd1b2f6e 100644 --- a/test/wpt/tests/fetch/api/basic/integrity.sub.any.js +++ b/test/wpt/tests/fetch/api/basic/integrity.sub.any.js @@ -28,6 +28,9 @@ function integrity(desc, url, integrity, initRequestMode, shouldPass) { const topSha256 = "sha256-KHIDZcXnR2oBHk9DrAA+5fFiR6JjudYjqoXtMR1zvzk="; const topSha384 = "sha384-MgZYnnAzPM/MjhqfOIMfQK5qcFvGZsGLzx4Phd7/A8fHTqqLqXqKo8cNzY3xEPTL"; const topSha512 = "sha512-D6yns0qxG0E7+TwkevZ4Jt5t7Iy3ugmAajG/dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg=="; +const topSha512wrongpadding = "sha512-D6yns0qxG0E7+TwkevZ4Jt5t7Iy3ugmAajG/dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg"; +const topSha512base64url = "sha512-D6yns0qxG0E7-TwkevZ4Jt5t7Iy3ugmAajG_dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg=="; +const topSha512base64url_nopadding = "sha512-D6yns0qxG0E7-TwkevZ4Jt5t7Iy3ugmAajG_dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg"; const invalidSha256 = "sha256-dKUcPOn/AlUjWIwcHeHNqYXPlvyGiq+2dWOdFcE+24I="; const invalidSha512 = "sha512-oUceBRNxPxnY60g/VtPCj2syT4wo4EZh2CgYdWy9veW8+OsReTXoh7dizMGZafvx9+QhMS39L/gIkxnPIn41Zg=="; @@ -38,13 +41,20 @@ const corsUrl = const corsUrl2 = `https://{{host}}:{{ports[https][0]}}${path}` integrity("Empty string integrity", url, "", /* initRequestMode */ undefined, - /* shouldPass */ true); + /* shouldPass */ true); integrity("SHA-256 integrity", url, topSha256, /* initRequestMode */ undefined, /* shouldPass */ true); integrity("SHA-384 integrity", url, topSha384, /* initRequestMode */ undefined, /* shouldPass */ true); integrity("SHA-512 integrity", url, topSha512, /* initRequestMode */ undefined, /* shouldPass */ true); +integrity("SHA-512 integrity with missing padding", url, topSha512wrongpadding, + /* initRequestMode */ undefined, /* shouldPass */ true); +integrity("SHA-512 integrity base64url encoded", url, topSha512base64url, + /* initRequestMode */ undefined, /* shouldPass */ true); +integrity("SHA-512 integrity base64url encoded with missing padding", url, + topSha512base64url_nopadding, /* initRequestMode */ undefined, + /* shouldPass */ true); integrity("Invalid integrity", url, invalidSha256, /* initRequestMode */ undefined, /* shouldPass */ false); integrity("Multiple integrities: valid stronger than invalid", url, diff --git a/test/wpt/tests/fetch/api/basic/keepalive.any.js b/test/wpt/tests/fetch/api/basic/keepalive.any.js index 4f33284d0c7..899d41d676a 100644 --- a/test/wpt/tests/fetch/api/basic/keepalive.any.js +++ b/test/wpt/tests/fetch/api/basic/keepalive.any.js @@ -14,16 +14,30 @@ const { HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT } = get_host_info(); -for (const method of ['GET', 'POST']) { - promise_test(async (test) => { - const token1 = token(); - const iframe = document.createElement('iframe'); - iframe.src = getKeepAliveIframeUrl(token1, method); - document.body.appendChild(iframe); - await iframeLoaded(iframe); - assert_equals(await getTokenFromMessage(), token1); - iframe.remove(); +/** + * In a different-site iframe, test to fetch a keepalive URL on the specified + * document event. + */ +function keepaliveSimpleRequestTest(method) { + for (const evt of ['load', 'pagehide', 'unload']) { + const desc = + `[keepalive] simple ${method} request on '${evt}' [no payload]`; + promise_test(async (test) => { + const token1 = token(); + const iframe = document.createElement('iframe'); + iframe.src = getKeepAliveIframeUrl(token1, method, {sendOn: evt}); + document.body.appendChild(iframe); + await iframeLoaded(iframe); + if (evt != 'load') { + iframe.remove(); + } + assert_equals(await getTokenFromMessage(), token1); + + assertStashedTokenAsync(desc, token1); + }, `${desc}; setting up`); + } +} - assertStashedTokenAsync(`simple ${method} request: no payload`, token1); - }, `simple ${method} request: no payload; setting up`); +for (const method of ['GET', 'POST']) { + keepaliveSimpleRequestTest(method); } diff --git a/test/wpt/tests/fetch/api/basic/scheme-blob.sub.any.js b/test/wpt/tests/fetch/api/basic/scheme-blob.sub.any.js index a6059ea93d9..8afdc033c9d 100644 --- a/test/wpt/tests/fetch/api/basic/scheme-blob.sub.any.js +++ b/test/wpt/tests/fetch/api/basic/scheme-blob.sub.any.js @@ -57,6 +57,10 @@ let empty_data_blob = new Blob([], {type: "text/plain"}); checkFetchResponse(URL.createObjectURL(empty_data_blob), "", "text/plain", 0, "Fetching URL.createObjectURL(empty_data_blob) is OK"); +let invalid_type_blob = new Blob([], {type: "invalid"}); +checkFetchResponse(URL.createObjectURL(invalid_type_blob), "", "", 0, + "Fetching URL.createObjectURL(invalid_type_blob) is OK"); + promise_test(function(test) { return fetch("/images/blue.png").then(function(resp) { return resp.arrayBuffer(); diff --git a/test/wpt/tests/fetch/api/cors/cors-basic.any.js b/test/wpt/tests/fetch/api/cors/cors-basic.any.js index 23f5f91c87d..95de0af2d8f 100644 --- a/test/wpt/tests/fetch/api/cors/cors-basic.any.js +++ b/test/wpt/tests/fetch/api/cors/cors-basic.any.js @@ -1,37 +1,43 @@ // META: script=../resources/utils.js // META: script=/common/get-host-info.sub.js +const { + HTTPS_ORIGIN, + HTTP_ORIGIN_WITH_DIFFERENT_PORT, + HTTP_REMOTE_ORIGIN, + HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, + HTTPS_REMOTE_ORIGIN, +} = get_host_info(); + function cors(desc, origin) { - var url = origin + dirname(location.pathname); - var urlParameters = "?pipe=header(Access-Control-Allow-Origin,*)"; + const url = `${origin}${dirname(location.pathname)}${RESOURCES_DIR}top.txt`; + const urlAllowCors = `${url}?pipe=header(Access-Control-Allow-Origin,*)`; - promise_test(function(test) { - return fetch(url + RESOURCES_DIR + "top.txt" + urlParameters, {"mode": "no-cors"} ).then(function(resp) { + promise_test((test) => { + return fetch(urlAllowCors, {'mode': 'no-cors'}).then((resp) => { assert_equals(resp.status, 0, "Opaque filter: status is 0"); assert_equals(resp.statusText, "", "Opaque filter: statusText is \"\""); assert_equals(resp.type , "opaque", "Opaque filter: response's type is opaque"); - return resp.text().then(function(value) { + return resp.text().then((value) => { assert_equals(value, "", "Opaque response should have an empty body"); }); }); - }, desc + " [no-cors mode]"); + }, `${desc} [no-cors mode]`); - promise_test(function(test) { - return promise_rejects_js(test, TypeError, fetch(url + RESOURCES_DIR + "top.txt", {"mode": "cors"})); - }, desc + " [server forbid CORS]"); + promise_test((test) => { + return promise_rejects_js(test, TypeError, fetch(url, {'mode': 'cors'})); + }, `${desc} [server forbid CORS]`); - promise_test(function(test) { - return fetch(url + RESOURCES_DIR + "top.txt" + urlParameters, {"mode": "cors"} ).then(function(resp) { + promise_test((test) => { + return fetch(urlAllowCors, {'mode': 'cors'}).then((resp) => { assert_equals(resp.status, 200, "Fetch's response's status is 200"); assert_equals(resp.type , "cors", "CORS response's type is cors"); }); - }, desc + " [cors mode]"); + }, `${desc} [cors mode]`); } -var host_info = get_host_info(); - -cors("Same domain different port", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT); -cors("Same domain different protocol different port", host_info.HTTPS_ORIGIN); -cors("Cross domain basic usage", host_info.HTTP_REMOTE_ORIGIN); -cors("Cross domain different port", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT); -cors("Cross domain different protocol", host_info.HTTPS_REMOTE_ORIGIN); +cors('Same domain different port', HTTP_ORIGIN_WITH_DIFFERENT_PORT); +cors('Same domain different protocol different port', HTTPS_ORIGIN); +cors('Cross domain basic usage', HTTP_REMOTE_ORIGIN); +cors('Cross domain different port', HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT); +cors('Cross domain different protocol', HTTPS_REMOTE_ORIGIN); diff --git a/test/wpt/tests/fetch/api/cors/cors-keepalive.any.js b/test/wpt/tests/fetch/api/cors/cors-keepalive.any.js new file mode 100644 index 00000000000..f68d90ef9aa --- /dev/null +++ b/test/wpt/tests/fetch/api/cors/cors-keepalive.any.js @@ -0,0 +1,118 @@ +// META: global=window +// META: timeout=long +// META: title=Fetch API: keepalive handling +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/common/utils.js +// META: script=/common/get-host-info.sub.js +// META: script=../resources/keepalive-helper.js +// META: script=../resources/utils.js + +'use strict'; + +const { + HTTP_NOTSAMESITE_ORIGIN, + HTTPS_ORIGIN, + HTTP_ORIGIN_WITH_DIFFERENT_PORT, + HTTP_REMOTE_ORIGIN, + HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, + HTTPS_REMOTE_ORIGIN, +} = get_host_info(); + +/** + * Tests to cover the basic behaviors of keepalive + cors/no-cors mode requests + * to different `origin` when the initiator document is still alive. They should + * behave the same as without setting keepalive. + */ +function keepaliveCorsBasicTest(desc, origin) { + const url = `${origin}${dirname(location.pathname)}${RESOURCES_DIR}top.txt`; + const urlAllowCors = `${url}?pipe=header(Access-Control-Allow-Origin,*)`; + + promise_test((test) => { + return fetch(urlAllowCors, {keepalive: true, 'mode': 'no-cors'}) + .then((resp) => { + assert_equals(resp.status, 0, 'Opaque filter: status is 0'); + assert_equals(resp.statusText, '', 'Opaque filter: statusText is ""'); + assert_equals( + resp.type, 'opaque', 'Opaque filter: response\'s type is opaque'); + return resp.text().then((value) => { + assert_equals( + value, '', 'Opaque response should have an empty body'); + }); + }); + }, `${desc} [no-cors mode]`); + + promise_test((test) => { + return promise_rejects_js( + test, TypeError, fetch(url, {keepalive: true, 'mode': 'cors'})); + }, `${desc} [cors mode, server forbid CORS]`); + + promise_test((test) => { + return fetch(urlAllowCors, {keepalive: true, 'mode': 'cors'}) + .then((resp) => { + assert_equals(resp.status, 200, 'Fetch\'s response\'s status is 200'); + assert_equals(resp.type, 'cors', 'CORS response\'s type is cors'); + }); + }, `${desc} [cors mode]`); +} + +keepaliveCorsBasicTest( + `[keepalive] Same domain different port`, HTTP_ORIGIN_WITH_DIFFERENT_PORT); +keepaliveCorsBasicTest( + `[keepalive] Same domain different protocol different port`, HTTPS_ORIGIN); +keepaliveCorsBasicTest( + `[keepalive] Cross domain basic usage`, HTTP_REMOTE_ORIGIN); +keepaliveCorsBasicTest( + `[keepalive] Cross domain different port`, + HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT); +keepaliveCorsBasicTest( + `[keepalive] Cross domain different protocol`, HTTPS_REMOTE_ORIGIN); + +/** + * In a same-site iframe, and in `unload` event handler, test to fetch + * a keepalive URL that involves in different cors modes. + */ +function keepaliveCorsInUnloadTest(description, origin, method) { + const evt = 'unload'; + for (const mode of ['no-cors', 'cors']) { + for (const disallowOrigin of [false, true]) { + const desc = `${description} ${method} request in ${evt} [${mode} mode` + + (disallowOrigin ? `, server forbid CORS]` : `]`); + const shouldPass = !disallowOrigin || mode === 'no-cors'; + promise_test(async (test) => { + const token1 = token(); + const iframe = document.createElement('iframe'); + iframe.src = getKeepAliveIframeUrl(token1, method, { + frameOrigin: '', + requestOrigin: origin, + sendOn: evt, + mode: mode, + disallowOrigin + }); + document.body.appendChild(iframe); + await iframeLoaded(iframe); + iframe.remove(); + assert_equals(await getTokenFromMessage(), token1); + + assertStashedTokenAsync(desc, token1, {shouldPass}); + }, `${desc}; setting up`); + } + } +} + +for (const method of ['GET', 'POST']) { + keepaliveCorsInUnloadTest( + '[keepalive] Same domain different port', HTTP_ORIGIN_WITH_DIFFERENT_PORT, + method); + keepaliveCorsInUnloadTest( + `[keepalive] Same domain different protocol different port`, HTTPS_ORIGIN, + method); + keepaliveCorsInUnloadTest( + `[keepalive] Cross domain basic usage`, HTTP_REMOTE_ORIGIN, method); + keepaliveCorsInUnloadTest( + `[keepalive] Cross domain different port`, + HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, method); + keepaliveCorsInUnloadTest( + `[keepalive] Cross domain different protocol`, HTTPS_REMOTE_ORIGIN, + method); +} diff --git a/test/wpt/tests/fetch/api/cors/cors-preflight-star.any.js b/test/wpt/tests/fetch/api/cors/cors-preflight-star.any.js index e8cbc80b808..f9fb20469cf 100644 --- a/test/wpt/tests/fetch/api/cors/cors-preflight-star.any.js +++ b/test/wpt/tests/fetch/api/cors/cors-preflight-star.any.js @@ -80,3 +80,7 @@ preflightTest(true, true, "PATCH", "*", "PATCH", []) preflightTest(false, true, "PATCH", "*", "patch", []) preflightTest(false, true, "patch", "*", "PATCH", []) preflightTest(true, true, "patch", "*", "patch", []) + +// "Authorization" header can't be wildcarded. +preflightTest(false, false, "*", "*", "POST", ["Authorization", "123"]) +preflightTest(true, false, "*", "*, Authorization", "POST", ["Authorization", "123"]) diff --git a/test/wpt/tests/fetch/api/crashtests/body-window-destroy.html b/test/wpt/tests/fetch/api/crashtests/body-window-destroy.html new file mode 100644 index 00000000000..646d3c5f8ce --- /dev/null +++ b/test/wpt/tests/fetch/api/crashtests/body-window-destroy.html @@ -0,0 +1,11 @@ + + + diff --git a/test/wpt/tests/fetch/api/request/destination/resources/dummy_video.webm b/test/wpt/tests/fetch/api/request/destination/resources/dummy_video.webm new file mode 100644 index 00000000000..c3d433a3e02 Binary files /dev/null and b/test/wpt/tests/fetch/api/request/destination/resources/dummy_video.webm differ diff --git a/test/wpt/tests/fetch/api/request/multi-globals/construct-in-detached-frame.window.js b/test/wpt/tests/fetch/api/request/multi-globals/construct-in-detached-frame.window.js new file mode 100644 index 00000000000..b0d6ba5b80d --- /dev/null +++ b/test/wpt/tests/fetch/api/request/multi-globals/construct-in-detached-frame.window.js @@ -0,0 +1,11 @@ +// This is a regression test for Chromium issue https://crbug.com/1427266. +test(() => { + const iframe = document.createElement('iframe'); + document.body.append(iframe); + const otherRequest = iframe.contentWindow.Request; + iframe.remove(); + const r1 = new otherRequest('resource', { method: 'POST', body: 'string' }); + const r2 = new otherRequest(r1); + assert_true(r1.bodyUsed); + assert_false(r2.bodyUsed); +}, 'creating a request from another request in a detached realm should work'); diff --git a/test/wpt/tests/fetch/api/resources/keepalive-helper.js b/test/wpt/tests/fetch/api/resources/keepalive-helper.js index c7048d1ff33..ad1d4b2c7c3 100644 --- a/test/wpt/tests/fetch/api/resources/keepalive-helper.js +++ b/test/wpt/tests/fetch/api/resources/keepalive-helper.js @@ -1,19 +1,35 @@ // Utility functions to help testing keepalive requests. -// Returns a different-site URL to an iframe that loads a keepalive URL. +// Returns a URL to an iframe that loads a keepalive URL on iframe loaded. // // The keepalive URL points to a target that stores `token`. The token will then -// be posted back to parent document. +// be posted back on iframe loaded to the parent document. // `method` defaults to GET. -// `sendOnPagehide` to tell if request should be sent on pagehide instead. -function getKeepAliveIframeUrl(token, method, sendOnPagehide = false) { +// `frameOrigin` to specify the origin of the iframe to load. If not set, +// default to a different site origin. +// `requestOrigin` to specify the origin of the fetch request target. +// `sendOn` to specify the name of the event when the keepalive request should +// be sent instead of the default 'load'. +// `mode` to specify the fetch request's CORS mode. +// `disallowOrigin` to ask the iframe to set up a server that forbids CORS +// requests. +function getKeepAliveIframeUrl(token, method, { + frameOrigin = 'DEFAULT', + requestOrigin = '', + sendOn = 'load', + mode = 'cors', + disallowOrigin = false +} = {}) { const https = location.protocol.startsWith('https'); - const frameOrigin = - get_host_info()[https ? 'HTTPS_NOTSAMESITE_ORIGIN' : 'HTTP_NOTSAMESITE_ORIGIN']; + frameOrigin = frameOrigin === 'DEFAULT' ? + get_host_info()[https ? 'HTTPS_NOTSAMESITE_ORIGIN' : 'HTTP_NOTSAMESITE_ORIGIN'] : + frameOrigin; return `${frameOrigin}/fetch/api/resources/keepalive-iframe.html?` + `token=${token}&` + `method=${method}&` + - `sendOnPagehide=${sendOnPagehide}`; + `sendOn=${sendOn}&` + + `mode=${mode}&` + (disallowOrigin ? `disallowOrigin=1&` : ``) + + `origin=${requestOrigin}`; } // Returns a different-site URL to an iframe that loads a keepalive URL. diff --git a/test/wpt/tests/fetch/api/resources/keepalive-iframe.html b/test/wpt/tests/fetch/api/resources/keepalive-iframe.html index ac00f3a331a..335a1f8e318 100644 --- a/test/wpt/tests/fetch/api/resources/keepalive-iframe.html +++ b/test/wpt/tests/fetch/api/resources/keepalive-iframe.html @@ -3,12 +3,18 @@ diff --git a/test/wpt/tests/fetch/api/resources/stash-put.py b/test/wpt/tests/fetch/api/resources/stash-put.py index dbc7ceebb88..0530e1ba5b4 100644 --- a/test/wpt/tests/fetch/api/resources/stash-put.py +++ b/test/wpt/tests/fetch/api/resources/stash-put.py @@ -1,17 +1,19 @@ from wptserve.utils import isomorphic_decode def main(request, response): - if request.method == u'OPTIONS': - # CORS preflight - response.headers.set(b'Access-Control-Allow-Origin', b'*') - response.headers.set(b'Access-Control-Allow-Methods', b'*') - response.headers.set(b'Access-Control-Allow-Headers', b'*') - return 'done' + if request.method == u'OPTIONS': + # CORS preflight + response.headers.set(b'Access-Control-Allow-Origin', b'*') + response.headers.set(b'Access-Control-Allow-Methods', b'*') + response.headers.set(b'Access-Control-Allow-Headers', b'*') + return 'done' + + url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/' + key = request.GET.first(b'key') + value = request.GET.first(b'value') + # value here must be a text string. It will be json.dump()'ed in stash-take.py. + request.server.stash.put(key, isomorphic_decode(value), url_dir) - url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/' - key = request.GET.first(b"key") - value = request.GET.first(b"value") - # value here must be a text string. It will be json.dump()'ed in stash-take.py. - request.server.stash.put(key, isomorphic_decode(value), url_dir) + if b'disallow_origin' not in request.GET: response.headers.set(b'Access-Control-Allow-Origin', b'*') - return "done" + return 'done' diff --git a/test/wpt/tests/fetch/api/response/response-body-read-task-handling.html b/test/wpt/tests/fetch/api/response/response-body-read-task-handling.html index c2c90eaa8bd..64b07556661 100644 --- a/test/wpt/tests/fetch/api/response/response-body-read-task-handling.html +++ b/test/wpt/tests/fetch/api/response/response-body-read-task-handling.html @@ -35,9 +35,7 @@ // The fulfill handler above shouldn't have run yet. If it has run, // throw to reject this promise and fail the test. - if (executed) { - throw "shouldn't have run microtasks yet"; - } + assert_false(executed, "shouldn't have run microtasks yet"); // Otherwise act as if there's no "then" property so the promise // fulfills and the test passes. @@ -49,6 +47,40 @@ return response.body.getReader().read(); }); }, "reading from a body stream should occur in a microtask scope"); + +promise_test(function() { + return fetch("../resources/data.json").then(function(response) { + // Add a getter for "then" that will incidentally be invoked + // during promise resolution. + Object.prototype.__defineGetter__('then', () => { + // Clean up behind ourselves. + delete Object.prototype.then; + + // This promise should (like all promises) be resolved + // asynchronously. + var executed = false; + Promise.resolve().then(_ => { executed = true; }); + + // This shouldn't run microtasks! They should only run + // after the fetch is resolved. + performMicrotaskCheckpoint(); + + // The fulfill handler above shouldn't have run yet. If it has run, + // throw to reject this promise and fail the test. + assert_false(executed, "shouldn't have run microtasks yet"); + + // Otherwise act as if there's no "then" property so the promise + // fulfills and the test passes. + return undefined; + }); + + // Create a read request, incidentally resolving a promise with an + // object value, thereby invoking the getter installed above. + return response.body.pipeTo(new WritableStream({ + write(chunk) {} + })) + }); +}, "piping from a body stream to a JS-written WritableStream should occur in a microtask scope"); diff --git a/test/wpt/tests/fetch/api/response/response-cancel-stream.any.js b/test/wpt/tests/fetch/api/response/response-cancel-stream.any.js index baa46de4039..91140d1afd1 100644 --- a/test/wpt/tests/fetch/api/response/response-cancel-stream.any.js +++ b/test/wpt/tests/fetch/api/response/response-cancel-stream.any.js @@ -55,3 +55,10 @@ promise_test(function() { return readAll(reader).then(() => reader.cancel()); }); }, "Cancelling a closed Response stream"); + +promise_test(async () => { + const response = await fetch(RESOURCES_DIR + "top.txt"); + const { body } = response; + await body.cancel(); + assert_equals(body, response.body, ".body should not change after cancellation"); +}, "Accessing .body after canceling it"); diff --git a/test/wpt/tests/fetch/api/response/response-static-json.any.js b/test/wpt/tests/fetch/api/response/response-static-json.any.js index 3c8a2b637f7..5ec79e69aa3 100644 --- a/test/wpt/tests/fetch/api/response/response-static-json.any.js +++ b/test/wpt/tests/fetch/api/response/response-static-json.any.js @@ -79,3 +79,18 @@ promise_test(async function () { } ) }, "Check static json() propagates JSON serializer errors"); + +const encodingChecks = [ + ["𝌆", [34, 240, 157, 140, 134, 34]], + ["\uDF06\uD834", [34, 92, 117, 100, 102, 48, 54, 92, 117, 100, 56, 51, 52, 34]], + ["\uDEAD", [34, 92, 117, 100, 101, 97, 100, 34]], +]; + +for (const [input, expected] of encodingChecks) { + promise_test(async function () { + const response = Response.json(input); + const buffer = await response.arrayBuffer(); + const data = new Uint8Array(buffer); + assert_array_equals(data, expected); + }, `Check response returned by static json() with input ${input}`); +} diff --git a/test/wpt/tests/fetch/content-length/resources/content-lengths.json b/test/wpt/tests/fetch/content-length/resources/content-lengths.json index dac9c82dc09..ac6f1a24680 100644 --- a/test/wpt/tests/fetch/content-length/resources/content-lengths.json +++ b/test/wpt/tests/fetch/content-length/resources/content-lengths.json @@ -31,6 +31,22 @@ "input": "Content-Length: 30\r\nContent-Length: 30,30", "output": 30 }, + { + "input": "Content-Length: 30,30\r\nContent-Length: 30,30", + "output": 30 + }, + { + "input": "Content-Length: 30,30, 30 \r\nContent-Length: 30 ", + "output": 30 + }, + { + "input": "Content-Length: 30,42\r\nContent-Length: 30", + "output": null + }, + { + "input": "Content-Length: 30,42\r\nContent-Length: 30,42", + "output": null + }, { "input": "Content-Length: 42,30", "output": null diff --git a/test/wpt/tests/fetch/corb/resources/response_block_probe.js b/test/wpt/tests/fetch/corb/resources/response_block_probe.js index d23ad488af2..9c3b87bcbd3 100644 --- a/test/wpt/tests/fetch/corb/resources/response_block_probe.js +++ b/test/wpt/tests/fetch/corb/resources/response_block_probe.js @@ -1 +1 @@ -window.script_callback(); +alert(1); // Arbitrary JavaScript. Details don't matter for the test. diff --git a/test/wpt/tests/fetch/corb/response_block.tentative.https.html b/test/wpt/tests/fetch/corb/response_block.tentative.https.html new file mode 100644 index 00000000000..6b116000d45 --- /dev/null +++ b/test/wpt/tests/fetch/corb/response_block.tentative.https.html @@ -0,0 +1,50 @@ + + + + + + diff --git a/test/wpt/tests/fetch/corb/response_block.tentative.sub.https.html b/test/wpt/tests/fetch/corb/response_block.tentative.sub.https.html deleted file mode 100644 index 860e0d3b93c..00000000000 --- a/test/wpt/tests/fetch/corb/response_block.tentative.sub.https.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - diff --git a/test/wpt/tests/fetch/fetch-later/META.yml b/test/wpt/tests/fetch/fetch-later/META.yml new file mode 100644 index 00000000000..f8fd46bec3e --- /dev/null +++ b/test/wpt/tests/fetch/fetch-later/META.yml @@ -0,0 +1,3 @@ +spec: https://whatpr.org/fetch/1647/094ea69...152d725.html#fetch-later-method +suggested_reviewers: + - mingyc diff --git a/test/wpt/tests/fetch/fetch-later/README.md b/test/wpt/tests/fetch/fetch-later/README.md new file mode 100644 index 00000000000..661e2b91843 --- /dev/null +++ b/test/wpt/tests/fetch/fetch-later/README.md @@ -0,0 +1,3 @@ +# FetchLater Tests + +These tests cover [FetchLater method](https://whatpr.org/fetch/1647/094ea69...152d725.html#fetch-later-method) related behaviors. diff --git a/test/wpt/tests/fetch/fetch-later/basic.tentative.https.window.js b/test/wpt/tests/fetch/fetch-later/basic.tentative.https.window.js new file mode 100644 index 00000000000..a8ca011a7c9 --- /dev/null +++ b/test/wpt/tests/fetch/fetch-later/basic.tentative.https.window.js @@ -0,0 +1,13 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js + +'use strict'; + +test(() => { + assert_throws_js(TypeError, () => fetchLater()); +}, `fetchLater() cannot be called without request.`); + +test(() => { + const result = fetchLater('/'); + assert_false(result.sent); +}, `fetchLater()'s return tells the deferred request is not yet sent.`); diff --git a/test/wpt/tests/fetch/fetch-later/non-secure.window.js b/test/wpt/tests/fetch/fetch-later/non-secure.window.js new file mode 100644 index 00000000000..2f2c3ea8d34 --- /dev/null +++ b/test/wpt/tests/fetch/fetch-later/non-secure.window.js @@ -0,0 +1,8 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js + +'use strict'; + +test(() => { + assert_false(window.hasOwnProperty('fetchLater')); +}, `fetchLater() is not supported in non-secure context.`); diff --git a/test/wpt/tests/fetch/fetch-later/sendondiscard.tentative.https.window.js b/test/wpt/tests/fetch/fetch-later/sendondiscard.tentative.https.window.js new file mode 100644 index 00000000000..0613d18dffb --- /dev/null +++ b/test/wpt/tests/fetch/fetch-later/sendondiscard.tentative.https.window.js @@ -0,0 +1,28 @@ +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/common/utils.js +// META: script=/pending-beacon/resources/pending_beacon-helper.js + +'use strict'; + +parallelPromiseTest(async t => { + const uuid = token(); + const url = generateSetBeaconURL(uuid); + const numPerMethod = 20; + const total = numPerMethod * 2; + + // Loads an iframe that creates `numPerMethod` GET & POST fetchLater requests. + const iframe = await loadScriptAsIframe(` + const url = "${url}"; + for (let i = 0; i < ${numPerMethod}; i++) { + let get = fetchLater(url); + let post = fetchLater(url, {method: 'POST'}); + } + `); + + // Delete the iframe to trigger deferred request sending. + document.body.removeChild(iframe); + + // The iframe should have sent all requests. + await expectBeacon(uuid, {count: total}); +}, 'A discarded document sends all its fetchLater requests with default config.'); diff --git a/test/wpt/tests/fetch/h1-parsing/resources-with-0x00-in-header.window.js b/test/wpt/tests/fetch/h1-parsing/resources-with-0x00-in-header.window.js index f1afeeb740b..37a61c12b56 100644 --- a/test/wpt/tests/fetch/h1-parsing/resources-with-0x00-in-header.window.js +++ b/test/wpt/tests/fetch/h1-parsing/resources-with-0x00-in-header.window.js @@ -15,7 +15,7 @@ async_test(t => { // https://github.com/whatwg/html/issues/125 and https://github.com/whatwg/html/issues/1230 this // should be changed to use the load event instead. t.step_timeout(() => { - assert_equals(frame.contentDocument, null); + assert_equals(window.frameLoaded, undefined); t.done(); }, 1000); document.body.append(frame); diff --git a/test/wpt/tests/fetch/h1-parsing/resources/document-with-0x00-in-header.py b/test/wpt/tests/fetch/h1-parsing/resources/document-with-0x00-in-header.py index 223b3c40278..d91998b998d 100644 --- a/test/wpt/tests/fetch/h1-parsing/resources/document-with-0x00-in-header.py +++ b/test/wpt/tests/fetch/h1-parsing/resources/document-with-0x00-in-header.py @@ -1,4 +1,4 @@ def main(request, response): response.headers.set(b"Content-Type", b"text/html") response.headers.set(b"Custom", b"\0") - return b"This is a document." + return b"This is a document." diff --git a/test/wpt/tests/fetch/local-network-access/README.md b/test/wpt/tests/fetch/local-network-access/README.md deleted file mode 100644 index 8995e3d7ef6..00000000000 --- a/test/wpt/tests/fetch/local-network-access/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Local Network Access tests - -This directory contains tests for Local Network Access' integration with -the Fetch specification. - -See also: - -* [The specification](https://wicg.github.io/local-network-access/) -* [The repository](https://github.com/WICG/local-network-access/) -* [Open issues](https://github.com/WICG/local-network-access/issues/) diff --git a/test/wpt/tests/fetch/orb/resources/script-asm-js-invalid.js b/test/wpt/tests/fetch/orb/resources/script-asm-js-invalid.js new file mode 100644 index 00000000000..8d1bbd6abc8 --- /dev/null +++ b/test/wpt/tests/fetch/orb/resources/script-asm-js-invalid.js @@ -0,0 +1,4 @@ +function f() { + "use asm"; + return; +} diff --git a/test/wpt/tests/fetch/orb/resources/script-asm-js-valid.js b/test/wpt/tests/fetch/orb/resources/script-asm-js-valid.js new file mode 100644 index 00000000000..79b375fe054 --- /dev/null +++ b/test/wpt/tests/fetch/orb/resources/script-asm-js-valid.js @@ -0,0 +1,4 @@ +function f() { + "use asm"; + return {}; +} diff --git a/test/wpt/tests/fetch/orb/tentative/known-mime-type.sub.any.js b/test/wpt/tests/fetch/orb/tentative/known-mime-type.sub.any.js index 66a63c8b28a..b0521e8b363 100644 --- a/test/wpt/tests/fetch/orb/tentative/known-mime-type.sub.any.js +++ b/test/wpt/tests/fetch/orb/tentative/known-mime-type.sub.any.js @@ -74,3 +74,13 @@ promise_test(async () => { promise_test(async () => { await fetchORB(`${path}/script-iso-8559-1.js`, null, contentType("application/json")); }, "ORB shouldn't block opaque text/javascript (iso-8559-1 encoded)"); + +// Test javascript validation can correctly parse asm.js. +promise_test(async () => { + await fetchORB(`${path}/script-asm-js-valid.js`, null, contentType("application/json")); +}, "ORB shouldn't block text/javascript with valid asm.js"); + +// Test javascript validation can correctly parse invalid asm.js with valid JS syntax. +promise_test(async () => { + await fetchORB(`${path}/script-asm-js-invalid.js`, null, contentType("application/json")); +}, "ORB shouldn't block text/javascript with invalid asm.js"); diff --git a/test/wpt/tests/fetch/local-network-access/META.yml b/test/wpt/tests/fetch/private-network-access/META.yml similarity index 100% rename from test/wpt/tests/fetch/local-network-access/META.yml rename to test/wpt/tests/fetch/private-network-access/META.yml diff --git a/test/wpt/tests/fetch/private-network-access/README.md b/test/wpt/tests/fetch/private-network-access/README.md new file mode 100644 index 00000000000..a69aab48723 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/README.md @@ -0,0 +1,10 @@ +# Private Network Access tests + +This directory contains tests for Private Network Access' integration with +the Fetch specification. + +See also: + +* [The specification](https://wicg.github.io/private-network-access/) +* [The repository](https://github.com/WICG/private-network-access/) +* [Open issues](https://github.com/WICG/private-network-access/issues/) diff --git a/test/wpt/tests/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js b/test/wpt/tests/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js new file mode 100644 index 00000000000..21233f61ea6 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js @@ -0,0 +1,91 @@ +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=resources/support.sub.js +// META: script=/fenced-frame/resources/utils.js +// META: timeout=long +// +// Spec: https://wicg.github.io/private-network-access/#integration-fetch +// +// These tests verify that contexts can navigate fenced frames to more-public or +// same address spaces without private network access preflight request header. + +setup(() => { + assert_true(window.isSecureContext); +}); + +// Source: secure local context. +// +// All fetches unaffected by Private Network Access. + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: {server: Server.HTTPS_LOCAL}, + expected: FrameTestResult.SUCCESS, + }), + 'local to local: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: {server: Server.HTTPS_PRIVATE}, + expected: FrameTestResult.SUCCESS, + }), + 'local to private: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: {server: Server.HTTPS_PUBLIC}, + expected: FrameTestResult.SUCCESS, + }), + 'local to public: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_PRIVATE}, + target: {server: Server.HTTPS_PRIVATE}, + expected: FrameTestResult.SUCCESS, + }), + 'private to private: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_PRIVATE}, + target: {server: Server.HTTPS_PUBLIC}, + expected: FrameTestResult.SUCCESS, + }), + 'private to public: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: {server: Server.HTTPS_PUBLIC}, + target: {server: Server.HTTPS_PUBLIC}, + expected: FrameTestResult.SUCCESS, + }), + 'public to public: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: {server: Server.HTTPS_PUBLIC}, + expected: FrameTestResult.SUCCESS, + }), + 'treat-as-public-address to public: no preflight required.'); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTPS_PUBLIC, + behavior: {preflight: PreflightBehavior.optionalSuccess(token())} + }, + expected: FrameTestResult.SUCCESS, + }), + 'treat-as-public-address to local: optional preflight'); diff --git a/test/wpt/tests/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js b/test/wpt/tests/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js new file mode 100644 index 00000000000..2dff325e3e1 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js @@ -0,0 +1,330 @@ +// META: script=/common/subset-tests-by-key.js +// META: script=/common/utils.js +// META: script=resources/support.sub.js +// META: script=/fenced-frame/resources/utils.js +// META: variant=?include=baseline +// META: variant=?include=from-local +// META: variant=?include=from-private +// META: variant=?include=from-public +// META: timeout=long +// +// Spec: https://wicg.github.io/private-network-access/#integration-fetch +// +// These tests verify that secure contexts can fetch subresources in fenced +// frames from all address spaces, provided that the target server, if more +// private than the initiator, respond affirmatively to preflight requests. +// + +setup(() => { + // Making sure we are in a secure context, as expected. + assert_true(window.isSecureContext); +}); + +// Source: secure local context. +// +// All fetches unaffected by Private Network Access. + +subsetTestByKey( + 'from-local', promise_test, t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: {server: Server.HTTPS_LOCAL}, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'local to local: no preflight required.'); + +subsetTestByKey( + 'from-local', promise_test, + t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: { + server: Server.HTTPS_PRIVATE, + behavior: {response: ResponseBehavior.allowCrossOrigin()}, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'local to private: no preflight required.'); + + +subsetTestByKey( + 'from-local', promise_test, + t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: { + server: Server.HTTPS_PUBLIC, + behavior: {response: ResponseBehavior.allowCrossOrigin()}, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'local to public: no preflight required.'); + +// Strictly speaking, the following two tests do not exercise PNA-specific +// logic, but they serve as a baseline for comparison, ensuring that non-PNA +// preflight requests are sent and handled as expected. + +subsetTestByKey( + 'baseline', promise_test, + t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: { + server: Server.HTTPS_PUBLIC, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'PUT', mode: 'cors'}, + expected: FetchTestResult.FAILURE, + }), + 'local to public: PUT preflight failure.'); + +subsetTestByKey( + 'baseline', promise_test, + t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_LOCAL}, + target: { + server: Server.HTTPS_PUBLIC, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + } + }, + fetchOptions: {method: 'PUT', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'local to public: PUT preflight success.'); + +// Generates tests of preflight behavior for a single (source, target) pair. +// +// Scenarios: +// +// - cors mode: +// - preflight response has non-2xx HTTP code +// - preflight response is missing CORS headers +// - preflight response is missing the PNA-specific `Access-Control` header +// - final response is missing CORS headers +// - success +// - success with PUT method (non-"simple" request) +// - no-cors mode: +// - preflight response has non-2xx HTTP code +// - preflight response is missing CORS headers +// - preflight response is missing the PNA-specific `Access-Control` header +// - success +// +function makePreflightTests({ + subsetKey, + source, + sourceDescription, + targetServer, + targetDescription, +}) { + const prefix = `${sourceDescription} to ${targetDescription}: `; + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'failed preflight.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.noCorsHeader(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'missing CORS headers on preflight response.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.noPnaHeader(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'missing PNA header on preflight response.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.success(token())}, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'missing CORS headers on final response.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + prefix + 'success.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: {method: 'PUT', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + prefix + 'PUT success.'); + + subsetTestByKey( + subsetKey, promise_test, t => fencedFrameFetchTest(t, { + source, + target: {server: targetServer}, + fetchOptions: {method: 'GET', mode: 'no-cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'no-CORS mode failed preflight.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.noCorsHeader(token())}, + }, + fetchOptions: {method: 'GET', mode: 'no-cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'no-CORS mode missing CORS headers on preflight response.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.noPnaHeader(token())}, + }, + fetchOptions: {method: 'GET', mode: 'no-cors'}, + expected: FetchTestResult.FAILURE, + }), + prefix + 'no-CORS mode missing PNA header on preflight response.'); + + subsetTestByKey( + subsetKey, promise_test, + t => fencedFrameFetchTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.success(token())}, + }, + fetchOptions: {method: 'GET', mode: 'no-cors'}, + expected: FetchTestResult.OPAQUE, + }), + prefix + 'no-CORS mode success.'); +} + +// Source: private secure context. +// +// Fetches to the local address space require a successful preflight response +// carrying a PNA-specific header. + +makePreflightTests({ + subsetKey: 'from-private', + source: {server: Server.HTTPS_PRIVATE}, + sourceDescription: 'private', + targetServer: Server.HTTPS_LOCAL, + targetDescription: 'local', +}); + +subsetTestByKey( + 'from-private', promise_test, t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_PRIVATE}, + target: {server: Server.HTTPS_PRIVATE}, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'private to private: no preflight required.'); + +subsetTestByKey( + 'from-private', promise_test, + t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_PRIVATE}, + target: { + server: Server.HTTPS_PRIVATE, + behavior: {response: ResponseBehavior.allowCrossOrigin()}, + }, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'private to public: no preflight required.'); + +// Source: public secure context. +// +// Fetches to the local and private address spaces require a successful +// preflight response carrying a PNA-specific header. + +makePreflightTests({ + subsetKey: 'from-public', + source: {server: Server.HTTPS_PUBLIC}, + sourceDescription: 'public', + targetServer: Server.HTTPS_LOCAL, + targetDescription: 'local', +}); + +makePreflightTests({ + subsetKey: 'from-public', + source: {server: Server.HTTPS_PUBLIC}, + sourceDescription: 'public', + targetServer: Server.HTTPS_PRIVATE, + targetDescription: 'private', +}); + +subsetTestByKey( + 'from-public', promise_test, t => fencedFrameFetchTest(t, { + source: {server: Server.HTTPS_PUBLIC}, + target: {server: Server.HTTPS_PUBLIC}, + fetchOptions: {method: 'GET', mode: 'cors'}, + expected: FetchTestResult.SUCCESS, + }), + 'public to public: no preflight required.'); diff --git a/test/wpt/tests/fetch/private-network-access/fenced-frame.tentative.https.window.js b/test/wpt/tests/fetch/private-network-access/fenced-frame.tentative.https.window.js new file mode 100644 index 00000000000..370cc9fbe9d --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/fenced-frame.tentative.https.window.js @@ -0,0 +1,150 @@ +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=resources/support.sub.js +// META: script=/fenced-frame/resources/utils.js +// META: timeout=long +// +// Spec: https://wicg.github.io/private-network-access/#integration-fetch +// +// These tests verify that contexts can navigate fenced frames to less-public +// address spaces iff the target server responds affirmatively to preflight +// requests. + +setup(() => { + assert_true(window.isSecureContext); +}); + +// Generates tests of preflight behavior for a single (source, target) pair. +// +// Scenarios: +// +// - parent navigates child: +// - preflight response has non-2xx HTTP code +// - preflight response is missing CORS headers +// - preflight response is missing the PNA-specific `Access-Control` header +// - preflight response has the required PNA related headers, but still fails +// because of the limitation of fenced frame that subjects to PNA checks. +// +function makePreflightTests({ + sourceName, + sourceServer, + sourceTreatAsPublic, + targetName, + targetServer, +}) { + const prefix = `${sourceName} to ${targetName}: `; + + const source = { + server: sourceServer, + treatAsPublic: sourceTreatAsPublic, + }; + + promise_test_parallel( + t => fencedFrameTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.failure()}, + }, + expected: FrameTestResult.FAILURE, + }), + prefix + 'failed preflight.'); + + promise_test_parallel( + t => fencedFrameTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.noCorsHeader(token())}, + }, + expected: FrameTestResult.FAILURE, + }), + prefix + 'missing CORS headers.'); + + promise_test_parallel( + t => fencedFrameTest(t, { + source, + target: { + server: targetServer, + behavior: {preflight: PreflightBehavior.noPnaHeader(token())}, + }, + expected: FrameTestResult.FAILURE, + }), + prefix + 'missing PNA header.'); + + promise_test_parallel( + t => fencedFrameTest(t, { + source, + target: { + server: targetServer, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: FrameTestResult.FAILURE, + }), + prefix + 'failed because fenced frames are incompatible with PNA.'); +} + +// Source: private secure context. +// +// Fetches to the local address space require a successful preflight response +// carrying a PNA-specific header. + +makePreflightTests({ + sourceServer: Server.HTTPS_PRIVATE, + sourceName: 'private', + targetServer: Server.HTTPS_LOCAL, + targetName: 'local', +}); + +// Source: public secure context. +// +// Fetches to the local and private address spaces require a successful +// preflight response carrying a PNA-specific header. + +makePreflightTests({ + sourceServer: Server.HTTPS_PUBLIC, + sourceName: 'public', + targetServer: Server.HTTPS_LOCAL, + targetName: 'local', +}); + +makePreflightTests({ + sourceServer: Server.HTTPS_PUBLIC, + sourceName: 'public', + targetServer: Server.HTTPS_PRIVATE, + targetName: 'private', +}); + +// The following tests verify that `CSP: treat-as-public-address` makes +// documents behave as if they had been served from a public IP address. + +makePreflightTests({ + sourceServer: Server.HTTPS_LOCAL, + sourceTreatAsPublic: true, + sourceName: 'treat-as-public-address', + targetServer: Server.OTHER_HTTPS_LOCAL, + targetName: 'local', +}); + +promise_test_parallel( + t => fencedFrameTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: {server: Server.HTTPS_LOCAL}, + expected: FrameTestResult.FAILURE, + }), + 'treat-as-public-address to local (same-origin): fenced frame embedder ' + + 'initiated navigation has opaque origin.'); + +makePreflightTests({ + sourceServer: Server.HTTPS_LOCAL, + sourceTreatAsPublic: true, + sourceName: 'treat-as-public-address', + targetServer: Server.HTTPS_PRIVATE, + targetName: 'private', +}); diff --git a/test/wpt/tests/fetch/local-network-access/fetch-from-treat-as-public.https.window.js b/test/wpt/tests/fetch/private-network-access/fetch-from-treat-as-public.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/fetch-from-treat-as-public.https.window.js rename to test/wpt/tests/fetch/private-network-access/fetch-from-treat-as-public.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/fetch.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/fetch.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/fetch.window.js b/test/wpt/tests/fetch/private-network-access/fetch.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/fetch.window.js rename to test/wpt/tests/fetch/private-network-access/fetch.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/iframe.tentative.https.window.js b/test/wpt/tests/fetch/private-network-access/iframe.tentative.https.window.js similarity index 63% rename from test/wpt/tests/fetch/local-network-access/iframe.tentative.https.window.js rename to test/wpt/tests/fetch/private-network-access/iframe.tentative.https.window.js index 6a83b88d3ff..0c12970557d 100644 --- a/test/wpt/tests/fetch/local-network-access/iframe.tentative.https.window.js +++ b/test/wpt/tests/fetch/private-network-access/iframe.tentative.https.window.js @@ -1,6 +1,13 @@ +// META: script=/common/subset-tests-by-key.js // META: script=/common/dispatcher/dispatcher.js // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: timeout=long +// META: variant=?include=from-local +// META: variant=?include=from-private +// META: variant=?include=from-public +// META: variant=?include=from-treat-as-public +// META: variant=?include=grandparent // // Spec: https://wicg.github.io/private-network-access/#integration-fetch // @@ -18,22 +25,22 @@ setup(() => { // // All fetches unaffected by Private Network Access. -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-local", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_LOCAL }, target: { server: Server.HTTPS_LOCAL }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to local: no preflight required."); -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-local", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_LOCAL }, target: { server: Server.HTTPS_PRIVATE }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to private: no preflight required."); -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-local", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_LOCAL }, target: { server: Server.HTTPS_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to public: no preflight required."); // Generates tests of preflight behavior for a single (source, target) pair. @@ -47,6 +54,7 @@ promise_test_parallel(t => iframeTest(t, { // - success // function makePreflightTests({ + key, sourceName, sourceServer, sourceTreatAsPublic, @@ -67,7 +75,7 @@ function makePreflightTests({ server: targetServer, behavior: { preflight: PreflightBehavior.failure() }, }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), prefix + "failed preflight."); promise_test_parallel(t => iframeTest(t, { @@ -76,7 +84,7 @@ function makePreflightTests({ server: targetServer, behavior: { preflight: PreflightBehavior.noCorsHeader(token()) }, }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), prefix + "missing CORS headers."); promise_test_parallel(t => iframeTest(t, { @@ -85,7 +93,7 @@ function makePreflightTests({ server: targetServer, behavior: { preflight: PreflightBehavior.noPnaHeader(token()) }, }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), prefix + "missing PNA header."); promise_test_parallel(t => iframeTest(t, { @@ -94,7 +102,7 @@ function makePreflightTests({ server: targetServer, behavior: { preflight: PreflightBehavior.success(token()) }, }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), prefix + "success."); } @@ -103,23 +111,23 @@ function makePreflightTests({ // Fetches to the local address space require a successful preflight response // carrying a PNA-specific header. -makePreflightTests({ +subsetTestByKey('from-private', makePreflightTests, { sourceServer: Server.HTTPS_PRIVATE, - sourceName: "private", + sourceName: 'private', targetServer: Server.HTTPS_LOCAL, - targetName: "local", + targetName: 'local', }); -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-private", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_PRIVATE }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "private to private: no preflight required."); -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-private", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "private to public: no preflight required."); // Source: public secure context. @@ -127,30 +135,30 @@ promise_test_parallel(t => iframeTest(t, { // Fetches to the local and private address spaces require a successful // preflight response carrying a PNA-specific header. -makePreflightTests({ +subsetTestByKey('from-public', makePreflightTests, { sourceServer: Server.HTTPS_PUBLIC, sourceName: "public", targetServer: Server.HTTPS_LOCAL, targetName: "local", }); -makePreflightTests({ +subsetTestByKey('from-public', makePreflightTests, { sourceServer: Server.HTTPS_PUBLIC, sourceName: "public", targetServer: Server.HTTPS_PRIVATE, targetName: "private", }); -promise_test_parallel(t => iframeTest(t, { +subsetTestByKey("from-public", promise_test_parallel, t => iframeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "public to public: no preflight required."); // The following tests verify that `CSP: treat-as-public-address` makes // documents behave as if they had been served from a public IP address. -makePreflightTests({ +subsetTestByKey('from-treat-as-public', makePreflightTests, { sourceServer: Server.HTTPS_LOCAL, sourceTreatAsPublic: true, sourceName: "treat-as-public-address", @@ -158,16 +166,20 @@ makePreflightTests({ targetName: "local", }); -promise_test_parallel(t => iframeTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { server: Server.HTTPS_LOCAL }, - expected: IframeTestResult.SUCCESS, -}), "treat-as-public-address to local (same-origin): no preflight required."); +subsetTestByKey( + 'from-treat-as-public', promise_test_parallel, + t => iframeTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: {server: Server.HTTPS_LOCAL}, + expected: FrameTestResult.SUCCESS, + }), + 'treat-as-public-address to local (same-origin): no preflight required.' +); -makePreflightTests({ +subsetTestByKey('from-treat-as-public', makePreflightTests, { sourceServer: Server.HTTPS_LOCAL, sourceTreatAsPublic: true, sourceName: "treat-as-public-address", @@ -175,49 +187,57 @@ makePreflightTests({ targetName: "private", }); -promise_test_parallel(t => iframeTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { server: Server.HTTPS_PUBLIC }, - expected: IframeTestResult.SUCCESS, -}), "treat-as-public-address to public: no preflight required."); +subsetTestByKey( + 'from-treat-as-public', promise_test_parallel, + t => iframeTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: {server: Server.HTTPS_PUBLIC}, + expected: FrameTestResult.SUCCESS, + }), + 'treat-as-public-address to public: no preflight required.' +); -promise_test_parallel(t => iframeTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTPS_PUBLIC, - behavior: { preflight: PreflightBehavior.optionalSuccess(token()) } - }, - expected: IframeTestResult.SUCCESS, -}), "treat-as-public-address to local: optional preflight"); +subsetTestByKey( + 'from-treat-as-public', promise_test_parallel, + t => iframeTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTPS_PUBLIC, + behavior: {preflight: PreflightBehavior.optionalSuccess(token())} + }, + expected: FrameTestResult.SUCCESS, + }), + 'treat-as-public-address to local: optional preflight' +); // The following tests verify that when a grandparent frame navigates its // grandchild, the IP address space of the grandparent is compared against the // IP address space of the response. Indeed, the navigation initiator in this // case is the grandparent, not the parent. -iframeGrandparentTest({ - name: "local to local, grandparent navigates: no preflight required.", +subsetTestByKey('grandparent', iframeGrandparentTest, { + name: 'local to local, grandparent navigates: no preflight required.', grandparentServer: Server.HTTPS_LOCAL, - child: { server: Server.HTTPS_PUBLIC }, - grandchild: { server: Server.OTHER_HTTPS_LOCAL }, - expected: IframeTestResult.SUCCESS, + child: {server: Server.HTTPS_PUBLIC}, + grandchild: {server: Server.OTHER_HTTPS_LOCAL}, + expected: FrameTestResult.SUCCESS, }); -iframeGrandparentTest({ +subsetTestByKey('grandparent', iframeGrandparentTest, { name: "local to local (same-origin), grandparent navigates: no preflight required.", grandparentServer: Server.HTTPS_LOCAL, child: { server: Server.HTTPS_PUBLIC }, grandchild: { server: Server.HTTPS_LOCAL }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }); -iframeGrandparentTest({ +subsetTestByKey('grandparent', iframeGrandparentTest, { name: "public to local, grandparent navigates: failure.", grandparentServer: Server.HTTPS_PUBLIC, child: { @@ -228,10 +248,10 @@ iframeGrandparentTest({ server: Server.HTTPS_LOCAL, behavior: { preflight: PreflightBehavior.failure() }, }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }); -iframeGrandparentTest({ +subsetTestByKey('grandparent', iframeGrandparentTest, { name: "public to local, grandparent navigates: success.", grandparentServer: Server.HTTPS_PUBLIC, child: { @@ -242,5 +262,5 @@ iframeGrandparentTest({ server: Server.HTTPS_LOCAL, behavior: { preflight: PreflightBehavior.success(token()) }, }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }); diff --git a/test/wpt/tests/fetch/local-network-access/iframe.tentative.window.js b/test/wpt/tests/fetch/private-network-access/iframe.tentative.window.js similarity index 86% rename from test/wpt/tests/fetch/local-network-access/iframe.tentative.window.js rename to test/wpt/tests/fetch/private-network-access/iframe.tentative.window.js index e00cb202bec..c0770df8385 100644 --- a/test/wpt/tests/fetch/local-network-access/iframe.tentative.window.js +++ b/test/wpt/tests/fetch/private-network-access/iframe.tentative.window.js @@ -18,55 +18,55 @@ setup(() => { promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_LOCAL }, target: { server: Server.HTTP_LOCAL }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to local: no preflight required."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_LOCAL }, target: { server: Server.HTTP_PRIVATE }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to private: no preflight required."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_LOCAL }, target: { server: Server.HTTP_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "local to public: no preflight required."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PRIVATE }, target: { server: Server.HTTP_LOCAL }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), "private to local: failure."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PRIVATE }, target: { server: Server.HTTP_PRIVATE }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "private to private: no preflight required."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PRIVATE }, target: { server: Server.HTTP_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "private to public: no preflight required."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PUBLIC }, target: { server: Server.HTTP_LOCAL }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), "public to local: failure."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PUBLIC }, target: { server: Server.HTTP_PRIVATE }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), "public to private: failure."); promise_test_parallel(t => iframeTest(t, { source: { server: Server.HTTP_PUBLIC }, target: { server: Server.HTTP_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "public to public: no preflight required."); promise_test_parallel(t => iframeTest(t, { @@ -75,7 +75,7 @@ promise_test_parallel(t => iframeTest(t, { treatAsPublic: true, }, target: { server: Server.HTTP_LOCAL }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), "treat-as-public-address to local: failure."); promise_test_parallel(t => iframeTest(t, { @@ -84,7 +84,7 @@ promise_test_parallel(t => iframeTest(t, { treatAsPublic: true, }, target: { server: Server.HTTP_PRIVATE }, - expected: IframeTestResult.FAILURE, + expected: FrameTestResult.FAILURE, }), "treat-as-public-address to private: failure."); promise_test_parallel(t => iframeTest(t, { @@ -93,7 +93,7 @@ promise_test_parallel(t => iframeTest(t, { treatAsPublic: true, }, target: { server: Server.HTTP_PUBLIC }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }), "treat-as-public-address to public: no preflight required."); // The following test verifies that when a grandparent frame navigates its @@ -106,5 +106,5 @@ iframeGrandparentTest({ grandparentServer: Server.HTTP_LOCAL, child: { server: Server.HTTP_PUBLIC }, grandchild: { server: Server.HTTP_LOCAL }, - expected: IframeTestResult.SUCCESS, + expected: FrameTestResult.SUCCESS, }); diff --git a/test/wpt/tests/fetch/local-network-access/mixed-content-fetch.tentative.https.window.js b/test/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js similarity index 77% rename from test/wpt/tests/fetch/local-network-access/mixed-content-fetch.tentative.https.window.js rename to test/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js index 6f7d765617c..54485dc7047 100644 --- a/test/wpt/tests/fetch/local-network-access/mixed-content-fetch.tentative.https.window.js +++ b/test/wpt/tests/fetch/private-network-access/mixed-content-fetch.tentative.https.window.js @@ -1,10 +1,10 @@ // META: script=/common/utils.js // META: script=resources/support.sub.js // -// Spec: https://wicg.github.io/local-network-access +// Spec: https://wicg.github.io/private-network-access // // These tests verify that secure contexts can fetch non-secure subresources -// from more local address spaces, avoiding mixed context checks, as long as +// from more private address spaces, avoiding mixed context checks, as long as // they specify a valid `targetAddressSpace` fetch option that matches the // target server's address space. @@ -16,9 +16,9 @@ setup(() => { // Given `addressSpace`, returns the other three possible IP address spaces. function otherAddressSpaces(addressSpace) { switch (addressSpace) { - case "loopback": return ["unknown", "local", "public"]; - case "local": return ["unknown", "loopback", "public"]; - case "public": return ["unknown", "loopback", "local"]; + case "local": return ["unknown", "private", "public"]; + case "private": return ["unknown", "local", "public"]; + case "public": return ["unknown", "local", "private"]; } } @@ -169,66 +169,64 @@ function makeNoBypassTests({ source, target }) { }, fetchOptions: { targetAddressSpace: correctAddressSpace }, expected: FetchTestResult.FAILURE, - }), prefix + 'not a local network request.'); + }), prefix + 'not a private network request.'); } -// Source: loopback secure context. +// Source: local secure context. // -// Fetches to the loopback and local address spaces cannot use +// Fetches to the local and private address spaces cannot use // `targetAddressSpace` to bypass mixed content, as they are not otherwise -// blocked by Local Network Access. +// blocked by Private Network Access. -makeNoBypassTests({ source: "loopback", target: "loopback" }); -makeNoBypassTests({ source: "loopback", target: "local" }); -makeNoBypassTests({ source: "loopback", target: "public" }); +makeNoBypassTests({ source: "local", target: "local" }); +makeNoBypassTests({ source: "local", target: "private" }); +makeNoBypassTests({ source: "local", target: "public" }); -// Source: local secure context. +// Source: private secure context. // -// Fetches to the loopback address space requires the right `targetAddressSpace` +// Fetches to the local address space requires the right `targetAddressSpace` // option, as well as a successful preflight response carrying a PNA-specific // header. // -// Fetches to the local address space cannot use `targetAddressSpace` to -// bypass mixed content, as they are not otherwise blocked by Local Network +// Fetches to the private address space cannot use `targetAddressSpace` to +// bypass mixed content, as they are not otherwise blocked by Private Network // Access. -makeTests({ source: "local", target: "loopback" }); +makeTests({ source: "private", target: "local" }); -makeNoBypassTests({ source: "local", target: "local" }); -makeNoBypassTests({ source: "local", target: "public" }); +makeNoBypassTests({ source: "private", target: "private" }); +makeNoBypassTests({ source: "private", target: "public" }); // Source: public secure context. // -// Fetches to the loopback and local address spaces require the right +// Fetches to the local and private address spaces require the right // `targetAddressSpace` option, as well as a successful preflight response // carrying a PNA-specific header. -makeTests({ source: "public", target: "loopback" }); makeTests({ source: "public", target: "local" }); +makeTests({ source: "public", target: "private" }); makeNoBypassTests({ source: "public", target: "public" }); -// These tests verify that documents fetched from the `loopback` address space -// yet carrying the `treat-as-public-address` CSP directive are treated as if -// they had been fetched from the `public` address space. +// These tests verify that documents fetched from the `local` address space yet +// carrying the `treat-as-public-address` CSP directive are treated as if they +// had been fetched from the `public` address space. -promise_test_parallel( - t => fetchTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTP_LOCAL, - behavior: { - preflight: PreflightBehavior.optionalSuccess(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {targetAddressSpace: 'local'}, - expected: FetchTestResult.FAILURE, - }), - 'https-treat-as-public to http-loopback: wrong targetAddressSpace "local".'); +promise_test_parallel(t => fetchTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTP_LOCAL, + behavior: { + preflight: PreflightBehavior.optionalSuccess(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + fetchOptions: { targetAddressSpace: "private" }, + expected: FetchTestResult.FAILURE, +}), 'https-treat-as-public to http-local: wrong targetAddressSpace "private".'); promise_test_parallel(t => fetchTest(t, { source: { @@ -242,9 +240,9 @@ promise_test_parallel(t => fetchTest(t, { response: ResponseBehavior.allowCrossOrigin(), }, }, - fetchOptions: { targetAddressSpace: "loopback" }, + fetchOptions: { targetAddressSpace: "local" }, expected: FetchTestResult.SUCCESS, -}), "https-treat-as-public to http-loopback: success."); +}), "https-treat-as-public to http-local: success."); promise_test_parallel(t => fetchTest(t, { source: { @@ -258,9 +256,9 @@ promise_test_parallel(t => fetchTest(t, { response: ResponseBehavior.allowCrossOrigin(), }, }, - fetchOptions: { targetAddressSpace: "loopback" }, + fetchOptions: { targetAddressSpace: "local" }, expected: FetchTestResult.FAILURE, -}), 'https-treat-as-public to http-local: wrong targetAddressSpace "loopback".'); +}), 'https-treat-as-public to http-private: wrong targetAddressSpace "local".'); promise_test_parallel(t => fetchTest(t, { source: { @@ -274,6 +272,6 @@ promise_test_parallel(t => fetchTest(t, { response: ResponseBehavior.allowCrossOrigin(), }, }, - fetchOptions: { targetAddressSpace: "local" }, + fetchOptions: { targetAddressSpace: "private" }, expected: FetchTestResult.SUCCESS, -}), "https-treat-as-public to http-local: success."); +}), "https-treat-as-public to http-private: success."); diff --git a/test/wpt/tests/fetch/local-network-access/nested-worker.https.window.js b/test/wpt/tests/fetch/private-network-access/nested-worker.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/nested-worker.https.window.js rename to test/wpt/tests/fetch/private-network-access/nested-worker.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/nested-worker.window.js b/test/wpt/tests/fetch/private-network-access/nested-worker.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/nested-worker.window.js rename to test/wpt/tests/fetch/private-network-access/nested-worker.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/preflight-cache.https.window.js b/test/wpt/tests/fetch/private-network-access/preflight-cache.https.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/preflight-cache.https.window.js rename to test/wpt/tests/fetch/private-network-access/preflight-cache.https.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/redirect.https.window.js b/test/wpt/tests/fetch/private-network-access/redirect.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/redirect.https.window.js rename to test/wpt/tests/fetch/private-network-access/redirect.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/resources/executor.html b/test/wpt/tests/fetch/private-network-access/resources/executor.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/executor.html rename to test/wpt/tests/fetch/private-network-access/resources/executor.html diff --git a/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html new file mode 100644 index 00000000000..b14601dba51 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html @@ -0,0 +1,25 @@ + + + +Fetcher + \ No newline at end of file diff --git a/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html.headers b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html.headers new file mode 100644 index 00000000000..6247f6d6321 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-fetcher.https.html.headers @@ -0,0 +1 @@ +Supports-Loading-Mode: fenced-frame \ No newline at end of file diff --git a/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access-target.https.html b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access-target.https.html new file mode 100644 index 00000000000..2b55e056f39 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access-target.https.html @@ -0,0 +1,8 @@ + + + +Fenced frame target + diff --git a/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html new file mode 100644 index 00000000000..98f118432e0 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html @@ -0,0 +1,14 @@ + + + + + +Fenced frame + + diff --git a/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html.headers b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html.headers new file mode 100644 index 00000000000..6247f6d6321 --- /dev/null +++ b/test/wpt/tests/fetch/private-network-access/resources/fenced-frame-local-network-access.https.html.headers @@ -0,0 +1 @@ +Supports-Loading-Mode: fenced-frame \ No newline at end of file diff --git a/test/wpt/tests/fetch/local-network-access/resources/fetcher.html b/test/wpt/tests/fetch/private-network-access/resources/fetcher.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/fetcher.html rename to test/wpt/tests/fetch/private-network-access/resources/fetcher.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/fetcher.js b/test/wpt/tests/fetch/private-network-access/resources/fetcher.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/fetcher.js rename to test/wpt/tests/fetch/private-network-access/resources/fetcher.js diff --git a/test/wpt/tests/fetch/local-network-access/resources/iframed.html b/test/wpt/tests/fetch/private-network-access/resources/iframed.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/iframed.html rename to test/wpt/tests/fetch/private-network-access/resources/iframed.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/iframer.html b/test/wpt/tests/fetch/private-network-access/resources/iframer.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/iframer.html rename to test/wpt/tests/fetch/private-network-access/resources/iframer.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/preflight.py b/test/wpt/tests/fetch/private-network-access/resources/preflight.py similarity index 97% rename from test/wpt/tests/fetch/local-network-access/resources/preflight.py rename to test/wpt/tests/fetch/private-network-access/resources/preflight.py index 4b0bfefd4d6..be3abdbb2a1 100644 --- a/test/wpt/tests/fetch/local-network-access/resources/preflight.py +++ b/test/wpt/tests/fetch/private-network-access/resources/preflight.py @@ -85,6 +85,9 @@ def _is_preflight_optional(request): def _get_preflight_uuid(request): return request.GET.get(b"preflight-uuid") +def _is_loaded_in_fenced_frame(request): + return request.GET.get(b"is-loaded-in-fenced-frame") + def _should_treat_as_public_once(request): uuid = request.GET.get(b"treat-as-public-once") if uuid is None: @@ -155,6 +158,9 @@ def _handle_final_request(request, response): if mime_type is not None: headers.append(("Content-Type", mime_type),) + if _is_loaded_in_fenced_frame(request): + headers.append(("Supports-Loading-Mode", "fenced-frame")) + body = _final_response_body(request) return (headers, body) diff --git a/test/wpt/tests/fetch/local-network-access/resources/service-worker-bridge.html b/test/wpt/tests/fetch/private-network-access/resources/service-worker-bridge.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/service-worker-bridge.html rename to test/wpt/tests/fetch/private-network-access/resources/service-worker-bridge.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/service-worker.js b/test/wpt/tests/fetch/private-network-access/resources/service-worker.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/service-worker.js rename to test/wpt/tests/fetch/private-network-access/resources/service-worker.js diff --git a/test/wpt/tests/fetch/local-network-access/resources/shared-fetcher.js b/test/wpt/tests/fetch/private-network-access/resources/shared-fetcher.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/shared-fetcher.js rename to test/wpt/tests/fetch/private-network-access/resources/shared-fetcher.js diff --git a/test/wpt/tests/fetch/local-network-access/resources/shared-worker-blob-fetcher.html b/test/wpt/tests/fetch/private-network-access/resources/shared-worker-blob-fetcher.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/shared-worker-blob-fetcher.html rename to test/wpt/tests/fetch/private-network-access/resources/shared-worker-blob-fetcher.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/shared-worker-fetcher.html b/test/wpt/tests/fetch/private-network-access/resources/shared-worker-fetcher.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/shared-worker-fetcher.html rename to test/wpt/tests/fetch/private-network-access/resources/shared-worker-fetcher.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/socket-opener.html b/test/wpt/tests/fetch/private-network-access/resources/socket-opener.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/socket-opener.html rename to test/wpt/tests/fetch/private-network-access/resources/socket-opener.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/support.sub.js b/test/wpt/tests/fetch/private-network-access/resources/support.sub.js similarity index 86% rename from test/wpt/tests/fetch/local-network-access/resources/support.sub.js rename to test/wpt/tests/fetch/private-network-access/resources/support.sub.js index a09c46031f5..27d733d8b7f 100644 --- a/test/wpt/tests/fetch/local-network-access/resources/support.sub.js +++ b/test/wpt/tests/fetch/private-network-access/resources/support.sub.js @@ -75,21 +75,21 @@ async function postMessageAndAwaitReply(target, message) { // Maps protocol (without the trailing colon) and address space to port. const SERVER_PORTS = { "http": { - "loopback": {{ports[http][0]}}, - "local": {{ports[http-private][0]}}, + "local": {{ports[http][0]}}, + "private": {{ports[http-private][0]}}, "public": {{ports[http-public][0]}}, }, "https": { - "loopback": {{ports[https][0]}}, - "other-loopback": {{ports[https][1]}}, - "local": {{ports[https-private][0]}}, + "local": {{ports[https][0]}}, + "other-local": {{ports[https][1]}}, + "private": {{ports[https-private][0]}}, "public": {{ports[https-public][0]}}, }, "ws": { - "loopback": {{ports[ws][0]}}, + "local": {{ports[ws][0]}}, }, "wss": { - "loopback": {{ports[wss][0]}}, + "local": {{ports[wss][0]}}, }, }; @@ -127,15 +127,15 @@ class Server { }; } - static HTTP_LOCAL = Server.get("http", "loopback"); - static HTTP_PRIVATE = Server.get("http", "local"); + static HTTP_LOCAL = Server.get("http", "local"); + static HTTP_PRIVATE = Server.get("http", "private"); static HTTP_PUBLIC = Server.get("http", "public"); - static HTTPS_LOCAL = Server.get("https", "loopback"); - static OTHER_HTTPS_LOCAL = Server.get("https", "other-loopback"); - static HTTPS_PRIVATE = Server.get("https", "local"); + static HTTPS_LOCAL = Server.get("https", "local"); + static OTHER_HTTPS_LOCAL = Server.get("https", "other-local"); + static HTTPS_PRIVATE = Server.get("https", "private"); static HTTPS_PUBLIC = Server.get("https", "public"); - static WS_LOCAL = Server.get("ws", "loopback"); - static WSS_LOCAL = Server.get("wss", "loopback"); + static WS_LOCAL = Server.get("ws", "local"); + static WSS_LOCAL = Server.get("wss", "local"); }; // Resolves a URL relative to the current location, returning an absolute URL. @@ -341,6 +341,40 @@ async function fetchTest(t, { source, target, fetchOptions, expected }) { } } +// Similar to `fetchTest`, but replaced iframes with fenced frames. +async function fencedFrameFetchTest(t, { source, target, fetchOptions, expected }) { + const fetcher_url = + resolveUrl("resources/fenced-frame-fetcher.https.html", sourceResolveOptions(source)); + + const target_url = preflightUrl(target); + target_url.searchParams.set("is-loaded-in-fenced-frame", true); + + fetcher_url.searchParams.set("mode", fetchOptions.mode); + fetcher_url.searchParams.set("method", fetchOptions.method); + fetcher_url.searchParams.set("url", target_url); + + const error_token = token(); + const ok_token = token(); + const body_token = token(); + const type_token = token(); + const source_url = generateURL(fetcher_url, [error_token, ok_token, body_token, type_token]); + + const urn = await generateURNFromFledge(source_url, []); + attachFencedFrame(urn); + + const error = await nextValueFromServer(error_token); + const ok = await nextValueFromServer(ok_token); + const body = await nextValueFromServer(body_token); + const type = await nextValueFromServer(type_token); + + assert_equals(error, expected.error || "" , "error"); + assert_equals(body, expected.body || "", "response body"); + assert_equals(ok, expected.ok !== undefined ? expected.ok.toString() : "", "response ok"); + if (expected.type !== undefined) { + assert_equals(type, expected.type, "response type"); + } +} + const XhrTestResult = { SUCCESS: { loaded: true, @@ -393,7 +427,7 @@ async function xhrTest(t, { source, target, method, expected }) { assert_equals(body, expected.body, "response body"); } -const IframeTestResult = { +const FrameTestResult = { SUCCESS: "loaded", FAILURE: "timeout", }; @@ -429,6 +463,37 @@ async function iframeTest(t, { source, target, expected }) { assert_equals(result, expected); } +// Similar to `iframeTest`, but replaced iframes with fenced frames. +async function fencedFrameTest(t, { source, target, expected }) { + // Allows running tests in parallel. + const target_url = preflightUrl(target); + target_url.searchParams.set("file", "fenced-frame-local-network-access-target.https.html"); + target_url.searchParams.set("is-loaded-in-fenced-frame", true); + + const frame_loaded_key = token(); + const child_frame_target = generateURL(target_url, [frame_loaded_key]); + + const source_url = + resolveUrl("resources/fenced-frame-local-network-access.https.html", sourceResolveOptions(source)); + source_url.searchParams.set("fenced_frame_url", child_frame_target); + + const urn = await generateURNFromFledge(source_url, []); + attachFencedFrame(urn); + + // The grandchild fenced frame writes a value to the server iff it loads + // successfully. + const result = (expected == FrameTestResult.SUCCESS) ? + await nextValueFromServer(frame_loaded_key) : + await Promise.race([ + nextValueFromServer(frame_loaded_key), + new Promise((resolve) => { + t.step_timeout(() => resolve("timeout"), 10000 /* ms */); + }), + ]); + + assert_equals(result, expected); +} + const iframeGrandparentTest = ({ name, grandparentServer, diff --git a/test/wpt/tests/fetch/local-network-access/resources/worker-blob-fetcher.html b/test/wpt/tests/fetch/private-network-access/resources/worker-blob-fetcher.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/worker-blob-fetcher.html rename to test/wpt/tests/fetch/private-network-access/resources/worker-blob-fetcher.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/worker-fetcher.html b/test/wpt/tests/fetch/private-network-access/resources/worker-fetcher.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/worker-fetcher.html rename to test/wpt/tests/fetch/private-network-access/resources/worker-fetcher.html diff --git a/test/wpt/tests/fetch/local-network-access/resources/worker-fetcher.js b/test/wpt/tests/fetch/private-network-access/resources/worker-fetcher.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/worker-fetcher.js rename to test/wpt/tests/fetch/private-network-access/resources/worker-fetcher.js diff --git a/test/wpt/tests/fetch/local-network-access/resources/xhr-sender.html b/test/wpt/tests/fetch/private-network-access/resources/xhr-sender.html similarity index 100% rename from test/wpt/tests/fetch/local-network-access/resources/xhr-sender.html rename to test/wpt/tests/fetch/private-network-access/resources/xhr-sender.html diff --git a/test/wpt/tests/fetch/local-network-access/service-worker-background-fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/service-worker-background-fetch.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/service-worker-background-fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/service-worker-background-fetch.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/service-worker-fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js similarity index 88% rename from test/wpt/tests/fetch/local-network-access/service-worker-fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js index 3d0f6d8097a..cb6d1f79b01 100644 --- a/test/wpt/tests/fetch/local-network-access/service-worker-fetch.https.window.js +++ b/test/wpt/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js @@ -1,5 +1,8 @@ // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: script=/common/subset-tests.js +// META: variant=?1-8 +// META: variant=?9-last // // Spec: https://wicg.github.io/private-network-access/#integration-fetch // @@ -75,13 +78,13 @@ async function makeTest(t, { source, target, expected }) { } } -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL }, target: { server: Server.HTTPS_LOCAL }, expected: TestResult.SUCCESS, }), "local to local: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_LOCAL, @@ -90,7 +93,7 @@ promise_test(t => makeTest(t, { expected: TestResult.FAILURE, }), "private to local: failed preflight."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_LOCAL, @@ -102,13 +105,13 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "private to local: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_PRIVATE }, expected: TestResult.SUCCESS, }), "private to private: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_LOCAL, @@ -117,7 +120,7 @@ promise_test(t => makeTest(t, { expected: TestResult.FAILURE, }), "public to local: failed preflight."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_LOCAL, @@ -129,7 +132,7 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "public to local: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PRIVATE, @@ -138,7 +141,7 @@ promise_test(t => makeTest(t, { expected: TestResult.FAILURE, }), "public to private: failed preflight."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PRIVATE, @@ -150,13 +153,13 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "public to private: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PUBLIC }, expected: TestResult.SUCCESS, }), "public to public: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -168,7 +171,7 @@ promise_test(t => makeTest(t, { expected: TestResult.FAILURE, }), "treat-as-public to local: failed preflight."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -183,7 +186,7 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to local: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -192,7 +195,7 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to local (same-origin): no preflight required."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -204,7 +207,7 @@ promise_test(t => makeTest(t, { expected: TestResult.FAILURE, }), "treat-as-public to private: failed preflight."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -219,7 +222,7 @@ promise_test(t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to private: success."); -promise_test(t => makeTest(t, { +subsetTest(promise_test, t => makeTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, diff --git a/test/wpt/tests/fetch/local-network-access/service-worker-update.https.window.js b/test/wpt/tests/fetch/private-network-access/service-worker-update.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/service-worker-update.https.window.js rename to test/wpt/tests/fetch/private-network-access/service-worker-update.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/service-worker.https.window.js b/test/wpt/tests/fetch/private-network-access/service-worker.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/service-worker.https.window.js rename to test/wpt/tests/fetch/private-network-access/service-worker.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker-blob-fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker-blob-fetch.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker-blob-fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker-blob-fetch.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker-blob-fetch.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker-blob-fetch.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker-blob-fetch.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker-blob-fetch.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker-fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker-fetch.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker-fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker-fetch.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker-fetch.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker-fetch.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker-fetch.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker-fetch.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker.https.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker.https.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/shared-worker.window.js b/test/wpt/tests/fetch/private-network-access/shared-worker.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/shared-worker.window.js rename to test/wpt/tests/fetch/private-network-access/shared-worker.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/websocket.https.window.js b/test/wpt/tests/fetch/private-network-access/websocket.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/websocket.https.window.js rename to test/wpt/tests/fetch/private-network-access/websocket.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/websocket.window.js b/test/wpt/tests/fetch/private-network-access/websocket.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/websocket.window.js rename to test/wpt/tests/fetch/private-network-access/websocket.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/worker-blob-fetch.window.js b/test/wpt/tests/fetch/private-network-access/worker-blob-fetch.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/worker-blob-fetch.window.js rename to test/wpt/tests/fetch/private-network-access/worker-blob-fetch.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/worker-fetch.https.window.js b/test/wpt/tests/fetch/private-network-access/worker-fetch.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/worker-fetch.https.window.js rename to test/wpt/tests/fetch/private-network-access/worker-fetch.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/worker-fetch.window.js b/test/wpt/tests/fetch/private-network-access/worker-fetch.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/worker-fetch.window.js rename to test/wpt/tests/fetch/private-network-access/worker-fetch.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/worker.https.window.js b/test/wpt/tests/fetch/private-network-access/worker.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/worker.https.window.js rename to test/wpt/tests/fetch/private-network-access/worker.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/worker.window.js b/test/wpt/tests/fetch/private-network-access/worker.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/worker.window.js rename to test/wpt/tests/fetch/private-network-access/worker.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/xhr-from-treat-as-public.https.window.js b/test/wpt/tests/fetch/private-network-access/xhr-from-treat-as-public.tentative.https.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/xhr-from-treat-as-public.https.window.js rename to test/wpt/tests/fetch/private-network-access/xhr-from-treat-as-public.tentative.https.window.js diff --git a/test/wpt/tests/fetch/local-network-access/xhr.https.window.js b/test/wpt/tests/fetch/private-network-access/xhr.https.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/xhr.https.window.js rename to test/wpt/tests/fetch/private-network-access/xhr.https.tentative.window.js diff --git a/test/wpt/tests/fetch/local-network-access/xhr.window.js b/test/wpt/tests/fetch/private-network-access/xhr.tentative.window.js similarity index 100% rename from test/wpt/tests/fetch/local-network-access/xhr.window.js rename to test/wpt/tests/fetch/private-network-access/xhr.tentative.window.js diff --git a/test/wpt/tests/fetch/range/blob.any.js b/test/wpt/tests/fetch/range/blob.any.js index 1db3b248f6c..7bcd4b9d11f 100644 --- a/test/wpt/tests/fetch/range/blob.any.js +++ b/test/wpt/tests/fetch/range/blob.any.js @@ -10,6 +10,15 @@ const supportedBlobRange = [ content_range: "bytes 9-21/30", result: "Hello, World!", }, + { + name: "A blob range request with no type.", + data: ["A simple Hello, World! example"], + type: undefined, + range: "bytes=9-21", + content_length: 13, + content_range: "bytes 9-21/30", + result: "Hello, World!", + }, { name: "A blob range request with no end.", data: ["Range with no end"], @@ -201,7 +210,7 @@ supportedBlobRange.forEach(({ name, data, type, range, content_length, content_r }); assert_equals(resp.status, 206, "HTTP status is 206"); assert_equals(resp.type, "basic", "response type is basic"); - assert_equals(resp.headers.get("Content-Type"), type, "Content-Type is " + resp.headers.get("Content-Type")); + assert_equals(resp.headers.get("Content-Type"), type || "", "Content-Type is " + resp.headers.get("Content-Type")); assert_equals(resp.headers.get("Content-Length"), content_length.toString(), "Content-Length is " + resp.headers.get("Content-Length")); assert_equals(resp.headers.get("Content-Range"), content_range, "Content-Range is " + resp.headers.get("Content-Range")); const text = await resp.text(); diff --git a/test/wpt/tests/interfaces/attribution-reporting-api.idl b/test/wpt/tests/interfaces/attribution-reporting-api.idl index 76640f54c8d..ed4497b56ff 100644 --- a/test/wpt/tests/interfaces/attribution-reporting-api.idl +++ b/test/wpt/tests/interfaces/attribution-reporting-api.idl @@ -4,9 +4,23 @@ // Source: Attribution Reporting (https://wicg.github.io/attribution-reporting-api/) interface mixin HTMLAttributionSrcElementUtils { - [CEReactions] attribute USVString attributionSrc; + [CEReactions, SecureContext] attribute USVString attributionSrc; }; HTMLAnchorElement includes HTMLAttributionSrcElementUtils; HTMLImageElement includes HTMLAttributionSrcElementUtils; HTMLScriptElement includes HTMLAttributionSrcElementUtils; + +dictionary AttributionReportingRequestOptions { + required boolean eventSourceEligible; + required boolean triggerEligible; +}; + +partial dictionary RequestInit { + AttributionReportingRequestOptions attributionReporting; +}; + +partial interface XMLHttpRequest { + [SecureContext] + undefined setAttributionReporting(AttributionReportingRequestOptions options); +}; diff --git a/test/wpt/tests/interfaces/captured-mouse-events.tentative.idl b/test/wpt/tests/interfaces/captured-mouse-events.tentative.idl new file mode 100644 index 00000000000..7b081cd9fd8 --- /dev/null +++ b/test/wpt/tests/interfaces/captured-mouse-events.tentative.idl @@ -0,0 +1,25 @@ +// https://screen-share.github.io/mouse-events/ + +enum CaptureStartFocusBehavior { + "focus-captured-surface", + "no-focus-change" +}; + +[Exposed=Window, SecureContext] +interface CaptureController : EventTarget { + constructor(); + undefined setFocusBehavior(CaptureStartFocusBehavior focusBehavior); + attribute EventHandler oncapturedmousechange; +}; + +[Exposed=Window] +interface CapturedMouseEvent : Event { + constructor(DOMString type, optional CapturedMouseEventInit eventInitDict = {}); + readonly attribute long surfaceX; + readonly attribute long surfaceY; +}; + +dictionary CapturedMouseEventInit : EventInit { + long surfaceX = -1; + long surfaceY = -1; +}; diff --git a/test/wpt/tests/interfaces/css-anchor-position.idl b/test/wpt/tests/interfaces/css-anchor-position.idl new file mode 100644 index 00000000000..c5da3f43f72 --- /dev/null +++ b/test/wpt/tests/interfaces/css-anchor-position.idl @@ -0,0 +1,11 @@ +// Source: CSS Anchor Positioning (https://drafts.csswg.org/css-anchor-position-1/) + +[Exposed=Window] +interface CSSPositionFallbackRule : CSSGroupingRule { + readonly attribute CSSOMString name; +}; + +[Exposed=Window] +interface CSSTryRule : CSSRule { + [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; +}; diff --git a/test/wpt/tests/interfaces/css-cascade-6.idl b/test/wpt/tests/interfaces/css-cascade-6.idl index 37cdfb82930..3bdf6ba3a6b 100644 --- a/test/wpt/tests/interfaces/css-cascade-6.idl +++ b/test/wpt/tests/interfaces/css-cascade-6.idl @@ -5,6 +5,6 @@ [Exposed=Window] interface CSSScopeRule : CSSGroupingRule { - readonly attribute CSSOMString start; - readonly attribute CSSOMString end; + readonly attribute CSSOMString? start; + readonly attribute CSSOMString? end; }; diff --git a/test/wpt/tests/interfaces/css-cascade.idl b/test/wpt/tests/interfaces/css-cascade.idl index 9011dc7fd9e..0dd9969f6eb 100644 --- a/test/wpt/tests/interfaces/css-cascade.idl +++ b/test/wpt/tests/interfaces/css-cascade.idl @@ -3,10 +3,6 @@ // (https://github.com/w3c/webref) // Source: CSS Cascading and Inheritance Level 5 (https://drafts.csswg.org/css-cascade-5/) -partial interface CSSImportRule { - readonly attribute CSSOMString? layerName; -}; - [Exposed=Window] interface CSSLayerBlockRule : CSSGroupingRule { readonly attribute CSSOMString name; diff --git a/test/wpt/tests/interfaces/cssom.idl b/test/wpt/tests/interfaces/cssom.idl index 222b3dc09ec..0574f1a771c 100644 --- a/test/wpt/tests/interfaces/cssom.idl +++ b/test/wpt/tests/interfaces/cssom.idl @@ -96,17 +96,13 @@ interface CSSRule { const unsigned short NAMESPACE_RULE = 10; }; -[Exposed=Window] -interface CSSStyleRule : CSSRule { - attribute CSSOMString selectorText; - [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; -}; - [Exposed=Window] interface CSSImportRule : CSSRule { readonly attribute USVString href; [SameObject, PutForwards=mediaText] readonly attribute MediaList media; - [SameObject] readonly attribute CSSStyleSheet styleSheet; + [SameObject] readonly attribute CSSStyleSheet? styleSheet; + readonly attribute CSSOMString? layerName; + readonly attribute CSSOMString? supportsText; }; [Exposed=Window] @@ -116,6 +112,12 @@ interface CSSGroupingRule : CSSRule { undefined deleteRule(unsigned long index); }; +[Exposed=Window] +interface CSSStyleRule : CSSGroupingRule { + attribute CSSOMString selectorText; + [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; +}; + [Exposed=Window] interface CSSPageRule : CSSGroupingRule { attribute CSSOMString selectorText; diff --git a/test/wpt/tests/interfaces/document-picture-in-picture.idl b/test/wpt/tests/interfaces/document-picture-in-picture.idl new file mode 100644 index 00000000000..742f65e6f06 --- /dev/null +++ b/test/wpt/tests/interfaces/document-picture-in-picture.idl @@ -0,0 +1,34 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: Document Picture-in-Picture Specification (https://wicg.github.io/document-picture-in-picture/) + +[Exposed=Window] +partial interface Window { + [SameObject, SecureContext] readonly attribute DocumentPictureInPicture + documentPictureInPicture; +}; + +[Exposed=Window, SecureContext] +interface DocumentPictureInPicture : EventTarget { + [NewObject] Promise requestWindow( + optional DocumentPictureInPictureOptions options = {}); + readonly attribute Window window; + attribute EventHandler onenter; +}; + +dictionary DocumentPictureInPictureOptions { + [EnforceRange] unsigned long long width = 0; + [EnforceRange] unsigned long long height = 0; + boolean copyStyleSheets = false; +}; + +[Exposed=Window] +interface DocumentPictureInPictureEvent : Event { + constructor(DOMString type, DocumentPictureInPictureEventInit eventInitDict); + [SameObject] readonly attribute Window window; +}; + +dictionary DocumentPictureInPictureEventInit : EventInit { + required Window window; +}; diff --git a/test/wpt/tests/interfaces/dom.idl b/test/wpt/tests/interfaces/dom.idl index c5b5c94dbcc..c2def872fa2 100644 --- a/test/wpt/tests/interfaces/dom.idl +++ b/test/wpt/tests/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; diff --git a/test/wpt/tests/interfaces/fenced-frame.idl b/test/wpt/tests/interfaces/fenced-frame.idl index 2869b95e6bb..440ec2bbaa1 100644 --- a/test/wpt/tests/interfaces/fenced-frame.idl +++ b/test/wpt/tests/interfaces/fenced-frame.idl @@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: Fenced frame (https://wicg.github.io/fenced-frame/) +// Source: Fenced Frame (https://wicg.github.io/fenced-frame/) [Exposed=Window] interface HTMLFencedFrameElement : HTMLElement { @@ -10,19 +10,22 @@ interface HTMLFencedFrameElement : HTMLElement { [CEReactions] attribute FencedFrameConfig? config; [CEReactions] attribute DOMString width; [CEReactions] attribute DOMString height; + [CEReactions] attribute DOMString allow; }; enum OpaqueProperty {"opaque"}; typedef (unsigned long or OpaqueProperty) FencedFrameConfigSize; -typedef (USVString or OpaqueProperty) FencedFrameConfigURL; +typedef USVString FencedFrameConfigURL; [Exposed=Window] interface FencedFrameConfig { - constructor(USVString url); - readonly attribute FencedFrameConfigURL? url; - readonly attribute FencedFrameConfigSize? width; - readonly attribute FencedFrameConfigSize? height; + readonly attribute FencedFrameConfigSize? containerWidth; + readonly attribute FencedFrameConfigSize? containerHeight; + readonly attribute FencedFrameConfigSize? contentWidth; + readonly attribute FencedFrameConfigSize? contentHeight; + + undefined setSharedStorageContext(DOMString contextString); }; enum FenceReportingDestination { diff --git a/test/wpt/tests/interfaces/fs.idl b/test/wpt/tests/interfaces/fs.idl index e2474132abf..e341ab387d9 100644 --- a/test/wpt/tests/interfaces/fs.idl +++ b/test/wpt/tests/interfaces/fs.idl @@ -15,6 +15,7 @@ interface FileSystemHandle { Promise isSameEntry(FileSystemHandle other); }; + dictionary FileSystemCreateWritableOptions { boolean keepExistingData = false; }; @@ -26,6 +27,7 @@ interface FileSystemFileHandle : FileSystemHandle { [Exposed=DedicatedWorker] Promise createSyncAccessHandle(); }; + dictionary FileSystemGetFileOptions { boolean create = false; }; @@ -49,6 +51,7 @@ interface FileSystemDirectoryHandle : FileSystemHandle { Promise?> resolve(FileSystemHandle possibleDescendant); }; + enum WriteCommandType { "write", "seek", @@ -70,6 +73,7 @@ interface FileSystemWritableFileStream : WritableStream { Promise seek(unsigned long long position); Promise truncate(unsigned long long size); }; + dictionary FileSystemReadWriteOptions { [EnforceRange] unsigned long long at; }; diff --git a/test/wpt/tests/interfaces/html.idl b/test/wpt/tests/interfaces/html.idl index 33d4de0db97..99b33705b39 100644 --- a/test/wpt/tests/interfaces/html.idl +++ b/test/wpt/tests/interfaces/html.idl @@ -1643,6 +1643,14 @@ 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; diff --git a/test/wpt/tests/interfaces/mediastream-recording.idl b/test/wpt/tests/interfaces/mediastream-recording.idl index 99f30282333..496bfcf2e27 100644 --- a/test/wpt/tests/interfaces/mediastream-recording.idl +++ b/test/wpt/tests/interfaces/mediastream-recording.idl @@ -34,6 +34,8 @@ dictionary MediaRecorderOptions { unsigned long videoBitsPerSecond; unsigned long bitsPerSecond; BitrateMode audioBitrateMode = "variable"; + DOMHighResTimeStamp videoKeyFrameIntervalDuration; + unsigned long videoKeyFrameIntervalCount; }; enum BitrateMode { diff --git a/test/wpt/tests/interfaces/notifications.idl b/test/wpt/tests/interfaces/notifications.idl index bfcfa2e66af..4300b171071 100644 --- a/test/wpt/tests/interfaces/notifications.idl +++ b/test/wpt/tests/interfaces/notifications.idl @@ -28,7 +28,7 @@ interface Notification : EventTarget { [SameObject] readonly attribute FrozenArray vibrate; readonly attribute EpochTimeStamp timestamp; readonly attribute boolean renotify; - readonly attribute boolean silent; + readonly attribute boolean? silent; readonly attribute boolean requireInteraction; [SameObject] readonly attribute any data; [SameObject] readonly attribute FrozenArray actions; @@ -47,7 +47,7 @@ dictionary NotificationOptions { VibratePattern vibrate; EpochTimeStamp timestamp; boolean renotify = false; - boolean silent = false; + boolean? silent = null; boolean requireInteraction = false; any data = null; sequence actions = []; @@ -72,6 +72,7 @@ dictionary NotificationAction { }; callback NotificationPermissionCallback = undefined (NotificationPermission permission); + dictionary GetNotificationOptions { DOMString tag = ""; }; diff --git a/test/wpt/tests/interfaces/permissions-policy.idl b/test/wpt/tests/interfaces/permissions-policy.idl index a789d41738c..16945e3a9b7 100644 --- a/test/wpt/tests/interfaces/permissions-policy.idl +++ b/test/wpt/tests/interfaces/permissions-policy.idl @@ -18,6 +18,7 @@ partial interface Document { partial interface HTMLIFrameElement { [SameObject] readonly attribute PermissionsPolicy permissionsPolicy; }; + [Exposed=Window] interface PermissionsPolicyViolationReportBody : ReportBody { readonly attribute DOMString featureId; diff --git a/test/wpt/tests/interfaces/real-world-meshing.idl b/test/wpt/tests/interfaces/real-world-meshing.idl new file mode 100644 index 00000000000..38fe71f6c66 --- /dev/null +++ b/test/wpt/tests/interfaces/real-world-meshing.idl @@ -0,0 +1,21 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: WebXR Mesh Detection Module (https://immersive-web.github.io/real-world-meshing/) + +[Exposed=Window] interface XRMesh { + [SameObject] readonly attribute XRSpace meshSpace; + + readonly attribute FrozenArray vertices; + readonly attribute Uint32Array indices; + readonly attribute DOMHighResTimeStamp lastChangedTime; + readonly attribute DOMString? semanticLabel; +}; + +[Exposed=Window] interface XRMeshSet { + readonly setlike; +}; + +partial interface XRFrame { + readonly attribute XRMeshSet detectedMeshs; +}; diff --git a/test/wpt/tests/interfaces/resource-timing.idl b/test/wpt/tests/interfaces/resource-timing.idl index 151e5d46d84..33fed05b756 100644 --- a/test/wpt/tests/interfaces/resource-timing.idl +++ b/test/wpt/tests/interfaces/resource-timing.idl @@ -18,6 +18,7 @@ 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; @@ -25,6 +26,7 @@ interface PerformanceResourceTiming : PerformanceEntry { readonly attribute unsigned long long decodedBodySize; readonly attribute unsigned short responseStatus; readonly attribute RenderBlockingStatusType renderBlockingStatus; + readonly attribute DOMString contentType; [Default] object toJSON(); }; diff --git a/test/wpt/tests/interfaces/scheduling-apis.idl b/test/wpt/tests/interfaces/scheduling-apis.idl index 9ed49cfb689..1e84e79cd15 100644 --- a/test/wpt/tests/interfaces/scheduling-apis.idl +++ b/test/wpt/tests/interfaces/scheduling-apis.idl @@ -45,8 +45,14 @@ interface TaskController : AbortController { undefined setPriority(TaskPriority priority); }; +dictionary TaskSignalAnyInit { + (TaskPriority or TaskSignal) priority = "user-visible"; +}; + [Exposed=(Window, Worker)] interface TaskSignal : AbortSignal { + [NewObject] static TaskSignal _any(sequence signals, optional TaskSignalAnyInit init = {}); + readonly attribute TaskPriority priority; attribute EventHandler onprioritychange; diff --git a/test/wpt/tests/interfaces/screen-capture.idl b/test/wpt/tests/interfaces/screen-capture.idl index 9abd4d2c1ad..830b96d16fa 100644 --- a/test/wpt/tests/interfaces/screen-capture.idl +++ b/test/wpt/tests/interfaces/screen-capture.idl @@ -13,7 +13,7 @@ enum CaptureStartFocusBehavior { }; [Exposed=Window, SecureContext] -interface CaptureController { +interface CaptureController : EventTarget { constructor(); undefined setFocusBehavior(CaptureStartFocusBehavior focusBehavior); }; diff --git a/test/wpt/tests/interfaces/scroll-animations.idl b/test/wpt/tests/interfaces/scroll-animations.idl index 14215509c9f..31b3746e9d4 100644 --- a/test/wpt/tests/interfaces/scroll-animations.idl +++ b/test/wpt/tests/interfaces/scroll-animations.idl @@ -36,7 +36,11 @@ interface ViewTimeline : ScrollTimeline { readonly attribute CSSNumericValue endOffset; }; +dictionary AnimationTimeOptions { + DOMString? range; +}; + [Exposed=Window] partial interface AnimationTimeline { - CSSNumericValue? getCurrentTime(optional CSSOMString rangeName); + CSSNumericValue? getCurrentTime(optional AnimationTimeOptions options = {}); }; diff --git a/test/wpt/tests/interfaces/secure-payment-confirmation.idl b/test/wpt/tests/interfaces/secure-payment-confirmation.idl index 9061b243477..08ec8065c53 100644 --- a/test/wpt/tests/interfaces/secure-payment-confirmation.idl +++ b/test/wpt/tests/interfaces/secure-payment-confirmation.idl @@ -15,6 +15,7 @@ dictionary SecurePaymentConfirmationRequest { sequence locale; boolean showOptOut; }; + partial dictionary AuthenticationExtensionsClientInputs { AuthenticationExtensionsPaymentInputs payment; }; @@ -30,9 +31,11 @@ dictionary AuthenticationExtensionsPaymentInputs { PaymentCurrencyAmount total; PaymentCredentialInstrument instrument; }; + dictionary CollectedClientPaymentData : CollectedClientData { required CollectedClientAdditionalPaymentData payment; }; + dictionary CollectedClientAdditionalPaymentData { required USVString rpId; required USVString topOrigin; @@ -41,6 +44,7 @@ dictionary CollectedClientAdditionalPaymentData { required PaymentCurrencyAmount total; required PaymentCredentialInstrument instrument; }; + dictionary PaymentCredentialInstrument { required USVString displayName; required USVString icon; diff --git a/test/wpt/tests/interfaces/shared-storage.idl b/test/wpt/tests/interfaces/shared-storage.idl new file mode 100644 index 00000000000..eb5806f9a6d --- /dev/null +++ b/test/wpt/tests/interfaces/shared-storage.idl @@ -0,0 +1,80 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: Shared Storage API (https://wicg.github.io/shared-storage/) + +[Exposed=(Window)] +interface SharedStorageWorklet : Worklet { +}; + +[Exposed=SharedStorageWorklet, Global=SharedStorageWorklet] +interface SharedStorageWorkletGlobalScope : WorkletGlobalScope { + undefined register(DOMString name, + SharedStorageOperationConstructor operationCtor); +}; + +callback SharedStorageOperationConstructor = + SharedStorageOperation(optional SharedStorageRunOperationMethodOptions options); + +[Exposed=SharedStorageWorklet] +interface SharedStorageOperation { +}; + +dictionary SharedStorageRunOperationMethodOptions { + object data; + boolean resolveToConfig = false; + boolean keepAlive = false; +}; + +[Exposed=SharedStorageWorklet] +interface SharedStorageRunOperation : SharedStorageOperation { + Promise run(object data); +}; + +[Exposed=SharedStorageWorklet] +interface SharedStorageSelectURLOperation : SharedStorageOperation { + Promise run(object data, + FrozenArray urls); +}; + +[Exposed=(Window,SharedStorageWorklet)] +interface SharedStorage { + Promise set(DOMString key, + DOMString value, + optional SharedStorageSetMethodOptions options = {}); + Promise append(DOMString key, + DOMString value); + Promise delete(DOMString key); + Promise clear(); +}; + +dictionary SharedStorageSetMethodOptions { + boolean ignoreIfPresent = false; +}; + +typedef (USVString or FencedFrameConfig) SharedStorageResponse; + +[Exposed=(Window)] +interface WindowSharedStorage : SharedStorage { + Promise run(DOMString name, + optional SharedStorageRunOperationMethodOptions options = {}); + Promise selectURL(DOMString name, + FrozenArray urls, + optional SharedStorageRunOperationMethodOptions options = {}); + + readonly attribute SharedStorageWorklet worklet; +}; + +dictionary SharedStorageUrlWithMetadata { + required USVString url; + object reportingMetadata; +}; + +[Exposed=(SharedStorageWorklet)] +interface WorkletSharedStorage : SharedStorage { + Promise get(DOMString key); + Promise length(); + Promise remainingBudget(); + + async iterable; +}; diff --git a/test/wpt/tests/interfaces/storage-buckets.idl b/test/wpt/tests/interfaces/storage-buckets.idl new file mode 100644 index 00000000000..f3d500a5711 --- /dev/null +++ b/test/wpt/tests/interfaces/storage-buckets.idl @@ -0,0 +1,53 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into webref +// (https://github.com/w3c/webref) +// Source: Storage Buckets API (https://wicg.github.io/storage-buckets/) + +[SecureContext] +interface mixin NavigatorStorageBuckets { + [SameObject] readonly attribute StorageBucketManager storageBuckets; +}; +Navigator includes NavigatorStorageBuckets; +WorkerNavigator includes NavigatorStorageBuckets; + +[Exposed=(Window,Worker), + SecureContext] +interface StorageBucketManager { + Promise open(DOMString name, optional StorageBucketOptions options = {}); + Promise> keys(); + Promise delete(DOMString name); +}; + +enum StorageBucketDurability { + "strict", + "relaxed" +}; + +dictionary StorageBucketOptions { + boolean? persisted = null; + StorageBucketDurability? durability = null; + unsigned long long? quota = null; + DOMHighResTimeStamp? expires = null; +}; + +[Exposed=(Window,Worker), + SecureContext] +interface StorageBucket { + readonly attribute DOMString name; + + [Exposed=Window] Promise persist(); + Promise persisted(); + + Promise estimate(); + + Promise durability(); + + Promise setExpires(DOMHighResTimeStamp expires); + Promise expires(); + + [SameObject] readonly attribute IDBFactory indexedDB; + + [SameObject] readonly attribute CacheStorage caches; + + Promise getDirectory(); +}; diff --git a/test/wpt/tests/interfaces/trust-token-api.idl b/test/wpt/tests/interfaces/trust-token-api.idl index ee339590827..f521acea1f5 100644 --- a/test/wpt/tests/interfaces/trust-token-api.idl +++ b/test/wpt/tests/interfaces/trust-token-api.idl @@ -5,14 +5,11 @@ enum RefreshPolicy { "none", "refresh" }; -enum TokenType { "private-state-token" }; - enum TokenVersion { "1" }; enum OperationType { "token-request", "send-redemption-record", "token-redemption" }; dictionary PrivateToken { - required TokenType type; required TokenVersion version; required OperationType operation; RefreshPolicy refreshPolicy = "none"; @@ -24,6 +21,6 @@ partial dictionary RequestInit { }; partial interface Document { - Promise hasPrivateTokens(USVString issuer, USVString type); - Promise hasRedemptionRecord(USVString issuer, USVString type); + Promise hasPrivateTokens(USVString issuer); + Promise hasRedemptionRecord(USVString issuer); }; diff --git a/test/wpt/tests/interfaces/turtledove.idl b/test/wpt/tests/interfaces/turtledove.idl index cd81a3d87ef..f5867e995a8 100644 --- a/test/wpt/tests/interfaces/turtledove.idl +++ b/test/wpt/tests/interfaces/turtledove.idl @@ -1,7 +1,7 @@ // GENERATED CONTENT - DO NOT EDIT // Content was automatically extracted by Reffy into webref // (https://github.com/w3c/webref) -// Source: FLEDGE (https://wicg.github.io/turtledove/) +// Source: Protected Audience (formerly FLEDGE) (https://wicg.github.io/turtledove/) [SecureContext] partial interface Navigator { @@ -25,7 +25,7 @@ dictionary AuctionAdInterestGroup { DOMString executionMode = "compatibility"; USVString biddingLogicURL; USVString biddingWasmHelperURL; - USVString dailyUpdateURL; + USVString updateURL; USVString trustedBiddingSignalsURL; sequence trustedBiddingSignalsKeys; any userBiddingSignals; @@ -67,9 +67,15 @@ dictionary AuctionAdConfig { AbortSignal? signal; }; +[Exposed=InterestGroupScriptRunnerGlobalScope] +interface InterestGroupScriptRunnerGlobalScope { +}; + [Exposed=InterestGroupBiddingScriptRunnerGlobalScope, -Global=InterestGroupBiddingScriptRunnerGlobalScope] -interface InterestGroupBiddingScriptRunnerGlobalScope { + Global=(InterestGroupScriptRunnerGlobalScope, + InterestGroupBiddingScriptRunnerGlobalScope)] +interface InterestGroupBiddingScriptRunnerGlobalScope + : InterestGroupScriptRunnerGlobalScope { boolean setBid(); boolean setBid(GenerateBidOutput generateBidOutput); undefined setPriority(double priority); @@ -77,14 +83,19 @@ interface InterestGroupBiddingScriptRunnerGlobalScope { }; [Exposed=InterestGroupScoringScriptRunnerGlobalScope, -Global=InterestGroupScoringScriptRunnerGlobalScope] -interface InterestGroupScoringScriptRunnerGlobalScope { + Global=(InterestGroupScriptRunnerGlobalScope, + InterestGroupScoringScriptRunnerGlobalScope)] +interface InterestGroupScoringScriptRunnerGlobalScope + : InterestGroupScriptRunnerGlobalScope { }; [Exposed=InterestGroupReportingScriptRunnerGlobalScope, -Global=InterestGroupReportingScriptRunnerGlobalScope] -interface InterestGroupReportingScriptRunnerGlobalScope { + Global=(InterestGroupScriptRunnerGlobalScope, + InterestGroupReportingScriptRunnerGlobalScope)] +interface InterestGroupReportingScriptRunnerGlobalScope + : InterestGroupScriptRunnerGlobalScope { undefined sendReportTo(DOMString url); + undefined registerAdBeacon(record map); }; dictionary AdRender { @@ -96,7 +107,7 @@ dictionary AdRender { dictionary GenerateBidOutput { required double bid; required (DOMString or AdRender) adRender; - DOMString ad; + any ad; sequence<(DOMString or AdRender)> adComponents; double adCost; double modelingSignals; diff --git a/test/wpt/tests/interfaces/url.idl b/test/wpt/tests/interfaces/url.idl index 6549e45f419..a5e4d1eb492 100644 --- a/test/wpt/tests/interfaces/url.idl +++ b/test/wpt/tests/interfaces/url.idl @@ -33,10 +33,10 @@ interface URLSearchParams { 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/wpt/tests/interfaces/webauthn.idl b/test/wpt/tests/interfaces/webauthn.idl index 58a9e285232..9a37207ba2c 100644 --- a/test/wpt/tests/interfaces/webauthn.idl +++ b/test/wpt/tests/interfaces/webauthn.idl @@ -12,51 +12,56 @@ interface PublicKeyCredential : Credential { static Promise isConditionalMediationAvailable(); PublicKeyCredentialJSON toJSON(); }; + typedef DOMString Base64URLString; typedef (RegistrationResponseJSON or AuthenticationResponseJSON) PublicKeyCredentialJSON; dictionary RegistrationResponseJSON { - Base64URLString id; - Base64URLString rawId; - AuthenticatorAttestationResponseJSON response; - DOMString? authenticatorAttachment; - AuthenticationExtensionsClientOutputsJSON clientExtensionResults; - DOMString type; + required Base64URLString id; + required Base64URLString rawId; + required AuthenticatorAttestationResponseJSON response; + DOMString authenticatorAttachment; + required AuthenticationExtensionsClientOutputsJSON clientExtensionResults; + required DOMString type; }; dictionary AuthenticatorAttestationResponseJSON { - Base64URLString clientDataJSON; - Base64URLString attestationObject; - sequence transports; + required Base64URLString clientDataJSON; + required Base64URLString attestationObject; + required sequence transports; }; dictionary AuthenticationResponseJSON { - Base64URLString id; - Base64URLString rawId; - AuthenticatorAssertionResponseJSON response; - DOMString? authenticatorAttachment; - AuthenticationExtensionsClientOutputsJSON clientExtensionResults; - DOMString type; + required Base64URLString id; + required Base64URLString rawId; + required AuthenticatorAssertionResponseJSON response; + DOMString authenticatorAttachment; + required AuthenticationExtensionsClientOutputsJSON clientExtensionResults; + required DOMString type; }; dictionary AuthenticatorAssertionResponseJSON { - Base64URLString clientDataJSON; - Base64URLString authenticatorData; - Base64URLString signature; - Base64URLString? userHandle; + required Base64URLString clientDataJSON; + required Base64URLString authenticatorData; + required Base64URLString signature; + Base64URLString userHandle; }; dictionary AuthenticationExtensionsClientOutputsJSON { }; + partial dictionary CredentialCreationOptions { PublicKeyCredentialCreationOptions publicKey; }; + partial dictionary CredentialRequestOptions { PublicKeyCredentialRequestOptions publicKey; }; + partial interface PublicKeyCredential { static Promise isUserVerifyingPlatformAuthenticatorAvailable(); }; + partial interface PublicKeyCredential { static PublicKeyCredentialCreationOptions parseCreationOptionsFromJSON(PublicKeyCredentialCreationOptionsJSON options); }; @@ -87,6 +92,7 @@ dictionary PublicKeyCredentialDescriptorJSON { dictionary AuthenticationExtensionsClientInputsJSON { }; + partial interface PublicKeyCredential { static PublicKeyCredentialRequestOptions parseRequestOptionsFromJSON(PublicKeyCredentialRequestOptionsJSON options); }; @@ -99,10 +105,12 @@ dictionary PublicKeyCredentialRequestOptionsJSON { DOMString userVerification = "preferred"; AuthenticationExtensionsClientInputsJSON extensions; }; + [SecureContext, Exposed=Window] interface AuthenticatorResponse { [SameObject] readonly attribute ArrayBuffer clientDataJSON; }; + [SecureContext, Exposed=Window] interface AuthenticatorAttestationResponse : AuthenticatorResponse { [SameObject] readonly attribute ArrayBuffer attestationObject; @@ -111,6 +119,7 @@ interface AuthenticatorAttestationResponse : AuthenticatorResponse { ArrayBuffer? getPublicKey(); COSEAlgorithmIdentifier getPublicKeyAlgorithm(); }; + [SecureContext, Exposed=Window] interface AuthenticatorAssertionResponse : AuthenticatorResponse { [SameObject] readonly attribute ArrayBuffer authenticatorData; @@ -118,10 +127,12 @@ interface AuthenticatorAssertionResponse : AuthenticatorResponse { [SameObject] readonly attribute ArrayBuffer? userHandle; [SameObject] readonly attribute ArrayBuffer? attestationObject; }; + dictionary PublicKeyCredentialParameters { required DOMString type; required COSEAlgorithmIdentifier alg; }; + dictionary PublicKeyCredentialCreationOptions { required PublicKeyCredentialRpEntity rp; required PublicKeyCredentialUserEntity user; @@ -136,37 +147,45 @@ dictionary PublicKeyCredentialCreationOptions { sequence attestationFormats = []; AuthenticationExtensionsClientInputs extensions; }; + dictionary PublicKeyCredentialEntity { required DOMString name; }; + dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity { DOMString id; }; + dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity { required BufferSource id; required DOMString displayName; }; + dictionary AuthenticatorSelectionCriteria { DOMString authenticatorAttachment; DOMString residentKey; boolean requireResidentKey = false; DOMString userVerification = "preferred"; }; + enum AuthenticatorAttachment { "platform", "cross-platform" }; + enum ResidentKeyRequirement { "discouraged", "preferred", "required" }; + enum AttestationConveyancePreference { "none", "indirect", "direct", "enterprise" }; + dictionary PublicKeyCredentialRequestOptions { required BufferSource challenge; unsigned long timeout; @@ -177,10 +196,13 @@ dictionary PublicKeyCredentialRequestOptions { sequence attestationFormats = []; AuthenticationExtensionsClientInputs extensions; }; + dictionary AuthenticationExtensionsClientInputs { }; + dictionary AuthenticationExtensionsClientOutputs { }; + dictionary CollectedClientData { required DOMString type; required DOMString challenge; @@ -195,42 +217,54 @@ dictionary TokenBinding { }; enum TokenBindingStatus { "present", "supported" }; + enum PublicKeyCredentialType { "public-key" }; + dictionary PublicKeyCredentialDescriptor { required DOMString type; required BufferSource id; sequence transports; }; + enum AuthenticatorTransport { "usb", "nfc", "ble", + "smart-card", "hybrid", "internal" }; + typedef long COSEAlgorithmIdentifier; + enum UserVerificationRequirement { "required", "preferred", "discouraged" }; + partial dictionary AuthenticationExtensionsClientInputs { USVString appid; }; + partial dictionary AuthenticationExtensionsClientOutputs { boolean appid; }; + partial dictionary AuthenticationExtensionsClientInputs { USVString appidExclude; }; + partial dictionary AuthenticationExtensionsClientOutputs { boolean appidExclude; }; + partial dictionary AuthenticationExtensionsClientInputs { boolean credProps; }; + dictionary CredentialPropertiesOutput { boolean rk; }; @@ -238,6 +272,7 @@ dictionary CredentialPropertiesOutput { partial dictionary AuthenticationExtensionsClientOutputs { CredentialPropertiesOutput credProps; }; + dictionary AuthenticationExtensionsPRFValues { required BufferSource first; BufferSource second; @@ -289,12 +324,14 @@ dictionary AuthenticationExtensionsLargeBlobOutputs { partial dictionary AuthenticationExtensionsClientInputs { boolean uvm; }; + typedef sequence UvmEntry; typedef sequence UvmEntries; partial dictionary AuthenticationExtensionsClientOutputs { UvmEntries uvm; }; + dictionary AuthenticationExtensionsDevicePublicKeyInputs { DOMString attestation = "none"; sequence attestationFormats = []; diff --git a/test/wpt/tests/interfaces/webcodecs-av1-codec-registration.idl b/test/wpt/tests/interfaces/webcodecs-av1-codec-registration.idl index 00e4493d3c0..ab20879728d 100644 --- a/test/wpt/tests/interfaces/webcodecs-av1-codec-registration.idl +++ b/test/wpt/tests/interfaces/webcodecs-av1-codec-registration.idl @@ -3,6 +3,14 @@ // (https://github.com/w3c/webref) // Source: AV1 WebCodecs Registration (https://w3c.github.io/webcodecs/av1_codec_registration.html) +partial dictionary VideoEncoderConfig { + AV1EncoderConfig av1; +}; + +dictionary AV1EncoderConfig { + boolean forceScreenContentTools = false; +}; + partial dictionary VideoEncoderEncodeOptions { VideoEncoderEncodeOptionsForAv1 av1; }; diff --git a/test/wpt/tests/interfaces/webcodecs-avc-codec-registration.idl b/test/wpt/tests/interfaces/webcodecs-avc-codec-registration.idl index d4074f647da..2b952c22194 100644 --- a/test/wpt/tests/interfaces/webcodecs-avc-codec-registration.idl +++ b/test/wpt/tests/interfaces/webcodecs-avc-codec-registration.idl @@ -15,3 +15,11 @@ enum AvcBitstreamFormat { "annexb", "avc", }; + +partial dictionary VideoEncoderEncodeOptions { + VideoEncoderEncodeOptionsForAvc avc; +}; + +dictionary VideoEncoderEncodeOptionsForAvc { + unsigned short? quantizer; +}; diff --git a/test/wpt/tests/interfaces/webcodecs.idl b/test/wpt/tests/interfaces/webcodecs.idl index 77649029db6..0b95dc8b757 100644 --- a/test/wpt/tests/interfaces/webcodecs.idl +++ b/test/wpt/tests/interfaces/webcodecs.idl @@ -161,6 +161,7 @@ dictionary AudioEncoderConfig { [EnforceRange] unsigned long sampleRate; [EnforceRange] unsigned long numberOfChannels; [EnforceRange] unsigned long long bitrate; + BitrateMode bitrateMode; }; dictionary VideoEncoderConfig { diff --git a/test/wpt/tests/interfaces/webgpu.idl b/test/wpt/tests/interfaces/webgpu.idl index 284327a5789..25943d99c35 100644 --- a/test/wpt/tests/interfaces/webgpu.idl +++ b/test/wpt/tests/interfaces/webgpu.idl @@ -18,6 +18,7 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxTextureDimension3D; readonly attribute unsigned long maxTextureArrayLayers; readonly attribute unsigned long maxBindGroups; + readonly attribute unsigned long maxBindGroupsPlusVertexBuffers; readonly attribute unsigned long maxBindingsPerBindGroup; readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout; readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout; @@ -26,7 +27,6 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxStorageBuffersPerShaderStage; readonly attribute unsigned long maxStorageTexturesPerShaderStage; readonly attribute unsigned long maxUniformBuffersPerShaderStage; - readonly attribute unsigned long maxFragmentCombinedOutputResources; readonly attribute unsigned long long maxUniformBufferBindingSize; readonly attribute unsigned long long maxStorageBufferBindingSize; readonly attribute unsigned long minUniformBufferOffsetAlignment; @@ -85,7 +85,7 @@ dictionary GPURequestAdapterOptions { enum GPUPowerPreference { "low-power", - "high-performance" + "high-performance", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -98,7 +98,8 @@ interface GPUAdapter { Promise requestAdapterInfo(optional sequence unmaskHints = []); }; -dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase { +dictionary GPUDeviceDescriptor + : GPUObjectDescriptorBase { sequence requiredFeatures = []; record requiredLimits = {}; GPUQueueDescriptor defaultQueue = {}; @@ -115,7 +116,7 @@ enum GPUFeatureName { "shader-f16", "rg11b10ufloat-renderable", "bgra8unorm-storage", - "float32-filterable" + "float32-filterable", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -151,8 +152,8 @@ GPUDevice includes GPUObjectBase; [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUBuffer { - readonly attribute GPUSize64 size; - readonly attribute GPUBufferUsageFlags usage; + readonly attribute GPUSize64Out size; + readonly attribute GPUFlagsConstant usage; readonly attribute GPUBufferMapState mapState; @@ -167,10 +168,11 @@ GPUBuffer includes GPUObjectBase; enum GPUBufferMapState { "unmapped", "pending", - "mapped" + "mapped", }; -dictionary GPUBufferDescriptor : GPUObjectDescriptorBase { +dictionary GPUBufferDescriptor + : GPUObjectDescriptorBase { required GPUSize64 size; required GPUBufferUsageFlags usage; boolean mappedAtCreation = false; @@ -204,18 +206,19 @@ interface GPUTexture { undefined destroy(); - readonly attribute GPUIntegerCoordinate width; - readonly attribute GPUIntegerCoordinate height; - readonly attribute GPUIntegerCoordinate depthOrArrayLayers; - readonly attribute GPUIntegerCoordinate mipLevelCount; - readonly attribute GPUSize32 sampleCount; + readonly attribute GPUIntegerCoordinateOut width; + readonly attribute GPUIntegerCoordinateOut height; + readonly attribute GPUIntegerCoordinateOut depthOrArrayLayers; + readonly attribute GPUIntegerCoordinateOut mipLevelCount; + readonly attribute GPUSize32Out sampleCount; readonly attribute GPUTextureDimension dimension; readonly attribute GPUTextureFormat format; - readonly attribute GPUTextureUsageFlags usage; + readonly attribute GPUFlagsConstant usage; }; GPUTexture includes GPUObjectBase; -dictionary GPUTextureDescriptor : GPUObjectDescriptorBase { +dictionary GPUTextureDescriptor + : GPUObjectDescriptorBase { required GPUExtent3D size; GPUIntegerCoordinate mipLevelCount = 1; GPUSize32 sampleCount = 1; @@ -228,7 +231,7 @@ dictionary GPUTextureDescriptor : GPUObjectDescriptorBase { enum GPUTextureDimension { "1d", "2d", - "3d" + "3d", }; typedef [EnforceRange] unsigned long GPUTextureUsageFlags; @@ -246,7 +249,8 @@ interface GPUTextureView { }; GPUTextureView includes GPUObjectBase; -dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase { +dictionary GPUTextureViewDescriptor + : GPUObjectDescriptorBase { GPUTextureFormat format; GPUTextureViewDimension dimension; GPUTextureAspect aspect = "all"; @@ -262,13 +266,13 @@ enum GPUTextureViewDimension { "2d-array", "cube", "cube-array", - "3d" + "3d", }; enum GPUTextureAspect { "all", "stencil-only", - "depth-only" + "depth-only", }; enum GPUTextureFormat { @@ -388,7 +392,7 @@ enum GPUTextureFormat { "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", - "astc-12x12-unorm-srgb" + "astc-12x12-unorm-srgb", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -396,8 +400,9 @@ interface GPUExternalTexture { }; GPUExternalTexture includes GPUObjectBase; -dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase { - required HTMLVideoElement source; +dictionary GPUExternalTextureDescriptor + : GPUObjectDescriptorBase { + required (HTMLVideoElement or VideoFrame) source; PredefinedColorSpace colorSpace = "srgb"; }; @@ -406,7 +411,8 @@ interface GPUSampler { }; GPUSampler includes GPUObjectBase; -dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { +dictionary GPUSamplerDescriptor + : GPUObjectDescriptorBase { GPUAddressMode addressModeU = "clamp-to-edge"; GPUAddressMode addressModeV = "clamp-to-edge"; GPUAddressMode addressModeW = "clamp-to-edge"; @@ -422,17 +428,17 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase { enum GPUAddressMode { "clamp-to-edge", "repeat", - "mirror-repeat" + "mirror-repeat", }; enum GPUFilterMode { "nearest", - "linear" + "linear", }; enum GPUMipmapFilterMode { "nearest", - "linear" + "linear", }; enum GPUCompareFunction { @@ -443,7 +449,7 @@ enum GPUCompareFunction { "greater", "not-equal", "greater-equal", - "always" + "always", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -451,7 +457,8 @@ interface GPUBindGroupLayout { }; GPUBindGroupLayout includes GPUObjectBase; -dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase { +dictionary GPUBindGroupLayoutDescriptor + : GPUObjectDescriptorBase { required sequence entries; }; @@ -477,7 +484,7 @@ namespace GPUShaderStage { enum GPUBufferBindingType { "uniform", "storage", - "read-only-storage" + "read-only-storage", }; dictionary GPUBufferBindingLayout { @@ -489,7 +496,7 @@ dictionary GPUBufferBindingLayout { enum GPUSamplerBindingType { "filtering", "non-filtering", - "comparison" + "comparison", }; dictionary GPUSamplerBindingLayout { @@ -501,7 +508,7 @@ enum GPUTextureSampleType { "unfilterable-float", "depth", "sint", - "uint" + "uint", }; dictionary GPUTextureBindingLayout { @@ -511,7 +518,7 @@ dictionary GPUTextureBindingLayout { }; enum GPUStorageTextureAccess { - "write-only" + "write-only", }; dictionary GPUStorageTextureBindingLayout { @@ -528,7 +535,8 @@ interface GPUBindGroup { }; GPUBindGroup includes GPUObjectBase; -dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase { +dictionary GPUBindGroupDescriptor + : GPUObjectDescriptorBase { required GPUBindGroupLayout layout; required sequence entries; }; @@ -551,7 +559,8 @@ interface GPUPipelineLayout { }; GPUPipelineLayout includes GPUObjectBase; -dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase { +dictionary GPUPipelineLayoutDescriptor + : GPUObjectDescriptorBase { required sequence bindGroupLayouts; }; @@ -561,7 +570,8 @@ interface GPUShaderModule { }; GPUShaderModule includes GPUObjectBase; -dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase { +dictionary GPUShaderModuleDescriptor + : GPUObjectDescriptorBase { required USVString code; object sourceMap; record hints; @@ -574,7 +584,7 @@ dictionary GPUShaderModuleCompilationHint { enum GPUCompilationMessageType { "error", "warning", - "info" + "info", }; [Exposed=(Window, DedicatedWorker), Serializable, SecureContext] @@ -604,14 +614,15 @@ dictionary GPUPipelineErrorInit { enum GPUPipelineErrorReason { "validation", - "internal" + "internal", }; enum GPUAutoLayoutMode { - "auto" + "auto", }; -dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase { +dictionary GPUPipelineDescriptorBase + : GPUObjectDescriptorBase { required (GPUPipelineLayout or GPUAutoLayoutMode) layout; }; @@ -633,7 +644,8 @@ interface GPUComputePipeline { GPUComputePipeline includes GPUObjectBase; GPUComputePipeline includes GPUPipelineBase; -dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase { +dictionary GPUComputePipelineDescriptor + : GPUPipelineDescriptorBase { required GPUProgrammableStage compute; }; @@ -643,7 +655,8 @@ interface GPURenderPipeline { GPURenderPipeline includes GPUObjectBase; GPURenderPipeline includes GPUPipelineBase; -dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase { +dictionary GPURenderPipelineDescriptor + : GPUPipelineDescriptorBase { required GPUVertexState vertex; GPUPrimitiveState primitive = {}; GPUDepthStencilState depthStencil; @@ -666,18 +679,18 @@ enum GPUPrimitiveTopology { "line-list", "line-strip", "triangle-list", - "triangle-strip" + "triangle-strip", }; enum GPUFrontFace { "ccw", - "cw" + "cw", }; enum GPUCullMode { "none", "front", - "back" + "back", }; dictionary GPUMultisampleState { @@ -686,7 +699,8 @@ dictionary GPUMultisampleState { boolean alphaToCoverageEnabled = false; }; -dictionary GPUFragmentState : GPUProgrammableStage { +dictionary GPUFragmentState + : GPUProgrammableStage { required sequence targets; }; @@ -731,7 +745,7 @@ enum GPUBlendFactor { "one-minus-dst-alpha", "src-alpha-saturated", "constant", - "one-minus-constant" + "one-minus-constant", }; enum GPUBlendOperation { @@ -739,7 +753,7 @@ enum GPUBlendOperation { "subtract", "reverse-subtract", "min", - "max" + "max", }; dictionary GPUDepthStencilState { @@ -774,12 +788,12 @@ enum GPUStencilOperation { "increment-clamp", "decrement-clamp", "increment-wrap", - "decrement-wrap" + "decrement-wrap", }; enum GPUIndexFormat { "uint16", - "uint32" + "uint32", }; enum GPUVertexFormat { @@ -812,15 +826,16 @@ enum GPUVertexFormat { "sint32", "sint32x2", "sint32x3", - "sint32x4" + "sint32x4", }; enum GPUVertexStepMode { "vertex", - "instance" + "instance", }; -dictionary GPUVertexState : GPUProgrammableStage { +dictionary GPUVertexState + : GPUProgrammableStage { sequence buffers = []; }; @@ -837,17 +852,43 @@ dictionary GPUVertexAttribute { required GPUIndex32 shaderLocation; }; -dictionary GPUImageDataLayout { GPUSize64 offset = 0; GPUSize32 bytesPerRow; GPUSize32 rowsPerImage;}; -dictionary GPUImageCopyBuffer : GPUImageDataLayout { required GPUBuffer buffer;}; -dictionary GPUImageCopyTexture { required GPUTexture texture; GPUIntegerCoordinate mipLevel = 0; GPUOrigin3D origin = {}; GPUTextureAspect aspect = "all";}; -dictionary GPUImageCopyTextureTagged : GPUImageCopyTexture { PredefinedColorSpace colorSpace = "srgb"; boolean premultipliedAlpha = false;}; -dictionary GPUImageCopyExternalImage { required (ImageBitmap or HTMLVideoElement or HTMLCanvasElement or OffscreenCanvas) source; GPUOrigin2D origin = {}; boolean flipY = false;}; +dictionary GPUImageDataLayout { + GPUSize64 offset = 0; + GPUSize32 bytesPerRow; + GPUSize32 rowsPerImage; +}; + +dictionary GPUImageCopyBuffer + : GPUImageDataLayout { + required GPUBuffer buffer; +}; + +dictionary GPUImageCopyTexture { + required GPUTexture texture; + GPUIntegerCoordinate mipLevel = 0; + GPUOrigin3D origin = {}; + GPUTextureAspect aspect = "all"; +}; + +dictionary GPUImageCopyTextureTagged + : GPUImageCopyTexture { + PredefinedColorSpace colorSpace = "srgb"; + boolean premultipliedAlpha = false; +}; + +dictionary GPUImageCopyExternalImage { + required (ImageBitmap or HTMLVideoElement or HTMLCanvasElement or OffscreenCanvas) source; + GPUOrigin2D origin = {}; + boolean flipY = false; +}; + [Exposed=(Window, DedicatedWorker), SecureContext] interface GPUCommandBuffer { }; GPUCommandBuffer includes GPUObjectBase; -dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase { +dictionary GPUCommandBufferDescriptor + : GPUObjectDescriptorBase { }; interface mixin GPUCommandsMixin { @@ -900,14 +941,15 @@ GPUCommandEncoder includes GPUObjectBase; GPUCommandEncoder includes GPUCommandsMixin; GPUCommandEncoder includes GPUDebugCommandsMixin; -dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase { +dictionary GPUCommandEncoderDescriptor + : GPUObjectDescriptorBase { }; interface mixin GPUBindingCommandsMixin { - undefined setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup, + undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, optional sequence dynamicOffsets = []); - undefined setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup, + undefined setBindGroup(GPUIndex32 index, GPUBindGroup? bindGroup, Uint32Array dynamicOffsetsData, GPUSize64 dynamicOffsetsDataStart, GPUSize32 dynamicOffsetsDataLength); @@ -932,21 +974,15 @@ GPUComputePassEncoder includes GPUCommandsMixin; GPUComputePassEncoder includes GPUDebugCommandsMixin; GPUComputePassEncoder includes GPUBindingCommandsMixin; -enum GPUComputePassTimestampLocation { - "beginning", - "end" -}; - -dictionary GPUComputePassTimestampWrite { +dictionary GPUComputePassTimestampWrites { required GPUQuerySet querySet; - required GPUSize32 queryIndex; - required GPUComputePassTimestampLocation location; + GPUSize32 beginningOfPassWriteIndex; + GPUSize32 endOfPassWriteIndex; }; -typedef sequence GPUComputePassTimestampWrites; - -dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase { - GPUComputePassTimestampWrites timestampWrites = []; +dictionary GPUComputePassDescriptor + : GPUObjectDescriptorBase { + GPUComputePassTimestampWrites timestampWrites; }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -973,24 +1009,18 @@ GPURenderPassEncoder includes GPUDebugCommandsMixin; GPURenderPassEncoder includes GPUBindingCommandsMixin; GPURenderPassEncoder includes GPURenderCommandsMixin; -enum GPURenderPassTimestampLocation { - "beginning", - "end" -}; - -dictionary GPURenderPassTimestampWrite { +dictionary GPURenderPassTimestampWrites { required GPUQuerySet querySet; - required GPUSize32 queryIndex; - required GPURenderPassTimestampLocation location; + GPUSize32 beginningOfPassWriteIndex; + GPUSize32 endOfPassWriteIndex; }; -typedef sequence GPURenderPassTimestampWrites; - -dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase { +dictionary GPURenderPassDescriptor + : GPUObjectDescriptorBase { required sequence colorAttachments; GPURenderPassDepthStencilAttachment depthStencilAttachment; GPUQuerySet occlusionQuerySet; - GPURenderPassTimestampWrites timestampWrites = []; + GPURenderPassTimestampWrites timestampWrites; GPUSize64 maxDrawCount = 50000000; }; @@ -1019,15 +1049,16 @@ dictionary GPURenderPassDepthStencilAttachment { enum GPULoadOp { "load", - "clear" + "clear", }; enum GPUStoreOp { "store", - "discard" + "discard", }; -dictionary GPURenderPassLayout : GPUObjectDescriptorBase { +dictionary GPURenderPassLayout + : GPUObjectDescriptorBase { required sequence colorFormats; GPUTextureFormat depthStencilFormat; GPUSize32 sampleCount = 1; @@ -1037,7 +1068,7 @@ interface mixin GPURenderCommandsMixin { undefined setPipeline(GPURenderPipeline pipeline); undefined setIndexBuffer(GPUBuffer buffer, GPUIndexFormat indexFormat, optional GPUSize64 offset = 0, optional GPUSize64 size); - undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); + undefined setVertexBuffer(GPUIndex32 slot, GPUBuffer? buffer, optional GPUSize64 offset = 0, optional GPUSize64 size); undefined draw(GPUSize32 vertexCount, optional GPUSize32 instanceCount = 1, optional GPUSize32 firstVertex = 0, optional GPUSize32 firstInstance = 0); @@ -1055,7 +1086,8 @@ interface GPURenderBundle { }; GPURenderBundle includes GPUObjectBase; -dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase { +dictionary GPURenderBundleDescriptor + : GPUObjectDescriptorBase { }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1068,12 +1100,14 @@ GPURenderBundleEncoder includes GPUDebugCommandsMixin; GPURenderBundleEncoder includes GPUBindingCommandsMixin; GPURenderBundleEncoder includes GPURenderCommandsMixin; -dictionary GPURenderBundleEncoderDescriptor : GPURenderPassLayout { +dictionary GPURenderBundleEncoderDescriptor + : GPURenderPassLayout { boolean depthReadOnly = false; boolean stencilReadOnly = false; }; -dictionary GPUQueueDescriptor : GPUObjectDescriptorBase { +dictionary GPUQueueDescriptor + : GPUObjectDescriptorBase { }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1107,18 +1141,19 @@ interface GPUQuerySet { undefined destroy(); readonly attribute GPUQueryType type; - readonly attribute GPUSize32 count; + readonly attribute GPUSize32Out count; }; GPUQuerySet includes GPUObjectBase; -dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase { +dictionary GPUQuerySetDescriptor + : GPUObjectDescriptorBase { required GPUQueryType type; required GPUSize32 count; }; enum GPUQueryType { "occlusion", - "timestamp" + "timestamp", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1133,7 +1168,7 @@ interface GPUCanvasContext { enum GPUCanvasAlphaMode { "opaque", - "premultiplied" + "premultiplied", }; dictionary GPUCanvasConfiguration { @@ -1147,7 +1182,7 @@ dictionary GPUCanvasConfiguration { enum GPUDeviceLostReason { "unknown", - "destroyed" + "destroyed", }; [Exposed=(Window, DedicatedWorker), SecureContext] @@ -1166,24 +1201,27 @@ interface GPUError { }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUValidationError : GPUError { +interface GPUValidationError + : GPUError { constructor(DOMString message); }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUOutOfMemoryError : GPUError { +interface GPUOutOfMemoryError + : GPUError { constructor(DOMString message); }; [Exposed=(Window, DedicatedWorker), SecureContext] -interface GPUInternalError : GPUError { +interface GPUInternalError + : GPUError { constructor(DOMString message); }; enum GPUErrorFilter { "validation", "out-of-memory", - "internal" + "internal", }; partial interface GPUDevice { @@ -1220,6 +1258,10 @@ typedef [EnforceRange] unsigned long GPUIndex32; typedef [EnforceRange] unsigned long GPUSize32; typedef [EnforceRange] long GPUSignedOffset32; +typedef unsigned long long GPUSize64Out; +typedef unsigned long GPUIntegerCoordinateOut; +typedef unsigned long GPUSize32Out; + typedef unsigned long GPUFlagsConstant; dictionary GPUColorDict { diff --git a/test/wpt/tests/interfaces/webnn.idl b/test/wpt/tests/interfaces/webnn.idl index 2c2ab35e909..17e30803b88 100644 --- a/test/wpt/tests/interfaces/webnn.idl +++ b/test/wpt/tests/interfaces/webnn.idl @@ -127,10 +127,10 @@ interface MLGraphBuilder { constructor(MLContext context); // Create an operand for a graph input. - MLOperand input(DOMString name, MLOperandDescriptor desc); + MLOperand input(DOMString name, MLOperandDescriptor descriptor); // Create an operand for a graph constant. - MLOperand constant(MLOperandDescriptor desc, MLBufferView bufferView); + MLOperand constant(MLOperandDescriptor descriptor, MLBufferView bufferView); // Create a single-value operand from the specified number of the specified type. MLOperand constant(double value, optional MLOperandType type = "float32"); @@ -489,13 +489,8 @@ partial interface MLGraphBuilder { MLActivation sigmoid(); }; -dictionary MLSliceOptions { - sequence axes; -}; - partial interface MLGraphBuilder { - MLOperand slice(MLOperand input, sequence starts, sequence sizes, - optional MLSliceOptions options = {}); + MLOperand slice(MLOperand input, sequence starts, sequence sizes); }; partial interface MLGraphBuilder { diff --git a/test/wpt/tests/interfaces/webrtc-encoded-transform.idl b/test/wpt/tests/interfaces/webrtc-encoded-transform.idl index e48f1080c41..6dd2ba3fffa 100644 --- a/test/wpt/tests/interfaces/webrtc-encoded-transform.idl +++ b/test/wpt/tests/interfaces/webrtc-encoded-transform.idl @@ -27,7 +27,7 @@ typedef [EnforceRange] unsigned long long SmallCryptoKeyID; typedef (SmallCryptoKeyID or bigint) CryptoKeyID; [Exposed=(Window,DedicatedWorker)] -interface SFrameTransform { +interface SFrameTransform : EventTarget { constructor(optional SFrameTransformOptions options = {}); Promise setEncryptionKey(CryptoKey key, optional CryptoKeyID keyID); attribute EventHandler onerror; @@ -72,7 +72,8 @@ dictionary RTCEncodedVideoFrameMetadata { unsigned long temporalIndex; unsigned long synchronizationSource; octet payloadType; - sequence contributingSources; + sequence contributingSources; + long long timestamp; // microseconds }; // New interfaces to define encoded video and audio frames. Will eventually diff --git a/test/wpt/tests/interfaces/webrtc-stats.idl b/test/wpt/tests/interfaces/webrtc-stats.idl index 7e820a26df4..b398c73e3f4 100644 --- a/test/wpt/tests/interfaces/webrtc-stats.idl +++ b/test/wpt/tests/interfaces/webrtc-stats.idl @@ -13,8 +13,6 @@ enum RTCStatsType { "media-playout", "peer-connection", "data-channel", -"stream", -"track", "transport", "candidate-pair", "local-candidate", @@ -94,6 +92,8 @@ dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats { boolean powerEfficientDecoder; unsigned long framesAssembledFromMultiplePackets; double totalAssemblyTime; + unsigned long long retransmittedPacketsReceived; + unsigned long long retransmittedBytesReceived; }; dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats { diff --git a/test/wpt/tests/interfaces/webrtc.idl b/test/wpt/tests/interfaces/webrtc.idl index 578cbe92974..4c31d3be67a 100644 --- a/test/wpt/tests/interfaces/webrtc.idl +++ b/test/wpt/tests/interfaces/webrtc.idl @@ -441,13 +441,13 @@ enum RTCIceGathererState { }; enum RTCIceTransportState { + "closed", + "failed", + "disconnected", "new", "checking", - "connected", "completed", - "disconnected", - "failed", - "closed" + "connected" }; enum RTCIceRole { diff --git a/test/wpt/tests/interfaces/webtransport.idl b/test/wpt/tests/interfaces/webtransport.idl index 2bea483e1b9..a9f514e2366 100644 --- a/test/wpt/tests/interfaces/webtransport.idl +++ b/test/wpt/tests/interfaces/webtransport.idl @@ -98,6 +98,7 @@ dictionary WebTransportDatagramStats { [Exposed=(Window,Worker), SecureContext, Transferable] interface WebTransportSendStream : WritableStream { + attribute long long? sendOrder; Promise getStats(); }; @@ -130,12 +131,12 @@ interface WebTransportError : DOMException { constructor(optional DOMString message = "", optional WebTransportErrorOptions options = {}); readonly attribute WebTransportErrorSource source; - readonly attribute octet? streamErrorCode; + readonly attribute unsigned long? streamErrorCode; }; dictionary WebTransportErrorOptions { WebTransportErrorSource source = "stream"; - [Clamp] octet? streamErrorCode = null; + [Clamp] unsigned long? streamErrorCode = null; }; enum WebTransportErrorSource { diff --git a/test/wpt/tests/interfaces/webxrlayers.idl b/test/wpt/tests/interfaces/webxrlayers.idl index e182f47b9c5..c8b3a71c699 100644 --- a/test/wpt/tests/interfaces/webxrlayers.idl +++ b/test/wpt/tests/interfaces/webxrlayers.idl @@ -11,6 +11,12 @@ enum XRLayerLayout { "stereo-top-bottom" }; +enum XRLayerQuality { + "default", + "text-optimized", + "graphics-optimized" +}; + [Exposed=Window] interface XRCompositionLayer : XRLayer { readonly attribute XRLayerLayout layout; @@ -18,6 +24,7 @@ enum XRLayerLayout { attribute boolean forceMonoPresentation; attribute float opacity; readonly attribute unsigned long mipLevels; + attribute XRLayerQuality quality; readonly attribute boolean needsRedraw; @@ -106,6 +113,7 @@ dictionary XRProjectionLayerInit { GLenum colorFormat = 0x1908; // RGBA GLenum depthFormat = 0x1902; // DEPTH_COMPONENT double scaleFactor = 1.0; + boolean clearOnAccess = true; }; dictionary XRLayerInit { @@ -117,6 +125,7 @@ dictionary XRLayerInit { required unsigned long viewPixelHeight; XRLayerLayout layout = "mono"; boolean isStatic = false; + boolean clearOnAccess = true; }; dictionary XRQuadLayerInit : XRLayerInit { diff --git a/test/wpt/tests/lint.ignore b/test/wpt/tests/lint.ignore index 6f8ec10470b..489c717cd6a 100644 --- a/test/wpt/tests/lint.ignore +++ b/test/wpt/tests/lint.ignore @@ -48,6 +48,7 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.bmp TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.sxg TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.wbn TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.avif +TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.annexb ## .gitignore W3C-TEST.ORG: .gitignore @@ -225,7 +226,11 @@ SET TIMEOUT: service-workers/service-worker/activation.https.html SET TIMEOUT: service-workers/service-worker/fetch-frame-resource.https.html SET TIMEOUT: service-workers/service-worker/fetch-request-redirect.https.html SET TIMEOUT: service-workers/service-worker/fetch-waits-for-activate.https.html +SET TIMEOUT: service-workers/service-worker/postMessage-client-worker.js SET TIMEOUT: service-workers/service-worker/update-recovery.https.html +SET TIMEOUT: service-workers/service-worker/resources/controlled-frame-postMessage.html +SET TIMEOUT: service-workers/service-worker/resources/controlled-worker-late-postMessage.js +SET TIMEOUT: service-workers/service-worker/resources/controlled-worker-postMessage.js SET TIMEOUT: service-workers/service-worker/resources/extendable-event-async-waituntil.js SET TIMEOUT: service-workers/service-worker/resources/fetch-event-async-respond-with-worker.js SET TIMEOUT: service-workers/service-worker/resources/fetch-event-test-worker.js @@ -247,11 +252,16 @@ SET TIMEOUT: webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/me SET TIMEOUT: webauthn/*timeout.https.html SET TIMEOUT: webdriver/* SET TIMEOUT: webmessaging/* +SET TIMEOUT: webrtc-encoded-transform/script-metadata-transform-worker.js +SET TIMEOUT: webrtc-encoded-transform/script-transform-generateKeyFrame.js +SET TIMEOUT: webrtc-encoded-transform/script-transform-sendKeyFrameRequest.js SET TIMEOUT: webstorage/eventTestHarness.js SET TIMEOUT: webvtt/* SET TIMEOUT: workers/* SET TIMEOUT: xhr/resources/init.htm SET TIMEOUT: xhr/resources/xmlhttprequest-timeout.js +SET TIMEOUT: fenced-frame/resolve-to-config-promise.https.html +SET TIMEOUT: credential-management/support/fedcm-iframe.html # generate_tests implementation and sample usage GENERATE_TESTS: resources/test/tests/functional/generate-callback.html @@ -361,7 +371,6 @@ SET TIMEOUT: speculation-rules/prerender/resources/media-autoplay-attribute.html SET TIMEOUT: speculation-rules/prerender/resources/media-play.html SET TIMEOUT: html/browsers/browsing-the-web/back-forward-cache/timers.html SET TIMEOUT: dom/abort/crashtests/timeout-close.html -SET TIMEOUT: common/rendering-utils.js # setTimeout use in reftests SET TIMEOUT: acid/acid3/test.html @@ -427,8 +436,12 @@ TRAILING WHITESPACE: css/css-fonts/support/fonts/gsubtest-lookup3.ufo/features.f SET TIMEOUT: css/compositing/mix-blend-mode/mix-blend-mode-parent-with-3D-transform-and-transition.html SET TIMEOUT: css/compositing/mix-blend-mode/mix-blend-mode-sibling-with-3D-transform-and-transition.html +SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-background-repaint-parent.html +SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-background-repaint.html SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-border-repaint-parent.html SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-border-repaint.html +SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-outline-repaint-parent.html +SET TIMEOUT: css/css-backgrounds/color-mix-currentcolor-outline-repaint.html SET TIMEOUT: css/css-backgrounds/currentcolor-border-repaint-parent.html SET TIMEOUT: css/css-transitions/events-007.html SET TIMEOUT: css/css-transitions/support/generalParallelTest.js @@ -593,7 +606,7 @@ AHEM SYSTEM FONT: acid/acid3/test.html AHEM SYSTEM FONT: resource-timing/font-timestamps.html AHEM SYSTEM FONT: resource-timing/initiator-type/style.html AHEM SYSTEM FONT: resource-timing/resources/iframe-reload-TAO.sub.html -AHEM SYSTEM FONT: html/canvas/element/drawing-text-to-the-canvas/2d.text.measure.fontBoundingBox.ahem.html +AHEM SYSTEM FONT: html/canvas/element/text/2d.text.measure.fontBoundingBox.ahem.html AHEM SYSTEM FONT: css/css-font-loading/fontface-override-descriptors.html AHEM SYSTEM FONT: css/css-font-loading/fontface-size-adjust-descriptor.html AHEM SYSTEM FONT: css/css-font-loading/fontface-size-adjust-descriptor-ref.html @@ -602,7 +615,12 @@ AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-012.html AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-012-ref.html AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-013.html AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-013-ref.html +AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-014.html +AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-014-ref.html +AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-metrics-override.html +AHEM SYSTEM FONT: css/css-fonts/font-size-adjust-metrics-override-ref.html AHEM SYSTEM FONT: css/css-fonts/line-gap-override.html +AHEM SYSTEM FONT: css/css-fonts/parsing/font-size-adjust-computed.html AHEM SYSTEM FONT: html/dom/render-blocking/remove-attr-unblocks-rendering.optional.html AHEM SYSTEM FONT: html/dom/render-blocking/remove-element-unblocks-rendering.optional.html @@ -655,8 +673,8 @@ TESTHARNESS-IN-OTHER-TYPE: svg/svg-in-svg/svg-in-svg-circular-filter-reference-c # Adding the testharnessreport.js script causes the test to never complete. MISSING-TESTHARNESSREPORT: accessibility/crashtests/computed-node-checked.html -PRINT STATEMENT: webdriver/tests/print/* PRINT STATEMENT: webdriver/tests/bidi/browsing_context/print/* +PRINT STATEMENT: webdriver/tests/classic/print/* PRINT STATEMENT: webdriver/tests/support/fixtures_bidi.py DUPLICATE-BASENAME-PATH: acid/acid3/empty.html @@ -669,6 +687,10 @@ DUPLICATE-BASENAME-PATH: svg/struct/reftests/reference/green-100x100.svg SET TIMEOUT: mediacapture-insertable-streams/MediaStreamTrackProcessor-video.https.html +# This is a subresource which cannot use step_timeout without becoming a test +# itself. See https://github.com/web-platform-tests/wpt/issues/16933 +SET TIMEOUT: scroll-to-text-fragment/iframe-target.html + # Ported crashtests from Mozilla SET TIMEOUT: editing/crashtests/backcolor-in-nested-editing-host-td-from-DOMAttrModified.html SET TIMEOUT: editing/crashtests/contenteditable-will-be-blurred-by-focus-event-listener.html diff --git a/test/wpt/tests/resources/chromium/webusb-test.js b/test/wpt/tests/resources/chromium/webusb-test.js index 94ff1bcadd9..7cca63d9196 100644 --- a/test/wpt/tests/resources/chromium/webusb-test.js +++ b/test/wpt/tests/resources/chromium/webusb-test.js @@ -440,11 +440,11 @@ class FakeWebUsbService { } } - getPermission(deviceFilters) { + getPermission(options) { return new Promise(resolve => { if (navigator.usb.test.onrequestdevice) { navigator.usb.test.onrequestdevice( - new USBDeviceRequestEvent(deviceFilters, resolve)); + new USBDeviceRequestEvent(options, resolve)); } else { resolve({ result: null }); } @@ -457,8 +457,9 @@ class FakeWebUsbService { } class USBDeviceRequestEvent { - constructor(deviceFilters, resolve) { - this.filters = convertMojoDeviceFilters(deviceFilters); + constructor(options, resolve) { + this.filters = convertMojoDeviceFilters(options.filters); + this.exclusionFilters = convertMojoDeviceFilters(options.exclusionFilters); this.resolveFunc_ = resolve; } diff --git a/test/wpt/tests/resources/chromium/webxr-test.js b/test/wpt/tests/resources/chromium/webxr-test.js index ab2c6faa0ee..c5eb1bd14b8 100644 --- a/test/wpt/tests/resources/chromium/webxr-test.js +++ b/test/wpt/tests/resources/chromium/webxr-test.js @@ -985,8 +985,6 @@ class MockRuntime { environmentProviderRequest.handle); } - setInputSourceButtonListener(listener) { listener.$.close(); } - // XREnvironmentIntegrationProvider implementation: subscribeToHitTest(nativeOriginInformation, entityTypes, ray) { if (!this.supportedModes_.includes(xrSessionMojom.XRSessionMode.kImmersiveAr)) { @@ -1212,7 +1210,6 @@ class MockRuntime { clientReceiver: clientReceiver, enabledFeatures: enabled_features, deviceConfig: { - usesInputEventing: false, defaultFramebufferScale: this.defaultFramebufferScale_, supportsViewportScaling: true, depthConfiguration: diff --git a/test/wpt/tests/resources/idlharness.js b/test/wpt/tests/resources/idlharness.js index 46aa11e5ca1..8f741b09b26 100644 --- a/test/wpt/tests/resources/idlharness.js +++ b/test/wpt/tests/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/wpt/tests/resources/test/tests/functional/assert-throws-dom.html b/test/wpt/tests/resources/test/tests/functional/assert-throws-dom.html new file mode 100644 index 00000000000..4dd66b2372a --- /dev/null +++ b/test/wpt/tests/resources/test/tests/functional/assert-throws-dom.html @@ -0,0 +1,55 @@ + +assert_throws_dom + + +
+ + + diff --git a/test/wpt/tests/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html b/test/wpt/tests/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html index 05e6e0b1e06..f635768c69f 100644 --- a/test/wpt/tests/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html +++ b/test/wpt/tests/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html @@ -3,7 +3,6 @@ - idlharness: Partial dictionary diff --git a/test/wpt/tests/resources/test/tests/functional/idlharness/IdlInterface/test_partial_interface_of.html b/test/wpt/tests/resources/test/tests/functional/idlharness/IdlInterface/test_partial_interface_of.html index 671196cc5df..7dd9e676af4 100644 --- a/test/wpt/tests/resources/test/tests/functional/idlharness/IdlInterface/test_partial_interface_of.html +++ b/test/wpt/tests/resources/test/tests/functional/idlharness/IdlInterface/test_partial_interface_of.html @@ -3,7 +3,6 @@ - idlharness: Partial interface diff --git a/test/wpt/tests/resources/test/tox.ini b/test/wpt/tests/resources/test/tox.ini index 4fbeb67fb52..12013a1a705 100644 --- a/test/wpt/tests/resources/test/tox.ini +++ b/test/wpt/tests/resources/test/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py37,py38,py39,py310 +envlist = py37,py38,py39,py310,py311 skipsdist=True [testenv] diff --git a/test/wpt/tests/resources/testdriver.js b/test/wpt/tests/resources/testdriver.js index 446b033b0a4..a23d6eaf4cf 100644 --- a/test/wpt/tests/resources/testdriver.js +++ b/test/wpt/tests/resources/testdriver.js @@ -296,12 +296,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); }, @@ -334,9 +328,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); @@ -349,8 +343,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. @@ -680,6 +674,134 @@ 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); + }, + + /** + * 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); + } }; window.test_driver_internal = { @@ -805,5 +927,32 @@ throw new Error("set_spc_transaction_mode() is not implemented by testdriver-vendor.js"); }, + async cancel_fedcm_dialog(context=null) { + throw new Error("cancel_fedcm_dialog() 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"); + } }; })(); diff --git a/test/wpt/tests/resources/testharness.js b/test/wpt/tests/resources/testharness.js index 112790bb1ee..413993089be 100644 --- a/test/wpt/tests/resources/testharness.js +++ b/test/wpt/tests/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); } } } @@ -3673,8 +3677,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/wpt/tests/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html b/test/wpt/tests/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html new file mode 100644 index 00000000000..7e2a604621d --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html @@ -0,0 +1,44 @@ + + + + + + + + + + diff --git a/test/wpt/tests/service-workers/service-worker/controlled-iframe-postMessage.https.html b/test/wpt/tests/service-workers/service-worker/controlled-iframe-postMessage.https.html new file mode 100644 index 00000000000..8f39b7fdbf8 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/controlled-iframe-postMessage.https.html @@ -0,0 +1,67 @@ + + + + + + + + + + diff --git a/test/wpt/tests/service-workers/service-worker/detached-context.https.html b/test/wpt/tests/service-workers/service-worker/detached-context.https.html index 747a953f620..ce8e4cc8400 100644 --- a/test/wpt/tests/service-workers/service-worker/detached-context.https.html +++ b/test/wpt/tests/service-workers/service-worker/detached-context.https.html @@ -119,23 +119,6 @@ } assert_not_equals(get_navigator().serviceWorker, null); iframe.remove(); - assert_throws_js(TypeError, () => get_navigator()); - }, 'accessing navigator on a removed frame'); - -// It seems weird that about:blank and blank.html (the test above) have -// different behavior. These expectations are based on Chromium behavior, which -// might not be right. -test(t => { - const iframe = document.createElement('iframe'); - iframe.src = 'about:blank'; - document.body.appendChild(iframe); - const f = iframe.contentWindow.Function; - function get_navigator() { - return f('return navigator')(); - } assert_not_equals(get_navigator().serviceWorker, null); - iframe.remove(); - assert_equals(get_navigator().serviceWorker, null); - }, 'accessing navigator.serviceWorker on a removed about:blank frame'); - + }, 'accessing navigator on a removed frame'); diff --git a/test/wpt/tests/service-workers/service-worker/fetch-error.https.html b/test/wpt/tests/service-workers/service-worker/fetch-error.https.html index ca2f884a9b3..e9fdf574312 100644 --- a/test/wpt/tests/service-workers/service-worker/fetch-error.https.html +++ b/test/wpt/tests/service-workers/service-worker/fetch-error.https.html @@ -21,12 +21,8 @@ const iframe = await with_iframe(scope); test.add_cleanup(() => iframe.remove()); const response = await iframe.contentWindow.fetch("fetch-error-test"); - try { - await response.text(); - assert_unreached(); - } catch (error) { - assert_true(error.message.includes("Sorry")); - } + return promise_rejects_js(test, iframe.contentWindow.TypeError, + response.text(), 'text() should reject'); }, "Make sure a load that makes progress does not time out"); diff --git a/test/wpt/tests/service-workers/service-worker/navigation-redirect.https.html b/test/wpt/tests/service-workers/service-worker/navigation-redirect.https.html index d7d3d5259a4..a87de569316 100644 --- a/test/wpt/tests/service-workers/service-worker/navigation-redirect.https.html +++ b/test/wpt/tests/service-workers/service-worker/navigation-redirect.https.html @@ -1,8 +1,8 @@ Service Worker: Navigation redirection - - + + diff --git a/test/wpt/tests/service-workers/service-worker/navigation-timing.https.html b/test/wpt/tests/service-workers/service-worker/navigation-timing.https.html index 6b51a5c2da2..75cab40458c 100644 --- a/test/wpt/tests/service-workers/service-worker/navigation-timing.https.html +++ b/test/wpt/tests/service-workers/service-worker/navigation-timing.https.html @@ -54,6 +54,7 @@ t.add_cleanup(() => frame.remove()); const timing = await navigate_in_frame(frame, scope); + assert_greater_than(timing.workerStart, 0); verify(timing); }, 'Service worker controlled navigation timing network fallback'); diff --git a/test/wpt/tests/service-workers/service-worker/partitioned-cookies.tentative.https.html b/test/wpt/tests/service-workers/service-worker/partitioned-cookies.tentative.https.html index 6744edc0eac..5f6371cb428 100644 --- a/test/wpt/tests/service-workers/service-worker/partitioned-cookies.tentative.https.html +++ b/test/wpt/tests/service-workers/service-worker/partitioned-cookies.tentative.https.html @@ -23,6 +23,14 @@ const scope = './resources/partitioned-cookies-' const absolute_scope = new URL(scope, window.location).href; + // Set a Partitioned cookie. + document.cookie = '__Host-partitioned=123; Secure; Path=/; SameSite=None; Partitioned;'; + assert_true(document.cookie.includes('__Host-partitioned=123')); + + // Set an unpartitioned cookie. + document.cookie = 'unpartitioned=456; Secure; Path=/; SameSite=None;'; + assert_true(document.cookie.includes('unpartitioned=456')); + const reg = await service_worker_unregister_and_register(t, script, scope); await wait_for_state(t, reg.installing, 'activated'); t.add_cleanup(() => reg.unregister()); @@ -55,11 +63,36 @@ await wait_promise; assert_true(got.ok, 'Message passing'); - // Set a Partitioned cookie. - document.cookie = '__Host-partitioned=123; Secure; Path=/; SameSite=None; Partitioned;'; - assert_true(document.cookie.includes('__Host-partitioned=123')); + // Test that the partitioned cookie is available to this worker via HTTP. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({type: 'echo_cookies_http'}); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_true(got.cookies.includes('__Host-partitioned'), 'Can access partitioned cookie via HTTP'); + assert_true(got.cookies.includes('unpartitioned'), 'Can access unpartitioned cookie via HTTP'); + + // Test that the partitioned cookie is available to this worker via CookieStore API. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({type: 'echo_cookies_js'}); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_true(got.cookies.includes('__Host-partitioned'), 'Can access partitioned cookie via JS'); + assert_true(got.cookies.includes('unpartitioned'), 'Can access unpartitioned cookie via JS'); - // Test that the partitioned cookie is available to this worker. + // Test that the partitioned cookie is not available to this worker in HTTP + // requests from importScripts. wait_promise = new Promise(resolve => { resolve_wait_promise = resolve; }); @@ -67,10 +100,11 @@ got = ev.data; resolve_wait_promise(); }; - filtered_registrations[0].active.postMessage({type: 'echo_cookies'}); + filtered_registrations[0].active.postMessage({type: 'echo_cookies_import'}); await wait_promise; assert_true(got.ok, 'Get cookies'); - assert_true(got.cookies.includes('__Host-partitioned'), 'Can access partitioned cookie'); + assert_true(got.cookies.includes('__Host-partitioned'), 'Can access partitioned cookie via importScripts'); + assert_true(got.cookies.includes('unpartitioned'), 'Can access unpartitioned cookie via importScripts'); const popup = window.open( new URL( @@ -82,4 +116,4 @@ - \ No newline at end of file + diff --git a/test/wpt/tests/service-workers/service-worker/postMessage-client-worker.js b/test/wpt/tests/service-workers/service-worker/postMessage-client-worker.js new file mode 100644 index 00000000000..64d944d2b54 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/postMessage-client-worker.js @@ -0,0 +1,23 @@ +async function doTest(e) +{ + if (e.resultingClientId) { + const promise = new Promise(async resolve => { + let counter = 0; + const client = await self.clients.get(e.resultingClientId); + if (client) + client.postMessage(counter++); + if (e.request.url.includes("repeatMessage")) { + setInterval(() => { + if (client) + client.postMessage(counter++); + }, 100); + } + setTimeout(() => { + resolve(fetch(e.request)); + }, 1000); + }); + e.respondWith(promise); + } +} + +self.addEventListener("fetch", e => e.waitUntil(doTest(e))); diff --git a/test/wpt/tests/service-workers/service-worker/resource-timing.sub.https.html b/test/wpt/tests/service-workers/service-worker/resource-timing.sub.https.html index 9808ae5ae1b..e8328f3597b 100644 --- a/test/wpt/tests/service-workers/service-worker/resource-timing.sub.https.html +++ b/test/wpt/tests/service-workers/service-worker/resource-timing.sub.https.html @@ -114,9 +114,9 @@ }); verify({ performance: performance, - resource: 'resources/missing.jpg', + resource: 'resources/missing.asis', // ORB-compatible 404 response. mode: 'cross-origin', - description: 'Network fallback cross-origin load failure', + description: 'Network fallback cross-origin load failure (404 response)', }); // Tests for respondWith(fetch()). verify({ diff --git a/test/wpt/tests/service-workers/service-worker/resources/controlled-frame-postMessage.html b/test/wpt/tests/service-workers/service-worker/resources/controlled-frame-postMessage.html new file mode 100644 index 00000000000..c4428e88a3d --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/controlled-frame-postMessage.html @@ -0,0 +1,39 @@ + + + + + diff --git a/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-late-postMessage.js b/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-late-postMessage.js new file mode 100644 index 00000000000..41d2db43b1f --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-late-postMessage.js @@ -0,0 +1,6 @@ +setTimeout(() => { + navigator.serviceWorker.onmessage = e => self.postMessage(e.data); +}, 500); +setTimeout(() => { + self.postMessage("No message received"); +}, 5000); diff --git a/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-postMessage.js b/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-postMessage.js new file mode 100644 index 00000000000..628dc65db11 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/controlled-worker-postMessage.js @@ -0,0 +1,4 @@ +navigator.serviceWorker.onmessage = e => self.postMessage(e.data); +setTimeout(() => { + self.postMessage("No message received"); +}, 5000); diff --git a/test/wpt/tests/service-workers/service-worker/resources/fetch-access-control.py b/test/wpt/tests/service-workers/service-worker/resources/fetch-access-control.py index 446af87b249..380a7d62225 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/fetch-access-control.py +++ b/test/wpt/tests/service-workers/service-worker/resources/fetch-access-control.py @@ -35,8 +35,13 @@ def main(request, response): return headers, body if b"VIDEO" in request.GET: - headers.append((b"Content-Type", b"video/ogg")) - body = open(os.path.join(request.doc_root, u"media", u"movie_5.ogv"), "rb").read() + if b"mp4" in request.GET: + headers.append((b"Content-Type", b"video/mp4")) + body = open(os.path.join(request.doc_root, u"media", u"movie_5.mp4"), "rb").read() + else: + headers.append((b"Content-Type", b"video/ogg")) + body = open(os.path.join(request.doc_root, u"media", u"movie_5.ogv"), "rb").read() + length = len(body) # If "PartialContent" is specified, the requestor wants to test range # requests. For the initial request, respond with "206 Partial Content" diff --git a/test/wpt/tests/service-workers/service-worker/resources/missing.asis b/test/wpt/tests/service-workers/service-worker/resources/missing.asis new file mode 100644 index 00000000000..4846fe01d61 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/resources/missing.asis @@ -0,0 +1,4 @@ +HTTP/1.1 404 Not Found +Content-Type: text/javascript + +alert("hello"); diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html index ff24bf3670c..25ddf601457 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-credentialless-frame.html @@ -21,6 +21,9 @@ document.cookie = '__Host-partitioned=123; Secure; Path=/; SameSite=None; Partitioned;'; assert_true(document.cookie.includes('__Host-partitioned=123')); + // Make sure DOM cannot access the unpartitioned cookie. + assert_false(document.cookie.includes('unpartitioned=456')); + const reg = await service_worker_unregister_and_register(t, script, scope); await wait_for_state(t, reg.installing, 'activated'); @@ -50,7 +53,44 @@ await wait_promise; assert_true(got.ok, 'Message passing'); - // Test that the partitioned cookie is available to this worker. + // Test that the partitioned cookie is available to this worker via CookieStore API. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({type: 'echo_cookies_js'}); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_true( + got.cookies.includes('__Host-partitioned'), + 'Credentialless frame worker can access partitioned cookie via JS'); + assert_false( + got.cookies.includes('unpartitioned'), + 'Credentialless frame worker cannot access unpartitioned cookie via JS'); + + // Test that the partitioned cookie is available to this worker via HTTP. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({ type: 'echo_cookies_http' }); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_true( + got.cookies.includes('__Host-partitioned'), + 'Credentialless frame worker can access partitioned cookie via HTTP'); + assert_false( + got.cookies.includes('unpartitioned'), + 'Credentialless frame worker cannot access unpartitioned cookie via HTTP'); + + // Test that the partitioned cookie is not available to this worker in HTTP + // requests from importScripts. wait_promise = new Promise(resolve => { resolve_wait_promise = resolve; }); @@ -58,12 +98,17 @@ got = ev.data; resolve_wait_promise(); }; - filtered_registrations[0].active.postMessage({type: 'echo_cookies'}); + filtered_registrations[0].active.postMessage({ type: 'echo_cookies_import' }); await wait_promise; assert_true(got.ok, 'Get cookies'); - assert_true(got.cookies.includes('__Host-partitioned'), 'Can access partitioned cookie');; + assert_true( + got.cookies.includes('__Host-partitioned'), + 'Credentialless frame worker can access partitioned cookie via importScripts'); + assert_false( + got.cookies.includes('unpartitioned'), + 'Credentialless frame worker cannot access unpartitioned cookie via importScripts'); }); - \ No newline at end of file + diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html index d3962d2e600..00b3412c41f 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-frame.html @@ -16,6 +16,7 @@ const absolute_scope = new URL(scope, window.location).href; assert_false(document.cookie.includes('__Host-partitioned=123'), 'DOM cannot access partitioned cookie'); + assert_true(document.cookie.includes('unpartitioned=456'), 'DOM can access unpartitioned cookie'); const reg = await service_worker_unregister_and_register(t, script, scope); await wait_for_state(t, reg.installing, 'activated'); @@ -46,7 +47,7 @@ await wait_promise; assert_true(got.ok, 'Message passing'); - // Test that the partitioned cookie is not available to this worker. + // Test that the partitioned cookie is not available to this worker via HTTP. wait_promise = new Promise(resolve => { resolve_wait_promise = resolve; }); @@ -54,14 +55,54 @@ got = ev.data; resolve_wait_promise(); }; - filtered_registrations[0].active.postMessage({type: 'echo_cookies'}); + filtered_registrations[0].active.postMessage({type: 'echo_cookies_http'}); await wait_promise; assert_true(got.ok, 'Get cookies'); assert_false( got.cookies.includes('__Host-partitioned'), - 'Worker cannot access partitioned cookie'); + 'Worker cannot access partitioned cookie via HTTP'); + assert_true( + got.cookies.includes('unpartitioned'), + 'Worker can access unpartitioned cookie via HTTP'); + + // Test that the partitioned cookie is not available to this worker via CookieStore API. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({type: 'echo_cookies_js'}); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_false( + got.cookies.includes('__Host-partitioned'), + 'Worker cannot access partitioned cookie via JS'); + assert_true( + got.cookies.includes('unpartitioned'), + 'Worker can access unpartitioned cookie via JS'); + + // Test that the partitioned cookie is not available to this worker in HTTP + // requests from importScripts. + wait_promise = new Promise(resolve => { + resolve_wait_promise = resolve; + }); + on_message = ev => { + got = ev.data; + resolve_wait_promise(); + }; + filtered_registrations[0].active.postMessage({type: 'echo_cookies_import'}); + await wait_promise; + assert_true(got.ok, 'Get cookies'); + assert_false( + got.cookies.includes('__Host-partitioned'), + 'Worker cannot access partitioned cookie via importScripts'); + assert_true( + got.cookies.includes('unpartitioned'), + 'Worker can access unpartitioned cookie via importScripts'); }); - \ No newline at end of file + diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js index 2f54a984b19..767dbf44327 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-sw.js @@ -6,8 +6,12 @@ async function onMessage(event) { switch (event.data.type) { case 'test_message': return onTestMessage(event); - case 'echo_cookies': - return onEchoCookies(event); + case 'echo_cookies_http': + return onEchoCookiesHttp(event); + case 'echo_cookies_js': + return onEchoCookiesJs(event); + case 'echo_cookies_import': + return onEchoCookiesImport(event); default: return; } @@ -18,8 +22,19 @@ async function onTestMessage(event) { event.source.postMessage({ok: true}); } +async function onEchoCookiesHttp(event) { + try { + const resp = await fetch( + `${self.origin}/cookies/resources/list.py`, {credentials: 'include'}); + const cookies = await resp.json(); + event.source.postMessage({ok: true, cookies: Object.keys(cookies)}); + } catch (err) { + event.source.postMessage({ok: false}); + } +} + // echo_cookies returns the names of all of the cookies available to the worker. -async function onEchoCookies(event) { +async function onEchoCookiesJs(event) { try { const cookie_objects = await self.cookieStore.getAll(); const cookies = cookie_objects.map(c => c.name); @@ -28,3 +43,11 @@ async function onEchoCookies(event) { event.source.postMessage({ok: false}); } } + +// Sets `self._cookies` variable, array of the names of cookies available to +// the request. +importScripts(`${self.origin}/cookies/resources/list-cookies-for-script.py`); + +function onEchoCookiesImport(event) { + event.source.postMessage({ok: true, cookies: self._cookies}); +} diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html index 8e90609da22..40d38b3f79f 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-3p-window.html @@ -19,7 +19,7 @@ './partitioned-cookies-3p-frame.html', first_party_origin + location.pathname).href; document.body.appendChild(iframe); - fetch_tests_from_window(iframe.contentWindow); + await fetch_tests_from_window(iframe.contentWindow); const credentialless_frame = document.createElement('iframe'); credentialless_frame.credentialless = true; @@ -27,7 +27,7 @@ './partitioned-cookies-3p-credentialless-frame.html', first_party_origin + location.pathname).href; document.body.appendChild(credentialless_frame); - fetch_tests_from_window(credentialless_frame.contentWindow); + await fetch_tests_from_window(credentialless_frame.contentWindow); }); diff --git a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js index 2f54a984b19..767dbf44327 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js +++ b/test/wpt/tests/service-workers/service-worker/resources/partitioned-cookies-sw.js @@ -6,8 +6,12 @@ async function onMessage(event) { switch (event.data.type) { case 'test_message': return onTestMessage(event); - case 'echo_cookies': - return onEchoCookies(event); + case 'echo_cookies_http': + return onEchoCookiesHttp(event); + case 'echo_cookies_js': + return onEchoCookiesJs(event); + case 'echo_cookies_import': + return onEchoCookiesImport(event); default: return; } @@ -18,8 +22,19 @@ async function onTestMessage(event) { event.source.postMessage({ok: true}); } +async function onEchoCookiesHttp(event) { + try { + const resp = await fetch( + `${self.origin}/cookies/resources/list.py`, {credentials: 'include'}); + const cookies = await resp.json(); + event.source.postMessage({ok: true, cookies: Object.keys(cookies)}); + } catch (err) { + event.source.postMessage({ok: false}); + } +} + // echo_cookies returns the names of all of the cookies available to the worker. -async function onEchoCookies(event) { +async function onEchoCookiesJs(event) { try { const cookie_objects = await self.cookieStore.getAll(); const cookies = cookie_objects.map(c => c.name); @@ -28,3 +43,11 @@ async function onEchoCookies(event) { event.source.postMessage({ok: false}); } } + +// Sets `self._cookies` variable, array of the names of cookies available to +// the request. +importScripts(`${self.origin}/cookies/resources/list-cookies-for-script.py`); + +function onEchoCookiesImport(event) { + event.source.postMessage({ok: true, cookies: self._cookies}); +} diff --git a/test/wpt/tests/service-workers/service-worker/resources/resource-timing-iframe.sub.html b/test/wpt/tests/service-workers/service-worker/resources/resource-timing-iframe.sub.html index 384c29b536b..ec4c726331d 100644 --- a/test/wpt/tests/service-workers/service-worker/resources/resource-timing-iframe.sub.html +++ b/test/wpt/tests/service-workers/service-worker/resources/resource-timing-iframe.sub.html @@ -5,6 +5,6 @@ - + diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/README.md b/test/wpt/tests/service-workers/service-worker/tentative/static-router/README.md new file mode 100644 index 00000000000..8826b3c7827 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/README.md @@ -0,0 +1,4 @@ +A test stuite for the ServiceWorker Static Routing API. + +WICG proposal: https://github.com/WICG/proposals/issues/102 +Specification PR: https://github.com/w3c/ServiceWorker/pull/1686 diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt new file mode 100644 index 00000000000..f3d9861c137 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt @@ -0,0 +1 @@ +Network diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html new file mode 100644 index 00000000000..0c3e3e78707 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html @@ -0,0 +1,3 @@ + +Simple +Here's a simple html file. diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple.html b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple.html new file mode 100644 index 00000000000..0c3e3e78707 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/simple.html @@ -0,0 +1,3 @@ + +Simple +Here's a simple html file. diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js new file mode 100644 index 00000000000..4655ab5321c --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js @@ -0,0 +1,35 @@ +'use strict'; + +var requests = []; + +self.addEventListener('install', e => { + e.registerRouter([ + { + condition: {urlPattern: '/**/*.txt??*'}, + // Note: "??*" is for allowing arbitrary query strings. + // Upon my experiment, the URLPattern needs two '?'s for specifying + // a coming string as a query. + source: 'network' + }, { + condition: { + urlPattern: '/**/simple-test-for-condition-main-resource.html'}, + source: 'network' + }]); + self.skipWaiting(); +}); + +self.addEventListener('activate', e => { + e.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', function(event) { + requests.push({url: event.request.url, mode: event.request.mode}); + const url = new URL(event.request.url); + const nonce = url.searchParams.get('nonce'); + event.respondWith(new Response(nonce)); +}); + +self.addEventListener('message', function(event) { + event.data.port.postMessage({requests: requests}); + requests = []; +}); diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js new file mode 100644 index 00000000000..64a7f7d24fd --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js @@ -0,0 +1,303 @@ +// Copied from +// service-workers/service-worker/resources/testharness-helpers.js to be used under tentative. + +// Adapter for testharness.js-style tests with Service Workers + +/** + * @param options an object that represents RegistrationOptions except for scope. + * @param options.type a WorkerType. + * @param options.updateViaCache a ServiceWorkerUpdateViaCache. + * @see https://w3c.github.io/ServiceWorker/#dictdef-registrationoptions + */ +function service_worker_unregister_and_register(test, url, scope, options) { + if (!scope || scope.length == 0) + return Promise.reject(new Error('tests must define a scope')); + + if (options && options.scope) + return Promise.reject(new Error('scope must not be passed in options')); + + options = Object.assign({ scope: scope }, options); + return service_worker_unregister(test, scope) + .then(function() { + return navigator.serviceWorker.register(url, options); + }) + .catch(unreached_rejection(test, + 'unregister and register should not fail')); +} + +// This unregisters the registration that precisely matches scope. Use this +// when unregistering by scope. If no registration is found, it just resolves. +function service_worker_unregister(test, scope) { + var absoluteScope = (new URL(scope, window.location).href); + return navigator.serviceWorker.getRegistration(scope) + .then(function(registration) { + if (registration && registration.scope === absoluteScope) + return registration.unregister(); + }) + .catch(unreached_rejection(test, 'unregister should not fail')); +} + +function service_worker_unregister_and_done(test, scope) { + return service_worker_unregister(test, scope) + .then(test.done.bind(test)); +} + +function unreached_fulfillment(test, prefix) { + return test.step_func(function(result) { + var error_prefix = prefix || 'unexpected fulfillment'; + assert_unreached(error_prefix + ': ' + result); + }); +} + +// Rejection-specific helper that provides more details +function unreached_rejection(test, prefix) { + return test.step_func(function(error) { + var reason = error.message || error.name || error; + var error_prefix = prefix || 'unexpected rejection'; + assert_unreached(error_prefix + ': ' + reason); + }); +} + +/** + * Adds an iframe to the document and returns a promise that resolves to the + * iframe when it finishes loading. The caller is responsible for removing the + * iframe later if needed. + * + * @param {string} url + * @returns {HTMLIFrameElement} + */ +function with_iframe(url) { + return new Promise(function(resolve) { + var frame = document.createElement('iframe'); + frame.className = 'test-iframe'; + frame.src = url; + frame.onload = function() { resolve(frame); }; + document.body.appendChild(frame); + }); +} + +function normalizeURL(url) { + return new URL(url, self.location).toString().replace(/#.*$/, ''); +} + +function wait_for_update(test, registration) { + if (!registration || registration.unregister == undefined) { + return Promise.reject(new Error( + 'wait_for_update must be passed a ServiceWorkerRegistration')); + } + + return new Promise(test.step_func(function(resolve) { + var handler = test.step_func(function() { + registration.removeEventListener('updatefound', handler); + resolve(registration.installing); + }); + registration.addEventListener('updatefound', handler); + })); +} + +// Return true if |state_a| is more advanced than |state_b|. +function is_state_advanced(state_a, state_b) { + if (state_b === 'installing') { + switch (state_a) { + case 'installed': + case 'activating': + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'installed') { + switch (state_a) { + case 'activating': + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'activating') { + switch (state_a) { + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'activated') { + switch (state_a) { + case 'redundant': + return true; + } + } + return false; +} + +function wait_for_state(test, worker, state) { + if (!worker || worker.state == undefined) { + return Promise.reject(new Error( + 'wait_for_state needs a ServiceWorker object to be passed.')); + } + if (worker.state === state) + return Promise.resolve(state); + + if (is_state_advanced(worker.state, state)) { + return Promise.reject(new Error( + `Waiting for ${state} but the worker is already ${worker.state}.`)); + } + return new Promise(test.step_func(function(resolve, reject) { + worker.addEventListener('statechange', test.step_func(function() { + if (worker.state === state) + resolve(state); + + if (is_state_advanced(worker.state, state)) { + reject(new Error( + `The state of the worker becomes ${worker.state} while waiting` + + `for ${state}.`)); + } + })); + })); +} + +// Declare a test that runs entirely in the ServiceWorkerGlobalScope. The |url| +// is the service worker script URL. This function: +// - Instantiates a new test with the description specified in |description|. +// The test will succeed if the specified service worker can be successfully +// registered and installed. +// - Creates a new ServiceWorker registration with a scope unique to the current +// document URL. Note that this doesn't allow more than one +// service_worker_test() to be run from the same document. +// - Waits for the new worker to begin installing. +// - Imports tests results from tests running inside the ServiceWorker. +function service_worker_test(url, description) { + // If the document URL is https://example.com/document and the script URL is + // https://example.com/script/worker.js, then the scope would be + // https://example.com/script/scope/document. + var scope = new URL('scope' + window.location.pathname, + new URL(url, window.location)).toString(); + promise_test(function(test) { + return service_worker_unregister_and_register(test, url, scope) + .then(function(registration) { + add_completion_callback(function() { + registration.unregister(); + }); + return wait_for_update(test, registration) + .then(function(worker) { + return fetch_tests_from_worker(worker); + }); + }); + }, description); +} + +function base_path() { + return location.pathname.replace(/\/[^\/]*$/, '/'); +} + +function test_login(test, origin, username, password, cookie) { + return new Promise(function(resolve, reject) { + with_iframe( + origin + base_path() + + 'resources/fetch-access-control-login.html') + .then(test.step_func(function(frame) { + var channel = new MessageChannel(); + channel.port1.onmessage = test.step_func(function() { + frame.remove(); + resolve(); + }); + frame.contentWindow.postMessage( + {username: username, password: password, cookie: cookie}, + origin, [channel.port2]); + })); + }); +} + +function test_websocket(test, frame, url) { + return new Promise(function(resolve, reject) { + var ws = new frame.contentWindow.WebSocket(url, ['echo', 'chat']); + var openCalled = false; + ws.addEventListener('open', test.step_func(function(e) { + assert_equals(ws.readyState, 1, "The WebSocket should be open"); + openCalled = true; + ws.close(); + }), true); + + ws.addEventListener('close', test.step_func(function(e) { + assert_true(openCalled, "The WebSocket should be closed after being opened"); + resolve(); + }), true); + + ws.addEventListener('error', reject); + }); +} + +function login_https(test) { + var host_info = get_host_info(); + return test_login(test, host_info.HTTPS_REMOTE_ORIGIN, + 'username1s', 'password1s', 'cookie1') + .then(function() { + return test_login(test, host_info.HTTPS_ORIGIN, + 'username2s', 'password2s', 'cookie2'); + }); +} + +function websocket(test, frame) { + return test_websocket(test, frame, get_websocket_url()); +} + +function get_websocket_url() { + return 'wss://{{host}}:{{ports[wss][0]}}/echo'; +} + +// The navigator.serviceWorker.register() method guarantees that the newly +// installing worker is available as registration.installing when its promise +// resolves. However some tests test installation using a element where +// it is possible for the installing worker to have already become the waiting +// or active worker. So this method is used to get the newest worker when these +// tests need access to the ServiceWorker itself. +function get_newest_worker(registration) { + if (registration.installing) + return registration.installing; + if (registration.waiting) + return registration.waiting; + if (registration.active) + return registration.active; +} + +function register_using_link(script, options) { + var scope = options.scope; + var link = document.createElement('link'); + link.setAttribute('rel', 'serviceworker'); + link.setAttribute('href', script); + link.setAttribute('scope', scope); + document.getElementsByTagName('head')[0].appendChild(link); + return new Promise(function(resolve, reject) { + link.onload = resolve; + link.onerror = reject; + }) + .then(() => navigator.serviceWorker.getRegistration(scope)); +} + +function with_sandboxed_iframe(url, sandbox) { + return new Promise(function(resolve) { + var frame = document.createElement('iframe'); + frame.sandbox = sandbox; + frame.src = url; + frame.onload = function() { resolve(frame); }; + document.body.appendChild(frame); + }); +} + +// Registers, waits for activation, then unregisters on a sample scope. +// +// This can be used to wait for a period of time needed to register, +// activate, and then unregister a service worker. When checking that +// certain behavior does *NOT* happen, this is preferable to using an +// arbitrary delay. +async function wait_for_activation_on_sample_scope(t, window_or_workerglobalscope) { + const script = '/service-workers/service-worker/resources/empty-worker.js'; + const scope = 'resources/there/is/no/there/there?' + Date.now(); + let registration = await window_or_workerglobalscope.navigator.serviceWorker.register(script, { scope }); + await wait_for_state(t, registration.installing, 'activated'); + await registration.unregister(); +} + diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html b/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html new file mode 100644 index 00000000000..5a55783af57 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html @@ -0,0 +1,58 @@ + + +Static Router: simply skip fetch handler for main resource if pattern matches + + + + + + + diff --git a/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html b/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html new file mode 100644 index 00000000000..721c2797603 --- /dev/null +++ b/test/wpt/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html @@ -0,0 +1,48 @@ + + +Static Router: simply skip fetch handler if pattern matches + + + + + + diff --git a/test/wpt/tests/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js b/test/wpt/tests/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js new file mode 100644 index 00000000000..ba82edb72ec --- /dev/null +++ b/test/wpt/tests/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js @@ -0,0 +1,35 @@ +// META: title=Bucket quota enforcement for indexeddb +// META: script=/storage/buckets/resources/util.js + +promise_test(async t => { + const arraySize = 1e6; + const objectStoreName = "storageManager"; + const dbname = + this.window ? window.location.pathname : 'estimate-worker.https.html'; + + let quota = arraySize / 2; + const bucket = await navigator.storageBuckets.open('idb', {quota}); + + await indexedDbDeleteRequest(bucket.indexedDB, dbname); + + const db = + await indexedDbOpenRequest(t, bucket.indexedDB, dbname, (db_to_upgrade) => { + db_to_upgrade.createObjectStore(objectStoreName); + }); + + const txn = db.transaction(objectStoreName, 'readwrite'); + const buffer = new ArrayBuffer(arraySize); + const view = new Uint8Array(buffer); + + for (let i = 0; i < arraySize; i++) { + view[i] = Math.floor(Math.random() * 255); + } + + const testBlob = new Blob([buffer], {type: 'binary/random'}); + txn.objectStore(objectStoreName).add(testBlob, 1); + + await promise_rejects_dom( + t, 'QuotaExceededError', transactionPromise(txn)); + + db.close(); +}, 'IDB respects bucket quota'); diff --git a/test/wpt/tests/storage/buckets/bucket-storage-policy.tentative.https.any.js b/test/wpt/tests/storage/buckets/bucket-storage-policy.tentative.https.any.js new file mode 100644 index 00000000000..d6dce3675d0 --- /dev/null +++ b/test/wpt/tests/storage/buckets/bucket-storage-policy.tentative.https.any.js @@ -0,0 +1,21 @@ +// META: title=Buckets API: Tests for bucket storage policies. +// META: script=/storage/buckets/resources/util.js +// META: global=window,worker + +'use strict'; + +promise_test(async testCase => { + await prepareForBucketTest(testCase); + + await promise_rejects_js( + testCase, TypeError, + navigator.storageBuckets.open('negative', {quota: -1})); + + await promise_rejects_js( + testCase, TypeError, navigator.storageBuckets.open('zero', {quota: 0})); + + await promise_rejects_js( + testCase, TypeError, + navigator.storageBuckets.open( + 'above_max', {quota: Number.MAX_SAFE_INTEGER + 1})); +}, 'The open promise should reject with a TypeError when quota is requested outside the range of 1 to Number.MAX_SAFE_INTEGER.'); diff --git a/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js b/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js deleted file mode 100644 index a66fd81cd43..00000000000 --- a/test/wpt/tests/storage/buckets/buckets_storage_policy.tentative.https.any.js +++ /dev/null @@ -1,46 +0,0 @@ -// META: title=Buckets API: Tests for bucket storage policies. -// META: script=/storage/buckets/resources/util.js -// META: global=window,worker - -'use strict'; - -promise_test(async testCase => { - await prepareForBucketTest(testCase); - - await promise_rejects_js( - testCase, TypeError, - navigator.storageBuckets.open('negative', {quota: -1})); - - await promise_rejects_js( - testCase, TypeError, navigator.storageBuckets.open('zero', {quota: 0})); - - await promise_rejects_js( - testCase, TypeError, - navigator.storageBuckets.open( - 'above_max', {quota: Number.MAX_SAFE_INTEGER + 1})); -}, 'The open promise should reject with a TypeError when quota is requested outside the range of 1 to Number.MAX_SAFE_INTEGER.'); - - -promise_test(async testCase => { - await prepareForBucketTest(testCase); - - // IndexedDB - { - const quota = 1; - const bucket = await navigator.storageBuckets.open('idb', {quota}); - - const objectStoreName = 'store'; - const db = await indexedDbOpenRequest( - testCase, bucket.indexedDB, 'db', (db_to_upgrade) => { - db_to_upgrade.createObjectStore(objectStoreName); - }); - - const overflowBuffer = new Uint8Array(quota + 1); - - const txn = db.transaction(objectStoreName, 'readwrite'); - txn.objectStore(objectStoreName).add('', overflowBuffer); - - await promise_rejects_dom( - testCase, 'QuotaExceededError', transactionPromise(txn)); - } -}, 'A QuotaExceededError is thrown when a storage API exceeds the quota of the bucket its in.'); diff --git a/test/wpt/tests/storage/storagemanager-persist-persisted-match.https.any.js b/test/wpt/tests/storage/storagemanager-persist-persisted-match.https.any.js new file mode 100644 index 00000000000..edbe67fae2c --- /dev/null +++ b/test/wpt/tests/storage/storagemanager-persist-persisted-match.https.any.js @@ -0,0 +1,9 @@ +// META: title=StorageManager: result of persist() matches result of persisted() + +promise_test(async t => { + var persistResult = await navigator.storage.persist(); + assert_equals(typeof persistResult, 'boolean', persistResult + ' should be boolean'); + var persistedResult = await navigator.storage.persisted(); + assert_equals(typeof persistedResult, 'boolean', persistedResult + ' should be boolean'); + assert_equals(persistResult, persistedResult); +}, 'navigator.storage.persist() resolves to a value that matches navigator.storage.persisted()'); diff --git a/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js b/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js index ccc45f2877d..f6ee5edeaa9 100644 --- a/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js +++ b/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js @@ -24,11 +24,8 @@ promise_test(async t => { // The page should not be eligible for BFCache because of the usage // of WebSocket. await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); - // The `BrowsingInstanceNotSwapped` reason will be added because of the - // sticky feature, and it will be reported as "Internal error". await assertNotRestoredFromBFCache(rc1, [ 'WebSocketSticky', - 'MainResourceHasCacheControlNoStore', - 'Internal error' + 'MainResourceHasCacheControlNoStore' ]); }); diff --git a/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js index 563fd4792ef..f37a04af91a 100644 --- a/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js +++ b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js @@ -24,12 +24,9 @@ promise_test(async t => { // The page should not be eligible for BFCache because of the usage // of WebSocket. await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); - // The `BrowsingInstanceNotSwapped` reason will be added because of the - // sticky feature, and it will be reported as "Internal error". await assertNotRestoredFromBFCache(rc1, [ 'WebSocket', 'WebSocketSticky', - 'MainResourceHasCacheControlNoStore', - 'Internal error' + 'MainResourceHasCacheControlNoStore' ]); }); diff --git a/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js index 2baf38f303c..6c48a570101 100644 --- a/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js +++ b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js @@ -17,5 +17,5 @@ promise_test(async t => { await openWebSocket(rc1); // The page should not be eligible for BFCache because of open WebSocket connection. await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); - await assertNotRestoredFromBFCache(rc1, ['WebSocket']); + await assertNotRestoredFromBFCache(rc1, ['websocket']); }); diff --git a/test/wpt/tests/xhr/blob-range.any.js b/test/wpt/tests/xhr/blob-range.any.js new file mode 100644 index 00000000000..2a5c54fc34f --- /dev/null +++ b/test/wpt/tests/xhr/blob-range.any.js @@ -0,0 +1,246 @@ +// See also /fetch/range/blob.any.js + +const supportedBlobRange = [ + { + name: "A simple blob range request.", + data: ["A simple Hello, World! example"], + type: "text/plain", + range: "bytes=9-21", + content_length: 13, + content_range: "bytes 9-21/30", + result: "Hello, World!", + }, + { + name: "A blob range request with no type.", + data: ["A simple Hello, World! example"], + type: undefined, + range: "bytes=9-21", + content_length: 13, + content_range: "bytes 9-21/30", + result: "Hello, World!", + }, + { + name: "A blob range request with no end.", + data: ["Range with no end"], + type: "text/plain", + range: "bytes=11-", + content_length: 6, + content_range: "bytes 11-16/17", + result: "no end", + }, + { + name: "A blob range request with no start.", + data: ["Range with no start"], + type: "text/plain", + range: "bytes=-8", + content_length: 8, + content_range: "bytes 11-18/19", + result: "no start", + }, + { + name: "A simple blob range request with whitespace.", + data: ["A simple Hello, World! example"], + type: "text/plain", + range: "bytes= \t9-21", + content_length: 13, + content_range: "bytes 9-21/30", + result: "Hello, World!", + }, + { + name: "Blob content with short content and a large range end", + data: ["Not much here"], + type: "text/plain", + range: "bytes=4-100000000000", + content_length: 9, + content_range: "bytes 4-12/13", + result: "much here", + }, + { + name: "Blob content with short content and a range end matching content length", + data: ["Not much here"], + type: "text/plain", + range: "bytes=4-13", + content_length: 9, + content_range: "bytes 4-12/13", + result: "much here", + }, + { + name: "Blob range with whitespace before and after hyphen", + data: ["Valid whitespace #1"], + type: "text/plain", + range: "bytes=5 - 10", + content_length: 6, + content_range: "bytes 5-10/19", + result: " white", + }, + { + name: "Blob range with whitespace after hyphen", + data: ["Valid whitespace #2"], + type: "text/plain", + range: "bytes=-\t 5", + content_length: 5, + content_range: "bytes 14-18/19", + result: "ce #2", + }, + { + name: "Blob range with whitespace around equals sign", + data: ["Valid whitespace #3"], + type: "text/plain", + range: "bytes \t =\t 6-", + content_length: 13, + content_range: "bytes 6-18/19", + result: "whitespace #3", + }, +]; + +const unsupportedBlobRange = [ + { + name: "Blob range with no value", + data: ["Blob range should have a value"], + type: "text/plain", + range: "", + }, + { + name: "Blob range with incorrect range header", + data: ["A"], + type: "text/plain", + range: "byte=0-" + }, + { + name: "Blob range with incorrect range header #2", + data: ["A"], + type: "text/plain", + range: "bytes" + }, + { + name: "Blob range with incorrect range header #3", + data: ["A"], + type: "text/plain", + range: "bytes\t \t" + }, + { + name: "Blob range request with multiple range values", + data: ["Multiple ranges are not currently supported"], + type: "text/plain", + range: "bytes=0-5,15-", + }, + { + name: "Blob range request with multiple range values and whitespace", + data: ["Multiple ranges are not currently supported"], + type: "text/plain", + range: "bytes=0-5, 15-", + }, + { + name: "Blob range request with trailing comma", + data: ["Range with invalid trailing comma"], + type: "text/plain", + range: "bytes=0-5,", + }, + { + name: "Blob range with no start or end", + data: ["Range with no start or end"], + type: "text/plain", + range: "bytes=-", + }, + { + name: "Blob range request with short range end", + data: ["Range end should be greater than range start"], + type: "text/plain", + range: "bytes=10-5", + }, + { + name: "Blob range start should be an ASCII digit", + data: ["Range start must be an ASCII digit"], + type: "text/plain", + range: "bytes=x-5", + }, + { + name: "Blob range should have a dash", + data: ["Blob range should have a dash"], + type: "text/plain", + range: "bytes=5", + }, + { + name: "Blob range end should be an ASCII digit", + data: ["Range end must be an ASCII digit"], + type: "text/plain", + range: "bytes=5-x", + }, + { + name: "Blob range should include '-'", + data: ["Range end must include '-'"], + type: "text/plain", + range: "bytes=x", + }, + { + name: "Blob range should include '='", + data: ["Range end must include '='"], + type: "text/plain", + range: "bytes 5-", + }, + { + name: "Blob range should include 'bytes='", + data: ["Range end must include 'bytes='"], + type: "text/plain", + range: "5-", + }, + { + name: "Blob content with short content and a large range start", + data: ["Not much here"], + type: "text/plain", + range: "bytes=100000-", + }, + { + name: "Blob content with short content and a range start matching the content length", + data: ["Not much here"], + type: "text/plain", + range: "bytes=13-", + }, +]; + +supportedBlobRange.forEach(({ name, data, type, range, content_length, content_range, result }) => { + promise_test(async t => { + const blob = new Blob(data, { "type" : type }); + const blobURL = URL.createObjectURL(blob); + t.add_cleanup(() => URL.revokeObjectURL(blobURL)); + const xhr = new XMLHttpRequest(); + xhr.open("GET", blobURL); + xhr.responseType = "text"; + xhr.setRequestHeader("Range", range); + await new Promise(resolve => { + xhr.onloadend = resolve; + xhr.send(); + }); + assert_equals(xhr.status, 206, "HTTP status is 206"); + assert_equals(xhr.getResponseHeader("Content-Type"), type || "", "Content-Type is " + xhr.getResponseHeader("Content-Type")); + assert_equals(xhr.getResponseHeader("Content-Length"), content_length.toString(), "Content-Length is " + xhr.getResponseHeader("Content-Length")); + assert_equals(xhr.getResponseHeader("Content-Range"), content_range, "Content-Range is " + xhr.getResponseHeader("Content-Range")); + assert_equals(xhr.responseText, result, "Response's body is correct"); + const all = xhr.getAllResponseHeaders().toLowerCase(); + assert_true(all.includes(`content-type: ${type || ""}`), "Expected Content-Type in getAllResponseHeaders()"); + assert_true(all.includes(`content-length: ${content_length}`), "Expected Content-Length in getAllResponseHeaders()"); + assert_true(all.includes(`content-range: ${content_range}`), "Expected Content-Range in getAllResponseHeaders()") + }, name); +}); + +unsupportedBlobRange.forEach(({ name, data, type, range }) => { + promise_test(t => { + const blob = new Blob(data, { "type" : type }); + const blobURL = URL.createObjectURL(blob); + t.add_cleanup(() => URL.revokeObjectURL(blobURL)); + + const xhr = new XMLHttpRequest(); + xhr.open("GET", blobURL, false); + xhr.setRequestHeader("Range", range); + assert_throws_dom("NetworkError", () => xhr.send()); + + xhr.open("GET", blobURL); + xhr.setRequestHeader("Range", range); + xhr.responseType = "text"; + return new Promise((resolve, reject) => { + xhr.onload = reject; + xhr.onerror = resolve; + xhr.send(); + }); + }, name); +}); diff --git a/test/wpt/tests/xhr/responsexml-invalid-type.html b/test/wpt/tests/xhr/responsexml-invalid-type.html new file mode 100644 index 00000000000..57ba462551f --- /dev/null +++ b/test/wpt/tests/xhr/responsexml-invalid-type.html @@ -0,0 +1,21 @@ + + + +XMLHttpRequest: response with an invalid responseXML document + + + + + + + diff --git a/test/wpt/tests/xhr/send-authentication-basic-cors-not-enabled.htm b/test/wpt/tests/xhr/send-authentication-basic-cors-not-enabled.htm index 2e7cbaf0340..41201960cc3 100644 --- a/test/wpt/tests/xhr/send-authentication-basic-cors-not-enabled.htm +++ b/test/wpt/tests/xhr/send-authentication-basic-cors-not-enabled.htm @@ -5,6 +5,7 @@ + @@ -13,10 +14,10 @@ +
+ @@ -16,9 +17,9 @@ var test = async_test(desc) test.step(function() { var client = new XMLHttpRequest(), - urlstart = location.host + location.pathname.replace(/\/[^\/]*$/, '/'), + urlstart = get_host_info().REMOTE_ORIGIN + location.pathname.replace(/\/[^\/]*$/, '/'), user = token() - client.open("GET", location.protocol + "//www1." + urlstart + "resources/" + pathsuffix, false) + client.open("GET", urlstart + "resources/" + pathsuffix, false) client.setRequestHeader("x-user", user) client.setRequestHeader("x-pass", 'pass') client.setRequestHeader("Authorization", "Basic " + btoa(user + ":pass")) diff --git a/test/wpt/tests/xhr/send-network-error-sync-events.sub.htm b/test/wpt/tests/xhr/send-network-error-sync-events.sub.htm index 2266eb36e1e..8011c58bdd1 100644 --- a/test/wpt/tests/xhr/send-network-error-sync-events.sub.htm +++ b/test/wpt/tests/xhr/send-network-error-sync-events.sub.htm @@ -17,7 +17,7 @@ { var xhr = new XMLHttpRequest(); - xhr.open("POST", "http://nonexistent.{{host}}:{{ports[http][0]}}", false); + xhr.open("POST", "http://{{host}}:1", false); // Bad port. assert_throws_dom("NetworkError", function() {