mirror of
https://github.com/servo/servo.git
synced 2025-07-19 13:23:46 +01:00
Update web-platform-tests to revision b7a8b84debb42268ea95a45bdad8f727d1facdf7
This commit is contained in:
parent
ba929208e4
commit
953dbda9a6
215 changed files with 6409 additions and 1644 deletions
File diff suppressed because it is too large
Load diff
|
@ -62,9 +62,6 @@
|
||||||
[Matching font-style: 'italic' should prefer 'italic' over 'oblique 20deg']
|
[Matching font-style: 'italic' should prefer 'italic' over 'oblique 20deg']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'italic' should prefer 'oblique 40deg 50deg' over 'oblique 5deg 10deg']
|
[Matching font-style: 'italic' should prefer 'oblique 40deg 50deg' over 'oblique 5deg 10deg']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -149,9 +146,6 @@
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
[Matching font-style: 'oblique 20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 40deg 50deg' over 'oblique 10deg']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique 20deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
[Matching font-style: 'oblique 20deg' should prefer 'oblique 0deg' over 'oblique -50deg -20deg']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -224,9 +218,6 @@
|
||||||
[Matching font-weight: '500' should prefer '450 460' over '400']
|
[Matching font-weight: '500' should prefer '450 460' over '400']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Matching font-weight: '501' should prefer '501' over '502 510']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg']
|
[Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -326,3 +317,12 @@
|
||||||
[Matching font-style: 'oblique -21deg' should prefer 'oblique -10deg' over 'italic']
|
[Matching font-style: 'oblique -21deg' should prefer 'oblique -10deg' over 'italic']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-weight: '399' should prefer '340 360' over '200 300']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-style: 'oblique 0deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-weight: '501' should prefer '500' over '450 460']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -38,3 +38,6 @@
|
||||||
[Test @font-face matching for weight 500]
|
[Test @font-face matching for weight 500]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Test @font-face matching for weight 400]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -74,18 +74,3 @@
|
||||||
[opacity end]
|
[opacity end]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[height end]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-top-width end]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-left-width end]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-bottom-width end]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-right-width end]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[navigation-unload-same-origin-fragment.html]
|
|
||||||
[Tests that a fragment navigation in the unload handler will not block the initial navigation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_5.html]
|
||||||
|
[Multiple history traversals, last would be aborted]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[name-attribute.window.html]
|
[name-attribute.window.html]
|
||||||
expected: CRASH
|
expected: TIMEOUT
|
||||||
[cross-origin <frame name=>]
|
[cross-origin <frame name=>]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[non-active-document.html]
|
|
||||||
[DOMParser]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[createHTMLDocument]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<template>]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[DOMContentLoaded-defer.html]
|
||||||
|
[The end: DOMContentLoaded and defer scripts]
|
||||||
|
expected: FAIL
|
||||||
|
|
11
tests/wpt/metadata/workers/Worker-custom-event.any.js.ini
Normal file
11
tests/wpt/metadata/workers/Worker-custom-event.any.js.ini
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[Worker-custom-event.any.worker.html]
|
||||||
|
|
||||||
|
[Worker-custom-event.any.sharedworker.html]
|
||||||
|
[Worker-custom-event]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[Worker-custom-event.any.serviceworker.html]
|
||||||
|
[Worker-custom-event]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Worker-replace-event-handler.any.sharedworker.html]
|
||||||
|
[Worker-replace-event-handler]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[Worker-replace-event-handler.any.worker.html]
|
||||||
|
|
||||||
|
[Worker-replace-event-handler.any.serviceworker.html]
|
||||||
|
[Worker-replace-event-handler]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
[WorkerNavigator-hardware-concurrency.any.sharedworker.html]
|
||||||
|
[WorkerNavigator-hardware-concurrency]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[WorkerNavigator-hardware-concurrency.any.worker.html]
|
||||||
|
[Test worker navigator hardware concurrency.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[WorkerNavigator-hardware-concurrency.any.serviceworker.html]
|
||||||
|
[WorkerNavigator-hardware-concurrency]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[005.html]
|
[005.html]
|
||||||
|
expected: ERROR
|
||||||
[dedicated worker in shared worker in dedicated worker]
|
[dedicated worker in shared worker in dedicated worker]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[003.html]
|
[003.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: ERROR
|
||||||
[shared]
|
[shared]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
9
tests/wpt/metadata/xhr/send-data-formdata.any.js.ini
Normal file
9
tests/wpt/metadata/xhr/send-data-formdata.any.js.ini
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[send-data-formdata.any.html]
|
||||||
|
[XMLHttpRequest.send(formdata)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[send-data-formdata.any.worker.html]
|
||||||
|
[XMLHttpRequest.send(formdata)]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -154,7 +154,7 @@ jobs:
|
||||||
- template: tools/ci/azure/install_certs.yml
|
- template: tools/ci/azure/install_certs.yml
|
||||||
- template: tools/ci/azure/update_hosts.yml
|
- template: tools/ci/azure/update_hosts.yml
|
||||||
- template: tools/ci/azure/update_manifest.yml
|
- template: tools/ci/azure/update_manifest.yml
|
||||||
- script: python ./wpt run --yes --no-manifest-update --install-fonts --manifest MANIFEST.json --metadata infrastructure/metadata/ --log-tbpl $(Build.ArtifactStagingDirectory)/edge.tbpl.log --log-tbpl-level info edge_webdriver infrastructure/
|
- script: python ./wpt run --yes --no-manifest-update --install-fonts --manifest MANIFEST.json --metadata infrastructure/metadata/ --webdriver-arg=--verbose --log-tbpl $(Build.ArtifactStagingDirectory)/edge.tbpl.log --log-tbpl-level info edge_webdriver infrastructure/
|
||||||
displayName: 'Run tests (Edge)'
|
displayName: 'Run tests (Edge)'
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
displayName: 'Publish results'
|
displayName: 'Publish results'
|
||||||
|
@ -183,7 +183,7 @@ jobs:
|
||||||
- template: tools/ci/azure/install_certs.yml
|
- template: tools/ci/azure/install_certs.yml
|
||||||
- template: tools/ci/azure/update_hosts.yml
|
- template: tools/ci/azure/update_hosts.yml
|
||||||
- template: tools/ci/azure/update_manifest.yml
|
- template: tools/ci/azure/update_manifest.yml
|
||||||
- script: python ./wpt run --no-manifest-update --no-fail-on-unexpected --install-fonts --test-types reftest testharness --this-chunk $(System.JobPositionInPhase) --total-chunks $(System.TotalJobsInPhase) --chunk-type hash --log-tbpl - --log-tbpl-level info --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json edge_webdriver
|
- script: python ./wpt run --no-manifest-update --no-fail-on-unexpected --install-fonts --webdriver-arg=--verbose --test-types reftest testharness --this-chunk $(System.JobPositionInPhase) --total-chunks $(System.TotalJobsInPhase) --chunk-type hash --log-tbpl - --log-tbpl-level info --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report_$(System.JobPositionInPhase).json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot_$(System.JobPositionInPhase).txt edge_webdriver
|
||||||
displayName: 'Run tests'
|
displayName: 'Run tests'
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
displayName: 'Publish results'
|
displayName: 'Publish results'
|
||||||
|
@ -217,7 +217,7 @@ jobs:
|
||||||
- template: tools/ci/azure/install_safari.yml
|
- template: tools/ci/azure/install_safari.yml
|
||||||
- template: tools/ci/azure/update_hosts.yml
|
- template: tools/ci/azure/update_hosts.yml
|
||||||
- template: tools/ci/azure/update_manifest.yml
|
- template: tools/ci/azure/update_manifest.yml
|
||||||
- script: no_proxy='*' ./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 --channel preview safari
|
- script: no_proxy='*' ./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 --channel preview safari
|
||||||
displayName: 'Run tests'
|
displayName: 'Run tests'
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
displayName: 'Publish results'
|
displayName: 'Publish results'
|
||||||
|
|
|
@ -1,133 +1,51 @@
|
||||||
version: 1
|
version: 1
|
||||||
|
reporting: checks-v1
|
||||||
policy:
|
policy:
|
||||||
pullRequests: public
|
pullRequests: public
|
||||||
tasks:
|
tasks:
|
||||||
$flattenDeep:
|
$let:
|
||||||
- $if: tasks_for == "github-push"
|
event_str: {$json: {$eval: event}}
|
||||||
then:
|
in:
|
||||||
$map:
|
$flattenDeep:
|
||||||
$flatten:
|
- $if: tasks_for == "github-push"
|
||||||
$match: {
|
|
||||||
event.ref == "refs/heads/master": [{name: firefox, channel: nightly}, {name: chrome, channel: dev}],
|
|
||||||
event.ref == "refs/heads/epochs/daily": [{name: firefox, channel: stable}, {name: chrome, channel: stable}],
|
|
||||||
event.ref == "refs/heads/epochs/weekly": [{name: firefox, channel: beta}, {name: chrome, channel: beta}]
|
|
||||||
}
|
|
||||||
each(browser):
|
|
||||||
$map:
|
|
||||||
- [testharness, 1, 15]
|
|
||||||
- [testharness, 2, 15]
|
|
||||||
- [testharness, 3, 15]
|
|
||||||
- [testharness, 4, 15]
|
|
||||||
- [testharness, 5, 15]
|
|
||||||
- [testharness, 6, 15]
|
|
||||||
- [testharness, 7, 15]
|
|
||||||
- [testharness, 8, 15]
|
|
||||||
- [testharness, 9, 15]
|
|
||||||
- [testharness, 10, 15]
|
|
||||||
- [testharness, 11, 15]
|
|
||||||
- [testharness, 12, 15]
|
|
||||||
- [testharness, 13, 15]
|
|
||||||
- [testharness, 14, 15]
|
|
||||||
- [testharness, 15, 15]
|
|
||||||
- [reftest, 1, 10]
|
|
||||||
- [reftest, 2, 10]
|
|
||||||
- [reftest, 3, 10]
|
|
||||||
- [reftest, 4, 10]
|
|
||||||
- [reftest, 5, 10]
|
|
||||||
- [reftest, 6, 10]
|
|
||||||
- [reftest, 7, 10]
|
|
||||||
- [reftest, 8, 10]
|
|
||||||
- [reftest, 9, 10]
|
|
||||||
- [reftest, 10, 10]
|
|
||||||
- [wdspec, 1, 1]
|
|
||||||
each(chunk):
|
|
||||||
taskId: {$eval: 'as_slugid(browser.name + browser.channel + chunk[0] + str(chunk[1]))'}
|
|
||||||
taskGroupId: {$eval: 'as_slugid("task group")'}
|
|
||||||
created: {$fromNow: ''}
|
|
||||||
deadline: {$fromNow: '24 hours'}
|
|
||||||
provisionerId: aws-provisioner-v1
|
|
||||||
workerType:
|
|
||||||
$if: event.repository.full_name == 'web-platform-tests/wpt'
|
|
||||||
then:
|
|
||||||
wpt-docker-worker
|
|
||||||
else:
|
|
||||||
github-worker
|
|
||||||
metadata:
|
|
||||||
name: wpt-${browser.name}-${browser.channel}-${chunk[0]}-${chunk[1]}
|
|
||||||
description: >-
|
|
||||||
A subset of WPT's "${chunk[0]}" tests (chunk number ${chunk[1]}
|
|
||||||
of ${chunk[2]}), run in the ${browser.channel} release of
|
|
||||||
${browser.name}.
|
|
||||||
owner: ${event.pusher.email}
|
|
||||||
source: ${event.repository.url}
|
|
||||||
payload:
|
|
||||||
image: harjgam/web-platform-tests:0.29
|
|
||||||
maxRunTime: 7200
|
|
||||||
artifacts:
|
|
||||||
public/results:
|
|
||||||
path: /home/test/artifacts
|
|
||||||
type: directory
|
|
||||||
command:
|
|
||||||
- /bin/bash
|
|
||||||
- --login
|
|
||||||
- -c
|
|
||||||
- set -ex;
|
|
||||||
~/start.sh
|
|
||||||
${event.repository.url}
|
|
||||||
${event.ref}
|
|
||||||
${event.after}
|
|
||||||
${browser.name}
|
|
||||||
${browser.channel};
|
|
||||||
cd ~/web-platform-tests;
|
|
||||||
./tools/ci/taskcluster-run.py
|
|
||||||
${browser.name}
|
|
||||||
--
|
|
||||||
--channel=${browser.channel}
|
|
||||||
--log-wptreport=../artifacts/wpt_report.json
|
|
||||||
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
|
||||||
--no-fail-on-unexpected
|
|
||||||
--test-type=${chunk[0]}
|
|
||||||
--this-chunk=${chunk[1]}
|
|
||||||
--total-chunks=${chunk[2]};
|
|
||||||
- $if: tasks_for == "github-pull-request"
|
|
||||||
# PR tasks that run the tests in various configurations
|
|
||||||
then:
|
|
||||||
# Taskcluster responds to a number of events issued by the GitHub API
|
|
||||||
# which should not trigger re-validation.
|
|
||||||
$if: event.action in ['opened', 'reopened', 'synchronize']
|
|
||||||
then:
|
then:
|
||||||
$map: [{name: firefox, channel: nightly}, {name: chrome, channel: dev}]
|
$map:
|
||||||
|
$flatten:
|
||||||
|
$match: {
|
||||||
|
event.ref == "refs/heads/master": [{name: firefox, channel: nightly}, {name: chrome, channel: dev}],
|
||||||
|
event.ref == "refs/heads/epochs/daily": [{name: firefox, channel: stable}, {name: chrome, channel: stable}],
|
||||||
|
event.ref == "refs/heads/epochs/weekly": [{name: firefox, channel: beta}, {name: chrome, channel: beta}]
|
||||||
|
}
|
||||||
each(browser):
|
each(browser):
|
||||||
$map:
|
$map:
|
||||||
- name: wpt-${browser.name}-${browser.channel}-stability
|
- [testharness, 1, 15]
|
||||||
checkout: FETCH_HEAD
|
- [testharness, 2, 15]
|
||||||
diff_range: HEAD^
|
- [testharness, 3, 15]
|
||||||
description: >-
|
- [testharness, 4, 15]
|
||||||
Verify that all tests affected by a pull request are stable
|
- [testharness, 5, 15]
|
||||||
when executed in ${browser.name}.
|
- [testharness, 6, 15]
|
||||||
extra_args: '--verify'
|
- [testharness, 7, 15]
|
||||||
- name: wpt-${browser.name}-${browser.channel}-results
|
- [testharness, 8, 15]
|
||||||
checkout: FETCH_HEAD
|
- [testharness, 9, 15]
|
||||||
diff_range: HEAD^
|
- [testharness, 10, 15]
|
||||||
description: >-
|
- [testharness, 11, 15]
|
||||||
Collect results for all tests affected by a pull request in
|
- [testharness, 12, 15]
|
||||||
${browser.name}.
|
- [testharness, 13, 15]
|
||||||
extra_args: >-
|
- [testharness, 14, 15]
|
||||||
--no-fail-on-unexpected
|
- [testharness, 15, 15]
|
||||||
--log-wptreport=../artifacts/wpt_report.json
|
- [reftest, 1, 10]
|
||||||
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
- [reftest, 2, 10]
|
||||||
- name: wpt-${browser.name}-${browser.channel}-results-without-changes
|
- [reftest, 3, 10]
|
||||||
checkout: FETCH_HEAD^
|
- [reftest, 4, 10]
|
||||||
diff_range: FETCH_HEAD
|
- [reftest, 5, 10]
|
||||||
description: >-
|
- [reftest, 6, 10]
|
||||||
Collect results for all tests affected by a pull request in
|
- [reftest, 7, 10]
|
||||||
${browser.name} but without the changes in the PR.
|
- [reftest, 8, 10]
|
||||||
extra_args: >-
|
- [reftest, 9, 10]
|
||||||
--no-fail-on-unexpected
|
- [reftest, 10, 10]
|
||||||
--log-wptreport=../artifacts/wpt_report.json
|
- [wdspec, 1, 1]
|
||||||
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
each(chunk):
|
||||||
each(operation):
|
taskId: {$eval: 'as_slugid(browser.name + browser.channel + chunk[0] + str(chunk[1]))'}
|
||||||
taskId: {$eval: 'as_slugid(operation.name)'}
|
|
||||||
taskGroupId: {$eval: 'as_slugid("task group")'}
|
taskGroupId: {$eval: 'as_slugid("task group")'}
|
||||||
created: {$fromNow: ''}
|
created: {$fromNow: ''}
|
||||||
deadline: {$fromNow: '24 hours'}
|
deadline: {$fromNow: '24 hours'}
|
||||||
|
@ -139,101 +57,273 @@ tasks:
|
||||||
else:
|
else:
|
||||||
github-worker
|
github-worker
|
||||||
metadata:
|
metadata:
|
||||||
name: ${operation.name}
|
name: wpt-${browser.name}-${browser.channel}-${chunk[0]}-${chunk[1]}
|
||||||
description: ${operation.description}
|
description: >-
|
||||||
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
A subset of WPT's "${chunk[0]}" tests (chunk number ${chunk[1]}
|
||||||
|
of ${chunk[2]}), run in the ${browser.channel} release of
|
||||||
|
${browser.name}.
|
||||||
|
owner: ${event.pusher.email}
|
||||||
source: ${event.repository.url}
|
source: ${event.repository.url}
|
||||||
payload:
|
payload:
|
||||||
image: harjgam/web-platform-tests:0.29
|
image: harjgam/web-platform-tests:0.30
|
||||||
maxRunTime: 7200
|
maxRunTime: 7200
|
||||||
artifacts:
|
artifacts:
|
||||||
public/results:
|
public/results:
|
||||||
path: /home/test/artifacts
|
path: /home/test/artifacts
|
||||||
type: directory
|
type: directory
|
||||||
# Fetch the GitHub-provided merge commit (rather than the pull
|
|
||||||
# request branch) so that the tasks simulate the behavior of the
|
|
||||||
# submitted patch after it is merged. Using the merge commit also
|
|
||||||
# simplifies detection of modified files because the first parent
|
|
||||||
# of the merge commit can consistently be used to summarize the
|
|
||||||
# changes.
|
|
||||||
command:
|
command:
|
||||||
- /bin/bash
|
- /bin/bash
|
||||||
- --login
|
- --login
|
||||||
- -c
|
- -c
|
||||||
- set -ex;
|
- set -ex;
|
||||||
|
echo "wpt-${browser.name}-${browser.channel}-${chunk[0]}-${chunk[1]}";
|
||||||
|
export TASK_EVENT='${event_str}';
|
||||||
~/start.sh
|
~/start.sh
|
||||||
${event.repository.clone_url}
|
${event.repository.url}
|
||||||
refs/pull/${event.number}/merge
|
${event.ref}
|
||||||
${operation.checkout}
|
${event.after};
|
||||||
${browser.name}
|
|
||||||
${browser.channel};
|
|
||||||
cd ~/web-platform-tests;
|
cd ~/web-platform-tests;
|
||||||
./tools/ci/taskcluster-run.py
|
./tools/ci/run_tc.py
|
||||||
--commit-range ${operation.diff_range}
|
--oom-killer
|
||||||
|
--hosts
|
||||||
|
--browser=${browser.name}
|
||||||
|
--channel=${browser.channel}
|
||||||
|
--xvfb
|
||||||
|
./tools/ci/taskcluster-run.py
|
||||||
${browser.name}
|
${browser.name}
|
||||||
--
|
--
|
||||||
--channel=${browser.channel}
|
--channel=${browser.channel}
|
||||||
${operation.extra_args};
|
--log-wptreport=../artifacts/wpt_report.json
|
||||||
- $map:
|
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
||||||
- name: lint
|
--no-fail-on-unexpected
|
||||||
description: >-
|
--test-type=${chunk[0]}
|
||||||
Lint for wpt-specific requirements
|
--this-chunk=${chunk[1]}
|
||||||
script: tools/ci/ci_lint.sh
|
--total-chunks=${chunk[2]};
|
||||||
conditions:
|
- $if: tasks_for == "github-pull-request"
|
||||||
push
|
# PR tasks that run the tests in various configurations
|
||||||
pull-request
|
then:
|
||||||
each(operation):
|
# Taskcluster responds to a number of events issued by the GitHub API
|
||||||
# Note: jsone doesn't short-circuit evaluation so all parts of the conditional are evaluated
|
# which should not trigger re-validation.
|
||||||
# Accessing properties using the [] notation allows them to evaluate as null in case they're undefined
|
$if: event.action in ['opened', 'reopened', 'synchronize']
|
||||||
# TODO: Allow running pushes on branches other than master
|
|
||||||
- $if: ("push" in operation.conditions && tasks_for == "github-push" && event['ref'] == "refs/heads/master") || ("pull-request" in operation.conditions && tasks_for == "github-pull-request" && event['action'] in ['opened', 'reopened', 'synchronize'])
|
|
||||||
then:
|
then:
|
||||||
$let:
|
$map: [{name: firefox, channel: nightly}, {name: chrome, channel: dev}]
|
||||||
checkout_ref:
|
each(browser):
|
||||||
$if: tasks_for == "github-push"
|
$map:
|
||||||
then:
|
# This is the main place to define new stability checks
|
||||||
${event.ref}
|
- name: wpt-${browser.name}-${browser.channel}-stability
|
||||||
else:
|
checkout: FETCH_HEAD
|
||||||
refs/pull/${event.number}/merge
|
diff_range: HEAD^
|
||||||
in:
|
description: >-
|
||||||
taskId: {$eval: 'as_slugid(operation.name)'}
|
Verify that all tests affected by a pull request are stable
|
||||||
taskGroupId: {$eval: 'as_slugid("task group")'}
|
when executed in ${browser.name}.
|
||||||
created: {$fromNow: ''}
|
extra_args: '--verify'
|
||||||
deadline: {$fromNow: '24 hours'}
|
- name: wpt-${browser.name}-${browser.channel}-results
|
||||||
provisionerId: aws-provisioner-v1
|
checkout: FETCH_HEAD
|
||||||
workerType:
|
diff_range: HEAD^
|
||||||
$if: event.repository.full_name == 'web-platform-tests/wpt'
|
description: >-
|
||||||
then:
|
Collect results for all tests affected by a pull request in
|
||||||
wpt-docker-worker
|
${browser.name}.
|
||||||
else:
|
extra_args: >-
|
||||||
github-worker
|
--no-fail-on-unexpected
|
||||||
metadata:
|
--log-wptreport=../artifacts/wpt_report.json
|
||||||
name: ${operation.name}
|
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
||||||
description: ${operation.description}
|
- name: wpt-${browser.name}-${browser.channel}-results-without-changes
|
||||||
owner: ${event.sender.login}@users.noreply.github.com
|
checkout: FETCH_HEAD^
|
||||||
source: ${event.repository.url}
|
diff_range: FETCH_HEAD
|
||||||
payload:
|
description: >-
|
||||||
image: harjgam/web-platform-tests:0.29
|
Collect results for all tests affected by a pull request in
|
||||||
maxRunTime: 7200
|
${browser.name} but without the changes in the PR.
|
||||||
artifacts:
|
extra_args: >-
|
||||||
public/results:
|
--no-fail-on-unexpected
|
||||||
path: /home/test/artifacts
|
--log-wptreport=../artifacts/wpt_report.json
|
||||||
type: directory
|
--log-wptscreenshot=../artifacts/wpt_screenshot.txt
|
||||||
# Fetch the GitHub-provided merge commit (rather than the pull
|
each(operation):
|
||||||
# request branch) so that the tasks simulate the behavior of the
|
taskId: {$eval: 'as_slugid(operation.name)'}
|
||||||
# submitted patch after it is merged. Using the merge commit also
|
taskGroupId: {$eval: 'as_slugid("task group")'}
|
||||||
# simplifies detection of modified files because the first parent
|
created: {$fromNow: ''}
|
||||||
# of the merge commit can consistently be used to summarize the
|
deadline: {$fromNow: '24 hours'}
|
||||||
# changes.
|
provisionerId: aws-provisioner-v1
|
||||||
command:
|
workerType:
|
||||||
- /bin/bash
|
$if: event.repository.full_name == 'web-platform-tests/wpt'
|
||||||
- --login
|
then:
|
||||||
- -c
|
wpt-docker-worker
|
||||||
- set -ex;
|
else:
|
||||||
~/start.sh
|
github-worker
|
||||||
${event.repository.clone_url}
|
metadata:
|
||||||
${checkout_ref}
|
name: ${operation.name}
|
||||||
FETCH_HEAD
|
description: ${operation.description}
|
||||||
none;
|
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
||||||
cd ~/web-platform-tests;
|
source: ${event.repository.url}
|
||||||
${operation.script};
|
payload:
|
||||||
|
image: harjgam/web-platform-tests:0.30
|
||||||
|
maxRunTime: 7200
|
||||||
|
artifacts:
|
||||||
|
public/results:
|
||||||
|
path: /home/test/artifacts
|
||||||
|
type: directory
|
||||||
|
# Fetch the GitHub-provided merge commit (rather than the pull
|
||||||
|
# request branch) so that the tasks simulate the behavior of the
|
||||||
|
# submitted patch after it is merged. Using the merge commit also
|
||||||
|
# simplifies detection of modified files because the first parent
|
||||||
|
# of the merge commit can consistently be used to summarize the
|
||||||
|
# changes.
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- --login
|
||||||
|
- -c
|
||||||
|
- set -ex;
|
||||||
|
echo "${operation.name}";
|
||||||
|
export TASK_EVENT='${event_str}';
|
||||||
|
~/start.sh
|
||||||
|
${event.repository.clone_url}
|
||||||
|
refs/pull/${event.number}/merge
|
||||||
|
FETCH_HEAD;
|
||||||
|
cd web-platform-tests;
|
||||||
|
./tools/ci/run_tc.py
|
||||||
|
--checkout=${operation.checkout}
|
||||||
|
--oom-killer
|
||||||
|
--browser=${browser.name}
|
||||||
|
--channel=${browser.channel}
|
||||||
|
--xvfb
|
||||||
|
stability
|
||||||
|
./tools/ci/taskcluster-run.py
|
||||||
|
--commit-range ${operation.diff_range}
|
||||||
|
${browser.name}
|
||||||
|
--
|
||||||
|
--channel=${browser.channel}
|
||||||
|
${operation.extra_args};
|
||||||
|
- $map:
|
||||||
|
# This is the main point to define new CI checks other than stability checks
|
||||||
|
- name: lint
|
||||||
|
description: >-
|
||||||
|
Lint for wpt-specific requirements
|
||||||
|
script: ./tools/ci/run_tc.py --no-hosts lint tools/ci/ci_lint.sh
|
||||||
|
conditions:
|
||||||
|
push
|
||||||
|
pull-request
|
||||||
|
- name: update built tests
|
||||||
|
description: >-
|
||||||
|
Ensure test suites that require a build step are updated
|
||||||
|
script: ./tools/ci/run_tc.py --no-hosts update_built tools/ci/ci_built_diff.sh
|
||||||
|
conditions:
|
||||||
|
pull-request
|
||||||
|
- name: tools/ unittests (Python 2)
|
||||||
|
description: >-
|
||||||
|
Unit tests for tools running under Python 2.7, excluding wptrunner
|
||||||
|
script: >-
|
||||||
|
export TOXENV=py27;
|
||||||
|
export HYPOTHESIS_PROFILE=ci;
|
||||||
|
./tools/ci/run_tc.py \
|
||||||
|
tools_unittest \
|
||||||
|
tools/ci/ci_tools_unittest.sh
|
||||||
|
conditions:
|
||||||
|
push
|
||||||
|
pull-request
|
||||||
|
- name: tools/ unittests (Python 3)
|
||||||
|
description: >-
|
||||||
|
Unit tests for tools running under Python 3, excluding wptrunner
|
||||||
|
script: >-
|
||||||
|
export TOXENV=py36;
|
||||||
|
export HYPOTHESIS_PROFILE=ci;
|
||||||
|
sudo apt install -qqy python3-pip;
|
||||||
|
./tools/ci/run_tc.py \
|
||||||
|
tools_unittest \
|
||||||
|
tools/ci/ci_tools_unittest.sh
|
||||||
|
conditions:
|
||||||
|
push
|
||||||
|
pull-request
|
||||||
|
- name: tools/wpt/ tests
|
||||||
|
description: >-
|
||||||
|
Integration tests for wpt commands
|
||||||
|
script: >-
|
||||||
|
export TOXENV=py27;
|
||||||
|
sudo apt install -qqy libnss3-tools;
|
||||||
|
./tools/ci/run_tc.py \
|
||||||
|
--oom-killer \
|
||||||
|
--browser=firefox \
|
||||||
|
--browser=chrome \
|
||||||
|
--channel=experimental \
|
||||||
|
--xvfb \
|
||||||
|
wpt_integration \
|
||||||
|
tools/ci/ci_wpt.sh
|
||||||
|
conditions:
|
||||||
|
pull-request
|
||||||
|
- name: resources/ tests
|
||||||
|
description: >-
|
||||||
|
Tests for testharness.js and other files in resources/
|
||||||
|
script: >-
|
||||||
|
export TOXENV=py27;
|
||||||
|
./tools/ci/run_tc.py \
|
||||||
|
--browser=firefox \
|
||||||
|
--channel=experimental \
|
||||||
|
--xvfb \
|
||||||
|
resources_unittest \
|
||||||
|
tools/ci/ci_resources_unittest.sh
|
||||||
|
conditions:
|
||||||
|
pull-request
|
||||||
|
- name: infrastructure/ tests
|
||||||
|
description: >-
|
||||||
|
Smoketests for wptrunner
|
||||||
|
script: >-
|
||||||
|
sudo apt install -qqy libnss3-tools libappindicator1 fonts-liberation;
|
||||||
|
./tools/ci/run_tc.py \
|
||||||
|
--oom-killer \
|
||||||
|
--browser=firefox \
|
||||||
|
--browser=chrome \
|
||||||
|
--channel=experimental \
|
||||||
|
--no-hosts \
|
||||||
|
--xvfb \
|
||||||
|
wptrunner_infrastructure \
|
||||||
|
tools/ci/ci_wptrunner_infrastructure.sh
|
||||||
|
conditions:
|
||||||
|
pull-request
|
||||||
|
each(operation):
|
||||||
|
# Note: jsone doesn't short-circuit evaluation so all parts of the conditional are evaluated
|
||||||
|
# Accessing properties using the [] notation allows them to evaluate as null in case they're undefined
|
||||||
|
# TODO: Allow running pushes on branches other than master
|
||||||
|
- $if: ("push" in operation.conditions && tasks_for == "github-push" && event['ref'] == "refs/heads/master") || ("pull-request" in operation.conditions && tasks_for == "github-pull-request" && event['action'] in ['opened', 'reopened', 'synchronize'])
|
||||||
|
then:
|
||||||
|
$let:
|
||||||
|
checkout_ref:
|
||||||
|
$if: tasks_for == "github-push"
|
||||||
|
then:
|
||||||
|
${event.ref}
|
||||||
|
else:
|
||||||
|
refs/pull/${event.number}/merge
|
||||||
|
in:
|
||||||
|
taskId: {$eval: 'as_slugid(operation.name)'}
|
||||||
|
taskGroupId: {$eval: 'as_slugid("task group")'}
|
||||||
|
created: {$fromNow: ''}
|
||||||
|
deadline: {$fromNow: '24 hours'}
|
||||||
|
provisionerId: aws-provisioner-v1
|
||||||
|
workerType:
|
||||||
|
$if: event.repository.full_name == 'web-platform-tests/wpt'
|
||||||
|
then:
|
||||||
|
wpt-docker-worker
|
||||||
|
else:
|
||||||
|
github-worker
|
||||||
|
metadata:
|
||||||
|
name: ${operation.name}
|
||||||
|
description: ${operation.description}
|
||||||
|
owner: ${event.sender.login}@users.noreply.github.com
|
||||||
|
source: ${event.repository.url}
|
||||||
|
payload:
|
||||||
|
image: harjgam/web-platform-tests:0.30
|
||||||
|
maxRunTime: 7200
|
||||||
|
artifacts:
|
||||||
|
public/results:
|
||||||
|
path: /home/test/artifacts
|
||||||
|
type: directory
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- --login
|
||||||
|
- -c
|
||||||
|
- set -ex;
|
||||||
|
echo "${operation.name}";
|
||||||
|
export TASK_EVENT='${event_str}';
|
||||||
|
~/start.sh
|
||||||
|
${event.repository.clone_url}
|
||||||
|
${checkout_ref}
|
||||||
|
FETCH_HEAD;
|
||||||
|
cd ~/web-platform-tests;
|
||||||
|
${operation.script};
|
||||||
|
|
|
@ -28,66 +28,11 @@ matrix:
|
||||||
secure: "EljDx50oNpDLs7rzwIv+z1PxIgB5KMnx1W0OQkpNvltR0rBW9g/aQaE+Z/c8M/sPqN1bkvKPybKzGKjb6j9Dw3/EJhah4SskH78r3yMAe2DU/ngxqqjjfXcCc2t5MKxzHAILTAxqScPj2z+lG1jeK1Z+K5hTbSP9lk+AvS0D16w="
|
secure: "EljDx50oNpDLs7rzwIv+z1PxIgB5KMnx1W0OQkpNvltR0rBW9g/aQaE+Z/c8M/sPqN1bkvKPybKzGKjb6j9Dw3/EJhah4SskH78r3yMAe2DU/ngxqqjjfXcCc2t5MKxzHAILTAxqScPj2z+lG1jeK1Z+K5hTbSP9lk+AvS0D16w="
|
||||||
file: $WPT_MANIFEST_FILE.gz
|
file: $WPT_MANIFEST_FILE.gz
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
- name: "update-built-tests.sh"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "2.7"
|
|
||||||
env: JOB=update_built SCRIPT=tools/ci/ci_built_diff.sh
|
|
||||||
- name: "build-css-testsuites.sh"
|
- name: "build-css-testsuites.sh"
|
||||||
if: type = pull_request
|
if: type = pull_request
|
||||||
os: linux
|
os: linux
|
||||||
python: "2.7"
|
python: "2.7"
|
||||||
env: JOB=build_css SCRIPT=css/build-css-testsuites.sh
|
env: JOB=build_css SCRIPT=css/build-css-testsuites.sh
|
||||||
- name: "tools/ unittests (Python 2)"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "2.7"
|
|
||||||
env: JOB=tools_unittest TOXENV=py27 HYPOTHESIS_PROFILE=ci SCRIPT=tools/ci/ci_tools_unittest.sh
|
|
||||||
- name: "tools/ unittests (Python 3)"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "3.6"
|
|
||||||
env: JOB=tools_unittest TOXENV=py36 HYPOTHESIS_PROFILE=ci SCRIPT=tools/ci/ci_tools_unittest.sh
|
|
||||||
- name: "tools/wpt/ tests"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "2.7"
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- libnss3-tools
|
|
||||||
env: JOB=wpt_integration TOXENV=py27 SCRIPT=tools/ci/ci_wpt.sh
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- fonts-liberation
|
|
||||||
- libappindicator1
|
|
||||||
- libnss3-tools
|
|
||||||
- pulseaudio
|
|
||||||
- name: "resources/ tests"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "2.7"
|
|
||||||
env: JOB=resources_unittest TOXENV=py27 SCRIPT=tools/ci/ci_resources_unittest.sh
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- fonts-liberation
|
|
||||||
- libappindicator1
|
|
||||||
- libnss3-tools
|
|
||||||
- pulseaudio
|
|
||||||
- name: "infrastructure/ tests"
|
|
||||||
if: type = pull_request
|
|
||||||
os: linux
|
|
||||||
python: "2.7"
|
|
||||||
env: JOB=wptrunner_infrastructure SCRIPT=tools/ci/ci_wptrunner_infrastructure.sh
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- fonts-liberation
|
|
||||||
- libappindicator1
|
|
||||||
- libnss3-tools
|
|
||||||
- pulseaudio
|
|
||||||
exclude:
|
exclude:
|
||||||
- env: # exclude empty env from the top-level above
|
- env: # exclude empty env from the top-level above
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
// META: script=support.js
|
||||||
|
|
||||||
|
function cursorRequestTest({ useIndex, useKeyCursor }) {
|
||||||
|
indexeddb_test(
|
||||||
|
(t, db) => {
|
||||||
|
const objStore = db.createObjectStore("my_objectstore");
|
||||||
|
objStore.add("data", 1);
|
||||||
|
objStore.createIndex("my_index", "");
|
||||||
|
},
|
||||||
|
(t, db) => {
|
||||||
|
const tx = db.transaction("my_objectstore");
|
||||||
|
let source = tx.objectStore("my_objectstore");
|
||||||
|
if (useIndex) source = source.index('my_index');
|
||||||
|
const req = useKeyCursor ? source.openKeyCursor() : source.openCursor();
|
||||||
|
let cursor;
|
||||||
|
|
||||||
|
req.onsuccess = t.step_func(() => {
|
||||||
|
cursor = req.result;
|
||||||
|
assert_equals(cursor.request, req, 'cursor.request');
|
||||||
|
assert_readonly(cursor, 'request');
|
||||||
|
});
|
||||||
|
|
||||||
|
req.transaction.oncomplete = t.step_func(() => {
|
||||||
|
setTimeout(t.step_func(() => {
|
||||||
|
assert_equals(cursor.request, req, 'cursor.request after transaction complete');
|
||||||
|
t.done();
|
||||||
|
}), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.transaction.onerror = t.unreached_func('Transaction error');
|
||||||
|
},
|
||||||
|
`cursor.request from ${useIndex ? 'IDBIndex' : 'IDBObjectStore'}.${useKeyCursor ? 'openKeyCursor' : 'openCursor'}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const useIndex of [false, true]) {
|
||||||
|
for (const useKeyCursor of [false, true]) {
|
||||||
|
cursorRequestTest({ useIndex, useKeyCursor });
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>Databases on different origins use separate locking</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/common/get-host-info.sub.js"></script>
|
||||||
|
<script src="support.js"></script>
|
||||||
|
<script src="support-promises.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var host_info = get_host_info();
|
||||||
|
|
||||||
|
promise_test(async testCase => {
|
||||||
|
await deleteAllDatabases(testCase);
|
||||||
|
|
||||||
|
// Create an iframe to open and hold a database on a different origin.
|
||||||
|
var iframe = document.createElement('iframe');
|
||||||
|
var newLocation = window.location.href.replace('www', 'www2');
|
||||||
|
|
||||||
|
const keepalive_watcher = new EventWatcher(testCase, window, 'message');
|
||||||
|
iframe.src = host_info.HTTP_REMOTE_ORIGIN +
|
||||||
|
'/IndexedDB/resources/idbfactory-origin-isolation-iframe.html';
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
|
||||||
|
// Wait until the iframe starts its transaction.
|
||||||
|
var event = await keepalive_watcher.wait_for('message');
|
||||||
|
assert_equals("keep_alive_started", event.data);
|
||||||
|
|
||||||
|
// Create our own database with the same name, and perform a simple get.
|
||||||
|
const db = await createNamedDatabase(
|
||||||
|
testCase, 'db-isolation-test', database => {
|
||||||
|
database.createObjectStore('s');
|
||||||
|
});
|
||||||
|
const tx = db.transaction('s');
|
||||||
|
var request = tx.objectStore('s').get(0);
|
||||||
|
request.onsuccess = testCase.step_func_done();
|
||||||
|
request.onerror = testCase.unreached_func("There should be no errors.");
|
||||||
|
}, "Test to make sure that origins have separate locking schemes");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
|
@ -0,0 +1,50 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>This iframe keeps a transaction on a database alive indefinitely to test</title>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
// Keeps the passed transaction alive indefinitely (by making requests
|
||||||
|
// against the named store). Returns a function that asserts that the
|
||||||
|
// transaction has not already completed and then ends the request loop so that
|
||||||
|
// the transaction may autocommit and complete.
|
||||||
|
function keep_alive(tx, store_name) {
|
||||||
|
let completed = false;
|
||||||
|
tx.addEventListener('complete', () => { completed = true; });
|
||||||
|
|
||||||
|
let keepSpinning = true;
|
||||||
|
|
||||||
|
function spin() {
|
||||||
|
if (!keepSpinning)
|
||||||
|
return;
|
||||||
|
tx.objectStore(store_name).get(0).onsuccess = spin;
|
||||||
|
}
|
||||||
|
spin();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
assert_false(completed, 'Transaction completed while kept alive');
|
||||||
|
keepSpinning = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const dbs_to_delete = await indexedDB.databases();
|
||||||
|
for (const db_info of dbs_to_delete) {
|
||||||
|
let request = indexedDB.deleteDatabase(db_info.name);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
request.onsuccess = resolve;
|
||||||
|
request.onerror = reject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var openRequest = indexedDB.open('db-isolation-test');
|
||||||
|
openRequest.onupgradeneeded = () => {
|
||||||
|
openRequest.result.createObjectStore('s');
|
||||||
|
};
|
||||||
|
openRequest.onsuccess = () => {
|
||||||
|
var tx = openRequest.result.transaction('s');
|
||||||
|
keep_alive(tx, 's');
|
||||||
|
window.parent.postMessage("keep_alive_started", "*");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
</script>
|
|
@ -48,7 +48,7 @@ async function waitForAnimationFrameWithCondition(condition) {
|
||||||
do {
|
do {
|
||||||
await new Promise(window.requestAnimationFrame);
|
await new Promise(window.requestAnimationFrame);
|
||||||
} while (!condition())
|
} while (!condition())
|
||||||
};
|
}
|
||||||
|
|
||||||
async function waitForDocumentTimelineAdvance() {
|
async function waitForDocumentTimelineAdvance() {
|
||||||
const timeAtStart = document.timeline.currentTime;
|
const timeAtStart = document.timeline.currentTime;
|
||||||
|
@ -56,3 +56,10 @@ async function waitForDocumentTimelineAdvance() {
|
||||||
await new Promise(window.requestAnimationFrame);
|
await new Promise(window.requestAnimationFrame);
|
||||||
} while (timeAtStart === document.timeline.currentTime)
|
} while (timeAtStart === document.timeline.currentTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait until animation's effect has a non-null localTime.
|
||||||
|
async function waitForNotNullLocalTime(animation) {
|
||||||
|
await waitForAnimationFrameWithCondition(_ => {
|
||||||
|
return animation.effect.getComputedTiming().localTime !== null;
|
||||||
|
});
|
||||||
|
}
|
|
@ -50,110 +50,98 @@ function setupAndRegisterTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_with_fill_mode_forwards(t) {
|
async function effect_with_fill_mode_forwards(t) {
|
||||||
const effect_with_fill_forwards = new KeyframeEffect(
|
const effect_with_fill_forwards = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 1000, fill: 'forwards' });
|
{ duration: 1000, fill: 'forwards' });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_with_fill_forwards);
|
effect_with_fill_forwards);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
await waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '0');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '0');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_without_fill_mode_forwards(t) {
|
async function effect_without_fill_mode_forwards(t) {
|
||||||
const effect_without_fill_forwards = new KeyframeEffect(
|
const effect_without_fill_forwards = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 1000 });
|
{ duration: 1000 });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_without_fill_forwards);
|
effect_without_fill_forwards);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
await waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '1');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '1');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_without_fill_forwards_at_end(t) {
|
async function effect_without_fill_forwards_at_end(t) {
|
||||||
const effect_without_fill_forwards_at_end = new KeyframeEffect(
|
const effect_without_fill_forwards_at_end = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 2000 });
|
{ duration: 2000 });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_without_fill_forwards_at_end);
|
effect_without_fill_forwards_at_end);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
await waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '1');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '1');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_with_fill_backwards(t) {
|
async function effect_with_fill_backwards(t) {
|
||||||
const effect_with_fill_backwards = new KeyframeEffect(
|
const effect_with_fill_backwards = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 1000, delay: 2001, fill: 'backwards' });
|
{ duration: 1000, delay: 2001, fill: 'backwards' });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_with_fill_backwards);
|
effect_with_fill_backwards);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
await waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '0.5');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '0.5');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_without_fill_backwards(t) {
|
async function effect_without_fill_backwards(t) {
|
||||||
const effect_without_fill_backwards = new KeyframeEffect(
|
const effect_without_fill_backwards = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 1000, delay: 2001 });
|
{ duration: 1000, delay: 2001 });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_without_fill_backwards);
|
effect_without_fill_backwards);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '1');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '1');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function effect_without_fill_backwards_at_start(t) {
|
async function effect_without_fill_backwards_at_start(t) {
|
||||||
const effect_without_fill_backwards_at_start = new KeyframeEffect(
|
const effect_without_fill_backwards_at_start = new KeyframeEffect(
|
||||||
target,
|
target,
|
||||||
{ opacity: [0.5, 0] },
|
{ opacity: [0.5, 0] },
|
||||||
{ duration: 1000, delay: 2000 });
|
{ duration: 1000, delay: 2000 });
|
||||||
const animation = new WorkletAnimation(
|
const animation = new WorkletAnimation(
|
||||||
'constant_time',
|
'constant_time',
|
||||||
effect_without_fill_backwards_at_start);
|
effect_without_fill_backwards_at_start);
|
||||||
animation.play();
|
animation.play();
|
||||||
|
await waitForNotNullLocalTime(animation);
|
||||||
|
|
||||||
await waitForAsyncAnimationFrames(1);
|
assert_equals(getComputedStyle(target).opacity, '0.5');
|
||||||
await waitForNextFrame();
|
|
||||||
|
|
||||||
assert_equals(getComputedStyle(target).opacity, '0.5');
|
animation.cancel();
|
||||||
|
|
||||||
animation.cancel();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<meta charset=utf-8>
|
<meta charset=utf-8>
|
||||||
<title>Clipboard IDL test</title>
|
<title>Clipboard IDL test</title>
|
||||||
<link rel="help" href="https://w3c.github.io/clipboard-apis/">
|
<link rel='help' href='https://w3c.github.io/clipboard-apis/'>
|
||||||
<script src=/resources/testharness.js></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src=/resources/testharnessreport.js></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
<script src=/resources/WebIDLParser.js></script>
|
<script src="/resources/WebIDLParser.js"></script>
|
||||||
<script src=/resources/idlharness.js></script>
|
<script src="/resources/idlharness.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ function fetchText(url) {
|
||||||
promise_test(() => {
|
promise_test(() => {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
[
|
[
|
||||||
"/interfaces/clipboard-apis.idl",
|
'/interfaces/clipboard-apis.idl',
|
||||||
"/interfaces/dom.idl",
|
'/interfaces/dom.idl',
|
||||||
].map(fetchText))
|
].map(fetchText))
|
||||||
.then(([idl, dom]) => doTest(idl, dom));
|
.then(([idl, dom]) => doTest(idl, dom));
|
||||||
}, "Test driver");
|
}, 'Test driver');
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,55 +9,59 @@ test(() => {
|
||||||
assert_not_equals(navigator.clipboard, undefined);
|
assert_not_equals(navigator.clipboard, undefined);
|
||||||
assert_true(navigator.clipboard instanceof Clipboard);
|
assert_true(navigator.clipboard instanceof Clipboard);
|
||||||
assert_equals(navigator.clipboard, navigator.clipboard);
|
assert_equals(navigator.clipboard, navigator.clipboard);
|
||||||
}, "navigator.clipboard exists");
|
}, 'navigator.clipboard exists');
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
const blob = new Blob(["hello"], {type: 'text/plain'});
|
const blob = new Blob(['hello'], {type: 'text/plain'});
|
||||||
await navigator.clipboard.write([blob]);
|
await navigator.clipboard.write({'text/plain': blob});
|
||||||
}, "navigator.clipboard.write([text/plain Blob]) succeeds");
|
}, 'navigator.clipboard.write({string : text/plain Blob}) succeeds');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
await promise_rejects(t, new TypeError(),
|
await promise_rejects(t, new TypeError(),
|
||||||
navigator.clipboard.write());
|
navigator.clipboard.write());
|
||||||
}, "navigator.clipboard.write() fails (expect [Blob])");
|
}, 'navigator.clipboard.write() fails (expect {string : Blob})');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
await promise_rejects(t, new TypeError(),
|
await promise_rejects(t, new TypeError(),
|
||||||
navigator.clipboard.write(null));
|
navigator.clipboard.write(null));
|
||||||
}, "navigator.clipboard.write(null) fails (expect [Blob])");
|
}, 'navigator.clipboard.write(null) fails (expect {string : Blob})');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
await promise_rejects(t, new TypeError(),
|
await promise_rejects(t, new TypeError(),
|
||||||
navigator.clipboard.write("Bad string"));
|
navigator.clipboard.write('Bad string'));
|
||||||
}, "navigator.clipboard.write(DOMString) fails (expect [Blob])");
|
}, 'navigator.clipboard.write(DOMString) fails (expect {string : Blob})');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const blob = new Blob(['hello'], {type: 'text/plain'});
|
||||||
|
await promise_rejects(t, 'NotAllowedError',
|
||||||
|
navigator.clipboard.write(blob));
|
||||||
|
}, 'navigator.clipboard.write(Blob) fails (expect {string : Blob})');
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
await navigator.clipboard.writeText("New clipboard text");
|
await navigator.clipboard.writeText('New clipboard text');
|
||||||
}, "navigator.clipboard.writeText(DOMString) succeeds");
|
}, 'navigator.clipboard.writeText(DOMString) succeeds');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
await promise_rejects(t, new TypeError(),
|
await promise_rejects(t, new TypeError(),
|
||||||
navigator.clipboard.writeText());
|
navigator.clipboard.writeText());
|
||||||
}, "navigator.clipboard.writeText() fails (expect DOMString)");
|
}, 'navigator.clipboard.writeText() fails (expect DOMString)');
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
const fetched = await fetch(
|
const fetched = await fetch(
|
||||||
'http://localhost:8001/clipboard-apis/resources/greenbox.png');
|
'http://localhost:8001/clipboard-apis/resources/greenbox.png');
|
||||||
const image = await fetched.blob();
|
const image = await fetched.blob();
|
||||||
|
|
||||||
await navigator.clipboard.write([image]);
|
await navigator.clipboard.write({'image/png' : image});
|
||||||
}, "navigator.clipboard.write([image/png Blob]) succeeds");
|
}, 'navigator.clipboard.write({string : image/png Blob}) succeeds');
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
const result = await navigator.clipboard.read();
|
const result = await navigator.clipboard.read();
|
||||||
assert_true(result instanceof Array);
|
assert_true(result instanceof Object);
|
||||||
assert_true(result[0] instanceof Blob);
|
}, 'navigator.clipboard.read() succeeds');
|
||||||
assert_equals(typeof result, "object");
|
|
||||||
}, "navigator.clipboard.read() succeeds");
|
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
const result = await navigator.clipboard.readText();
|
const result = await navigator.clipboard.readText();
|
||||||
assert_equals(typeof result, "string");
|
assert_equals(typeof result, 'string');
|
||||||
}, "navigator.clipboard.readText() succeeds");
|
}, 'navigator.clipboard.readText() succeeds');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -13,19 +13,20 @@ async function loadBlob(fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
const blobText = new Blob(["test text"], {type: 'text/plain'});
|
const blobText = new Blob(['test text'], {type: 'text/plain'});
|
||||||
const blobImage = await loadBlob('resources/greenbox.png');
|
const blobImage = await loadBlob('resources/greenbox.png');
|
||||||
|
|
||||||
assert_equals(blobText.type, "text/plain");
|
assert_equals(blobText.type, 'text/plain');
|
||||||
assert_equals(blobImage.type, "image/png");
|
assert_equals(blobImage.type, 'image/png');
|
||||||
|
|
||||||
await navigator.clipboard.write([blobText, blobImage]);
|
await navigator.clipboard.write(
|
||||||
|
{'text/plain' : blobText, 'image/png' : blobImage});
|
||||||
const output = await navigator.clipboard.read();
|
const output = await navigator.clipboard.read();
|
||||||
|
|
||||||
assert_equals(output.length, 2);
|
assert_equals(Object.keys(output).length, 2);
|
||||||
assert_equals(output[0].type, "text/plain");
|
assert_equals(output['text/plain'].type, 'text/plain');
|
||||||
assert_equals(output[1].type, "image/png");
|
assert_equals(output['image/png'].type, 'image/png');
|
||||||
}, "Verify write and read clipboard (multiple blobs)");
|
}, 'Verify write and read clipboard (multiple blobs)');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -10,19 +10,19 @@ async function readWriteTest(textInput) {
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
const blobInput = new Blob([textInput], {type: 'text/plain'});
|
const blobInput = new Blob([textInput], {type: 'text/plain'});
|
||||||
|
|
||||||
await navigator.clipboard.write([blobInput]);
|
await navigator.clipboard.write({'text/plain': blobInput});
|
||||||
const blobsOutput = await navigator.clipboard.read();
|
const blobsOutput = await navigator.clipboard.read();
|
||||||
assert_equals(blobsOutput.length, 1);
|
assert_equals(Object.keys(blobsOutput).length, 1);
|
||||||
const blobOutput = blobsOutput[0];
|
const blobOutput = blobsOutput['text/plain'];
|
||||||
assert_equals(blobOutput.type, "text/plain");
|
assert_equals(blobOutput.type, 'text/plain');
|
||||||
|
|
||||||
const textOutput = await (new Response(blobOutput)).text();
|
const textOutput = await (new Response(blobOutput)).text();
|
||||||
assert_equals(textOutput, textInput);
|
assert_equals(textOutput, textInput);
|
||||||
}, "Verify write and read clipboard given text: " + textInput);
|
}, 'Verify write and read clipboard given text: ' + textInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
readWriteTest("Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) test");
|
readWriteTest('Clipboard write ([text/plain Blob]) -> read ([text/plain Blob]) test');
|
||||||
readWriteTest("non-Latin1 text encoding test データ");
|
readWriteTest('non-Latin1 text encoding test データ');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -8,15 +8,15 @@ async function readWriteTest(textInput) {
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
const blobInput = new Blob([textInput], {type: 'text/plain'});
|
const blobInput = new Blob([textInput], {type: 'text/plain'});
|
||||||
|
|
||||||
await navigator.clipboard.write([blobInput]);
|
await navigator.clipboard.write({'text/plain': blobInput});
|
||||||
const textOutput = await navigator.clipboard.readText();
|
const textOutput = await navigator.clipboard.readText();
|
||||||
|
|
||||||
assert_equals(textOutput, textInput);
|
assert_equals(textOutput, textInput);
|
||||||
}, "Verify write and read clipboard given text: " + textInput);
|
}, 'Verify write and read clipboard given text: ' + textInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
readWriteTest("Clipboard write ([text/plain Blob]) -> read text test");
|
readWriteTest('Clipboard write ([text/plain Blob]) -> read text test');
|
||||||
readWriteTest("non-Latin1 text encoding test データ");
|
readWriteTest('non-Latin1 text encoding test データ');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>
|
|
||||||
Async Clipboard write duplicate mime type test
|
|
||||||
</title>
|
|
||||||
<script src="/resources/testharness.js"></script>
|
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
promise_test(async t => {
|
|
||||||
const blobText = new Blob(["test text"], {type: 'text/plain'});
|
|
||||||
const blobText2 = new Blob(["test text"], {type: 'text/plain'});
|
|
||||||
|
|
||||||
assert_equals(blobText.type, "text/plain");
|
|
||||||
assert_equals(blobText2.type, "text/plain");
|
|
||||||
|
|
||||||
|
|
||||||
await promise_rejects(t, 'NotAllowedError',
|
|
||||||
navigator.clipboard.write([blobText, blobText2]));
|
|
||||||
}, "Verify write and read clipboard (multiple blobs)");
|
|
||||||
</script>
|
|
||||||
<p>
|
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
|
||||||
clipboard and thus cannot be run async with other tests that might interact
|
|
||||||
with the clipboard.
|
|
||||||
</p>
|
|
|
@ -9,11 +9,11 @@
|
||||||
<p>
|
<p>
|
||||||
<p>The bottom image should display the same image as the top image.</p>
|
<p>The bottom image should display the same image as the top image.</p>
|
||||||
<p>Original Image:</p>
|
<p>Original Image:</p>
|
||||||
<image id='image-to-copy' width='20' height='20'
|
<image id="image-to-copy" width="20" height="20"
|
||||||
src="resources/greenbox.png"></image>
|
src="resources/greenbox.png"></image>
|
||||||
<p>Image after copy/paste:</p>
|
<p>Image after copy/paste:</p>
|
||||||
<image id='image-on-clipboard'></image>
|
<image id="image-on-clipboard"></image>
|
||||||
<canvas id='canvas' width='20' height='20'></canvas>
|
<canvas id="canvas" width="20" height="20"></canvas>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -39,12 +39,12 @@ async function loadBlob(fileName) {
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
const blobInput = await loadBlob('resources/greenbox.png');
|
const blobInput = await loadBlob('resources/greenbox.png');
|
||||||
|
|
||||||
assert_equals(blobInput.type, "image/png");
|
assert_equals(blobInput.type, 'image/png');
|
||||||
await navigator.clipboard.write([blobInput]);
|
await navigator.clipboard.write({'image/png' : blobInput});
|
||||||
const blobsOutput = await navigator.clipboard.read();
|
const blobsOutput = await navigator.clipboard.read();
|
||||||
assert_equals(blobsOutput.length, 1);
|
assert_equals(Object.keys(blobsOutput).length, 1);
|
||||||
const blobOutput = blobsOutput[0];
|
const blobOutput = blobsOutput['image/png'];
|
||||||
assert_equals(blobOutput.type, "image/png");
|
assert_equals(blobOutput.type, 'image/png');
|
||||||
|
|
||||||
document.getElementById('image-on-clipboard').src =
|
document.getElementById('image-on-clipboard').src =
|
||||||
window.URL.createObjectURL(blobOutput);
|
window.URL.createObjectURL(blobOutput);
|
||||||
|
@ -53,7 +53,7 @@ promise_test(async t => {
|
||||||
const comparableOutput = await getBitmapString(blobOutput);
|
const comparableOutput = await getBitmapString(blobOutput);
|
||||||
|
|
||||||
assert_equals(comparableOutput, comparableInput);
|
assert_equals(comparableOutput, comparableInput);
|
||||||
}, "Verify write and read clipboard ([image/png Blob])");
|
}, 'Verify write and read clipboard ([image/png Blob])');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -8,17 +8,17 @@ async function readWriteTest(textInput) {
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
await navigator.clipboard.writeText(textInput);
|
await navigator.clipboard.writeText(textInput);
|
||||||
const blobsOutput = await navigator.clipboard.read();
|
const blobsOutput = await navigator.clipboard.read();
|
||||||
assert_equals(blobsOutput.length, 1);
|
assert_equals(Object.keys(blobsOutput).length, 1);
|
||||||
const blobOutput = blobsOutput[0];
|
const blobOutput = blobsOutput['text/plain'];
|
||||||
assert_equals(blobOutput.type, "text/plain");
|
assert_equals(blobOutput.type, 'text/plain');
|
||||||
|
|
||||||
const textOutput = await (new Response(blobOutput)).text();
|
const textOutput = await (new Response(blobOutput)).text();
|
||||||
assert_equals(textOutput, textInput);
|
assert_equals(textOutput, textInput);
|
||||||
}, "Verify write and read clipboard given text: " + textInput);
|
}, 'Verify write and read clipboard given text: ' + textInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
readWriteTest("Clipboard write text -> read ([text/plain Blob]) test");
|
readWriteTest('Clipboard write text -> read ([text/plain Blob]) test');
|
||||||
readWriteTest("non-Latin1 text encoding test データ");
|
readWriteTest('non-Latin1 text encoding test データ');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -10,11 +10,11 @@ async function readWriteTest(textInput) {
|
||||||
const textOutput = await navigator.clipboard.readText();
|
const textOutput = await navigator.clipboard.readText();
|
||||||
|
|
||||||
assert_equals(textOutput, textInput);
|
assert_equals(textOutput, textInput);
|
||||||
}, "Verify write and read clipboard given text: " + textInput);
|
}, 'Verify write and read clipboard given text: ' + textInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
readWriteTest("Clipboard write text -> read text test");
|
readWriteTest('Clipboard write text -> read text test');
|
||||||
readWriteTest("non-Latin1 text encoding test データ");
|
readWriteTest('non-Latin1 text encoding test データ');
|
||||||
</script>
|
</script>
|
||||||
<p>
|
<p>
|
||||||
Note: This is a manual test because it writes/reads to the shared system
|
Note: This is a manual test because it writes/reads to the shared system
|
||||||
|
|
|
@ -11,9 +11,9 @@ async_test(t => {
|
||||||
document.oncopy = t.step_func_done(event => {
|
document.oncopy = t.step_func_done(event => {
|
||||||
// Nothing can be asserted about the event target until
|
// Nothing can be asserted about the event target until
|
||||||
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
||||||
// assert_equals(event.target, document.body, "event.target");
|
// assert_equals(event.target, document.body, 'event.target');
|
||||||
assert_true(event.isTrusted, "event.isTrusted");
|
assert_true(event.isTrusted, 'event.isTrusted');
|
||||||
assert_true(event.composed, "event.composed");
|
assert_true(event.composed, 'event.composed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,9 +11,9 @@ async_test(t => {
|
||||||
document.oncut = t.step_func_done(event => {
|
document.oncut = t.step_func_done(event => {
|
||||||
// Nothing can be asserted about the event target until
|
// Nothing can be asserted about the event target until
|
||||||
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
||||||
// assert_equals(event.target, document.body, "event.target");
|
// assert_equals(event.target, document.body, 'event.target');
|
||||||
assert_true(event.isTrusted, "event.isTrusted");
|
assert_true(event.isTrusted, 'event.isTrusted');
|
||||||
assert_true(event.composed, "event.composed");
|
assert_true(event.composed, 'event.composed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
<script>
|
<script>
|
||||||
setup({explicit_timeout: true});
|
setup({explicit_timeout: true});
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
getSelection().selectAllChildren(document.querySelector("p"));
|
getSelection().selectAllChildren(document.querySelector('p'));
|
||||||
document.onpaste = t.step_func_done(event => {
|
document.onpaste = t.step_func_done(event => {
|
||||||
// Nothing can be asserted about the event target until
|
// Nothing can be asserted about the event target until
|
||||||
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
// https://github.com/w3c/clipboard-apis/issues/70 is resolved.
|
||||||
// assert_equals(event.target, document.body, "event.target");
|
// assert_equals(event.target, document.body, 'event.target');
|
||||||
assert_true(event.isTrusted, "event.isTrusted");
|
assert_true(event.isTrusted, 'event.isTrusted');
|
||||||
assert_true(event.composed, "event.composed");
|
assert_true(event.composed, 'event.composed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<link rel="author" title="Google" href="https://www.google.com/" />
|
|
||||||
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#intrinsic-sizes" />
|
|
||||||
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1865" />
|
|
||||||
|
|
||||||
<script src="/resources/testharness.js"></script>
|
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
|
||||||
<script src="/resources/check-layout-th.js"></script>
|
|
||||||
|
|
||||||
<body onload="checkLayout('.flexbox')">
|
|
||||||
<div class="flexbox" style="display: flex; width: min-content;" data-expected-width="0">
|
|
||||||
<div style="overflow: auto;">
|
|
||||||
<div style="width: 100px; height: 100px;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flexbox" style="display: flex; width: min-content;" data-expected-width="10">
|
|
||||||
<div style="overflow: auto; border: 5px solid;">
|
|
||||||
<div style="width: 100px; height: 100px;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Grid Layout Test: Grid container baseline</title>
|
||||||
|
<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-baselines">
|
||||||
|
<meta name="assert" content="Grid container baseline should match the element with 'align-self: baseline' in the first row, even if it's an orthogonal element.">
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: inline-grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
background: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i1 {
|
||||||
|
width: 150px;
|
||||||
|
height: 100px;
|
||||||
|
background: magenta;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i2 {
|
||||||
|
align-self: baseline;
|
||||||
|
width: 75px;
|
||||||
|
height: 50px;
|
||||||
|
background: cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i3 {
|
||||||
|
width: 100px;
|
||||||
|
height: 75px;
|
||||||
|
background: yellow;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/resources/check-layout-th.js"></script>
|
||||||
|
<body onload="checkLayout('.wrapper')">
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: horizontal-tb;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" data-offset-y="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: horizontal-tb;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: vertical-lr;" data-offset-y="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: horizontal-tb;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: vertical-rl;" data-offset-y="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-y="40"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-lr;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" data-offset-x="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-lr;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: horizontal-tb;" data-offset-x="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-lr; text-orientation: sideways;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" data-offset-x="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-lr; text-orientation: sideways;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: horizontal-tb;" data-offset-x="0"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-rl;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" data-offset-x="75"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-rl;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: horizontal-tb;" data-offset-x="75"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="65"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-rl; text-orientation: sideways;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" data-offset-x="75"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper" style="writing-mode: vertical-rl; text-orientation: sideways;">
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="i1"></div>
|
||||||
|
<div class="i2" style="writing-mode: horizontal-tb;" data-offset-x="75"></div>
|
||||||
|
<div class="i3"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block; width: 20px; height: 10px; background: black" data-offset-x="75"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<title>CSS Position Absolute: Chrome chrash</title>
|
<title>CSS Position Absolute: Chrome crash</title>
|
||||||
<link rel="author" href="mailto:atotic@google.com">
|
<link rel="author" href="mailto:atotic@google.com">
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Position Absolute: Chrome crash</title>
|
||||||
|
<link rel="author" href="mailto:atotic@chromium.org">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=935805">
|
||||||
|
<meta name="assert" content="Nested abs/fixed/flex do not crash">
|
||||||
|
<style>
|
||||||
|
#flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.abs {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
#fixed {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="abs">
|
||||||
|
<div id="flex">
|
||||||
|
<div class="abs">
|
||||||
|
<div id="fixed"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
}, 'test passes if it does not crash');
|
||||||
|
</script>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Absolute inside inline container location should be correct</title>
|
||||||
|
<link rel="author" href="mailto:atotic@chromium.org">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<!-- There should be a green square below -->
|
||||||
|
<body style="margin:0">
|
||||||
|
<span id="container" style="position:relative;">
|
||||||
|
<div style="width:100px; height:100px; background:red;"></div>
|
||||||
|
<div id="target" style="position:absolute; left:0; top:0; width:100px; height:100px; background:green;"></div>
|
||||||
|
</span>
|
||||||
|
<script>
|
||||||
|
test(_ => {
|
||||||
|
let bounds = document.querySelector("#target").getBoundingClientRect();
|
||||||
|
let container_bounds = document.querySelector("#container").getBoundingClientRect();
|
||||||
|
assert_equals(bounds.x, container_bounds.x);
|
||||||
|
assert_equals(bounds.y, container_bounds.y);
|
||||||
|
}, "absolute inside inline container location should be correct.");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>position:sticky should operate correctly</title>
|
||||||
|
<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div style="position: fixed;">There should be text visible below.</div>
|
||||||
|
<div style="height: 200px;width:600px;position: fixed;top: 0px;">
|
||||||
|
<div style="position: relative;top: 100px;">
|
||||||
|
<div style="height: 150px;width: 500px;position: absolute;backface-visibility: hidden;background: white;">
|
||||||
|
</div>
|
||||||
|
<div style="overflow: hidden;">
|
||||||
|
<a style="position: relative;">THIS SHOULD STAY VISIBLE<BR>IF YOU SCROLL DOWN</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 2200px;">
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
window.scrollTo(0,300);
|
||||||
|
document.documentElement.classList.remove("reftest-wait");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>position:sticky should operate correctly</title>
|
||||||
|
<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
|
||||||
|
<meta name="assert" content="This test checks that the combination of position:sticky, overflow clip, and out-of-flow descendants are properly displayed when scrolled" />
|
||||||
|
<link rel="match" href="position-sticky-scroll-with-clip-and-abspos-ref.html">
|
||||||
|
|
||||||
|
<div style="position: fixed;">There should be text visible below.</div>
|
||||||
|
<div style="height: 200px;width:600px;position: sticky;top: 0px;">
|
||||||
|
<div style="position: relative;top: 100px;">
|
||||||
|
<div style="height: 150px;width: 500px;position: absolute;backface-visibility: hidden;background: white;">
|
||||||
|
</div>
|
||||||
|
<div style="overflow: hidden;">
|
||||||
|
<a style="position: relative;">THIS SHOULD STAY VISIBLE<BR>IF YOU SCROLL DOWN</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 2000px;">
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
window.scrollTo(0,300);
|
||||||
|
document.documentElement.classList.remove("reftest-wait");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src='/resources/testharness.js'></script>
|
||||||
|
<script src='/resources/testharnessreport.js'></script>
|
||||||
|
<link rel="author" title="David Grogan" href="dgrogan@chromium.org">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-flows">
|
||||||
|
<meta name="flags" content="" />
|
||||||
|
<style>
|
||||||
|
x-table {
|
||||||
|
display: table;
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
writing-mode: vertical-lr;
|
||||||
|
outline: 2px dashed blue;
|
||||||
|
}
|
||||||
|
x-caption {
|
||||||
|
display: table-caption;
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
writing-mode: horizontal-tb;
|
||||||
|
outline: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<x-table>
|
||||||
|
<x-caption>caption</x-caption>
|
||||||
|
</x-table>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let body_height = document.querySelector("body").offsetHeight;
|
||||||
|
test(() => {
|
||||||
|
assert_greater_than(body_height, 0, "Vertical table with horizontal caption doesn't make <body> have crazy height.");
|
||||||
|
assert_less_than(body_height, 10000, "Vertical table with horizontal caption doesn't make <body> have crazy height.");
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<div style="padding: 0.4px 0.6px">
|
||||||
|
<div style="width: 100px; height: 100px; border: 1px solid black"></div>
|
||||||
|
</div>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link ref="help" href="https://drafts.csswg.org/css-transforms-2/#perspective-property">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#backface-visibility-property">
|
||||||
|
<link rel="match" href="subpixel-perspective-backface-hidden-ref.html">
|
||||||
|
<meta name="assert" content="Subpixel-positioned contents should not renderred the same regardless of perspective and backface-visibility:hidden">
|
||||||
|
<div style="padding: 0.4px 0.6px">
|
||||||
|
<div style="perspective: 1000px; backface-visibility: hidden">
|
||||||
|
<div style="width: 100px; height: 100px;
|
||||||
|
backface-visibility: hidden;border: 1px solid black">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<div style="padding: 0.6px 0.4px">
|
||||||
|
<div style="width: 100px; height: 100px; border: 1px solid black"></div>
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link ref="help" href="https://drafts.csswg.org/css-transforms-2/#perspective-property">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-backface-visibility">
|
||||||
|
<link rel="match" href="subpixel-perspective-translate-z-0-ref.html">
|
||||||
|
<meta name="assert" content="Subpixel-positioned contents should be rendered the same regardless of perspective and translateZ(0)">
|
||||||
|
<div style="position: relative; top: 0.6px; left: 0.4px; width: 300px; height: 300px;
|
||||||
|
perspective: 1000px; overflow: hidden">
|
||||||
|
<div style="width: 100px; height: 100px;
|
||||||
|
transform: translateZ(0); border: 1px solid black"></div>
|
||||||
|
</div>
|
|
@ -568,5 +568,11 @@ test(() => {
|
||||||
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
|
||||||
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
|
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
|
||||||
|
|
||||||
</script>
|
test(() => {
|
||||||
|
const host = document.createElement("div");
|
||||||
|
const root = host.attachShadow({mode: "open"});
|
||||||
|
root.adoptedStyleSheets = [new CSSStyleSheet()];
|
||||||
|
document.body.offsetTop;
|
||||||
|
}, 'Forcing a style update after adding an adopted stylesheet on a disconnected shadow root should not crash.');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
|
@ -21,7 +21,7 @@ you must either [fix all lint errors](#fixing-lint-errors), or you must
|
||||||
You must fix any errors the lint tool reports, unless an error is for
|
You must fix any errors the lint tool reports, unless an error is for
|
||||||
something essential to a certain test or that for some other
|
something essential to a certain test or that for some other
|
||||||
exceptional reason shouldn't prevent the test from being merged; in
|
exceptional reason shouldn't prevent the test from being merged; in
|
||||||
those cases you can [whitelist test files](#updating-the-whiteslist)
|
those cases you can [whitelist test files](#updating-the-whitelist)
|
||||||
to suppress the errors. In all other cases, follow the instructions
|
to suppress the errors. In all other cases, follow the instructions
|
||||||
below to fix all errors reported.
|
below to fix all errors reported.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<meta charset="utf8">
|
<meta charset="utf8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
<title>Events must dispatch on disabled elements</title>
|
<title>Events must dispatch on disabled elements</title>
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
|
@ -5,9 +5,11 @@ if (typeof postMessage === 'function') {
|
||||||
onmessage = event => {
|
onmessage = event => {
|
||||||
switch(event.data.type) {
|
switch(event.data.type) {
|
||||||
case 'ready':
|
case 'ready':
|
||||||
navigator.idle.query().then(
|
new IdleDetector().start().then(() => {
|
||||||
() => postMessage({ enabled: true }),
|
postMessage({ enabled: true });
|
||||||
error => postMessage ({ enabled: false }));
|
}, error => {
|
||||||
|
postMessage ({ enabled: false });
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
navigator.idle.query().then(status => {
|
new IdleDetector().start().then(() => {
|
||||||
window.parent.postMessage({ enabled: true }, '*');
|
window.parent.postMessage({ enabled: true }, '*');
|
||||||
}, error => {
|
}, error => {
|
||||||
window.parent.postMessage({ enabled: false }, '*');
|
window.parent.postMessage({ enabled: false }, '*');
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
def main(request, response):
|
def main(request, response):
|
||||||
|
|
||||||
token = request.GET.first("token", None)
|
token = request.GET.first("token", None)
|
||||||
value = request.server.stash.take(token)
|
is_query = request.GET.first("query", None) != None
|
||||||
count = 0
|
with request.server.stash.lock:
|
||||||
if value != None:
|
value = request.server.stash.take(token)
|
||||||
count = int(value)
|
count = 0
|
||||||
if request.GET.first("query", None) != None:
|
if value != None:
|
||||||
|
count = int(value)
|
||||||
|
if is_query:
|
||||||
|
if count < 2:
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
else:
|
||||||
|
count = count + 1
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
if is_query:
|
||||||
headers = [("Count", count)]
|
headers = [("Count", count)]
|
||||||
content = ""
|
content = ""
|
||||||
if count < 2:
|
|
||||||
request.server.stash.put(token, count)
|
|
||||||
return 200, headers, content
|
return 200, headers, content
|
||||||
else:
|
else:
|
||||||
count = count + 1
|
|
||||||
content = "body { background: rgb(0, 128, 0); }"
|
content = "body { background: rgb(0, 128, 0); }"
|
||||||
if count > 1:
|
if count > 1:
|
||||||
content = "body { background: rgb(255, 0, 0); }"
|
content = "body { background: rgb(255, 0, 0); }"
|
||||||
|
@ -20,5 +25,4 @@ def main(request, response):
|
||||||
headers = [("Content-Type", "text/css"),
|
headers = [("Content-Type", "text/css"),
|
||||||
("Cache-Control", "private, max-age=0, stale-while-revalidate=60")]
|
("Cache-Control", "private, max-age=0, stale-while-revalidate=60")]
|
||||||
|
|
||||||
request.server.stash.put(token, count)
|
|
||||||
return 200, headers, content
|
return 200, headers, content
|
||||||
|
|
|
@ -3,18 +3,24 @@ import os.path
|
||||||
def main(request, response):
|
def main(request, response):
|
||||||
|
|
||||||
token = request.GET.first("token", None)
|
token = request.GET.first("token", None)
|
||||||
value = request.server.stash.take(token)
|
is_query = request.GET.first("query", None) != None
|
||||||
count = 0
|
with request.server.stash.lock:
|
||||||
if value != None:
|
value = request.server.stash.take(token)
|
||||||
count = int(value)
|
count = 0
|
||||||
if request.GET.first("query", None) != None:
|
if value != None:
|
||||||
|
count = int(value)
|
||||||
|
if is_query:
|
||||||
|
if count < 2:
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
else:
|
||||||
|
count = count + 1
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
|
||||||
|
if is_query:
|
||||||
headers = [("Count", count)]
|
headers = [("Count", count)]
|
||||||
content = ""
|
content = ""
|
||||||
if count < 2:
|
|
||||||
request.server.stash.put(token, count)
|
|
||||||
return 200, headers, content
|
return 200, headers, content
|
||||||
else:
|
else:
|
||||||
count = count + 1
|
|
||||||
filename = "green-16x16.png"
|
filename = "green-16x16.png"
|
||||||
if count > 1:
|
if count > 1:
|
||||||
filename = "green-256x256.png"
|
filename = "green-256x256.png"
|
||||||
|
@ -22,7 +28,6 @@ def main(request, response):
|
||||||
path = os.path.join(os.path.dirname(__file__), "../../images", filename)
|
path = os.path.join(os.path.dirname(__file__), "../../images", filename)
|
||||||
body = open(path, "rb").read()
|
body = open(path, "rb").read()
|
||||||
|
|
||||||
request.server.stash.put(token, count)
|
|
||||||
response.add_required_headers = False
|
response.add_required_headers = False
|
||||||
response.writer.write_status(200)
|
response.writer.write_status(200)
|
||||||
response.writer.write_header("content-length", len(body))
|
response.writer.write_header("content-length", len(body))
|
||||||
|
|
|
@ -6,23 +6,27 @@ def id_token():
|
||||||
|
|
||||||
def main(request, response):
|
def main(request, response):
|
||||||
token = request.GET.first("token", None)
|
token = request.GET.first("token", None)
|
||||||
value = request.server.stash.take(token)
|
is_query = request.GET.first("query", None) != None
|
||||||
count = 0
|
with request.server.stash.lock:
|
||||||
if value != None:
|
value = request.server.stash.take(token)
|
||||||
count = int(value)
|
count = 0
|
||||||
if request.GET.first("query", None) != None:
|
if value != None:
|
||||||
|
count = int(value)
|
||||||
|
if is_query:
|
||||||
|
if count < 2:
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
else:
|
||||||
|
count = count + 1
|
||||||
|
request.server.stash.put(token, count)
|
||||||
|
|
||||||
|
if is_query:
|
||||||
headers = [("Count", count)]
|
headers = [("Count", count)]
|
||||||
content = ""
|
content = ""
|
||||||
if count < 2:
|
|
||||||
request.server.stash.put(token, count)
|
|
||||||
return 200, headers, content
|
return 200, headers, content
|
||||||
else:
|
else:
|
||||||
count = count + 1
|
|
||||||
|
|
||||||
unique_id = id_token()
|
unique_id = id_token()
|
||||||
headers = [("Content-Type", "text/javascript"),
|
headers = [("Content-Type", "text/javascript"),
|
||||||
("Cache-Control", "private, max-age=0, stale-while-revalidate=60"),
|
("Cache-Control", "private, max-age=0, stale-while-revalidate=60"),
|
||||||
("Unique-Id", unique_id)]
|
("Unique-Id", unique_id)]
|
||||||
content = "report('{}')".format(unique_id)
|
content = "report('{}')".format(unique_id)
|
||||||
request.server.stash.put(token, count)
|
|
||||||
return 200, headers, content
|
return 200, headers, content
|
||||||
|
|
|
@ -77,11 +77,8 @@ test1.step(function(){
|
||||||
test3.step(function(){
|
test3.step(function(){
|
||||||
var c3 = new VTTCue(0, 2, "text3");
|
var c3 = new VTTCue(0, 2, "text3");
|
||||||
t1.addCue(c3);
|
t1.addCue(c3);
|
||||||
assert_equals(t1.activeCues.length, 1, "t1.activeCues.length after adding a cue in the same script");
|
assert_equals(t1.activeCues.length, 2, "t1.activeCues.length should be changed immediately");
|
||||||
test3.step_timeout(function(){
|
test3.done();
|
||||||
assert_equals(t1.activeCues.length, 2, "t1.activeCues.length after the event loop has spun");
|
|
||||||
test3.done();
|
|
||||||
}, 0);
|
|
||||||
});
|
});
|
||||||
test2.done();
|
test2.done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
var cueCount = 0;
|
var cueCount = 0;
|
||||||
function cueEntered() {
|
function cueEntered(event) {
|
||||||
var currentCue = event.target;
|
var currentCue = event.target;
|
||||||
|
|
||||||
// This cue is the currently active cue.
|
// This cue is the currently active cue.
|
||||||
|
|
|
@ -3,70 +3,76 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
let promise = navigator.idle.query();
|
let status = new IdleDetector();
|
||||||
assert_equals(promise.constructor, Promise,
|
|
||||||
'query() returns a promise');
|
|
||||||
|
|
||||||
let status = await promise;
|
let watcher = new EventWatcher(t, status, ["change"]);
|
||||||
assert_true(status instanceof IdleStatus,
|
|
||||||
'query() promise resolves to an IdleStatus');
|
await status.start();
|
||||||
|
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
assert_true(['active', 'idle'].includes(status.state.user),
|
assert_true(['active', 'idle'].includes(status.state.user),
|
||||||
'status has a valid user state');
|
'status has a valid user state');
|
||||||
assert_true(['locked', 'unlocked'].includes(status.state.screen),
|
assert_true(['locked', 'unlocked'].includes(status.state.screen),
|
||||||
'status has a valid screen state');
|
'status has a valid screen state');
|
||||||
|
|
||||||
}, 'query() basics');
|
}, 'start() basics');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
let used = false;
|
let used = false;
|
||||||
|
|
||||||
await navigator.idle.query({
|
new IdleDetector({
|
||||||
get threshold() {
|
get threshold() {
|
||||||
used = true;
|
used = true;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_true(used, 'query() options "threshold" member was used');
|
assert_true(used, 'constructor options "threshold" member was used');
|
||||||
}, 'query() uses threshold property');
|
}, 'constructor uses threshold property');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return promise_rejects(
|
try {
|
||||||
t,
|
new IdleDetector({threshold: 0});
|
||||||
new TypeError,
|
assert_unreached('Threshold of 0 should reject');
|
||||||
navigator.idle.query({threshold: 0}),
|
} catch (error) {
|
||||||
'Threshold of 0 should reject');
|
assert_equals(error.name, 'TypeError');
|
||||||
}, 'query() throws with invalid threshold (0)');
|
}
|
||||||
|
}, 'constructor throws with invalid threshold (0)');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return promise_rejects(
|
try {
|
||||||
t,
|
new IdleDetector({threshold: null});
|
||||||
new TypeError,
|
assert_unreached('Threshold of null should reject');
|
||||||
navigator.idle.query({threshold: null}),
|
} catch (error) {
|
||||||
'Threshold of null should reject');
|
assert_equals(error.name, 'TypeError');
|
||||||
}, 'query() throws with invalid threshold (null)');
|
}
|
||||||
|
}, 'constructor throws with invalid threshold (null)');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return promise_rejects(
|
try {
|
||||||
t,
|
new IdleDetector({threshold: -1});
|
||||||
new TypeError,
|
assert_unreached('Threshold of negative numbers should reject');
|
||||||
navigator.idle.query({threshold: -1}),
|
} catch (error) {
|
||||||
'Threshold of negative numbers should reject');
|
assert_equals(error.name, 'TypeError');
|
||||||
}, 'query() throws with invalid threshold (-1)');
|
}
|
||||||
|
}, 'constructor throws with invalid threshold (-1)');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return promise_rejects(
|
try {
|
||||||
t,
|
new IdleDetector({threshold: NaN});
|
||||||
new TypeError,
|
assert_unreached('Threshold of NaN should reject');
|
||||||
navigator.idle.query({threshold: NaN}),
|
} catch (error) {
|
||||||
'Threshold of NaN should reject');
|
assert_equals(error.name, 'TypeError');
|
||||||
}, 'query() throws with invalid threshold (NaN)');
|
}
|
||||||
|
}, 'constructor throws with invalid threshold (NaN)');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return navigator.idle.query();
|
new IdleDetector();
|
||||||
}, 'query() uses a default value for the threshold when none is passed');
|
}, 'constructor uses a default value for the threshold when none is passed');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
return navigator.idle.query({threshold: undefined});
|
new IdleDetector({threshold: undefined});
|
||||||
}, 'query() uses a default value for the threshold');
|
}, 'constructor uses a default value for the threshold');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,25 +19,25 @@ const cross_origin_worker_frame_src = base_src + sub +
|
||||||
relative_worker_frame_path;
|
relative_worker_frame_path;
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
||||||
'allows same-origin relocation.');
|
'allows same-origin relocation.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
||||||
'allows workers in same-origin relocation.');
|
'allows workers in same-origin relocation.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
|
||||||
expect_feature_unavailable_default, 'idle-detection');
|
expect_feature_unavailable_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
||||||
'disallows cross-origin relocation.');
|
'disallows cross-origin relocation.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
|
||||||
expect_feature_unavailable_default, 'idle-detection');
|
expect_feature_unavailable_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
}, 'Attribute allow="idle-detection" in top-level frame ' +
|
||||||
'disallows workers in cross-origin relocation.');
|
'disallows workers in cross-origin relocation.');
|
||||||
|
|
|
@ -15,25 +15,25 @@ const cross_origin_src = sub + same_origin_src;
|
||||||
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
||||||
'in same-origin iframe using Feature policy "idle-detection".');
|
'in same-origin iframe using Feature policy "idle-detection".');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
||||||
'in a worker in same-origin iframe using Feature policy "idle-detection".');
|
'in a worker in same-origin iframe using Feature policy "idle-detection".');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
||||||
'in cross-origin iframe using Feature policy "idle-detection".');
|
'in cross-origin iframe using Feature policy "idle-detection".');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
|
||||||
expect_feature_available_default, 'idle-detection');
|
expect_feature_available_default, 'idle-detection');
|
||||||
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
}, 'Attribute allow="idle-detection" in top-level frame can be enabled ' +
|
||||||
'in a worker in cross-origin iframe using Feature policy "idle-detection".');
|
'in a worker in cross-origin iframe using Feature policy "idle-detection".');
|
||||||
|
|
|
@ -14,31 +14,32 @@ const same_origin_worker_frame_src =
|
||||||
const cross_origin_src = sub + same_origin_src;
|
const cross_origin_src = sub + same_origin_src;
|
||||||
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
||||||
|
|
||||||
promise_test(
|
promise_test(async () => {
|
||||||
() => navigator.idle.query(),
|
await new IdleDetector().start();
|
||||||
|
},
|
||||||
'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
||||||
'frame allows the top-level document.');
|
'frame allows the top-level document.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_src,
|
||||||
expect_feature_available_default);
|
expect_feature_available_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
||||||
'frame allows same-origin iframes.');
|
'frame allows same-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
|
||||||
expect_feature_available_default);
|
expect_feature_available_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
||||||
'frame allows workers in same-origin iframes.');
|
'frame allows workers in same-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
|
||||||
expect_feature_available_default);
|
expect_feature_available_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
||||||
'frame allows cross-origin iframes.');
|
'frame allows cross-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
|
||||||
expect_feature_available_default);
|
expect_feature_available_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
}, 'Feature-Policy {"idle-detection" : ["*"]} explicity set by top-level ' +
|
||||||
'frame allows workers in cross-origin iframes.');
|
'frame allows workers in cross-origin iframes.');
|
||||||
|
|
|
@ -11,19 +11,20 @@ const same_origin_src =
|
||||||
const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
|
const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
|
||||||
same_origin_src;
|
same_origin_src;
|
||||||
|
|
||||||
promise_test(
|
promise_test(async () => {
|
||||||
() => navigator.idle.query(),
|
await new IdleDetector().start()
|
||||||
|
},
|
||||||
'Default "idle-detection" feature policy ["self"] ' +
|
'Default "idle-detection" feature policy ["self"] ' +
|
||||||
'allows the top-level document.');
|
'allows the top-level document.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_src,
|
||||||
expect_feature_available_default);
|
expect_feature_available_default);
|
||||||
}, 'Default "idle-detection" feature policy ["self"] ' +
|
}, 'Default "idle-detection" feature policy ["self"] ' +
|
||||||
'allows same-origin iframes.');
|
'allows same-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
|
||||||
expect_feature_unavailable_default);
|
expect_feature_unavailable_default);
|
||||||
}, 'Default "idle-detection" feature policy ["self"] ' +
|
}, 'Default "idle-detection" feature policy ["self"] ' +
|
||||||
'disallows cross-origin iframes.');
|
'disallows cross-origin iframes.');
|
||||||
|
|
|
@ -14,35 +14,37 @@ const same_origin_worker_frame_src =
|
||||||
const cross_origin_src = sub + same_origin_src;
|
const cross_origin_src = sub + same_origin_src;
|
||||||
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
const cross_origin_worker_frame_src = sub + same_origin_worker_frame_src;
|
||||||
|
|
||||||
promise_test(() => {
|
promise_test(async () => {
|
||||||
return navigator.idle.query().then(() => {
|
try {
|
||||||
|
let idleDetector = new IdleDetector();
|
||||||
|
await idleDetector.start();
|
||||||
assert_unreached('expected promise to reject with SecurityError');
|
assert_unreached('expected promise to reject with SecurityError');
|
||||||
}, error => {
|
} catch (error) {
|
||||||
assert_equals(error.name, 'SecurityError');
|
assert_equals(error.name, 'SecurityError');
|
||||||
});
|
}
|
||||||
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
||||||
'disallows query in the top-level document.');
|
'disallows query in the top-level document.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_src,
|
||||||
expect_feature_unavailable_default);
|
expect_feature_unavailable_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
||||||
'disallows same-origin iframes.');
|
'disallows same-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, same_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, same_origin_worker_frame_src,
|
||||||
expect_feature_unavailable_default);
|
expect_feature_unavailable_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
||||||
'disallows workers in same-origin iframes.');
|
'disallows workers in same-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_src,
|
||||||
expect_feature_unavailable_default);
|
expect_feature_unavailable_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
||||||
'disallows cross-origin iframes.');
|
'disallows cross-origin iframes.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
test_feature_availability('idle.query()', t, cross_origin_worker_frame_src,
|
test_feature_availability('new IdleDetector().start()', t, cross_origin_worker_frame_src,
|
||||||
expect_feature_unavailable_default);
|
expect_feature_unavailable_default);
|
||||||
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
}, 'Feature-Policy {"idle-detection" : []} explicitly set by top-level frame ' +
|
||||||
'disallows workers in cross-origin iframes.');
|
'disallows workers in cross-origin iframes.');
|
||||||
|
|
|
@ -1,28 +1,16 @@
|
||||||
[SecureContext]
|
|
||||||
interface mixin NavigatorIdle {
|
|
||||||
readonly attribute IdleManager idle;
|
|
||||||
};
|
|
||||||
|
|
||||||
Navigator includes NavigatorIdle;
|
|
||||||
WorkerNavigator includes NavigatorIdle;
|
|
||||||
|
|
||||||
[
|
|
||||||
SecureContext,
|
|
||||||
Exposed=(Window,Worker)
|
|
||||||
] interface IdleManager {
|
|
||||||
Promise<IdleStatus> query(optional IdleOptions options);
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary IdleOptions {
|
dictionary IdleOptions {
|
||||||
unsigned long threshold;
|
unsigned long threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
[
|
[
|
||||||
SecureContext,
|
SecureContext,
|
||||||
|
Constructor(optional IdleOptions options),
|
||||||
Exposed=(Window,Worker)
|
Exposed=(Window,Worker)
|
||||||
] interface IdleStatus : EventTarget {
|
] interface IdleDetector : EventTarget {
|
||||||
readonly attribute IdleState state;
|
readonly attribute IdleState state;
|
||||||
attribute EventHandler onchange;
|
attribute EventHandler onchange;
|
||||||
|
Promise<any> start();
|
||||||
|
void stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
|
@ -1,34 +1,36 @@
|
||||||
// META: script=/resources/WebIDLParser.js
|
// META: script=/resources/WebIDLParser.js
|
||||||
// META: script=/resources/idlharness.js
|
// META: script=/resources/idlharness.js
|
||||||
|
|
||||||
// https://github.com/inexorabletash/idle-detection
|
// https://github.com/samuelgoto/idle-detection
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async (t) => {
|
||||||
const srcs = ['./idle-detection.idl',
|
const srcs = ['./idle-detection.idl',
|
||||||
'/interfaces/dom.idl',
|
'/interfaces/dom.idl',
|
||||||
'/interfaces/html.idl'];
|
'/interfaces/html.idl'];
|
||||||
|
|
||||||
const [idle, dom, html] = await Promise.all(
|
const [idle, dom, html] = await Promise.all(
|
||||||
srcs.map(i => fetch(i).then(r => r.text())));
|
srcs.map(i => fetch(i).then(r => r.text()))
|
||||||
|
);
|
||||||
|
|
||||||
const idl_array = new IdlArray();
|
const idl_array = new IdlArray();
|
||||||
idl_array.add_idls(idle);
|
idl_array.add_idls(idle);
|
||||||
idl_array.add_dependency_idls(dom);
|
idl_array.add_dependency_idls(dom);
|
||||||
idl_array.add_dependency_idls(html);
|
idl_array.add_dependency_idls(html);
|
||||||
|
|
||||||
self.idle = await navigator.idle.query();
|
self.idle = new IdleDetector({threshold: 1});
|
||||||
|
|
||||||
|
let watcher = new EventWatcher(t, self.idle, ["change"]);
|
||||||
|
|
||||||
|
self.idle.start();
|
||||||
|
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
idl_array.add_objects({
|
idl_array.add_objects({
|
||||||
IdleManager: ['navigator.idle'],
|
IdleDetector: ['idle'],
|
||||||
IdleStatus: ['idle'],
|
|
||||||
IdleState: ['idle.state']
|
IdleState: ['idle.state']
|
||||||
});
|
});
|
||||||
if (self.Window) {
|
|
||||||
idl_array.add_objects({ Navigator: ['navigator'] });
|
|
||||||
} else {
|
|
||||||
idl_array.add_objects({ WorkerNavigator: ['navigator'] });
|
|
||||||
}
|
|
||||||
|
|
||||||
idl_array.test();
|
idl_array.test();
|
||||||
}, 'Test IDL implementation of Idle Detection API');
|
}, 'Test IDL implementation of Idle Detection API');
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<link rel="help" href="https://github.com/inexorabletash/idle-detection">
|
<link rel="help" href="https://github.com/samuelgoto/idle-detection">
|
||||||
<title>Tests the Idle Detection API</title>
|
<title>Tests the Idle Detection API</title>
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
|
<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
|
||||||
<script src="/gen/mojo/public/mojom/base/string16.mojom.js"></script>
|
<script src="/gen/mojo/public/mojom/base/string16.mojom.js"></script>
|
||||||
<script src="/gen/mojo/public/mojom/base/time.mojom.js"></script>
|
<script src="/gen/mojo/public/mojom/base/time.mojom.js"></script>
|
||||||
<script src="/gen/third_party/blink/public/platform/modules/idle/idle_manager.mojom.js"></script>
|
<script src="/gen/third_party/blink/public/mojom/idle/idle_manager.mojom.js"></script>
|
||||||
<script src="mock.js"></script>
|
<script src="mock.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
// Basic test that expects navigator.idle.query() to call internally
|
// Basic test that expects start() to call internally
|
||||||
// addMonitor, which in turn will return an ACTIVE state.
|
// addMonitor, which in turn return an ACTIVE state.
|
||||||
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
state: {
|
state: {
|
||||||
|
@ -23,36 +23,58 @@ promise_test(async t => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let status = await navigator.idle.query({threshold: 10});
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
assert_equals(status.state.user, "active");
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
assert_equals(status.state.screen, "locked");
|
|
||||||
|
await detector.start();
|
||||||
|
|
||||||
|
// Waits for the first event.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
|
assert_equals(detector.state.user, "active");
|
||||||
|
assert_equals(detector.state.screen, "locked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
}, 'query()');
|
}, 'query()');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
// Verifies that an event is thrown when a change of state from IDLE to ACTIVE
|
// Verifies that an event is thrown when a change of state from IDLE to ACTIVE
|
||||||
// is detected.
|
// is detected.
|
||||||
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
let first = Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.UNLOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
t.step_timeout(() => {
|
t.step_timeout(() => {
|
||||||
monitorPtr.update({
|
monitorPtr.update({
|
||||||
user: UserIdleState.IDLE,
|
user: UserIdleState.IDLE,
|
||||||
screen: ScreenIdleState.UNLOCKED
|
screen: ScreenIdleState.UNLOCKED
|
||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
return Promise.resolve({
|
|
||||||
state: {
|
return first;
|
||||||
user: UserIdleState.ACTIVE,
|
|
||||||
screen: ScreenIdleState.UNLOCKED
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let monitor = await navigator.idle.query({threshold: 10});
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
await new EventWatcher(t, monitor, ["change"]).wait_for("change");
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
|
|
||||||
assert_equals(monitor.state.user, "idle");
|
await detector.start();
|
||||||
assert_equals(monitor.state.screen, "unlocked");
|
|
||||||
|
// Wait for the initial state.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
|
// Wait for the first change in state.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
|
assert_equals(detector.state.user, "idle");
|
||||||
|
assert_equals(detector.state.screen, "unlocked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
}, 'updates once');
|
}, 'updates once');
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +82,13 @@ promise_test(async t => {
|
||||||
// Simulates the user being active, going idle and then going back active
|
// Simulates the user being active, going idle and then going back active
|
||||||
// again.
|
// again.
|
||||||
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
let first = Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.UNLOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Updates the client once with the user idle.
|
// Updates the client once with the user idle.
|
||||||
t.step_timeout(() => {
|
t.step_timeout(() => {
|
||||||
monitorPtr.update({
|
monitorPtr.update({
|
||||||
|
@ -74,25 +103,27 @@ promise_test(async t => {
|
||||||
screen: ScreenIdleState.UNLOCKED
|
screen: ScreenIdleState.UNLOCKED
|
||||||
});
|
});
|
||||||
}, 1);
|
}, 1);
|
||||||
return Promise.resolve({
|
return first;
|
||||||
state: {
|
|
||||||
user: UserIdleState.ACTIVE,
|
|
||||||
screen: ScreenIdleState.UNLOCKED
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let monitor = await navigator.idle.query({threshold: 10});
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
let watcher = new EventWatcher(t, monitor, ["change"]);
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
|
|
||||||
// waits for the first event.
|
await detector.start();
|
||||||
|
|
||||||
|
// Waits for the initial state.
|
||||||
await watcher.wait_for("change");
|
await watcher.wait_for("change");
|
||||||
assert_equals(monitor.state.user, "idle");
|
|
||||||
|
|
||||||
// waits for the second event.
|
// Waits for the first event.
|
||||||
await watcher.wait_for("change");
|
await watcher.wait_for("change");
|
||||||
assert_equals(monitor.state.user, "active");
|
assert_equals(detector.state.user, "idle");
|
||||||
|
|
||||||
|
// Waits for the second event.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
assert_equals(detector.state.user, "active");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
}, 'updates twice');
|
}, 'updates twice');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
|
@ -106,28 +137,140 @@ promise_test(async t => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let monitor = await navigator.idle.query({threshold: 10});
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
assert_equals(monitor.state.screen, "locked");
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
|
|
||||||
|
await detector.start();
|
||||||
|
|
||||||
|
// waits for the initial state.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
|
||||||
|
assert_equals(detector.state.screen, "locked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
}, 'locked screen');
|
}, 'locked screen');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
// Simulates the service becoming unavailable.
|
|
||||||
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
return new Promise((resolve, reject) => {
|
return Promise.resolve({
|
||||||
// leave the renderer deliberately hanging by not resolve()-ing.
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.LOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
|
let event = new Promise((resolve, reject) => {
|
||||||
|
detector.onchange = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
await detector.start();
|
||||||
|
|
||||||
|
// Waits for the first event.
|
||||||
|
await event;
|
||||||
|
|
||||||
|
assert_equals(detector.state.user, "active");
|
||||||
|
assert_equals(detector.state.screen, "locked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
|
}, 'IdleDetector.onchange');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.UNLOCKED
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let error = new Promise((resolve, reject) => {
|
let detector = new IdleDetector({threshold: 10});
|
||||||
navigator.idle.query({threshold: 10})
|
|
||||||
.then((e) => {reject("unexpected response :(")})
|
|
||||||
.catch((e) => {resolve(e.message)});
|
|
||||||
});
|
|
||||||
|
|
||||||
// simulates what happens when the service is unavailable.
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
close();
|
|
||||||
|
// Calling start() multiple times should be safe.
|
||||||
|
await detector.start();
|
||||||
|
await detector.start();
|
||||||
|
await detector.start();
|
||||||
|
await detector.start();
|
||||||
|
|
||||||
|
// waits for the initial state.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
assert_equals(detector.state.user, "active");
|
||||||
|
assert_equals(detector.state.screen, "unlocked");
|
||||||
|
|
||||||
|
// Calling stop() multiple times should be safe.
|
||||||
|
detector.stop();
|
||||||
|
detector.stop();
|
||||||
|
detector.stop();
|
||||||
|
detector.stop();
|
||||||
|
}, 'Safe to call start() or stop() multiple times');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.UNLOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
|
// Calling stop() before start() is a no-op.
|
||||||
|
detector.stop();
|
||||||
|
|
||||||
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
|
|
||||||
|
await detector.start();
|
||||||
|
|
||||||
|
// waits for the initial state.
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
assert_equals(detector.state.user, "active");
|
||||||
|
assert_equals(detector.state.screen, "unlocked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
|
}, 'Calling stop() after start() is a no-op');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.ACTIVE,
|
||||||
|
screen: ScreenIdleState.UNLOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let detector = new IdleDetector({threshold: 10});
|
||||||
|
|
||||||
|
let watcher = new EventWatcher(t, detector, ["change"]);
|
||||||
|
|
||||||
|
await detector.start();
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
detector.stop();
|
||||||
|
|
||||||
|
expect(addMonitor).andReturn((threshold, monitorPtr) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
state: {
|
||||||
|
user: UserIdleState.IDLE,
|
||||||
|
screen: ScreenIdleState.LOCKED
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restarting the monitor.
|
||||||
|
await detector.start();
|
||||||
|
await watcher.wait_for("change");
|
||||||
|
assert_equals(detector.state.user, "idle");
|
||||||
|
assert_equals(detector.state.screen, "locked");
|
||||||
|
|
||||||
|
detector.stop();
|
||||||
|
}, 'Calling start() after stop(): re-starting monitor.');
|
||||||
|
|
||||||
assert_equals(await error, "Idle detection not available");
|
|
||||||
}, "service unavailable");
|
|
||||||
</script>
|
</script>
|
|
@ -8,7 +8,9 @@ if (typeof postMessage === 'function') {
|
||||||
workerType = 'dedicated';
|
workerType = 'dedicated';
|
||||||
}
|
}
|
||||||
|
|
||||||
promise_test(() => navigator.idle.query(),
|
promise_test(async () => {
|
||||||
|
await new IdleDetector().start()
|
||||||
|
},
|
||||||
`Inherited header feature policy allows ${workerType} workers.`)
|
`Inherited header feature policy allows ${workerType} workers.`)
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -9,9 +9,14 @@ if (typeof postMessage === 'function') {
|
||||||
workerType = 'dedicated';
|
workerType = 'dedicated';
|
||||||
}
|
}
|
||||||
|
|
||||||
promise_test(() => navigator.idle.query().then(
|
promise_test(async () => {
|
||||||
() => assert_unreached('expected promise to reject with SecurityError'),
|
try {
|
||||||
error => assert_equals(error.name, 'SecurityError')),
|
await new IdleDetector().start();
|
||||||
`Inherited ${header} disallows ${workerType} workers.`);
|
assert_unreached('expected start() to throw with SecurityError');
|
||||||
|
} catch (error) {
|
||||||
|
assert_equals(error.name, 'SecurityError');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
`Inherited ${header} disallows ${workerType} workers.`);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="../resources/test-helper.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=B",
|
||||||
|
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=C": "../resources/log.js?pipe=sub&name=D"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
promise_test(t => {
|
||||||
|
return promise_rejects(t, TypeError(),
|
||||||
|
import('../resources/log.js?pipe=sub&name=A'),
|
||||||
|
'Dynamic import should fail');
|
||||||
|
}, 'The URL after mapping violates CSP (but not the URL before mapping)');
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return import('https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=C')
|
||||||
|
.then(() => assert_array_equals(log, ["log:D"]));
|
||||||
|
}, 'The URL before mapping violates CSP (but not the URL after mapping)');
|
||||||
|
</script>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="../resources/test-helper.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=B",
|
||||||
|
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=C": "../resources/log.js?pipe=sub&name=D"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="module">
|
||||||
|
import '../resources/log.js?pipe=sub&name=A';
|
||||||
|
</script>
|
||||||
|
<script type="module">
|
||||||
|
test(t => {
|
||||||
|
assert_array_equals(log, []);
|
||||||
|
}, 'The URL after mapping violates CSP (but not the URL before mapping)');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import 'https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=C';
|
||||||
|
</script>
|
||||||
|
<script type="module">
|
||||||
|
test(t => {
|
||||||
|
assert_array_equals(log, ["log:D"]);
|
||||||
|
}, 'The URL before mapping violates CSP (but not the URL after mapping)');
|
||||||
|
</script>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-wrong9e+pZbSYIkpB8BIE0Hs7yHajJDiX5mnT/wrong=' 'sha256-RAsyam34o4peVe9sCebtaZWRVhqAhudem+NlcnP2Kp8=';">
|
||||||
|
|
||||||
|
<!-- 'sha256-P5xqp9e+pZbSYIkpB8BIE0Hs7yHajJDiX5mnT/1PO1I=' -->
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 'sha256-RAsyam34o4peVe9sCebtaZWRVhqAhudem+NlcnP2Kp8=' -->
|
||||||
|
<script>
|
||||||
|
const log = [];
|
||||||
|
promise_test(() => {
|
||||||
|
return import("../resources/log.js?pipe=sub&name=A")
|
||||||
|
.then(() => assert_array_equals(log, ["log:A"]))
|
||||||
|
},
|
||||||
|
'Importmap should not be accepted due to wrong hash');
|
||||||
|
</script>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-P5xqp9e+pZbSYIkpB8BIE0Hs7yHajJDiX5mnT/1PO1I=' 'sha256-Ciqph+wQDoB2suzqZVHOD0iw99WqaTUwZXRl7ATzBxc=';">
|
||||||
|
|
||||||
|
<!-- 'sha256-P5xqp9e+pZbSYIkpB8BIE0Hs7yHajJDiX5mnT/1PO1I=' -->
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- 'sha256-Ciqph+wQDoB2suzqZVHOD0iw99WqaTUwZXRl7ATzBxc=' -->
|
||||||
|
<script>
|
||||||
|
const log = [];
|
||||||
|
promise_test(() => {
|
||||||
|
return import("../resources/log.js?pipe=sub&name=A")
|
||||||
|
.then(() => assert_array_equals(log, ["log:B"]))
|
||||||
|
},
|
||||||
|
'Importmap should be accepted due to hash');
|
||||||
|
</script>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc';">
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="importmap" nonce="wrong">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script nonce="abc">
|
||||||
|
const log = [];
|
||||||
|
promise_test(() => {
|
||||||
|
return import("../resources/log.js?pipe=sub&name=A")
|
||||||
|
.then(() => assert_array_equals(log, ["log:A"]))
|
||||||
|
},
|
||||||
|
'Importmap should be rejected due to nonce');
|
||||||
|
</script>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc';">
|
||||||
|
<script type="importmap" nonce="abc">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script nonce="abc">
|
||||||
|
const log = [];
|
||||||
|
promise_test(() => {
|
||||||
|
return import("../resources/log.js?pipe=sub&name=A")
|
||||||
|
.then(() => assert_array_equals(log, ["log:B"]))
|
||||||
|
},
|
||||||
|
'Importmap should be accepted according to its correct nonce');
|
||||||
|
</script>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
const log = [];
|
||||||
|
promise_test(() => {
|
||||||
|
return import("../resources/log.js?pipe=sub&name=A")
|
||||||
|
.then(() => assert_array_equals(log, ["log:B"]))
|
||||||
|
},
|
||||||
|
'Importmap should be accepted due to unsafe-inline');
|
||||||
|
</script>
|
|
@ -0,0 +1,9 @@
|
||||||
|
[actionsWithKeyPressed.html]
|
||||||
|
expected:
|
||||||
|
if product == "safari" or product == "firefox": ERROR
|
||||||
|
|
||||||
|
|
||||||
|
[TestDriver actions: actions with key pressed]
|
||||||
|
expected:
|
||||||
|
if product == "chrome": FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[generate_test_report.html]
|
||||||
|
expected:
|
||||||
|
if product == "firefox": ERROR
|
||||||
|
if product == "safari": ERROR
|
|
@ -0,0 +1,67 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>TestDriver actions: actions with key pressed</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/resources/testdriver.js"></script>
|
||||||
|
<script src="/resources/testdriver-actions.js"></script>
|
||||||
|
<script src="/resources/testdriver-vendor.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div#test1, div#test2 {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#test2 {
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 0;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="test1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="test2">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let keys = [];
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let test1 = document.getElementById("test1");
|
||||||
|
let test2 = document.getElementById("test2");
|
||||||
|
document.getElementById("test1").addEventListener("click",
|
||||||
|
e => {keys.push(e.getModifierState("Control"))});
|
||||||
|
document.getElementById("test2").addEventListener("click",
|
||||||
|
e => {keys.push(e.getModifierState("Control"))});
|
||||||
|
|
||||||
|
let actions = new test_driver.Actions()
|
||||||
|
.keyDown("\uE009")
|
||||||
|
.addTick()
|
||||||
|
.pointerMove(0, 0, {origin: test1})
|
||||||
|
.pointerDown()
|
||||||
|
.pointerUp()
|
||||||
|
.pointerMove(0, 0, {origin: test2})
|
||||||
|
.pointerDown()
|
||||||
|
.pointerUp()
|
||||||
|
.addTick()
|
||||||
|
.keyUp("\uE009")
|
||||||
|
.addTick()
|
||||||
|
.pointerMove(0, 0, {origin: test1})
|
||||||
|
.pointerDown()
|
||||||
|
.pointerUp();
|
||||||
|
|
||||||
|
actions.send()
|
||||||
|
.then(t.step_func_done(() => assert_array_equals(keys, [true, true, false])))
|
||||||
|
.catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>TestDriver generate_test_report method</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/resources/testdriver.js"></script>
|
||||||
|
<script src="/resources/testdriver-vendor.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async_test(t => {
|
||||||
|
test_driver
|
||||||
|
.generate_test_report("Test message.")
|
||||||
|
.then(() => t.done())
|
||||||
|
.catch(t.unreached_func("generate_test_report failed"));
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,30 +0,0 @@
|
||||||
// GENERATED CONTENT - DO NOT EDIT
|
|
||||||
// Content was automatically extracted by Reffy into reffy-reports
|
|
||||||
// (https://github.com/tidoust/reffy-reports)
|
|
||||||
// Source: Resize Observer 1 (https://wicg.github.io/ResizeObserver/)
|
|
||||||
|
|
||||||
[Constructor(ResizeObserverCallback callback),
|
|
||||||
Exposed=Window]
|
|
||||||
interface ResizeObserver {
|
|
||||||
void observe(Element target);
|
|
||||||
void unobserve(Element target);
|
|
||||||
void disconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, ResizeObserver observer);
|
|
||||||
|
|
||||||
[Constructor(Element target)
|
|
||||||
]
|
|
||||||
interface ResizeObserverEntry {
|
|
||||||
readonly attribute Element target;
|
|
||||||
readonly attribute DOMRectReadOnly contentRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
[Constructor(Element target)
|
|
||||||
]
|
|
||||||
interface ResizeObservation {
|
|
||||||
readonly attribute Element target;
|
|
||||||
readonly attribute float broadcastWidth;
|
|
||||||
readonly attribute float broadcastHeight;
|
|
||||||
boolean isActive();
|
|
||||||
};
|
|
|
@ -25,7 +25,7 @@ interface NamedFlow : EventTarget {
|
||||||
sequence<Region> getRegionsByContent(Node node);
|
sequence<Region> getRegionsByContent(Node node);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Region {
|
interface mixin Region {
|
||||||
readonly attribute CSSOMString regionOverset;
|
readonly attribute CSSOMString regionOverset;
|
||||||
sequence<Range>? getRegionFlowRanges();
|
sequence<Range>? getRegionFlowRanges();
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,7 @@ partial interface CSSStyleRule {
|
||||||
[SameObject] readonly attribute StylePropertyMap styleMap;
|
[SameObject] readonly attribute StylePropertyMap styleMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
partial interface ElementCSSInlineStyle {
|
partial interface mixin ElementCSSInlineStyle {
|
||||||
[SameObject] readonly attribute StylePropertyMap attributeStyleMap;
|
[SameObject] readonly attribute StylePropertyMap attributeStyleMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,11 @@ partial dictionary MediaTrackSupportedConstraints {
|
||||||
|
|
||||||
boolean brightness = true;
|
boolean brightness = true;
|
||||||
boolean contrast = true;
|
boolean contrast = true;
|
||||||
|
boolean pan = true;
|
||||||
boolean saturation = true;
|
boolean saturation = true;
|
||||||
boolean sharpness = true;
|
boolean sharpness = true;
|
||||||
boolean focusDistance = true;
|
boolean focusDistance = true;
|
||||||
|
boolean tilt = true;
|
||||||
boolean zoom = true;
|
boolean zoom = true;
|
||||||
boolean torch = true;
|
boolean torch = true;
|
||||||
};
|
};
|
||||||
|
@ -82,6 +84,8 @@ partial dictionary MediaTrackCapabilities {
|
||||||
MediaSettingsRange sharpness;
|
MediaSettingsRange sharpness;
|
||||||
|
|
||||||
MediaSettingsRange focusDistance;
|
MediaSettingsRange focusDistance;
|
||||||
|
MediaSettingsRange pan;
|
||||||
|
MediaSettingsRange tilt;
|
||||||
MediaSettingsRange zoom;
|
MediaSettingsRange zoom;
|
||||||
|
|
||||||
boolean torch;
|
boolean torch;
|
||||||
|
@ -104,6 +108,8 @@ partial dictionary MediaTrackConstraintSet {
|
||||||
ConstrainDouble sharpness;
|
ConstrainDouble sharpness;
|
||||||
|
|
||||||
ConstrainDouble focusDistance;
|
ConstrainDouble focusDistance;
|
||||||
|
ConstrainDouble pan;
|
||||||
|
ConstrainDouble tilt;
|
||||||
ConstrainDouble zoom;
|
ConstrainDouble zoom;
|
||||||
|
|
||||||
ConstrainBoolean torch;
|
ConstrainBoolean torch;
|
||||||
|
@ -126,6 +132,8 @@ partial dictionary MediaTrackSettings {
|
||||||
double sharpness;
|
double sharpness;
|
||||||
|
|
||||||
double focusDistance;
|
double focusDistance;
|
||||||
|
double pan;
|
||||||
|
double tilt;
|
||||||
double zoom;
|
double zoom;
|
||||||
|
|
||||||
boolean torch;
|
boolean torch;
|
||||||
|
|
43
tests/wpt/web-platform-tests/interfaces/resize-observer.idl
Normal file
43
tests/wpt/web-platform-tests/interfaces/resize-observer.idl
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
|
// Content was automatically extracted by Reffy into reffy-reports
|
||||||
|
// (https://github.com/tidoust/reffy-reports)
|
||||||
|
// Source: Resize Observer (https://drafts.csswg.org/resize-observer/)
|
||||||
|
|
||||||
|
enum ResizeObserverBoxOptions {
|
||||||
|
"border-box", "content-box"
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary ResizeObserverOptions {
|
||||||
|
ResizeObserverBoxOptions box = "content-box";
|
||||||
|
};
|
||||||
|
|
||||||
|
[Exposed=(Window),
|
||||||
|
Constructor(ResizeObserverCallback callback)]
|
||||||
|
interface ResizeObserver {
|
||||||
|
void observe(Element target, optional ResizeObserverOptions options);
|
||||||
|
void unobserve(Element target);
|
||||||
|
void disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, ResizeObserver observer);
|
||||||
|
|
||||||
|
[Exposed=Window, Constructor(Element target)]
|
||||||
|
interface ResizeObserverEntry {
|
||||||
|
readonly attribute Element target;
|
||||||
|
readonly attribute DOMRectReadOnly contentRect;
|
||||||
|
readonly attribute ResizeObserverSize borderBoxSize;
|
||||||
|
readonly attribute ResizeObserverSize contentBoxSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ResizeObserverSize {
|
||||||
|
readonly attribute unrestricted double inlineSize;
|
||||||
|
readonly attribute unrestricted double blockSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
[Constructor(Element target)
|
||||||
|
]
|
||||||
|
interface ResizeObservation {
|
||||||
|
readonly attribute Element target;
|
||||||
|
readonly attribute ResizeObserverBoxOptions observedBox;
|
||||||
|
readonly attribute ResizeObserverSize lastReportedSize;
|
||||||
|
};
|
|
@ -10,15 +10,15 @@ dictionary PerformanceMarkOptions {
|
||||||
|
|
||||||
dictionary PerformanceMeasureOptions {
|
dictionary PerformanceMeasureOptions {
|
||||||
any detail = null;
|
any detail = null;
|
||||||
(DOMString or DOMHighResTimeStamp) startTime;
|
(DOMString or DOMHighResTimeStamp) start;
|
||||||
DOMHighResTimeStamp duration;
|
DOMHighResTimeStamp duration;
|
||||||
(DOMString or DOMHighResTimeStamp) endTime;
|
(DOMString or DOMHighResTimeStamp) end;
|
||||||
};
|
};
|
||||||
|
|
||||||
partial interface Performance {
|
partial interface Performance {
|
||||||
PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions);
|
PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions);
|
||||||
void clearMarks(optional DOMString markName);
|
void clearMarks(optional DOMString markName);
|
||||||
PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions, optional DOMString endMark);
|
PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions)? startOrMeasureOptions, optional DOMString endMark);
|
||||||
void clearMeasures(optional DOMString measureName);
|
void clearMeasures(optional DOMString measureName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// GENERATED CONTENT - DO NOT EDIT
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
// Content was automatically extracted by Reffy into reffy-reports
|
// Content was automatically extracted by Reffy into reffy-reports
|
||||||
// (https://github.com/tidoust/reffy-reports)
|
// (https://github.com/tidoust/reffy-reports)
|
||||||
// Source: Web Authentication: An API for accessing Public Key Credentials - Level 1 (https://w3c.github.io/webauthn/)
|
// Source: Web Authentication: An API for accessing Public Key Credentials - Level 2 (https://w3c.github.io/webauthn/)
|
||||||
|
|
||||||
[SecureContext, Exposed=Window]
|
[SecureContext, Exposed=Window]
|
||||||
interface PublicKeyCredential : Credential {
|
interface PublicKeyCredential : Credential {
|
||||||
|
@ -30,6 +30,7 @@ interface AuthenticatorResponse {
|
||||||
[SecureContext, Exposed=Window]
|
[SecureContext, Exposed=Window]
|
||||||
interface AuthenticatorAttestationResponse : AuthenticatorResponse {
|
interface AuthenticatorAttestationResponse : AuthenticatorResponse {
|
||||||
[SameObject] readonly attribute ArrayBuffer attestationObject;
|
[SameObject] readonly attribute ArrayBuffer attestationObject;
|
||||||
|
sequence<AuthenticatorTransport> getTransports();
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window]
|
[SecureContext, Exposed=Window]
|
||||||
|
|
|
@ -20,7 +20,8 @@ enum RTCStatsType {
|
||||||
"candidate-pair",
|
"candidate-pair",
|
||||||
"local-candidate",
|
"local-candidate",
|
||||||
"remote-candidate",
|
"remote-candidate",
|
||||||
"certificate"
|
"certificate",
|
||||||
|
"stunserverconnection"
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary RTCRtpStreamStats : RTCStats {
|
dictionary RTCRtpStreamStats : RTCStats {
|
||||||
|
@ -28,11 +29,6 @@ dictionary RTCRtpStreamStats : RTCStats {
|
||||||
DOMString kind;
|
DOMString kind;
|
||||||
DOMString transportId;
|
DOMString transportId;
|
||||||
DOMString codecId;
|
DOMString codecId;
|
||||||
unsigned long firCount;
|
|
||||||
unsigned long pliCount;
|
|
||||||
unsigned long nackCount;
|
|
||||||
unsigned long sliCount;
|
|
||||||
unsigned long long qpSum;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary RTCCodecStats : RTCStats {
|
dictionary RTCCodecStats : RTCStats {
|
||||||
|
@ -72,13 +68,19 @@ dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
|
||||||
DOMString receiverId;
|
DOMString receiverId;
|
||||||
DOMString remoteId;
|
DOMString remoteId;
|
||||||
unsigned long framesDecoded;
|
unsigned long framesDecoded;
|
||||||
|
unsigned long long qpSum;
|
||||||
DOMHighResTimeStamp lastPacketReceivedTimestamp;
|
DOMHighResTimeStamp lastPacketReceivedTimestamp;
|
||||||
double averageRtcpInterval;
|
double averageRtcpInterval;
|
||||||
unsigned long fecPacketsReceived;
|
unsigned long fecPacketsReceived;
|
||||||
|
unsigned long fecPacketsDiscarded;
|
||||||
unsigned long long bytesReceived;
|
unsigned long long bytesReceived;
|
||||||
unsigned long packetsFailedDecryption;
|
unsigned long packetsFailedDecryption;
|
||||||
unsigned long packetsDuplicated;
|
unsigned long packetsDuplicated;
|
||||||
record<USVString, unsigned long> perDscpPacketsReceived;
|
record<USVString, unsigned long> perDscpPacketsReceived;
|
||||||
|
unsigned long nackCount;
|
||||||
|
unsigned long firCount;
|
||||||
|
unsigned long pliCount;
|
||||||
|
unsigned long sliCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
|
dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
|
||||||
|
@ -102,11 +104,16 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
|
||||||
DOMHighResTimeStamp lastPacketSentTimestamp;
|
DOMHighResTimeStamp lastPacketSentTimestamp;
|
||||||
double targetBitrate;
|
double targetBitrate;
|
||||||
unsigned long framesEncoded;
|
unsigned long framesEncoded;
|
||||||
|
unsigned long long qpSum;
|
||||||
double totalEncodeTime;
|
double totalEncodeTime;
|
||||||
double averageRtcpInterval;
|
double averageRtcpInterval;
|
||||||
RTCQualityLimitationReason qualityLimitationReason;
|
RTCQualityLimitationReason qualityLimitationReason;
|
||||||
record<DOMString, double> qualityLimitationDurations;
|
record<DOMString, double> qualityLimitationDurations;
|
||||||
record<USVString, unsigned long> perDscpPacketsSent;
|
record<USVString, unsigned long> perDscpPacketsSent;
|
||||||
|
unsigned long nackCount;
|
||||||
|
unsigned long firCount;
|
||||||
|
unsigned long pliCount;
|
||||||
|
unsigned long sliCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RTCQualityLimitationReason {
|
enum RTCQualityLimitationReason {
|
||||||
|
@ -198,6 +205,7 @@ dictionary RTCAudioReceiverStats : RTCAudioHandlerStats {
|
||||||
unsigned long long jitterBufferEmittedCount;
|
unsigned long long jitterBufferEmittedCount;
|
||||||
unsigned long long totalSamplesReceived;
|
unsigned long long totalSamplesReceived;
|
||||||
unsigned long long concealedSamples;
|
unsigned long long concealedSamples;
|
||||||
|
unsigned long long silentConcealedSamples;
|
||||||
unsigned long long concealmentEvents;
|
unsigned long long concealmentEvents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -298,6 +306,16 @@ dictionary RTCCertificateStats : RTCStats {
|
||||||
DOMString issuerCertificateId;
|
DOMString issuerCertificateId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary RTCStunServerConnectionStats : RTCStats {
|
||||||
|
DOMString url;
|
||||||
|
long port;
|
||||||
|
DOMString protocol;
|
||||||
|
RTCNetworkType networkType;
|
||||||
|
unsigned long totalRequestsSent;
|
||||||
|
unsigned long totalResponsesReceived;
|
||||||
|
double totalRoundTripTime;
|
||||||
|
};
|
||||||
|
|
||||||
partial dictionary RTCIceCandidateStats {
|
partial dictionary RTCIceCandidateStats {
|
||||||
boolean isRemote;
|
boolean isRemote;
|
||||||
};
|
};
|
||||||
|
@ -312,3 +330,7 @@ partial dictionary RTCRtpStreamStats {
|
||||||
DOMString mediaType;
|
DOMString mediaType;
|
||||||
double averageRTCPInterval;
|
double averageRTCPInterval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
partial dictionary RTCInboundRtpStreamStats {
|
||||||
|
double fractionLost;
|
||||||
|
};
|
||||||
|
|
|
@ -25,7 +25,6 @@ enum XREnvironmentBlendMode {
|
||||||
[SecureContext, Exposed=Window] interface XRSession : EventTarget {
|
[SecureContext, Exposed=Window] interface XRSession : EventTarget {
|
||||||
// Attributes
|
// Attributes
|
||||||
readonly attribute XRSessionMode mode;
|
readonly attribute XRSessionMode mode;
|
||||||
readonly attribute XRPresentationContext? outputContext;
|
|
||||||
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
||||||
readonly attribute XRRenderState renderState;
|
readonly attribute XRRenderState renderState;
|
||||||
readonly attribute XRSpace viewerSpace;
|
readonly attribute XRSpace viewerSpace;
|
||||||
|
@ -59,19 +58,20 @@ enum XRSessionMode {
|
||||||
|
|
||||||
dictionary XRSessionCreationOptions {
|
dictionary XRSessionCreationOptions {
|
||||||
XRSessionMode mode = "inline";
|
XRSessionMode mode = "inline";
|
||||||
XRPresentationContext? outputContext = null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary XRRenderStateInit {
|
dictionary XRRenderStateInit {
|
||||||
double depthNear;
|
double depthNear;
|
||||||
double depthFar;
|
double depthFar;
|
||||||
XRLayer? baseLayer;
|
XRLayer? baseLayer;
|
||||||
|
XRPresentationContext? outputContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRRenderState {
|
[SecureContext, Exposed=Window] interface XRRenderState {
|
||||||
readonly attribute double depthNear;
|
readonly attribute double depthNear;
|
||||||
readonly attribute double depthFar;
|
readonly attribute double depthFar;
|
||||||
readonly attribute XRLayer? baseLayer;
|
readonly attribute XRLayer? baseLayer;
|
||||||
|
readonly attribute XRPresentationContext? outputContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame);
|
callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame);
|
||||||
|
|
|
@ -804,4 +804,5 @@ CSS-COLLIDING-REF-NAME: css/vendor-imports/mozilla/mozilla-central-reftests/cont
|
||||||
|
|
||||||
# Signed Exchange files have hard-coded URLs in the certUrl field
|
# Signed Exchange files have hard-coded URLs in the certUrl field
|
||||||
WEB-PLATFORM.TEST:signed-exchange/resources/*.sxg
|
WEB-PLATFORM.TEST:signed-exchange/resources/*.sxg
|
||||||
|
WEB-PLATFORM.TEST:signed-exchange/appcache/resources/*.sxg
|
||||||
WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh
|
WEB-PLATFORM.TEST:signed-exchange/resources/generate-test-sxgs.sh
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><mo> paint lspace rspace</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>LTR case</h1>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 200px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<math>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="100px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="200px"></mspace>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 150px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<math>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="150px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="150px"></mspace>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 100px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<math>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="200px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="100px"></mspace>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<h1>RTL case</h1>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 200px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="100px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="200px"></mspace>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 150px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="150px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="150px"></mspace>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 100px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mspace width="200px"></mspace>
|
||||||
|
<mo lspace="0px" rspace="0px">→</mo>
|
||||||
|
<mspace width="100px"></mspace>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title><mo> paint lspace rspace</title>
|
||||||
|
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#tokenmo">
|
||||||
|
<meta name="assert" content="Verifies values for lspace and rspace for element mo in LTR and RTL modes.">
|
||||||
|
<link rel="match" href="mo-paint-lspace-rspace-ref.html">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>LTR case</h1>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 200px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<mth>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="100px" rspace="200px">→</mo>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 150px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<math>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="150px" rspace="150px">→</mo>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the left,
|
||||||
|
and a trailing space of 100px, which is as wide as the black block to the right.</p>
|
||||||
|
|
||||||
|
<math>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="200px" rspace="100px">→</mo>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<h1>RTL case</h1>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 200px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="100px" rspace="200px">→</mo>
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 150px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="150px" rspace="150px">→</mo>
|
||||||
|
<mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
|
||||||
|
<p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the right,
|
||||||
|
and a trailing space of 100px, which is as wide as the black block to the left.</p>
|
||||||
|
|
||||||
|
<math dir="rtl">
|
||||||
|
<mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
<mo lspace="200px" rspace="100px">→</mo>
|
||||||
|
<mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
|
||||||
|
</math>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,162 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- Copyright © 2019 Igalia. -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Frame checking test for MSE playback in presence of a reappend.</title>
|
||||||
|
<meta name="timeout" content="long">
|
||||||
|
<meta name="charset" content="UTF-8">
|
||||||
|
<link rel="author" title="Alicia Boya García" href="mailto:aboya@igalia.com">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="mediasource-util.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<canvas id="test-canvas"></canvas>
|
||||||
|
<script>
|
||||||
|
function waitForEventPromise(element, event) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
function handler(ev) {
|
||||||
|
element.removeEventListener(event, handler);
|
||||||
|
resolve(ev);
|
||||||
|
}
|
||||||
|
element.addEventListener(event, handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendBufferPromise(sourceBuffer, data) {
|
||||||
|
sourceBuffer.appendBuffer(data);
|
||||||
|
return waitForEventPromise(sourceBuffer, "update");
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForPlayerToReachTimePromise(mediaElement, time) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
function timeupdate() {
|
||||||
|
if (mediaElement.currentTime < time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mediaElement.removeEventListener("timeupdate", timeupdate);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
mediaElement.addEventListener("timeupdate", timeupdate);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPixel(imageData, x, y) {
|
||||||
|
return {
|
||||||
|
r: imageData.data[4 * (y * imageData.width + x)],
|
||||||
|
g: imageData.data[1 + 4 * (y * imageData.width + x)],
|
||||||
|
b: imageData.data[2 + 4 * (y * imageData.width + x)],
|
||||||
|
a: imageData.data[3 + 4 * (y * imageData.width + x)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPixelLit(pixel) {
|
||||||
|
const threshold = 200; // out of 255
|
||||||
|
return pixel.r >= threshold && pixel.g >= threshold && pixel.b >= threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test video has a few gray boxes. Each box interval (1 second) a new box is lit white and a different note
|
||||||
|
// is played. This test makes sure the right number of lit boxes and the right note are played at the right time.
|
||||||
|
const totalBoxes = 7;
|
||||||
|
const boxInterval = 1; // seconds
|
||||||
|
|
||||||
|
const videoWidth = 320;
|
||||||
|
const videoHeight = 240;
|
||||||
|
const boxesY = 210;
|
||||||
|
const boxSide = 20;
|
||||||
|
const boxMargin = 20;
|
||||||
|
const allBoxesWidth = totalBoxes * boxSide + (totalBoxes - 1) * boxMargin;
|
||||||
|
const boxesX = new Array(totalBoxes).fill(undefined)
|
||||||
|
.map((_, i) => (videoWidth - allBoxesWidth) / 2 + boxSide / 2 + i * (boxSide + boxMargin));
|
||||||
|
|
||||||
|
// Sound starts playing A4 (440 Hz) and goes one chromatic note up with every box lit.
|
||||||
|
// By comparing the player position to both the amount of boxes lit and the note played we can detect A/V
|
||||||
|
// synchronization issues automatically.
|
||||||
|
const noteFrequencies = new Array(1 + totalBoxes).fill(undefined)
|
||||||
|
.map((_, i) => 440 * Math.pow(Math.pow(2, 1 / 12), i));
|
||||||
|
|
||||||
|
// We also check the first second [0, 1) where no boxes are lit, therefore we start counting at -1 to do the check
|
||||||
|
// for zero lit boxes.
|
||||||
|
let boxesLitSoFar = -1;
|
||||||
|
|
||||||
|
mediasource_test(async function (test, mediaElement, mediaSource) {
|
||||||
|
const canvas = document.getElementById("test-canvas");
|
||||||
|
const canvasCtx = canvas.getContext("2d");
|
||||||
|
canvas.width = videoWidth;
|
||||||
|
canvas.height = videoHeight;
|
||||||
|
|
||||||
|
const videoData = await (await fetch("mp4/test-boxes-video.mp4")).arrayBuffer();
|
||||||
|
const audioData = (await (await fetch("mp4/test-boxes-audio.mp4")).arrayBuffer());
|
||||||
|
|
||||||
|
const videoSb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
|
||||||
|
const audioSb = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
|
||||||
|
|
||||||
|
mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
|
||||||
|
mediaElement.addEventListener('ended', onEnded);
|
||||||
|
mediaElement.addEventListener('timeupdate', onTimeUpdate);
|
||||||
|
|
||||||
|
await appendBufferPromise(videoSb, videoData);
|
||||||
|
await appendBufferPromise(audioSb, audioData);
|
||||||
|
mediaElement.play();
|
||||||
|
|
||||||
|
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
source = audioCtx.createMediaElementSource(mediaElement);
|
||||||
|
analyser = audioCtx.createAnalyser();
|
||||||
|
analyser.fftSize = 8192;
|
||||||
|
source.connect(analyser);
|
||||||
|
analyser.connect(audioCtx.destination);
|
||||||
|
|
||||||
|
const freqDomainArray = new Float32Array(analyser.frequencyBinCount);
|
||||||
|
|
||||||
|
function checkNoteBeingPlayed() {
|
||||||
|
const expectedNoteFrequency = noteFrequencies[boxesLitSoFar];
|
||||||
|
|
||||||
|
analyser.getFloatFrequencyData(freqDomainArray);
|
||||||
|
const maxBin = freqDomainArray.reduce((prev, curValue, i) =>
|
||||||
|
curValue > prev.value ? {index: i, value: curValue} : prev,
|
||||||
|
{index: -1, value: -Infinity});
|
||||||
|
const binFrequencyWidth = audioCtx.sampleRate / analyser.fftSize;
|
||||||
|
const binFreq = maxBin.index * binFrequencyWidth;
|
||||||
|
|
||||||
|
assert_true(Math.abs(expectedNoteFrequency - binFreq) <= binFrequencyWidth,
|
||||||
|
`The note being played matches the expected one (boxes lit: ${boxesLitSoFar}, ${expectedNoteFrequency.toFixed(1)} Hz)` +
|
||||||
|
`, found ~${binFreq.toFixed(1)} Hz`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countLitBoxesInCurrentVideoFrame() {
|
||||||
|
canvasCtx.drawImage(mediaElement, 0, 0);
|
||||||
|
const imageData = canvasCtx.getImageData(0, 0, videoWidth, videoHeight);
|
||||||
|
const lights = boxesX.map(boxX => isPixelLit(readPixel(imageData, boxX, boxesY)));
|
||||||
|
let litBoxes = 0;
|
||||||
|
for (let i = 0; i < lights.length; i++) {
|
||||||
|
if (lights[i])
|
||||||
|
litBoxes++;
|
||||||
|
}
|
||||||
|
for (let i = litBoxes; i < lights.length; i++) {
|
||||||
|
assert_false(lights[i], 'After the first non-lit box, all boxes must non-lit');
|
||||||
|
}
|
||||||
|
return litBoxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
await waitForPlayerToReachTimePromise(mediaElement, 2.5);
|
||||||
|
await appendBufferPromise(audioSb, audioData);
|
||||||
|
mediaSource.endOfStream();
|
||||||
|
|
||||||
|
function onTimeUpdate() {
|
||||||
|
const graceTime = 0.5;
|
||||||
|
if (mediaElement.currentTime >= (1 + boxesLitSoFar) * boxInterval + graceTime && boxesLitSoFar < totalBoxes) {
|
||||||
|
assert_equals(countLitBoxesInCurrentVideoFrame(), boxesLitSoFar + 1, "Num of lit boxes:");
|
||||||
|
boxesLitSoFar++;
|
||||||
|
checkNoteBeingPlayed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEnded() {
|
||||||
|
assert_equals(boxesLitSoFar, totalBoxes, "Boxes lit at video ended event");
|
||||||
|
test.done();
|
||||||
|
}
|
||||||
|
}, "Test the expected frames are played at the expected times, even in presence of reappends");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,146 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- Copyright © 2019 Igalia. -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Frame checking test for simple MSE playback.</title>
|
||||||
|
<meta name="timeout" content="long">
|
||||||
|
<meta name="charset" content="UTF-8">
|
||||||
|
<link rel="author" title="Alicia Boya García" href="mailto:aboya@igalia.com">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="mediasource-util.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<canvas id="test-canvas"></canvas>
|
||||||
|
<script>
|
||||||
|
function waitForEventPromise(element, event) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
function handler(ev) {
|
||||||
|
element.removeEventListener(event, handler);
|
||||||
|
resolve(ev);
|
||||||
|
}
|
||||||
|
element.addEventListener(event, handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendBufferPromise(sourceBuffer, data) {
|
||||||
|
sourceBuffer.appendBuffer(data);
|
||||||
|
return waitForEventPromise(sourceBuffer, "update");
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPixel(imageData, x, y) {
|
||||||
|
return {
|
||||||
|
r: imageData.data[4 * (y * imageData.width + x)],
|
||||||
|
g: imageData.data[1 + 4 * (y * imageData.width + x)],
|
||||||
|
b: imageData.data[2 + 4 * (y * imageData.width + x)],
|
||||||
|
a: imageData.data[3 + 4 * (y * imageData.width + x)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPixelLit(pixel) {
|
||||||
|
const threshold = 200; // out of 255
|
||||||
|
return pixel.r >= threshold && pixel.g >= threshold && pixel.b >= threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test video has a few gray boxes. Each box interval (1 second) a new box is lit white and a different note
|
||||||
|
// is played. This test makes sure the right number of lit boxes and the right note are played at the right time.
|
||||||
|
const totalBoxes = 7;
|
||||||
|
const boxInterval = 1; // seconds
|
||||||
|
|
||||||
|
const videoWidth = 320;
|
||||||
|
const videoHeight = 240;
|
||||||
|
const boxesY = 210;
|
||||||
|
const boxSide = 20;
|
||||||
|
const boxMargin = 20;
|
||||||
|
const allBoxesWidth = totalBoxes * boxSide + (totalBoxes - 1) * boxMargin;
|
||||||
|
const boxesX = new Array(totalBoxes).fill(undefined)
|
||||||
|
.map((_, i) => (videoWidth - allBoxesWidth) / 2 + boxSide / 2 + i * (boxSide + boxMargin));
|
||||||
|
|
||||||
|
// Sound starts playing A4 (440 Hz) and goes one chromatic note up with every box lit.
|
||||||
|
// By comparing the player position to both the amount of boxes lit and the note played we can detect A/V
|
||||||
|
// synchronization issues automatically.
|
||||||
|
const noteFrequencies = new Array(1 + totalBoxes).fill(undefined)
|
||||||
|
.map((_, i) => 440 * Math.pow(Math.pow(2, 1 / 12), i));
|
||||||
|
|
||||||
|
// We also check the first second [0, 1) where no boxes are lit, therefore we start counting at -1 to do the check
|
||||||
|
// for zero lit boxes.
|
||||||
|
let boxesLitSoFar = -1;
|
||||||
|
|
||||||
|
mediasource_test(async function (test, mediaElement, mediaSource) {
|
||||||
|
const canvas = document.getElementById("test-canvas");
|
||||||
|
const canvasCtx = canvas.getContext("2d");
|
||||||
|
canvas.width = videoWidth;
|
||||||
|
canvas.height = videoHeight;
|
||||||
|
|
||||||
|
const videoData = await (await fetch("mp4/test-boxes-video.mp4")).arrayBuffer();
|
||||||
|
const audioData = (await (await fetch("mp4/test-boxes-audio.mp4")).arrayBuffer());
|
||||||
|
|
||||||
|
const videoSb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
|
||||||
|
const audioSb = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
|
||||||
|
|
||||||
|
mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
|
||||||
|
mediaElement.addEventListener('ended', onEnded);
|
||||||
|
mediaElement.addEventListener('timeupdate', onTimeUpdate);
|
||||||
|
|
||||||
|
await appendBufferPromise(videoSb, videoData);
|
||||||
|
await appendBufferPromise(audioSb, audioData);
|
||||||
|
mediaSource.endOfStream();
|
||||||
|
mediaElement.play();
|
||||||
|
|
||||||
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
const source = audioCtx.createMediaElementSource(mediaElement);
|
||||||
|
const analyser = audioCtx.createAnalyser();
|
||||||
|
analyser.fftSize = 8192;
|
||||||
|
source.connect(analyser);
|
||||||
|
analyser.connect(audioCtx.destination);
|
||||||
|
|
||||||
|
const freqDomainArray = new Float32Array(analyser.frequencyBinCount);
|
||||||
|
|
||||||
|
function checkNoteBeingPlayed() {
|
||||||
|
const expectedNoteFrequency = noteFrequencies[boxesLitSoFar];
|
||||||
|
|
||||||
|
analyser.getFloatFrequencyData(freqDomainArray);
|
||||||
|
const maxBin = freqDomainArray.reduce((prev, curValue, i) =>
|
||||||
|
curValue > prev.value ? {index: i, value: curValue} : prev,
|
||||||
|
{index: -1, value: -Infinity});
|
||||||
|
const binFrequencyWidth = audioCtx.sampleRate / analyser.fftSize;
|
||||||
|
const binFreq = maxBin.index * binFrequencyWidth;
|
||||||
|
|
||||||
|
assert_true(Math.abs(expectedNoteFrequency - binFreq) <= binFrequencyWidth,
|
||||||
|
`The note being played matches the expected one (boxes lit: ${boxesLitSoFar}, ${expectedNoteFrequency.toFixed(1)} Hz)` +
|
||||||
|
`, found ~${binFreq.toFixed(1)} Hz`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countLitBoxesInCurrentVideoFrame() {
|
||||||
|
canvasCtx.drawImage(mediaElement, 0, 0);
|
||||||
|
const imageData = canvasCtx.getImageData(0, 0, videoWidth, videoHeight);
|
||||||
|
const lights = boxesX.map(boxX => isPixelLit(readPixel(imageData, boxX, boxesY)));
|
||||||
|
let litBoxes = 0;
|
||||||
|
for (let i = 0; i < lights.length; i++) {
|
||||||
|
if (lights[i])
|
||||||
|
litBoxes++;
|
||||||
|
}
|
||||||
|
for (let i = litBoxes; i < lights.length; i++) {
|
||||||
|
assert_false(lights[i], 'After the first non-lit box, all boxes must non-lit');
|
||||||
|
}
|
||||||
|
return litBoxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeUpdate() {
|
||||||
|
const graceTime = 0.5;
|
||||||
|
if (mediaElement.currentTime >= (1 + boxesLitSoFar) * boxInterval + graceTime && boxesLitSoFar < totalBoxes) {
|
||||||
|
assert_equals(countLitBoxesInCurrentVideoFrame(), boxesLitSoFar + 1, "Num of lit boxes:");
|
||||||
|
boxesLitSoFar++;
|
||||||
|
checkNoteBeingPlayed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEnded() {
|
||||||
|
assert_equals(boxesLitSoFar, totalBoxes, "Boxes lit at video ended event");
|
||||||
|
test.done();
|
||||||
|
}
|
||||||
|
}, "Test the expected frames are played at the expected times");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Binary file not shown.
Binary file not shown.
|
@ -24,220 +24,28 @@
|
||||||
|
|
||||||
let advanced_constraints_depth = [{
|
let advanced_constraints_depth = [{
|
||||||
videoKind: "depth",
|
videoKind: "depth",
|
||||||
focalLengthX: 0.5,
|
|
||||||
focalLengthY: 0.5,
|
|
||||||
principalPointX: 0.1,
|
|
||||||
principalPointY: 0.1,
|
|
||||||
deprojectionDistortionCoefficients: true,
|
|
||||||
projectionDistortionCoefficients: true,
|
|
||||||
depthNear: 0.5,
|
|
||||||
depthFar: 1,
|
|
||||||
depthToVideoTransform: true
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let advanced_constraints_color = [{
|
let advanced_constraints_color = [{
|
||||||
videoKind: "color",
|
videoKind: "color",
|
||||||
focalLengthX: 0.5,
|
}];
|
||||||
focalLengthY: 0.5,
|
|
||||||
principalPointX: 0.1,
|
|
||||||
principalPointY: 0.1,
|
|
||||||
deprojectionDistortionCoefficients: true,
|
|
||||||
projectionDistortionCoefficients: true
|
|
||||||
}];
|
|
||||||
|
|
||||||
/*
|
|
||||||
partial dictionary MediaTrackCapabilities {
|
|
||||||
// Apply to both depth stream track and color stream track:
|
|
||||||
DOMString videoKind;
|
|
||||||
(double or DoubleRange) focalLengthX;
|
|
||||||
(double or DoubleRange) focalLengthY;
|
|
||||||
(double or DoubleRange) principalPointX;
|
|
||||||
(double or DoubleRange) principalPointY;
|
|
||||||
boolean deprojectionDistortionCoefficients;
|
|
||||||
boolean projectionDistortionCoefficients;
|
|
||||||
// Apply to depth stream track:
|
|
||||||
(double or DoubleRange) depthNear;
|
|
||||||
(double or DoubleRange) depthFar;
|
|
||||||
boolean depthToVideoTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary DoubleRange {
|
|
||||||
double max;
|
|
||||||
double min;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
function validateMediaTrackCapabilities(capabilities, type) {
|
function validateMediaTrackCapabilities(capabilities, type) {
|
||||||
assert_string_field(capabilities, 'videoKind');
|
assert_string_field(capabilities, 'videoKind');
|
||||||
assert_number_or_number_range_field(capabilities, 'focalLengthX');
|
|
||||||
assert_number_or_number_range_field(capabilities, 'focalLengthY');
|
|
||||||
assert_number_or_number_range_field(capabilities, 'principalPointX');
|
|
||||||
assert_number_or_number_range_field(capabilities, 'principalPointY');
|
|
||||||
assert_boolean_field(capabilities, 'deprojectionDistortionCoefficients');
|
|
||||||
assert_boolean_field(capabilities, 'projectionDistortionCoefficients');
|
|
||||||
if (type == "depth") {
|
|
||||||
assert_number_or_number_range_field(capabilities, 'depthNear');
|
|
||||||
assert_number_or_number_range_field(capabilities, 'depthFar');
|
|
||||||
assert_boolean_field(capabilities, 'depthToVideoTransform');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
partial dictionary MediaTrackConstraintSet {
|
|
||||||
// Apply to both depth stream track and color stream track:
|
|
||||||
ConstrainDOMString videoKind;
|
|
||||||
ConstrainDouble focalLengthX;
|
|
||||||
ConstrainDouble focalLengthY;
|
|
||||||
ConstrainDouble principalPointX;
|
|
||||||
ConstrainDouble principalPointY;
|
|
||||||
ConstrainBoolean deprojectionDistortionCoefficients;
|
|
||||||
ConstrainBoolean projectionDistortionCoefficients;
|
|
||||||
// Apply to depth stream track:
|
|
||||||
ConstrainDouble depthNear;
|
|
||||||
ConstrainDouble depthFar;
|
|
||||||
ConstrainBoolean depthToVideoTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef (DOMString or sequence<DOMString> or ConstrainDOMStringParameters) ConstrainDOMString;
|
|
||||||
|
|
||||||
dictionary ConstrainDOMStringParameters {
|
|
||||||
(DOMString or sequence<DOMString>) exact;
|
|
||||||
(DOMString or sequence<DOMString>) ideal;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef (double or ConstrainDoubleRange) ConstrainDouble;
|
|
||||||
|
|
||||||
dictionary DoubleRange {
|
|
||||||
double max;
|
|
||||||
double min;
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary ConstrainDoubleRange : DoubleRange {
|
|
||||||
double exact;
|
|
||||||
double ideal;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef (boolean or ConstrainBooleanParameters) ConstrainBoolean;
|
|
||||||
|
|
||||||
dictionary ConstrainBooleanParameters {
|
|
||||||
boolean exact;
|
|
||||||
boolean ideal;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
function validateMediaTrackConstraintSet(constraints, type) {
|
function validateMediaTrackConstraintSet(constraints, type) {
|
||||||
assert_constrain_string_field(constraints, 'videoKind');
|
assert_constrain_string_field(constraints, 'videoKind');
|
||||||
assert_constrain_number_field(constraints, 'focalLengthX');
|
|
||||||
assert_constrain_number_field(constraints, 'focalLengthY');
|
|
||||||
assert_constrain_number_field(constraints, 'principalPointX');
|
|
||||||
assert_constrain_number_field(constraints, 'principalPointY');
|
|
||||||
assert_constrain_boolean_field(constraints, 'deprojectionDistortionCoefficients');
|
|
||||||
assert_constrain_boolean_field(constraints, 'projectionDistortionCoefficients');
|
|
||||||
if (type == "depth") {
|
|
||||||
assert_constrain_number_field(constraints, 'depthNear');
|
|
||||||
assert_constrain_number_field(constraints, 'depthFar');
|
|
||||||
assert_constrain_boolean_field(constraints, 'depthToVideoTransform');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
partial dictionary MediaTrackSettings {
|
|
||||||
// Apply to both depth stream track and color stream track:
|
|
||||||
DOMString videoKind;
|
|
||||||
double focalLengthX;
|
|
||||||
double focalLengthY;
|
|
||||||
double principalPointX;
|
|
||||||
double principalPointY;
|
|
||||||
DistortionCoefficients deprojectionDistortionCoefficients;
|
|
||||||
DistortionCoefficients projectionDistortionCoefficients;
|
|
||||||
// Apply to depth stream track:
|
|
||||||
double depthNear;
|
|
||||||
double depthFar;
|
|
||||||
Transformation depthToVideoTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary DistortionCoefficients {
|
|
||||||
double k1;
|
|
||||||
double k2;
|
|
||||||
double p1;
|
|
||||||
double p2;
|
|
||||||
double k3;
|
|
||||||
};
|
|
||||||
|
|
||||||
dictionary Transformation {
|
|
||||||
Float32Array transformationMatrix;
|
|
||||||
DOMString videoDeviceId;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum VideoKindEnum {
|
|
||||||
"color",
|
|
||||||
"depth"
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
function validateDistortionCoefficients(coefficients) {
|
|
||||||
assert_number_field(coefficients, 'k1');
|
|
||||||
assert_number_field(coefficients, 'k2');
|
|
||||||
assert_number_field(coefficients, 'p1');
|
|
||||||
assert_number_field(coefficients, 'p2');
|
|
||||||
assert_number_field(coefficients, 'k3');
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateTransformation(depthToVideoTransform) {
|
|
||||||
assert_array_field(depthToVideoTransform, 'transformationMatrix');
|
|
||||||
assert_string_field(depthToVideoTransform, 'videoDeviceId');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateMediaTrackSettings(settings, type) {
|
function validateMediaTrackSettings(settings, type) {
|
||||||
assert_string_field(settings, 'videoKind');
|
assert_string_field(settings, 'videoKind');
|
||||||
assert_enum_field(settings, 'videoKind', ['color', 'depth'])
|
assert_enum_field(settings, 'videoKind', ['color', 'depth'])
|
||||||
assert_number_field(settings, 'focalLengthX');
|
|
||||||
assert_number_field(settings, 'focalLengthY');
|
|
||||||
assert_number_field(settings, 'principalPointX');
|
|
||||||
assert_number_field(settings, 'principalPointY');
|
|
||||||
if (settings.deprojectionDistortionCoefficients) {
|
|
||||||
validateDistortionCoefficients(settings.deprojectionDistortionCoefficients);
|
|
||||||
}
|
|
||||||
if (settings.projectionDistortionCoefficients) {
|
|
||||||
validateDistortionCoefficients(settings.projectionDistortionCoefficients);
|
|
||||||
}
|
|
||||||
if (type == "depth") {
|
|
||||||
assert_number_field(settings, 'depthNear');
|
|
||||||
assert_number_field(settings, 'depthFar');
|
|
||||||
if (settings.depthToVideoTransform) {
|
|
||||||
validateTransformation(settings.depthToVideoTransform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
partial dictionary MediaTrackSupportedConstraints {
|
|
||||||
// Apply to both depth stream track and color stream track:
|
|
||||||
boolean videoKind = true;
|
|
||||||
boolean focalLengthX = false;
|
|
||||||
boolean focalLengthY = false;
|
|
||||||
boolean principalPointX = false;
|
|
||||||
boolean principalPointY = false;
|
|
||||||
boolean deprojectionDistortionCoefficients = false;
|
|
||||||
boolean projectionDistortionCoefficients = false;
|
|
||||||
// Apply to depth stream track:
|
|
||||||
boolean depthNear = false;
|
|
||||||
boolean depthFar = false;
|
|
||||||
boolean depthToVideoTransform = false;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
function validateMediaTrackSupportedConstraints(supports) {
|
function validateMediaTrackSupportedConstraints(supports) {
|
||||||
assert_boolean_field(supports, 'videoKind', true);
|
assert_boolean_field(supports, 'videoKind', true);
|
||||||
assert_boolean_field(supports, 'focalLengthX', false);
|
|
||||||
assert_boolean_field(supports, 'focalLengthY', false);
|
|
||||||
assert_boolean_field(supports, 'principalPointX', false);
|
|
||||||
assert_boolean_field(supports, 'principalPointY', false);
|
|
||||||
assert_boolean_field(supports, 'deprojectionDistortionCoefficients', false);
|
|
||||||
assert_boolean_field(supports, 'projectionDistortionCoefficients', false);
|
|
||||||
assert_boolean_field(supports, 'depthNear', false);
|
|
||||||
assert_boolean_field(supports, 'depthFar', false);
|
|
||||||
assert_boolean_field(supports, 'depthToVideoTransform', false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runDictionaryTests(type, constraints) {
|
function runDictionaryTests(type, constraints) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue