Bug 1429043 - Update web-platform-tests to revision 4de5305adf3d33badc23952672bcf28168fea37e, a=testonly

MozReview-Commit-ID: 8hFZiSUb5Qr


--HG--
rename : testing/web-platform/tests/bluetooth/idl-Bluetooth.html => testing/web-platform/tests/bluetooth/idl/idl-Bluetooth.html
rename : testing/web-platform/tests/cookies/secure/set-from-ws.https.sub.html => testing/web-platform/tests/cookies/secure/set-from-ws.sub.html
rename : testing/web-platform/tests/css/css-values/iframe/vh-support-transform-origin-iframe.html => testing/web-platform/tests/css/css-values/support/vh-support-transform-origin-iframe.html
rename : testing/web-platform/tests/css/css-values/iframe/vh-support-transform-translate-iframe.html => testing/web-platform/tests/css/css-values/support/vh-support-transform-translate-iframe.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/a-ref.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/a-ref.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/match/a-ref.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/match/a-ref.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/match/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/match/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/match/support/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/match/support/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/match/support/tools/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/match/support/tools/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/match/tools/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/match/tools/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/not-match/a-ref.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/not-match/a-ref.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/not-match/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/not-match/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/not-match/support/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/not-match/support/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/not-match/tools/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/not-match/tools/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/selectors/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/selectors/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/support/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/support/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/support/tools/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/support/tools/a.html
rename : testing/web-platform/tests/tools/lint/tests/dummy/css-unique/tools/a.html => testing/web-platform/tests/tools/lint/tests/dummy/css/css-unique/tools/a.html
rename : testing/web-platform/tests/tools/py/.hgignore => testing/web-platform/tests/tools/third_party/py/.hgignore
rename : testing/web-platform/tests/tools/py/AUTHORS => testing/web-platform/tests/tools/third_party/py/AUTHORS
rename : testing/web-platform/tests/tools/py/LICENSE => testing/web-platform/tests/tools/third_party/py/LICENSE
rename : testing/web-platform/tests/tools/py/bench/localpath.py => testing/web-platform/tests/tools/third_party/py/bench/localpath.py
rename : testing/web-platform/tests/tools/py/doc/Makefile => testing/web-platform/tests/tools/third_party/py/doc/Makefile
rename : testing/web-platform/tests/tools/py/doc/_templates/layout.html => testing/web-platform/tests/tools/third_party/py/doc/_templates/layout.html
rename : testing/web-platform/tests/tools/py/doc/announce/release-0.9.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-0.9.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-0.9.2.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-0.9.2.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.0.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.0.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.0.1.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.0.1.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.0.2.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.0.2.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.1.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.1.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.1.1.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.1.1.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.2.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.2.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.2.1.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.2.1.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.3.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.3.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.3.1.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.3.1.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.3.2.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.3.2.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.3.3.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.3.3.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.3.4.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.3.4.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.4.0.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.4.0.txt
rename : testing/web-platform/tests/tools/py/doc/announce/release-1.4.1.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/release-1.4.1.txt
rename : testing/web-platform/tests/tools/py/doc/announce/releases.txt => testing/web-platform/tests/tools/third_party/py/doc/announce/releases.txt
rename : testing/web-platform/tests/tools/py/doc/changelog.txt => testing/web-platform/tests/tools/third_party/py/doc/changelog.txt
rename : testing/web-platform/tests/tools/py/doc/code.txt => testing/web-platform/tests/tools/third_party/py/doc/code.txt
rename : testing/web-platform/tests/tools/py/doc/conf.py => testing/web-platform/tests/tools/third_party/py/doc/conf.py
rename : testing/web-platform/tests/tools/py/doc/download.html => testing/web-platform/tests/tools/third_party/py/doc/download.html
rename : testing/web-platform/tests/tools/py/doc/example/genhtml.py => testing/web-platform/tests/tools/third_party/py/doc/example/genhtml.py
rename : testing/web-platform/tests/tools/py/doc/example/genhtmlcss.py => testing/web-platform/tests/tools/third_party/py/doc/example/genhtmlcss.py
rename : testing/web-platform/tests/tools/py/doc/example/genxml.py => testing/web-platform/tests/tools/third_party/py/doc/example/genxml.py
rename : testing/web-platform/tests/tools/py/doc/faq.txt => testing/web-platform/tests/tools/third_party/py/doc/faq.txt
rename : testing/web-platform/tests/tools/py/doc/img/pylib.png => testing/web-platform/tests/tools/third_party/py/doc/img/pylib.png
rename : testing/web-platform/tests/tools/py/doc/io.txt => testing/web-platform/tests/tools/third_party/py/doc/io.txt
rename : testing/web-platform/tests/tools/py/doc/links.inc => testing/web-platform/tests/tools/third_party/py/doc/links.inc
rename : testing/web-platform/tests/tools/py/doc/log.txt => testing/web-platform/tests/tools/third_party/py/doc/log.txt
rename : testing/web-platform/tests/tools/py/doc/style.css => testing/web-platform/tests/tools/third_party/py/doc/style.css
rename : testing/web-platform/tests/tools/py/doc/xml.txt => testing/web-platform/tests/tools/third_party/py/doc/xml.txt
rename : testing/web-platform/tests/tools/py/py/__metainfo.py => testing/web-platform/tests/tools/third_party/py/py/__metainfo.py
rename : testing/web-platform/tests/tools/py/py/_builtin.py => testing/web-platform/tests/tools/third_party/py/py/_builtin.py
rename : testing/web-platform/tests/tools/py/py/_code/__init__.py => testing/web-platform/tests/tools/third_party/py/py/_code/__init__.py
rename : testing/web-platform/tests/tools/py/py/_code/_py2traceback.py => testing/web-platform/tests/tools/third_party/py/py/_code/_py2traceback.py
rename : testing/web-platform/tests/tools/py/py/_io/__init__.py => testing/web-platform/tests/tools/third_party/py/py/_io/__init__.py
rename : testing/web-platform/tests/tools/py/py/_io/capture.py => testing/web-platform/tests/tools/third_party/py/py/_io/capture.py
rename : testing/web-platform/tests/tools/py/py/_io/saferepr.py => testing/web-platform/tests/tools/third_party/py/py/_io/saferepr.py
rename : testing/web-platform/tests/tools/py/py/_log/__init__.py => testing/web-platform/tests/tools/third_party/py/py/_log/__init__.py
rename : testing/web-platform/tests/tools/py/py/_path/__init__.py => testing/web-platform/tests/tools/third_party/py/py/_path/__init__.py
rename : testing/web-platform/tests/tools/py/py/_path/cacheutil.py => testing/web-platform/tests/tools/third_party/py/py/_path/cacheutil.py
rename : testing/web-platform/tests/tools/py/py/_process/__init__.py => testing/web-platform/tests/tools/third_party/py/py/_process/__init__.py
rename : testing/web-platform/tests/tools/py/py/_process/cmdexec.py => testing/web-platform/tests/tools/third_party/py/py/_process/cmdexec.py
rename : testing/web-platform/tests/tools/py/py/_process/forkedfunc.py => testing/web-platform/tests/tools/third_party/py/py/_process/forkedfunc.py
rename : testing/web-platform/tests/tools/py/py/_process/killproc.py => testing/web-platform/tests/tools/third_party/py/py/_process/killproc.py
rename : testing/web-platform/tests/tools/pytest/_pytest/vendored_packages/pluggy-0.3.1.dist-info/WHEEL => testing/web-platform/tests/tools/third_party/py/py/_vendored_packages/apipkg-1.4.dist-info/WHEEL
rename : testing/web-platform/tests/tools/py/py/test.py => testing/web-platform/tests/tools/third_party/py/py/test.py
rename : testing/web-platform/tests/tools/py/testing/code/test_code.py => testing/web-platform/tests/tools/third_party/py/testing/code/test_code.py
rename : testing/web-platform/tests/tools/py/testing/conftest.py => testing/web-platform/tests/tools/third_party/py/testing/conftest.py
rename : testing/web-platform/tests/tools/py/testing/io_/__init__.py => testing/web-platform/tests/tools/third_party/py/testing/io_/__init__.py
rename : testing/web-platform/tests/tools/py/testing/path/repotest.dump => testing/web-platform/tests/tools/third_party/py/testing/path/repotest.dump
rename : testing/web-platform/tests/tools/py/testing/path/svntestbase.py => testing/web-platform/tests/tools/third_party/py/testing/path/svntestbase.py
rename : testing/web-platform/tests/tools/py/testing/path/test_svnurl.py => testing/web-platform/tests/tools/third_party/py/testing/path/test_svnurl.py
rename : testing/web-platform/tests/tools/py/testing/process/__init__.py => testing/web-platform/tests/tools/third_party/py/testing/process/__init__.py
rename : testing/web-platform/tests/tools/py/testing/root/__init__.py => testing/web-platform/tests/tools/third_party/py/testing/root/__init__.py
rename : testing/web-platform/tests/tools/py/testing/root/test_builtin.py => testing/web-platform/tests/tools/third_party/py/testing/root/test_builtin.py
rename : testing/web-platform/tests/tools/py/testing/root/test_std.py => testing/web-platform/tests/tools/third_party/py/testing/root/test_std.py
rename : testing/web-platform/tests/tools/pytest/.gitattributes => testing/web-platform/tests/tools/third_party/pytest/.gitattributes
rename : testing/web-platform/tests/tools/pytest/bench/bench.py => testing/web-platform/tests/tools/third_party/pytest/bench/bench.py
rename : testing/web-platform/tests/tools/pytest/bench/bench_argcomplete.py => testing/web-platform/tests/tools/third_party/pytest/bench/bench_argcomplete.py
rename : testing/web-platform/tests/tools/pytest/bench/empty.py => testing/web-platform/tests/tools/third_party/pytest/bench/empty.py
rename : testing/web-platform/tests/tools/pytest/bench/manyparam.py => testing/web-platform/tests/tools/third_party/pytest/bench/manyparam.py
rename : testing/web-platform/tests/tools/pytest/bench/skip.py => testing/web-platform/tests/tools/third_party/pytest/bench/skip.py
rename : testing/web-platform/tests/tools/pytest/doc/en/_templates/sidebarintro.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/_templates/sidebarintro.html
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/.gitignore => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/.gitignore
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/LICENSE => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/LICENSE
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/README => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/README
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/flask/layout.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/flask/layout.html
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/flask/relations.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/flask/relations.html
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/flask/static/flasky.css_t => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/flask/static/flasky.css_t
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/flask/theme.conf => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/flask/theme.conf
rename : testing/web-platform/tests/tools/pytest/doc/en/_themes/flask_theme_support.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/_themes/flask_theme_support.py
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.0.0.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.0.0.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.0.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.0.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.1.0.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.1.0.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.1.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.1.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.1.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.1.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.1.3.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.1.3.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.2.0.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.2.0.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.2.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.2.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.3.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.3.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.3.4.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.3.4.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.4.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.4.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.4.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.4.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.5.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.5.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.6.0.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.6.0.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.6.1.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.6.1.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.6.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.6.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.7.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.7.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.2.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.2.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.3.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.3.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.4.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.4.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.5.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.5.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.6.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.6.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/announce/release-2.8.7.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/announce/release-2.8.7.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/changelog.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/changelog.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/check_sphinx.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/check_sphinx.py
rename : testing/web-platform/tests/tools/pytest/doc/en/conftest.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/conftest.py
rename : testing/web-platform/tests/tools/pytest/doc/en/contributing.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/contributing.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/conftest.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/assertion/global_testmodule_config/test_hello.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/assertion/test_failures.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/assertion/test_failures.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/conftest.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/conftest.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/costlysetup/sub1/__init__.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/__init__.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/costlysetup/sub1/test_quick.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/costlysetup/sub1/test_quick.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/costlysetup/sub2/__init__.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/__init__.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/costlysetup/sub2/test_two.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/costlysetup/sub2/test_two.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/nonpython/test_simple.yml => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/nonpython/test_simple.yml
rename : testing/web-platform/tests/tools/pytest/doc/en/example/py2py3/conftest.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/py2py3/conftest.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/py2py3/test_py2.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/py2py3/test_py2.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/py2py3/test_py3.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/py2py3/test_py3.py
rename : testing/web-platform/tests/tools/pytest/doc/en/example/xfail_demo.py => testing/web-platform/tests/tools/third_party/pytest/doc/en/example/xfail_demo.py
rename : testing/web-platform/tests/tools/pytest/doc/en/funcargs.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/funcargs.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/img/cramer2.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/cramer2.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/freiburg2.jpg => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/freiburg2.jpg
rename : testing/web-platform/tests/tools/pytest/doc/en/img/gaynor3.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/gaynor3.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/keleshev.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/keleshev.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/pullrequest.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/pullrequest.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/pylib.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/pylib.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/pytest1.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/pytest1.png
rename : testing/web-platform/tests/tools/pytest/doc/en/img/pytest1favi.ico => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/pytest1favi.ico
rename : testing/web-platform/tests/tools/pytest/doc/en/img/theuni.png => testing/web-platform/tests/tools/third_party/pytest/doc/en/img/theuni.png
rename : testing/web-platform/tests/tools/pytest/doc/en/naming20.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/naming20.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/pytest.ini => testing/web-platform/tests/tools/third_party/pytest/doc/en/pytest.ini
rename : testing/web-platform/tests/tools/pytest/doc/en/test/config.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/config.html
rename : testing/web-platform/tests/tools/pytest/doc/en/test/dist.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/dist.html
rename : testing/web-platform/tests/tools/pytest/doc/en/test/extend.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/extend.html
rename : testing/web-platform/tests/tools/pytest/doc/en/test/index.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/index.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/test/plugin/django.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/plugin/django.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/test/plugin/index.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/plugin/index.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/test/plugin/oejskit.rst => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/plugin/oejskit.rst
rename : testing/web-platform/tests/tools/pytest/doc/en/test/test.html => testing/web-platform/tests/tools/third_party/pytest/doc/en/test/test.html
rename : testing/web-platform/tests/tools/pytest/extra/setup-py.test/setup.py => testing/web-platform/tests/tools/third_party/pytest/extra/setup-py.test/setup.py
rename : testing/web-platform/tests/tools/pytest/testing/cx_freeze/tests/test_doctest.txt => testing/web-platform/tests/tools/third_party/pytest/testing/freeze/tests/test_doctest.txt
This commit is contained in:
James Graham 2018-01-03 16:24:44 +00:00
Родитель 3a7a79b6b8
Коммит 0375220b76
2064 изменённых файлов: 82530 добавлений и 25532 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,2 +1,2 @@
local: 5b33b070378ae0806bed0b5e5e34de429a29e7db local: ac93fdadf1022211eec62258ad22b42cb37a6d14
upstream: df8508402c2b47f43c2f5bf8da8ba9e95a2a56b9 upstream: 45668a155fde7eb87c4c82721fc18fcf8c757c60

Просмотреть файл

@ -63,7 +63,7 @@ matrix:
- fonts-liberation - fonts-liberation
env: env:
- secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM="
- JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:unstable - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:dev
- os: linux - os: linux
python: "2.7" python: "2.7"
env: env:
@ -94,7 +94,7 @@ matrix:
- env: JOB=build_css SCRIPT=css/build-css-testsuites.sh - env: JOB=build_css SCRIPT=css/build-css-testsuites.sh
- env: - env:
- secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM="
- JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:unstable - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=chrome:dev
- env: - env:
- secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM="
- JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=sauce:MicrosoftEdge:14.14393 PLATFORM='Windows 10' - JOB=stability SCRIPT=tools/ci/ci_stability.sh PRODUCT=sauce:MicrosoftEdge:14.14393 PLATFORM='Windows 10'

Просмотреть файл

@ -21,6 +21,15 @@ _addTest(function(canvas, ctx) {
var g = ctx.createLinearGradient(0, 0, 100, 0); var g = ctx.createLinearGradient(0, 0, 100, 0);
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, ""); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, ""); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'null'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'undefined'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, null); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, undefined); });
var g = ctx.createRadialGradient(0, 0, 0, 100, 0, 0);
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, ""); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'null'); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'null'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'undefined'); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, 'undefined'); });
assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, null); }); assert_throws("SYNTAX_ERR", function() { g.addColorStop(0, null); });

Просмотреть файл

@ -1,10 +1,6 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <!doctype html>
<html>
<head>
<script src="/resources/testharness.js"></script> <script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
</head>
<body>
<script> <script>
function makeCanvas() { function makeCanvas() {
@ -86,6 +82,22 @@ function makeInvalidBlob() {
}); });
} }
function makeBrokenImage() {
return new Promise(resolve => {
const image = new Image();
image.src = "data,x";
image.onerror = () => resolve(image);
});
}
function makeAvailableButBrokenImage() {
return new Promise(resolve => {
const image = new Image();
image.src = "/images/broken.png";
image.onload = () => resolve(image);
});
}
imageSourceTypes = [ imageSourceTypes = [
{ name: 'HTMLImageElement', factory: makeImage }, { name: 'HTMLImageElement', factory: makeImage },
{ name: 'HTMLVideoElement', factory: makeVideo }, { name: 'HTMLVideoElement', factory: makeVideo },
@ -152,36 +164,48 @@ promise_test( t => {
}, "createImageBitmap with null image source rejects with a TypeError."); }, "createImageBitmap with null image source rejects with a TypeError.");
promise_test( t => { promise_test( t => {
return promise_rejects(t, new DOMException('', 'InvalidStateError'), return promise_rejects(t, "InvalidStateError",
createImageBitmap(new Image())); createImageBitmap(new Image()));
}, "createImageBitmap with empty image source rejects with a InvalidStateError."); }, "createImageBitmap with empty image source rejects with a InvalidStateError.");
promise_test( t => { promise_test( t => {
return promise_rejects(t, new DOMException('', 'InvalidStateError'), return promise_rejects(t, "InvalidStateError",
createImageBitmap(document.createElement('video'))); createImageBitmap(document.createElement('video')));
}, "createImageBitmap with empty video source rejects with a InvalidStateError."); }, "createImageBitmap with empty video source rejects with a InvalidStateError.");
promise_test( t => { promise_test( t => {
return makeOversizedCanvas().then(canvas => { return makeOversizedCanvas().then(canvas => {
return promise_rejects(t, new DOMException('', 'InvalidStateError'), return promise_rejects(t, "InvalidStateError",
createImageBitmap(canvas)); createImageBitmap(canvas));
}); });
}, "createImageBitmap with an oversized canvas source rejects with a RangeError."); }, "createImageBitmap with an oversized canvas source rejects with a RangeError.");
promise_test( t => { promise_test( t => {
return makeOversizedOffscreenCanvas().then(offscreenCanvas => { return makeOversizedOffscreenCanvas().then(offscreenCanvas => {
return promise_rejects(t, new DOMException('', 'InvalidStateError'), return promise_rejects(t, "InvalidStateError",
createImageBitmap(offscreenCanvas)); createImageBitmap(offscreenCanvas));
}); });
}, "createImageBitmap with an invalid OffscreenCanvas source rejects with a RangeError."); }, "createImageBitmap with an invalid OffscreenCanvas source rejects with a RangeError.");
promise_test( t => { promise_test( t => {
return makeInvalidBlob().then(blob => { return makeInvalidBlob().then(blob => {
return promise_rejects(t, new DOMException('', 'InvalidStateError'), return promise_rejects(t, "InvalidStateError",
createImageBitmap(blob)); createImageBitmap(blob));
}); });
}, "createImageBitmap with an undecodable blob source rejects with an InvalidStateError."); }, "createImageBitmap with an undecodable blob source rejects with an InvalidStateError.");
promise_test( t => {
return makeBrokenImage().then(image => {
return promise_rejects(t, "InvalidStateError",
createImageBitmap(image));
});
}, "createImageBitmap with a broken image source rejects with an InvalidStateError.");
promise_test( t => {
return makeAvailableButBrokenImage().then(image => {
return promise_rejects(t, "InvalidStateError",
createImageBitmap(image));
});
}, "createImageBitmap with an available but undecodable image source rejects with an InvalidStateError.");
</script> </script>
</body>
</html>

Просмотреть файл

@ -2092,6 +2092,15 @@
code: | code: |
var g = ctx.createLinearGradient(0, 0, 100, 0); var g = ctx.createLinearGradient(0, 0, 100, 0);
@assert throws SYNTAX_ERR g.addColorStop(0, ""); @assert throws SYNTAX_ERR g.addColorStop(0, "");
@assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)');
@assert throws SYNTAX_ERR g.addColorStop(0, 'null');
@assert throws SYNTAX_ERR g.addColorStop(0, 'undefined');
@assert throws SYNTAX_ERR g.addColorStop(0, null);
@assert throws SYNTAX_ERR g.addColorStop(0, undefined);
var g = ctx.createRadialGradient(0, 0, 0, 100, 0, 0);
@assert throws SYNTAX_ERR g.addColorStop(0, "");
@assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)');
@assert throws SYNTAX_ERR g.addColorStop(0, 'null'); @assert throws SYNTAX_ERR g.addColorStop(0, 'null');
@assert throws SYNTAX_ERR g.addColorStop(0, 'undefined'); @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined');
@assert throws SYNTAX_ERR g.addColorStop(0, null); @assert throws SYNTAX_ERR g.addColorStop(0, null);

Просмотреть файл

@ -0,0 +1,41 @@
<!doctype html>
<title>Revoking blob URL used with Request/fetch</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(function(t) {
const blob = new Blob(["test"]);
const url = URL.createObjectURL(blob);
const request = new Request(url);
// Revoke the object URL. Request should take a reference to the blob as
// soon as it receives it in open(), so the request succeeds even though we
// revoke the URL before calling fetch().
URL.revokeObjectURL(url);
return fetch(request).then(response => response.text()).then(text => {
assert_equals(text, 'test');
});
}, "Revoke blob URL after creating Request, will fetch");
promise_test(function(t) {
const blob = new Blob(["test"]);
const url = URL.createObjectURL(blob);
return fetch(url).then(response => response.text()).then(text => {
assert_equals(text, 'test');
});
// Revoke the object URL. fetch should have already resolved the blob URL.
URL.revokeObjectURL(url);
}, "Revoke blob URL after fetch, will fetch");
promise_test(t => {
const blob = new Blob(["test"]);
const url = URL.createObjectURL(blob);
URL.revokeObjectURL(url);
const request = new Request(url);
return promise_rejects(t, new TypeError, fetch(request));
}, "Revoke blob URL before creating Request, network error (after fetch)")
</script>

Просмотреть файл

@ -0,0 +1,104 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Blob constructor: endings option</title>
<link rel=help href="https://w3c.github.io/FileAPI/#constructorBlob">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
// Windows platforms use CRLF as the native line ending. All others use LF.
const crlf = navigator.platform.startsWith('Win');
const native_ending = crlf ? '\r\n' : '\n';
function readBlobAsPromise(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsText(blob);
reader.onload = e => resolve(reader.result);
reader.onerror = e => reject(reader.error);
});
}
[
'transparent',
'native'
].forEach(value => test(t => {
assert_class_string(new Blob([], {endings: value}), 'Blob',
`Constructor should allow "${value}" endings`);
}, `Valid "endings" value: ${JSON.stringify(value)}`));
[
null,
'',
'invalidEnumValue',
'Transparent',
'NATIVE',
0,
{}
].forEach(value => test(t => {
assert_throws(new TypeError(), () => new Blob([], {endings: value}),
'Blob constructor should throw');
}, `Invalid "endings" value: ${JSON.stringify(value)}`));
test(t => {
const test_error = {name: 'test'};
assert_throws(
test_error,
() => new Blob([], { get endings() { throw test_error; }}),
'Blob constructor should propagate exceptions from "endings" property');
}, 'Exception propagation from options');
test(t => {
let got = false;
new Blob([], { get endings() { got = true; } });
assert_true(got, 'The "endings" property was accessed during construction.');
}, 'The "endings" options property is used');
[
{name: 'LF', input: '\n', native: native_ending},
{name: 'CR', input: '\r', native: native_ending},
{name: 'CRLF', input: '\r\n', native: native_ending},
{name: 'CRCR', input: '\r\r', native: native_ending.repeat(2)},
{name: 'LFCR', input: '\n\r', native: native_ending.repeat(2)},
{name: 'LFLF', input: '\n\n', native: native_ending.repeat(2)},
{name: 'CRCRLF', input: '\r\r\n', native: native_ending.repeat(2)},
{name: 'CRLFLF', input: '\r\n\n', native: native_ending.repeat(2)},
{name: 'CRLFCR', input: '\r\n\r\n', native: native_ending.repeat(2)},
{name: 'CRLFCRLF', input: '\r\n\r\n', native: native_ending.repeat(2)},
{name: 'LFCRLFCR', input: '\n\r\n\r', native: native_ending.repeat(3)},
].forEach(testCase => {
promise_test(async t => {
const blob = new Blob([testCase.input]);
assert_equals(
await readBlobAsPromise(blob), testCase.input,
'Newlines should not change with endings unspecified');
}, `Input ${testCase.name} with endings unspecified`);
promise_test(async t => {
const blob = new Blob([testCase.input], {endings: 'transparent'});
assert_equals(
await readBlobAsPromise(blob), testCase.input,
'Newlines should not change with endings "transparent"');
}, `Input ${testCase.name} with endings 'transparent'`);
promise_test(async t => {
const blob = new Blob([testCase.input], {endings: 'native'});
assert_equals(
await readBlobAsPromise(blob), testCase.native,
'Newlines should match the platform with endings "native"');
}, `Input ${testCase.name} with endings 'native'`);
});
promise_test(async t => {
const blob = new Blob(['\r', '\n'], {endings: 'native'});
const expected = native_ending.repeat(2);
assert_equals(
await readBlobAsPromise(blob), expected,
'CR/LF in adjacent strings should be converted to two platform newlines');
}, `CR/LF in adjacent input strings`);
</script>

Просмотреть файл

@ -74,6 +74,20 @@ test_blob(function() {
type: "", type: "",
desc: "A plain object with @@iterator should be treated as a sequence for the blobParts argument." desc: "A plain object with @@iterator should be treated as a sequence for the blobParts argument."
}); });
test(t => {
const blob = new Blob({
[Symbol.iterator]() {
var i = 0;
return {next: () => [
{done:false, value:'ab'},
{done:false, value:'cde'},
{done:true}
][i++]
};
}
});
assert_equals(blob.size, 5, 'Custom @@iterator should be treated as a sequence');
}, "A plain object with custom @@iterator should be treated as a sequence for the blobParts argument.");
test_blob(function() { test_blob(function() {
return new Blob({ return new Blob({
[Symbol.iterator]: Array.prototype[Symbol.iterator], [Symbol.iterator]: Array.prototype[Symbol.iterator],
@ -392,26 +406,20 @@ test_blob(function() {
desc: "Array with mixed types" desc: "Array with mixed types"
}); });
// options argument
test(function() { test(function() {
new Blob([], { endings: "invalidEnumValue" }); const accessed = [];
new Blob([], { endings: null }); const stringified = [];
new Blob([], { endings: undefined });
new Blob([], { endings: 0 });
new Blob([], { get endings() { assert_unreached("Should not call getter"); } });
}, "The 'endings' property should be ignored.");
test(function() {
assert_throws(test_error, function() {
new Blob([], { new Blob([], {
get type() { throw test_error; } get type() { accessed.push('type'); },
get endings() { accessed.push('endings'); }
}); });
});
assert_throws(test_error, function() {
new Blob([], { new Blob([], {
type: { toString: function() { throw test_error; } } type: { toString: () => { stringified.push('type'); return ''; } },
}); endings: { toString: () => { stringified.push('endings'); return 'transparent'; } }
}); });
assert_array_equals(accessed, ['endings', 'type']);
assert_array_equals(stringified, ['endings', 'type']);
}, "options properties should be accessed in lexicographic order."); }, "options properties should be accessed in lexicographic order.");
test(function() { test(function() {
@ -449,19 +457,16 @@ test(function() {
}); });
}); });
test_blob(function() { [
return new Blob(["\na\r\nb\n\rc\r"], { endings: "transparent" }); 123,
}, { 123.4,
expected: "\na\r\nb\n\rc\r", true,
type: "", 'abc'
desc: "Newlines should not change when endings is 'transparent'." ].forEach(arg => {
}); test(t => {
test_blob(function() { assert_throws(new TypeError(), () => new Blob([], arg),
return new Blob(["\na\r\nb\n\rc\r"], { endings: "native" }); 'Blob constructor should throw with invalid property bag');
}, { }, `Passing ${JSON.stringify(arg)} for options should throw`);
expected: "\na\r\nb\n\rc\r",
type: "",
desc: "Newlines should not change when endings is 'native'."
}); });
var type_tests = [ var type_tests = [
@ -471,6 +476,7 @@ var type_tests = [
[[], 'A', 'a'], [[], 'A', 'a'],
[[], 'text/html', 'text/html'], [[], 'text/html', 'text/html'],
[[], 'TEXT/HTML', 'text/html'], [[], 'TEXT/HTML', 'text/html'],
[[], 'text/plain;charset=utf-8', 'text/plain;charset=utf-8'],
[[], '\u00E5', ''], [[], '\u00E5', ''],
[[], '\uD801\uDC7E', ''], // U+1047E [[], '\uD801\uDC7E', ''], // U+1047E
[[], ' image/gif ', ' image/gif '], [[], ' image/gif ', ' image/gif '],

Просмотреть файл

@ -0,0 +1,104 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>File constructor: endings option</title>
<link rel=help href="https://w3c.github.io/FileAPI/#file-constructor">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
// Windows platforms use CRLF as the native line ending. All others use LF.
const crlf = navigator.platform.startsWith('Win');
const native_ending = crlf ? '\r\n' : '\n';
function readBlobAsPromise(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsText(blob);
reader.onload = e => resolve(reader.result);
reader.onerror = e => reject(reader.error);
});
}
[
'transparent',
'native'
].forEach(value => test(t => {
assert_class_string(new File([], "name", {endings: value}), 'File',
`Constructor should allow "${value}" endings`);
}, `Valid "endings" value: ${JSON.stringify(value)}`));
[
null,
'',
'invalidEnumValue',
'Transparent',
'NATIVE',
0,
{}
].forEach(value => test(t => {
assert_throws(new TypeError(), () => new File([], "name", {endings: value}),
'File constructor should throw');
}, `Invalid "endings" value: ${JSON.stringify(value)}`));
test(t => {
const test_error = {name: 'test'};
assert_throws(
test_error,
() => new File([], "name", { get endings() { throw test_error; }}),
'File constructor should propagate exceptions from "endings" property');
}, 'Exception propagation from options');
test(t => {
let got = false;
new File([], "name", { get endings() { got = true; } });
assert_true(got, 'The "endings" property was accessed during construction.');
}, 'The "endings" options property is used');
[
{name: 'LF', input: '\n', native: native_ending},
{name: 'CR', input: '\r', native: native_ending},
{name: 'CRLF', input: '\r\n', native: native_ending},
{name: 'CRCR', input: '\r\r', native: native_ending.repeat(2)},
{name: 'LFCR', input: '\n\r', native: native_ending.repeat(2)},
{name: 'LFLF', input: '\n\n', native: native_ending.repeat(2)},
{name: 'CRCRLF', input: '\r\r\n', native: native_ending.repeat(2)},
{name: 'CRLFLF', input: '\r\n\n', native: native_ending.repeat(2)},
{name: 'CRLFCR', input: '\r\n\r\n', native: native_ending.repeat(2)},
{name: 'CRLFCRLF', input: '\r\n\r\n', native: native_ending.repeat(2)},
{name: 'LFCRLFCR', input: '\n\r\n\r', native: native_ending.repeat(3)},
].forEach(testCase => {
promise_test(async t => {
const file = new File([testCase.input], "name");
assert_equals(
await readBlobAsPromise(file), testCase.input,
'Newlines should not change with endings unspecified');
}, `Input ${testCase.name} with endings unspecified`);
promise_test(async t => {
const file = new File([testCase.input], "name", {endings: 'transparent'});
assert_equals(
await readBlobAsPromise(file), testCase.input,
'Newlines should not change with endings "transparent"');
}, `Input ${testCase.name} with endings 'transparent'`);
promise_test(async t => {
const file = new File([testCase.input], "name", {endings: 'native'});
assert_equals(
await readBlobAsPromise(file), testCase.native,
'Newlines should match the platform with endings "native"');
}, `Input ${testCase.name} with endings 'native'`);
});
promise_test(async t => {
const file = new File(['\r', '\n'], "name", {endings: 'native'});
const expected = native_ending.repeat(2);
assert_equals(
await readBlobAsPromise(file), expected,
'CR/LF in adjacent strings should be converted to two platform newlines');
}, `CR/LF in adjacent input strings`);
</script>

Просмотреть файл

@ -6,10 +6,20 @@
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<div id="log"></div> <div id="log"></div>
<script> <script>
const to_string_obj = { toString: () => 'a string' };
const to_string_throws = { toString: () => { throw new Error('expected'); } };
test(function() { test(function() {
assert_true("File" in window, "window should have a File property."); assert_true("File" in window, "window should have a File property.");
}, "File interface object exists"); }, "File interface object exists");
test(t => {
assert_throws(new TypeError(), () => new File(),
'Bits argument is required');
assert_throws(new TypeError(), () => new File([]),
'Name argument is required');
}, 'Required arguments');
function test_first_argument(arg1, expectedSize, testName) { function test_first_argument(arg1, expectedSize, testName) {
test(function() { test(function() {
var file = new File(arg1, "dummy"); var file = new File(arg1, "dummy");
@ -22,14 +32,48 @@ function test_first_argument(arg1, expectedSize, testName) {
}, testName); }, testName);
} }
test_first_argument([], 0, "empty fileBits");
test_first_argument(["bits"], 4, "DOMString fileBits"); test_first_argument(["bits"], 4, "DOMString fileBits");
test_first_argument(["𝓽𝓮𝔁𝓽"], 16, "Unicode DOMString fileBits"); test_first_argument(["𝓽𝓮𝔁𝓽"], 16, "Unicode DOMString fileBits");
test_first_argument([new String('string object')], 13, "String object fileBits");
test_first_argument([new Blob()], 0, "Empty Blob fileBits"); test_first_argument([new Blob()], 0, "Empty Blob fileBits");
test_first_argument([new Blob(["bits"])], 4, "Blob fileBits"); test_first_argument([new Blob(["bits"])], 4, "Blob fileBits");
test_first_argument([new File([], 'world.txt')], 0, "Empty File fileBits");
test_first_argument([new File(["bits"], 'world.txt')], 4, "File fileBits");
test_first_argument([new ArrayBuffer(8)], 8, "ArrayBuffer fileBits"); test_first_argument([new ArrayBuffer(8)], 8, "ArrayBuffer fileBits");
test_first_argument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4, "Typed array fileBits"); test_first_argument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4, "Typed array fileBits");
test_first_argument(["bits", new Blob(["bits"]), new Blob(), new Uint8Array([0x50, 0x41]), test_first_argument(["bits", new Blob(["bits"]), new Blob(), new Uint8Array([0x50, 0x41]),
new Uint16Array([0x5353]), new Uint32Array([0x53534150])], 16, "Various fileBits"); new Uint16Array([0x5353]), new Uint32Array([0x53534150])], 16, "Various fileBits");
test_first_argument([12], 2, "Number in fileBits");
test_first_argument([[1,2,3]], 5, "Array in fileBits");
test_first_argument([{}], 15, "Object in fileBits"); // "[object Object]"
test_first_argument([document], 21, "HTMLDocument in fileBits"); // "[object HTMLDocument]"
test_first_argument([to_string_obj], 8, "Object with toString in fileBits");
test_first_argument({[Symbol.iterator]() {
let i = 0;
return {next: () => [
{done:false, value:'ab'},
{done:false, value:'cde'},
{done:true}
][i++]};
}}, 5, 'Custom @@iterator');
[
'hello',
0,
null
].forEach(arg => {
test(t => {
assert_throws(new TypeError(), () => new File(arg, 'world.html'),
'Constructor should throw for invalid bits argument');
}, `Invalid bits argument: ${JSON.stringify(arg)}`);
});
test(t => {
assert_throws(new Error(), () => new File([to_string_throws], 'name.txt'),
'Constructor should propagate exceptions');
}, 'Bits argument: object that throws');
function test_second_argument(arg2, expectedFileName, testName) { function test_second_argument(arg2, expectedFileName, testName) {
test(function() { test(function() {
@ -41,23 +85,29 @@ function test_second_argument(arg2, expectedFileName, testName) {
test_second_argument("dummy", "dummy", "Using fileName"); test_second_argument("dummy", "dummy", "Using fileName");
test_second_argument("dummy/foo", "dummy:foo", "Using special character in fileName"); test_second_argument("dummy/foo", "dummy:foo", "Using special character in fileName");
test_second_argument(null, "null", "Using null fileName");
test_second_argument(1, "1", "Using number fileName");
test_second_argument('', '', "Using empty string fileName");
test_second_argument(document, '[object HTMLDocument]', "Using object fileName");
// testing the third argument // testing the third argument
test(function() { [
var file = new File(["bits"], "dummy", { type: "text/plain"}); {type: 'text/plain', expected: 'text/plain'},
{type: 'text/plain;charset=UTF-8', expected: 'text/plain;charset=utf-8'},
{type: 'TEXT/PLAIN', expected: 'text/plain'},
{type: '𝓽𝓮𝔁𝓽/𝔭𝔩𝔞𝔦𝔫', expected: ''},
{type: 'ascii/nonprintable\u001F', expected: ''},
{type: 'ascii/nonprintable\u007F', expected: ''},
{type: 'nonascii\u00EE', expected: ''},
{type: 'nonascii\u1234', expected: ''},
{type: 'nonparsable', expected: 'nonparsable'}
].forEach(testCase => {
test(t => {
var file = new File(["bits"], "dummy", { type: testCase.type});
assert_true(file instanceof File); assert_true(file instanceof File);
assert_equals(file.type, "text/plain"); assert_equals(file.type, testCase.expected);
}, "Using type on the File constructor"); }, `Using type in File constructor: ${testCase.type}`);
test(function() { });
var file = new File(["bits"], "dummy", { type: "TEXT/PLAIN"});
assert_true(file instanceof File);
assert_equals(file.type, "text/plain");
}, "Using uppercase characters in type");
test(function() {
var file = new File(["bits"], "dummy", { type: "𝓽𝓮𝔁𝓽/𝔭𝔩𝔞𝔦𝔫"});
assert_true(file instanceof File);
assert_equals(file.type, "");
}, "Using illegal character for type");
test(function() { test(function() {
var file = new File(["bits"], "dummy", { lastModified: 42 }); var file = new File(["bits"], "dummy", { lastModified: 42 });
assert_true(file instanceof File); assert_true(file instanceof File);
@ -68,5 +118,41 @@ test(function() {
assert_true(file instanceof File); assert_true(file instanceof File);
assert_equals(file.name, "dummy"); assert_equals(file.name, "dummy");
}, "Misusing name"); }, "Misusing name");
test(function() {
var file = new File(["bits"], "dummy", { unknownKey: "value" });
assert_true(file instanceof File);
assert_equals(file.name, "dummy");
}, "Unknown properties are ignored");
[
123,
123.4,
true,
'abc'
].forEach(arg => {
test(t => {
assert_throws(new TypeError(), () => new File(['bits'], 'name.txt', arg),
'Constructor should throw for invalid property bag type');
}, `Invalid property bag: ${JSON.stringify(arg)}`);
});
[
null,
undefined,
[1,2,3],
/regex/,
function() {}
].forEach(arg => {
test(t => {
assert_equals(new File(['bits'], 'name.txt', arg).size, 4,
'Constructor should accept object-ish property bag type');
}, `Unusual but valid property bag: ${arg}`);
});
test(t => {
assert_throws(new Error(),
() => new File(['bits'], 'name.txt', {type: to_string_throws}),
'Constructor should propagate exceptions');
}, 'Property bag propagates exceptions');
</script> </script>

Просмотреть файл

@ -0,0 +1,71 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Upload files in ISO-2022-JP form (tentative)</title>
<!--
NOTE: This test is tentative because encoding for filename
characters unrepresentable in the form charset is not yet
standardized.
-->
<link rel="help"
href="https://github.com/whatwg/html/issues/3223">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
<link rel="help"
href="https://w3c.github.io/FileAPI/#file-constructor">
<link rel="author" title="Benjamin C. Wiley Sittler"
href="mailto:bsittler@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/send-file-form-helper.js"></script>
<script>
'use strict';
formPostFileUploadTest({
fileNameSource: 'ASCII',
fileBaseName: 'file-for-upload-in-form.txt',
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: 'file-for-upload-in-form.txt',
});
formPostFileUploadTest({
fileNameSource: 'x-user-defined',
fileBaseName: 'file-for-upload-in-form-\uF7F0\uF793\uF783\uF7A0.txt',
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: (
'file-for-upload-in-form-&#63472;&#63379;&#63363;&#63392;.txt'),
});
formPostFileUploadTest({
fileNameSource: 'windows-1252',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: (
'file-for-upload-in-form-&#226;&#732;&#186;&#240;&#376;&#732;&#8218;.txt'),
});
formPostFileUploadTest({
fileNameSource: 'JIS X 0201 and JIS X 0208',
fileBaseName: 'file-for-upload-in-form-★星★.txt',
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: 'file-for-upload-in-form-\x1B$B!z@1!z\x1B(B.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: 'file-for-upload-in-form-&#9786;&#128514;.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: `file-for-upload-in-form-${kTestChars}.txt`,
formEncoding: 'ISO-2022-JP',
expectedEncodedBaseName: `file-for-upload-in-form-${
kTestFallbackIso2022jp
}.txt`,
});
</script>

Просмотреть файл

@ -0,0 +1,61 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Upload files in UTF-8 form</title>
<link rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
<link rel="help"
href="https://w3c.github.io/FileAPI/#file-constructor">
<link rel="author" title="Benjamin C. Wiley Sittler"
href="mailto:bsittler@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/send-file-form-helper.js"></script>
<script>
'use strict';
formPostFileUploadTest({
fileNameSource: 'ASCII',
fileBaseName: 'file-for-upload-in-form.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: 'file-for-upload-in-form.txt',
});
formPostFileUploadTest({
fileNameSource: 'x-user-defined',
fileBaseName: 'file-for-upload-in-form-\uF7F0\uF793\uF783\uF7A0.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: (
'file-for-upload-in-form-\uF7F0\uF793\uF783\uF7A0.txt'),
});
formPostFileUploadTest({
fileNameSource: 'windows-1252',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: 'file-for-upload-in-form-☺😂.txt',
});
formPostFileUploadTest({
fileNameSource: 'JIS X 0201 and JIS X 0208',
fileBaseName: 'file-for-upload-in-form-★星★.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: 'file-for-upload-in-form-★星★.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: 'file-for-upload-in-form-☺😂.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: `file-for-upload-in-form-${kTestChars}.txt`,
formEncoding: 'UTF-8',
expectedEncodedBaseName: `file-for-upload-in-form-${kTestChars}.txt`,
});
</script>

Просмотреть файл

@ -0,0 +1,70 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Upload files in Windows-1252 form (tentative)</title>
<!--
NOTE: This test is tentative because encoding for filename
characters unrepresentable in the form charset is not yet
standardized.
-->
<link rel="help"
href="https://github.com/whatwg/html/issues/3223">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
<link rel="help"
href="https://w3c.github.io/FileAPI/#file-constructor">
<link rel="author" title="Benjamin C. Wiley Sittler"
href="mailto:bsittler@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/send-file-form-helper.js"></script>
<script>
'use strict';
formPostFileUploadTest({
fileNameSource: 'ASCII',
fileBaseName: 'file-for-upload-in-form.txt',
formEncoding: 'windows-1252',
expectedEncodedBaseName: 'file-for-upload-in-form.txt',
});
formPostFileUploadTest({
fileNameSource: 'x-user-defined',
fileBaseName: 'file-for-upload-in-form-\uF7F0\uF793\uF783\uF7A0.txt',
formEncoding: 'windows-1252',
expectedEncodedBaseName: (
'file-for-upload-in-form-&#63472;&#63379;&#63363;&#63392;.txt'),
});
formPostFileUploadTest({
fileNameSource: 'windows-1252',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'windows-1252',
expectedEncodedBaseName: 'file-for-upload-in-form-☺😂.txt',
});
formPostFileUploadTest({
fileNameSource: 'JIS X 0201 and JIS X 0208',
fileBaseName: 'file-for-upload-in-form-★星★.txt',
formEncoding: 'windows-1252',
expectedEncodedBaseName: 'file-for-upload-in-form-&#9733;&#26143;&#9733;.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'windows-1252',
expectedEncodedBaseName: 'file-for-upload-in-form-&#9786;&#128514;.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: `file-for-upload-in-form-${kTestChars}.txt`,
formEncoding: 'windows-1252',
expectedEncodedBaseName: `file-for-upload-in-form-${
kTestFallbackWindows1252
}.txt`,
});
</script>

Просмотреть файл

@ -0,0 +1,70 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Upload files in x-user-defined form (tentative)</title>
<!--
NOTE: This test is tentative because encoding for filename
characters unrepresentable in the form charset is not yet
standardized.
-->
<link rel="help"
href="https://github.com/whatwg/html/issues/3223">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
<link rel="help"
href="https://w3c.github.io/FileAPI/#file-constructor">
<link rel="author" title="Benjamin C. Wiley Sittler"
href="mailto:bsittler@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/send-file-form-helper.js"></script>
<script>
'use strict';
formPostFileUploadTest({
fileNameSource: 'ASCII',
fileBaseName: 'file-for-upload-in-form.txt',
formEncoding: 'x-user-defined',
expectedEncodedBaseName: 'file-for-upload-in-form.txt',
});
formPostFileUploadTest({
fileNameSource: 'x-user-defined',
fileBaseName: 'file-for-upload-in-form-\uF7F0\uF793\uF783\uF7A0.txt',
formEncoding: 'x-user-defined',
expectedEncodedBaseName: 'file-for-upload-in-form-𓃠.txt',
});
formPostFileUploadTest({
fileNameSource: 'windows-1252',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'x-user-defined',
expectedEncodedBaseName: ('file-for-upload-in-form-' +
'&#226;&#732;&#186;&#240;&#376;&#732;&#8218;.txt'),
});
formPostFileUploadTest({
fileNameSource: 'JIS X 0201 and JIS X 0208',
fileBaseName: 'file-for-upload-in-form-★星★.txt',
formEncoding: 'x-user-defined',
expectedEncodedBaseName: 'file-for-upload-in-form-&#9733;&#26143;&#9733;.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: 'file-for-upload-in-form-☺😂.txt',
formEncoding: 'x-user-defined',
expectedEncodedBaseName: 'file-for-upload-in-form-&#9786;&#128514;.txt',
});
formPostFileUploadTest({
fileNameSource: 'Unicode',
fileBaseName: `file-for-upload-in-form-${kTestChars}.txt`,
formEncoding: 'x-user-defined',
expectedEncodedBaseName: `file-for-upload-in-form-${
kTestFallbackXUserDefined
}.txt`,
});
</script>

Просмотреть файл

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Upload ASCII-named file in UTF-8 form</title>
<link rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
<link rel="help"
href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
<link rel="help"
href="https://w3c.github.io/FileAPI/#file-constructor">
<link rel="author" title="Benjamin C. Wiley Sittler"
href="mailto:bsittler@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/send-file-form-helper.js"></script>
<script>
'use strict';
formPostFileUploadTest({
fileNameSource: 'ASCII',
fileBaseName: 'file-for-upload-in-form.txt',
formEncoding: 'UTF-8',
expectedEncodedBaseName: 'file-for-upload-in-form.txt',
});
</script>

Просмотреть файл

@ -30,8 +30,6 @@ setup(function() {
request.onload = function() { request.onload = function() {
var idls = request.responseText; var idls = request.responseText;
idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };");
idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface ArrayBuffer {};"); idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface ArrayBuffer {};");
idl_array.add_untested_idls("interface URL {};"); idl_array.add_untested_idls("interface URL {};");
idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface EventTarget {};"); idl_array.add_untested_idls("[Exposed=(Window,Worker)] interface EventTarget {};");

Просмотреть файл

@ -0,0 +1,249 @@
'use strict';
// Rationale for this particular test character sequence, which is
// used in filenames and also in file contents:
//
// - ABC~ ensures the string starts with something we can read to
// ensure it is from the correct source; ~ is used because even
// some 1-byte otherwise-ASCII-like parts of ISO-2022-JP
// interpret it differently.
// - ‾¥ are inside a single-byte range of ISO-2022-JP and help
// diagnose problems due to filesystem encoding or locale
// - ≈ is inside IBM437 and helps diagnose problems due to filesystem
// encoding or locale
// - ¤ is inside Latin-1 and helps diagnose problems due to
// filesystem encoding or locale; it is also the "simplest" case
// needing substitution in ISO-2022-JP
// - ・ is inside a single-byte range of ISO-2022-JP in some variants
// and helps diagnose problems due to filesystem encoding or locale;
// on the web it is distinct when decoding but unified when encoding
// - ・ is inside a double-byte range of ISO-2022-JP and helps
// diagnose problems due to filesystem encoding or locale
// - • is inside Windows-1252 and helps diagnose problems due to
// filesystem encoding or locale and also ensures these aren't
// accidentally turned into e.g. control codes
// - ∙ is inside IBM437 and helps diagnose problems due to filesystem
// encoding or locale
// - · is inside Latin-1 and helps diagnose problems due to
// filesystem encoding or locale and also ensures HTML named
// character references (e.g. &middot;) are not used
// - ☼ is inside IBM437 shadowing C0 and helps diagnose problems due to
// filesystem encoding or locale and also ensures these aren't
// accidentally turned into e.g. control codes
// - ★ is inside ISO-2022-JP on a non-Kanji page and makes correct
// output easier to spot
// - 星 is inside ISO-2022-JP on a Kanji page and makes correct
// output easier to spot
// - 🌟 is outside the BMP and makes incorrect surrogate pair
// substitution detectable and ensures substitutions work
// correctly immediately after Kanji 2-byte ISO-2022-JP
// - 星 repeated here ensures the correct codec state is used
// after a non-BMP substitution
// - ★ repeated here also makes correct output easier to spot
// - ☼ is inside IBM437 shadowing C0 and helps diagnose problems due to
// filesystem encoding or locale and also ensures these aren't
// accidentally turned into e.g. control codes and also ensures
// substitutions work correctly immediately after non-Kanji
// 2-byte ISO-2022-JP
// - · is inside Latin-1 and helps diagnose problems due to
// filesystem encoding or locale and also ensures HTML named
// character references (e.g. &middot;) are not used
// - ∙ is inside IBM437 and helps diagnose problems due to filesystem
// encoding or locale
// - • is inside Windows-1252 and again helps diagnose problems
// due to filesystem encoding or locale
// - ・ is inside a double-byte range of ISO-2022-JP and helps
// diagnose problems due to filesystem encoding or locale
// - ・ is inside a single-byte range of ISO-2022-JP in some variants
// and helps diagnose problems due to filesystem encoding or locale;
// on the web it is distinct when decoding but unified when encoding
// - ¤ is inside Latin-1 and helps diagnose problems due to
// filesystem encoding or locale; again it is a "simple"
// substitution case
// - ≈ is inside IBM437 and helps diagnose problems due to filesystem
// encoding or locale
// - ¥‾ are inside a single-byte range of ISO-2022-JP and help
// diagnose problems due to filesystem encoding or locale
// - ~XYZ ensures earlier errors don't lead to misencoding of
// simple ASCII
//
// Overall the near-symmetry makes common I18N mistakes like
// off-by-1-after-non-BMP easier to spot. All the characters
// are also allowed in Windows Unicode filenames.
const kTestChars = 'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ';
// NOTE: The expected interpretation of ISO-2022-JP according to
// https://encoding.spec.whatwg.org/#iso-2022-jp-encoder unifies
// single-byte and double-byte katakana.
const kTestFallbackIso2022jp =
('ABC~\x1B(J~\\≈¤\x1B$B!&!&\x1B(B•∙·☼\x1B$B!z@1\x1B(B🌟' +
'\x1B$B@1!z\x1B(B☼·∙•\x1B$B!&!&\x1B(B¤≈\x1B(J\\~\x1B(B~XYZ').replace(
/[^\0-\x7F]/gu,
x => `&#${x.codePointAt(0)};`);
// NOTE: \uFFFD is used here to replace Windows-1252 bytes to match
// how we will see them in the reflected POST bytes in a frame using
// UTF-8 byte interpretation. The bytes will actually be intact, but
// this code cannot tell and does not really care.
const kTestFallbackWindows1252 =
'ABC~‾\xA5≈\xA4・・\x95∙\xB7☼★星🌟星★☼\xB7∙\x95・・\xA4≈\xA5‾~XYZ'.replace(
/[^\0-\xFF]/gu,
x => `&#${x.codePointAt(0)};`).replace(/[\x80-\xFF]/g, '\uFFFD');
const kTestFallbackXUserDefined =
kTestChars.replace(/[^\0-\x7F]/gu, x => `&#${x.codePointAt(0)};`);
// formPostFileUploadTest - verifies multipart upload structure and
// numeric character reference replacement for filenames, field names,
// and field values.
//
// Uses /fetch/api/resources/echo-content.py to echo the upload
// POST with UTF-8 byte interpretation, leading to the "UTF-8 goggles"
// behavior documented below for expectedEncodedBaseName when non-
// UTF-8-compatible byte sequences appear in the formEncoding-encoded
// uploaded data.
//
// Fields in the parameter object:
//
// - fileNameSource: purely explanatory and gives a clue about which
// character encoding is the source for the non-7-bit-ASCII parts of
// the fileBaseName, or Unicode if no smaller-than-Unicode source
// contains all the characters. Used in the test name.
// - fileBaseName: the not-necessarily-just-7-bit-ASCII file basename
// used for the constructed test file. Used in the test name.
// - formEncoding: the acceptCharset of the form used to submit the
// test file. Used in the test name.
// - expectedEncodedBaseName: the expected formEncoding-encoded
// version of fileBaseName with unencodable characters replaced by
// numeric character references and non-7-bit-ASCII bytes seen
// through UTF-8 goggles; subsequences not interpretable as UTF-8
// have each byte represented here by \uFFFD REPLACEMENT CHARACTER.
const formPostFileUploadTest = ({
fileNameSource,
fileBaseName,
formEncoding,
expectedEncodedBaseName,
}) => {
promise_test(async testCase => {
if (document.readyState !== 'complete') {
await new Promise(resolve => addEventListener('load', resolve));
}
const formTargetFrame = Object.assign(document.createElement('iframe'), {
name: 'formtargetframe',
});
document.body.append(formTargetFrame);
testCase.add_cleanup(() => {
document.body.removeChild(formTargetFrame);
});
const form = Object.assign(document.createElement('form'), {
acceptCharset: formEncoding,
action: '/fetch/api/resources/echo-content.py',
method: 'POST',
enctype: 'multipart/form-data',
target: formTargetFrame.name,
});
document.body.append(form);
testCase.add_cleanup(() => {
document.body.removeChild(form);
});
// Used to verify that the browser agrees with the test about
// which form charset is used.
form.append(Object.assign(document.createElement('input'), {
type: 'hidden',
name: '_charset_',
}));
// Used to verify that the browser agrees with the test about
// field value replacement and encoding independently of file system
// idiosyncracies.
form.append(Object.assign(document.createElement('input'), {
type: 'hidden',
name: 'filename',
value: fileBaseName,
}));
// Same, but with name and value reversed to ensure field names
// get the same treatment.
form.append(Object.assign(document.createElement('input'), {
type: 'hidden',
name: fileBaseName,
value: 'filename',
}));
const fileInput = Object.assign(document.createElement('input'), {
type: 'file',
name: 'file',
});
form.append(fileInput);
// Removes c:\fakepath\ or other pseudofolder and returns just the
// final component of filePath; allows both / and \ as segment
// delimiters.
const baseNameOfFilePath = filePath => filePath.split(/[\/\\]/).pop();
await new Promise(resolve => {
const dataTransfer = new DataTransfer;
dataTransfer.items.add(
new File([kTestChars], fileBaseName, {type: 'text/plain'}));
fileInput.files = dataTransfer.files;
// For historical reasons .value will be prefixed with
// c:\fakepath\, but the basename should match the file name
// exposed through the newer .files[0].name API. This check
// verifies that assumption.
assert_equals(
fileInput.files[0].name,
baseNameOfFilePath(fileInput.value),
`The basename of the field's value should match its files[0].name`);
form.submit();
formTargetFrame.onload = resolve;
});
const formDataText = formTargetFrame.contentDocument.body.textContent;
const formDataLines = formDataText.split('\n');
if (formDataLines.length && !formDataLines[formDataLines.length - 1]) {
--formDataLines.length;
}
assert_greater_than(
formDataLines.length,
2,
`${fileBaseName}: multipart form data must have at least 3 lines: ${
JSON.stringify(formDataText)
}`);
const boundary = formDataLines[0];
assert_equals(
formDataLines[formDataLines.length - 1],
boundary + '--',
`${fileBaseName}: multipart form data must end with ${boundary}--: ${
JSON.stringify(formDataText)
}`);
const expectedText = [
boundary,
'Content-Disposition: form-data; name="_charset_"',
'',
formEncoding,
boundary,
'Content-Disposition: form-data; name="filename"',
'',
expectedEncodedBaseName,
boundary,
`Content-Disposition: form-data; name="${expectedEncodedBaseName}"`,
'',
'filename',
boundary,
`Content-Disposition: form-data; name="file"; ` +
`filename="${expectedEncodedBaseName}"`,
'Content-Type: text/plain',
'',
kTestChars,
boundary + '--',
].join('\n');
assert_true(
formDataText.startsWith(expectedText),
`Unexpected multipart-shaped form data received:\n${
formDataText
}\nExpected:\n${expectedText}`);
}, `Upload ${fileBaseName} (${fileNameSource}) in ${formEncoding} form`);
};

Просмотреть файл

@ -0,0 +1,46 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Blob/Unicode interaction: normalization and encoding</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
const OMICRON_WITH_OXIA = '\u1F79'; // NFC normalized to U+3CC
const CONTAINS_UNPAIRED_SURROGATES = 'abc\uDC00def\uD800ghi';
const REPLACED = 'abc\uFFFDdef\uFFFDghi';
function readBlobAsPromise(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsText(blob);
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
});
}
promise_test(async t => {
const blob = new Blob([OMICRON_WITH_OXIA]);
const result = await readBlobAsPromise(blob);
assert_equals(result, OMICRON_WITH_OXIA, 'String should not be normalized');
}, 'Test that strings are not NFC normalized by Blob constructor');
promise_test(async t => {
const file = new File([OMICRON_WITH_OXIA], 'name');
const result = await readBlobAsPromise(file);
assert_equals(result, OMICRON_WITH_OXIA, 'String should not be normalized');
}, 'Test that strings are not NFC normalized by File constructor');
promise_test(async t => {
const blob = new Blob([CONTAINS_UNPAIRED_SURROGATES]);
const result = await readBlobAsPromise(blob);
assert_equals(result, REPLACED, 'Unpaired surrogates should be replaced.');
}, 'Test that unpaired surrogates are replaced by Blob constructor');
promise_test(async t => {
const file = new File([CONTAINS_UNPAIRED_SURROGATES], 'name');
const result = await readBlobAsPromise(file);
assert_equals(result, REPLACED, 'Unpaired surrogates should be replaced.');
}, 'Test that unpaired surrogates are replaced by File constructor');
</script>

Просмотреть файл

@ -20,9 +20,8 @@
http.onloadend = function() { http.onloadend = function() {
var fileDisplay = document.querySelector("#fileDisplay"); var fileDisplay = document.querySelector("#fileDisplay");
fileDisplay.src = window.URL.createObjectURL(http.response); fileDisplay.src = window.URL.createObjectURL(http.response);
takeScreenshot(); fileDisplay.onload = takeScreenshot;
}; };
http.send(); http.send();
</script> </script>
</html> </html>

Просмотреть файл

@ -20,7 +20,7 @@ async_test(function(t) {
var idls = request.responseText; var idls = request.responseText;
// https://html.spec.whatwg.org/multipage/browsers.html#window // https://html.spec.whatwg.org/multipage/browsers.html#window
idlArray.add_untested_idls("[PrimaryGlobal] interface Window { };"); idlArray.add_untested_idls("[Global=Window, Exposed=Window] interface Window { };");
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
idlArray.add_untested_idls(`[NoInterfaceObject, Exposed=(Window,Worker)] idlArray.add_untested_idls(`[NoInterfaceObject, Exposed=(Window,Worker)]

Просмотреть файл

@ -53,8 +53,15 @@ Running Tests Manually
====================== ======================
The test server can be started using The test server can be started using
```
./wpt serve ./wpt serve
```
**On Windows**: You will need to preceed the prior command with
`python` or the path to the python binary.
```bash
python wpt serve
```
This will start HTTP servers on two ports and a websockets server on This will start HTTP servers on two ports and a websockets server on
one port. By default one web server starts on port 8000 and the other one port. By default one web server starts on port 8000 and the other
@ -82,12 +89,15 @@ file setup documented above, but you must *not* have the
test server already running when calling `wpt run`. The basic command test server already running when calling `wpt run`. The basic command
line syntax is: line syntax is:
``` ```bash
./wpt run product [tests] ./wpt run product [tests]
``` ```
**On Windows**: You will need to preceed the prior command with **On Windows**: You will need to preceed the prior command with
`python` or the path to the python binary. `python` or the path to the python binary.
```bash
python wpt product [tests]
```
where `product` is currently `firefox` or `chrome` and `[tests]` is a where `product` is currently `firefox` or `chrome` and `[tests]` is a
list of paths to tests. This will attempt to automatically locate a list of paths to tests. This will attempt to automatically locate a
@ -114,7 +124,7 @@ brew install nss
On other platforms, download the firefox archive and common.tests.zip On other platforms, download the firefox archive and common.tests.zip
archive for your platform from archive for your platform from
[https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/](Mozilla CI) [Mozilla CI](https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/).
Then extract `certutil[.exe]` from the tests.zip package and Then extract `certutil[.exe]` from the tests.zip package and
`libnss3[.so|.dll|.dynlib]` and put the former on your path and the latter on `libnss3[.so|.dll|.dynlib]` and put the former on your path and the latter on
@ -187,9 +197,13 @@ then remove the `tools` and `resources` directories, as above.
<span id="windows-notes">Windows Notes</span> <span id="windows-notes">Windows Notes</span>
============================================= =============================================
On Windows `wpt` commands mut bre prefixed with `python` or the path On Windows `wpt` commands must be prefixed with `python` or the path
to the python binary (if `python` is not in your `%PATH%`). to the python binary (if `python` is not in your `%PATH%`).
```bash
python wpt [command]
```
Alternatively, you may also use Alternatively, you may also use
[Bash on Ubuntu on Windows](https://msdn.microsoft.com/en-us/commandline/wsl/about) [Bash on Ubuntu on Windows](https://msdn.microsoft.com/en-us/commandline/wsl/about)
in the Windows 10 Anniversary Update build, then access your windows in the Windows 10 Anniversary Update build, then access your windows

Просмотреть файл

@ -29,11 +29,6 @@ setup(function() {
request.onload = function() { request.onload = function() {
var idls = request.responseText; var idls = request.responseText;
idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };");
idl_array.add_untested_idls("interface ArrayBuffer {};");
idl_array.add_untested_idls("interface ArrayBufferView {};");
idl_array.add_idls(idls); idl_array.add_idls(idls);
idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]}); idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]});

Просмотреть файл

@ -29,11 +29,6 @@ setup(function() {
request.onload = function() { request.onload = function() {
var idls = request.responseText; var idls = request.responseText;
idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };");
idl_array.add_untested_idls("interface ArrayBuffer {};");
idl_array.add_untested_idls("interface ArrayBufferView {};");
idl_array.add_idls(idls); idl_array.add_idls(idls);
idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]}); idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]});

Просмотреть файл

@ -17,7 +17,7 @@
{ {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open("POST", "http://nonexistent-origin.{{host}}}:{{ports[http][0]}}", false); xhr.open("POST", "http://nonexistent-origin.{{host}}:{{ports[http][0]}}", false);
assert_throws("NetworkError", function() assert_throws("NetworkError", function()
{ {
@ -25,6 +25,12 @@
}); });
assert_equals(xhr.readyState, 4) assert_equals(xhr.readyState, 4)
}, "http URL");
test(function()
{
var xhr = new XMLHttpRequest();
xhr.open("GET", "data:text/html;charset=utf-8;base64,PT0NUWVBFIGh0bWw%2BDQo8", false); xhr.open("GET", "data:text/html;charset=utf-8;base64,PT0NUWVBFIGh0bWw%2BDQo8", false);
assert_throws("NetworkError", function() assert_throws("NetworkError", function()
@ -33,7 +39,7 @@
}); });
assert_equals(xhr.readyState, 4) assert_equals(xhr.readyState, 4)
}); }, "data URL");
</script> </script>
</body> </body>
</html> </html>

Просмотреть файл

@ -15,8 +15,8 @@
<div id="log"></div> <div id="log"></div>
<script type="text/javascript"> <script type="text/javascript">
function testRedirectPost(code, shouldResendPost) { function testRedirectPost(params) {
var test = async_test(document.title + " (" + code + ")"); var test = async_test(document.title + " (" + params.name + ")");
var actual = []; var actual = [];
// We check upload.onprogress with a boolean because it *might* fire more than once // We check upload.onprogress with a boolean because it *might* fire more than once
var progressFiredReadyState1 = false; var progressFiredReadyState1 = false;
@ -24,13 +24,13 @@
var expectedHeaders, expectedEvents; var expectedHeaders, expectedEvents;
// 307 redirects should resend the POST data, and events and headers will be a little different.. // 307 redirects should resend the POST data, and events and headers will be a little different..
if(shouldResendPost) { if(params.expectResendPost) {
expectedHeaders = { expectedHeaders = {
"X-Request-Content-Length": "11988", "X-Request-Content-Length": "12000",
"X-Request-Content-Type": "text/plain;charset=UTF-8", "X-Request-Content-Type": "text/plain;charset=UTF-8",
"X-Request-Method": "POST", "X-Request-Method": "POST",
"X-Request-Query": "NO", "X-Request-Query": "NO",
"Content-Length": "11988" "Content-Length": "12000"
} }
expectedEvents = [ expectedEvents = [
"xhr onreadystatechange 1", "xhr onreadystatechange 1",
@ -63,6 +63,10 @@
"xhr loadend 4" "xhr loadend 4"
]; ];
} }
// Override expectations if provided.
if(params.expectedContentType)
expectedHeaders["X-Request-Content-Type"] = params.expectedContentType;
test.step(function() test.step(function()
{ {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
@ -105,20 +109,24 @@
} }
assert_array_equals(actual, expectedEvents, "events firing in expected order and states"); assert_array_equals(actual, expectedEvents, "events firing in expected order and states");
if (params.expectedBody)
assert_equals(xhr.response, params.expectedBody, 'request body was resent');
test.done(); test.done();
}); });
xhr.open("POST", "./resources/redirect.py?location=content.py&code=" + code, true); xhr.open("POST", "./resources/redirect.py?location=content.py&code=" + params.code, true);
xhr.send((new Array(1000)).join("Test Message")); xhr.send(params.body);
}); });
} }
const stringBody = "Test Message".repeat(1000);
const blobBody = new Blob(new Array(1000).fill("Test Message"));
testRedirectPost(301, false); testRedirectPost({name: "301", code: 301, expectResendPost: false, body: stringBody});
testRedirectPost(302, false); testRedirectPost({name: "302", code: 302, expectResendPost: false, body: stringBody});
testRedirectPost(303, false); testRedirectPost({name: "303", code: 303, expectResendPost: false, body: stringBody});
testRedirectPost(307, true); testRedirectPost({name: "307 (string)", code: 307, expectResendPost: true, body: stringBody, expectedBody: stringBody });
testRedirectPost({name: "307 (blob)", code: 307, expectResendPost: true, body: blobBody, expectedBody: stringBody, expectedContentType: "NO" });
</script> </script>
</body> </body>
</html> </html>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_disabled(Accelerometer);
run_fp_tests_disabled(LinearAccelerationSensor);
run_fp_tests_disabled(GravitySensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: accelerometer 'none'

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_by_attribute_redirect_on_load(Accelerometer);
run_fp_tests_enabled_by_attribute_redirect_on_load(LinearAccelerationSensor);
run_fp_tests_enabled_by_attribute_redirect_on_load(GravitySensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_by_attribute(Accelerometer);
run_fp_tests_enabled_by_attribute(LinearAccelerationSensor);
run_fp_tests_enabled_by_attribute(GravitySensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled(Accelerometer);
run_fp_tests_enabled(LinearAccelerationSensor);
run_fp_tests_enabled(GravitySensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: accelerometer *

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_on_self_origin(Accelerometer);
run_fp_tests_enabled_on_self_origin(LinearAccelerationSensor);
run_fp_tests_enabled_on_self_origin(GravitySensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: accelerometer 'self'

Просмотреть файл

@ -10,5 +10,6 @@
<script> <script>
runGenericSensorTests(Accelerometer); runGenericSensorTests(Accelerometer);
runGenericSensorTests(GravitySensor);
</script> </script>

Просмотреть файл

@ -16,5 +16,6 @@
<script> <script>
runGenericSensorInsecureContext("Accelerometer"); runGenericSensorInsecureContext("Accelerometer");
runGenericSensorInsecureContext("GravitySensor");
</script> </script>

Просмотреть файл

@ -16,5 +16,6 @@
<script> <script>
runGenericSensorOnerror(Accelerometer); runGenericSensorOnerror(Accelerometer);
runGenericSensorOnerror(GravitySensor);
</script> </script>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_disabled(AmbientLightSensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: ambient-light-sensor 'none'

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_by_attribute_redirect_on_load(AmbientLightSensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_by_attribute(AmbientLightSensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled(AmbientLightSensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: ambient-light-sensor *

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>
<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script>
<script>
"use strict";
run_fp_tests_enabled_on_self_origin(AmbientLightSensor);
</script>
</body>

Просмотреть файл

@ -0,0 +1 @@
Feature-Policy: ambient-light-sensor 'self'

Просмотреть файл

@ -0,0 +1,2 @@
@toddreifsteck
@igrigorik

Просмотреть файл

@ -0,0 +1,12 @@
# Web Bluetooth Testing
Web Bluetooth testing relies on the [Web Bluetooth Testing API] which must be
provided by browsers under test.
In this test suite `resources/bluetooth-helpers.js` detects and triggers
the API to be loaded as needed.
The Chromium implementation is provided by
`../resources/chromium/web-bluetooth-test.js`.
[Web Bluetooth Testing API]: https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/

Просмотреть файл

@ -0,0 +1,166 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict'
var base_uuid = '00000000-0000-1000-8000-00805f9b34fb'
test(() => {
let base_alias = 0x0
assert_equals(BluetoothUUID.getService(base_alias), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(base_alias), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(base_alias), base_uuid);
}, '0x0 should produce valid UUID.');
test(() => {
assert_equals(BluetoothUUID.getService(NaN), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(NaN), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(NaN), base_uuid);
}, 'NaN returns basic uuid');
test(() => {
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
let nine_digits = 0xfffffffff;
let thirteen_digits = 0xfffffffffffff;
let fourteen_digits = 0xffffffffffffff;
assert_equals(BluetoothUUID.getService(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getService(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
}, 'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
'should return max UUID');
test(() => {
assert_equals(BluetoothUUID.getService(Infinity), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(Infinity), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(Infinity), base_uuid);
}, 'Infinity returns base UUID');
test(() => {
let deadbeef_alias = 0xDEADBEEF;
let deadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb';
assert_equals(BluetoothUUID.getService(deadbeef_alias), deadbeef_uuid);
assert_equals(BluetoothUUID.getCharacteristic(deadbeef_alias), deadbeef_uuid);
assert_equals(BluetoothUUID.getDescriptor(deadbeef_alias), deadbeef_uuid);
}, '0xdeadbeef should produce valid UUID.');
test(() => {
let adeadbeef_alias = 0xADEADBEEF;
let adeadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb';
assert_equals(BluetoothUUID.getService(adeadbeef_alias), adeadbeef_uuid);
assert_equals(BluetoothUUID.getCharacteristic(adeadbeef_alias), adeadbeef_uuid);
assert_equals(BluetoothUUID.getDescriptor(adeadbeef_alias), adeadbeef_uuid);
}, 'Only first 32bits should be used.');
test(() => {
let basic_uuid = '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d';
assert_equals(BluetoothUUID.getService(basic_uuid), basic_uuid);
assert_equals(BluetoothUUID.getCharacteristic(basic_uuid), basic_uuid);
assert_equals(BluetoothUUID.getDescriptor(basic_uuid), basic_uuid);
}, 'A valid UUID String should return the same UUID.');
test(() => {
let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D';
assert_throws(TypeError(), () => BluetoothUUID.getService(all_caps_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(all_caps_uuid));
}, 'A UUID String with uppercase letters is an invalid UUID.');
test(() => {
let string_alias = 'deadbeef';
assert_throws(TypeError(), () => BluetoothUUID.getService(string_alias));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(string_alias));
}, 'A 32bit *String* alias is invalid.');
test(() => {
let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb';
assert_throws(TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(invalid_character_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
}, 'A UUID with invalid characters is an invalid UUID.');
test(() => {
assert_equals(BluetoothUUID.getService('alert_notification'),
'00001811-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
'00002a7e-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
'00002900-0000-1000-8000-00805f9b34fb');
}, 'A valid UUID from a name.');
test(() => {
assert_throws(TypeError(), () => {
BluetoothUUID.getService('aerobic_heart_rate_lower_limit');
});
assert_throws(TypeError(), () => {
BluetoothUUID.getService('gatt.characteristic_extended_properties');
});
assert_throws(TypeError(), () => {
BluetoothUUID.getCharacteristic('alert_notification');
});
assert_throws(TypeError(), () => {
BluetoothUUID.getCharacteristic('gatt.characteristic_extended_properties');
});
assert_throws(TypeError(), () => {
BluetoothUUID.getDescriptor('alert_notification');
});
assert_throws(TypeError(), () => {
BluetoothUUID.getDescriptor('aerobic_heart_rate_lower_limit');
});
}, 'Make sure attributes don\'t share a map');
test(() => {
let wrong_name = 'wrong_name';
assert_throws(TypeError(), () => BluetoothUUID.getService(wrong_name));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(wrong_name));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(wrong_name));
}, 'Invalid Descriptor name');
test(() => {
let object = {};
let array = [];
let func = () => {};
// cannonicalUUID
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(object));
// [] converts to '', which converts to 0 before the range check.
assert_equals(BluetoothUUID.canonicalUUID(array), base_uuid);
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(func));
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(undefined));
assert_equals(BluetoothUUID.canonicalUUID(null), base_uuid);
assert_equals(BluetoothUUID.canonicalUUID(false), base_uuid);
assert_equals(BluetoothUUID.canonicalUUID(true), BluetoothUUID.canonicalUUID(1));
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(NaN));
// getService
assert_throws(TypeError(), () => BluetoothUUID.getService(object));
assert_throws(TypeError(), () => BluetoothUUID.getService(array));
assert_throws(TypeError(), () => BluetoothUUID.getService(func));
assert_throws(TypeError(), () => BluetoothUUID.getService(undefined));
assert_throws(TypeError(), () => BluetoothUUID.getService(null));
assert_throws(TypeError(), () => BluetoothUUID.getService(false));
// getCharacteristic
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(object));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(array));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(func));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(undefined));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(null));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(false));
// getDescriptor
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(object));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(array));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(func));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(undefined));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(null));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(false));
}, 'Non-number and non-strings');
</script>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
test(() => {
assert_true('bluetooth' in navigator,
'navigator.bluetooth exists.');
}, 'navigator.bluetooth IDL test');
test(() => {
assert_equals(navigator.bluetooth, navigator.bluetooth);
}, '[SameObject] test for navigator.bluetooth');
</script>

Просмотреть файл

@ -0,0 +1,800 @@
'use strict';
function loadScript(path) {
let script = document.createElement('script');
let promise = new Promise(resolve => script.onload = resolve);
script.src = path;
script.async = false;
document.head.appendChild(script);
return promise;
}
function loadScripts(paths) {
let chain = Promise.resolve();
for (let path of paths) {
chain = chain.then(() => loadScript(path));
}
return chain;
}
function performChromiumSetup() {
// Make sure we are actually on Chromium.
if (!Mojo) {
return;
}
// Load the Chromium-specific resources.
let prefix = '/resources/chromium';
let extra = [];
if (window.location.pathname.includes('/LayoutTests/')) {
let root = window.location.pathname.match(/.*LayoutTests/);
prefix = `${root}/external/wpt/resources/chromium`;
extra = [
`${root}/resources/bluetooth/bluetooth-fake-adapter.js`,
];
} else if (window.location.pathname.startsWith('/bluetooth/https/')) {
extra = [
'/js-test-resources/bluetooth/bluetooth-fake-adapter.js',
];
}
return loadScripts([
`${prefix}/mojo_bindings.js`,
`${prefix}/mojo_layouttest_test.mojom.js`,
`${prefix}/uuid.mojom.js`,
`${prefix}/fake_bluetooth.mojom.js`,
`${prefix}/web-bluetooth-test.js`,
].concat(extra))
// Call setBluetoothFakeAdapter() to clean up any fake adapters left over
// by legacy tests.
// Legacy tests that use setBluetoothFakeAdapter() sometimes fail to clean
// their fake adapter. This is not a problem for these tests because the
// next setBluetoothFakeAdapter() will clean it up anyway but it is a
// problem for the new tests that do not use setBluetoothFakeAdapter().
// TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no
// longer used.
.then(() => setBluetoothFakeAdapter ? setBluetoothFakeAdapter('')
: undefined);
}
// These tests rely on the User Agent providing an implementation of the
// Web Bluetooth Testing API.
// https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/edit?ts=59b6d823#heading=h.7nki9mck5t64
function bluetooth_test(func, name, properties) {
Promise.resolve()
.then(() => promise_test(t => Promise.resolve()
// Trigger Chromium-specific setup.
.then(performChromiumSetup)
.then(() => func(t)), name, properties));
}
// HCI Error Codes. Used for simulateGATT[Dis]ConnectionResponse.
// For a complete list of possible error codes see
// BT 4.2 Vol 2 Part D 1.3 List Of Error Codes.
const HCI_SUCCESS = 0x0000;
const HCI_CONNECTION_TIMEOUT = 0x0008;
// GATT Error codes. Used for GATT operations responses.
// BT 4.2 Vol 3 Part F 3.4.1.1 Error Response
const GATT_SUCCESS = 0x0000;
const GATT_INVALID_HANDLE = 0x0001;
// Bluetooth UUID constants:
// Services:
var blocklist_test_service_uuid = "611c954a-263b-4f4a-aab6-01ddb953f985";
var request_disconnection_service_uuid = "01d7d889-7451-419f-aeb8-d65e7b9277af";
// Characteristics:
var blocklist_exclude_reads_characteristic_uuid =
"bad1c9a2-9a5b-4015-8b60-1579bbbf2135";
var request_disconnection_characteristic_uuid =
"01d7d88a-7451-419f-aeb8-d65e7b9277af";
// Descriptors:
var blocklist_test_descriptor_uuid = "bad2ddcf-60db-45cd-bef9-fd72b153cf7c";
// Sometimes we need to test that using either the name, alias, or UUID
// produces the same result. The following objects help us do that.
var generic_access = {
alias: 0x1800,
name: 'generic_access',
uuid: '00001800-0000-1000-8000-00805f9b34fb'
};
var device_name = {
alias: 0x2a00,
name: 'gap.device_name',
uuid: '00002a00-0000-1000-8000-00805f9b34fb'
};
var reconnection_address = {
alias: 0x2a03,
name: 'gap.reconnection_address',
uuid: '00002a03-0000-1000-8000-00805f9b34fb'
};
var heart_rate = {
alias: 0x180d,
name: 'heart_rate',
uuid: '0000180d-0000-1000-8000-00805f9b34fb'
};
var health_thermometer = {
alias: 0x1809,
name: 'health_thermometer',
uuid: '00001809-0000-1000-8000-00805f9b34fb'
};
var body_sensor_location = {
alias: 0x2a38,
name: 'body_sensor_location',
uuid: '00002a38-0000-1000-8000-00805f9b34fb'
};
var glucose = {
alias: 0x1808,
name: 'glucose',
uuid: '00001808-0000-1000-8000-00805f9b34fb'
};
var battery_service = {
alias: 0x180f,
name: 'battery_service',
uuid: '0000180f-0000-1000-8000-00805f9b34fb'
};
var battery_level = {
alias: 0x2A19,
name: 'battery_level',
uuid: '00002a19-0000-1000-8000-00805f9b34fb'
};
var user_description = {
alias: 0x2901,
name: 'gatt.characteristic_user_description',
uuid: '00002901-0000-1000-8000-00805f9b34fb'
};
var client_characteristic_configuration = {
alias: 0x2902,
name: 'gatt.client_characteristic_configuration',
uuid: '00002902-0000-1000-8000-00805f9b34fb'
};
var measurement_interval = {
alias: 0x2a21,
name: 'measurement_interval',
uuid: '00002a21-0000-1000-8000-00805f9b34fb'
};
// The following tests make sure the Web Bluetooth implementation
// responds correctly to the different types of errors the
// underlying platform might return for GATT operations.
// Each browser should map these characteristics to specific code paths
// that result in different errors thus increasing code coverage
// when testing. Therefore some of these characteristics might not be useful
// for all browsers.
//
// TODO(ortuno): According to the testing spec errorUUID(0x101) to
// errorUUID(0x1ff) should be use for the uuids of the characteristics.
var gatt_errors_tests = [{
testName: 'GATT Error: Unknown.',
uuid: errorUUID(0xA1),
error: new DOMException(
'GATT Error Unknown.',
'NotSupportedError')
}, {
testName: 'GATT Error: Failed.',
uuid: errorUUID(0xA2),
error: new DOMException(
'GATT operation failed for unknown reason.',
'NotSupportedError')
}, {
testName: 'GATT Error: In Progress.',
uuid: errorUUID(0xA3),
error: new DOMException(
'GATT operation already in progress.',
'NetworkError')
}, {
testName: 'GATT Error: Invalid Length.',
uuid: errorUUID(0xA4),
error: new DOMException(
'GATT Error: invalid attribute length.',
'InvalidModificationError')
}, {
testName: 'GATT Error: Not Permitted.',
uuid: errorUUID(0xA5),
error: new DOMException(
'GATT operation not permitted.',
'NotSupportedError')
}, {
testName: 'GATT Error: Not Authorized.',
uuid: errorUUID(0xA6),
error: new DOMException(
'GATT operation not authorized.',
'SecurityError')
}, {
testName: 'GATT Error: Not Paired.',
uuid: errorUUID(0xA7),
// TODO(ortuno): Change to InsufficientAuthenticationError or similiar
// once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is
// resolved.
error: new DOMException(
'GATT Error: Not paired.',
'NetworkError')
}, {
testName: 'GATT Error: Not Supported.',
uuid: errorUUID(0xA8),
error: new DOMException(
'GATT Error: Not supported.',
'NotSupportedError')
}];
function callWithTrustedClick(callback) {
return new Promise(resolve => {
let button = document.createElement('button');
button.textContent = 'click to continue test';
button.style.display = 'block';
button.style.fontSize = '20px';
button.style.padding = '10px';
button.onclick = () => {
document.body.removeChild(button);
resolve(callback());
};
document.body.appendChild(button);
test_driver.click(button);
});
}
// Calls requestDevice() in a context that's 'allowed to show a popup'.
function requestDeviceWithTrustedClick() {
let args = arguments;
return callWithTrustedClick(
() => navigator.bluetooth.requestDevice.apply(navigator.bluetooth, args));
}
// errorUUID(alias) returns a UUID with the top 32 bits of
// '00000000-97e5-4cd7-b9f1-f5a427670c59' replaced with the bits of |alias|.
// For example, errorUUID(0xDEADBEEF) returns
// 'deadbeef-97e5-4cd7-b9f1-f5a427670c59'. The bottom 96 bits of error UUIDs
// were generated as a type 4 (random) UUID.
function errorUUID(uuidAlias) {
// Make the number positive.
uuidAlias >>>= 0;
// Append the alias as a hex number.
var strAlias = '0000000' + uuidAlias.toString(16);
// Get last 8 digits of strAlias.
strAlias = strAlias.substr(-8);
// Append Base Error UUID
return strAlias + '-97e5-4cd7-b9f1-f5a427670c59';
}
// Function to test that a promise rejects with the expected error type and
// message.
function assert_promise_rejects_with_message(promise, expected, description) {
return promise.then(() => {
assert_unreached('Promise should have rejected: ' + description);
}, error => {
assert_equals(error.name, expected.name, 'Unexpected Error Name:');
if (expected.message) {
assert_equals(error.message, expected.message, 'Unexpected Error Message:');
}
});
}
function runGarbageCollection()
{
// Run gc() as a promise.
return new Promise(
function(resolve, reject) {
GCController.collect();
step_timeout(resolve, 0);
});
}
function eventPromise(target, type, options) {
return new Promise(resolve => {
let wrapper = function(event) {
target.removeEventListener(type, wrapper);
resolve(event);
};
target.addEventListener(type, wrapper, options);
});
}
// Helper function to assert that events are fired and a promise resolved
// in the correct order.
// 'event' should be passed as |should_be_first| to indicate that the events
// should be fired first, otherwise 'promiseresolved' should be passed.
// Attaches |num_listeners| |event| listeners to |object|. If all events have
// been fired and the promise resolved in the correct order, returns a promise
// that fulfills with the result of |object|.|func()| and |event.target.value|
// of each of event listeners. Otherwise throws an error.
function assert_promise_event_order_(should_be_first, object, func, event, num_listeners) {
let order = [];
let event_promises = [];
for (let i = 0; i < num_listeners; i++) {
event_promises.push(new Promise(resolve => {
let event_listener = (e) => {
object.removeEventListener(event, event_listener);
order.push('event');
resolve(e.target.value);
};
object.addEventListener(event, event_listener);
}));
}
let func_promise = object[func]().then(result => {
order.push('promiseresolved');
return result;
});
return Promise.all([func_promise, ...event_promises])
.then((result) => {
if (should_be_first !== order[0]) {
throw should_be_first === 'promiseresolved' ?
`'${event}' was fired before promise resolved.` :
`Promise resolved before '${event}' was fired.`;
}
if (order[0] !== 'promiseresolved' &&
order[order.length - 1] !== 'promiseresolved') {
throw 'Promise resolved in between event listeners.';
}
return result;
});
}
// See assert_promise_event_order_ above.
function assert_promise_resolves_before_event(
object, func, event, num_listeners=1) {
return assert_promise_event_order_(
'promiseresolved', object, func, event, num_listeners);
}
// See assert_promise_event_order_ above.
function assert_promise_resolves_after_event(
object, func, event, num_listeners=1) {
return assert_promise_event_order_(
'event', object, func, event, num_listeners);
}
// Returns a promise that resolves after 100ms unless
// the the event is fired on the object in which case
// the promise rejects.
function assert_no_events(object, event_name) {
return new Promise((resolve, reject) => {
let event_listener = (e) => {
object.removeEventListener(event_name, event_listener);
assert_unreached('Object should not fire an event.');
};
object.addEventListener(event_name, event_listener);
// TODO: Remove timeout.
// http://crbug.com/543884
step_timeout(() => {
object.removeEventListener(event_name, event_listener);
resolve();
}, 100);
});
}
class TestCharacteristicProperties {
// |properties| is an array of strings for property bits to be set
// as true.
constructor(properties) {
this.broadcast = false;
this.read = false;
this.writeWithoutResponse = false;
this.write = false;
this.notify = false;
this.indicate = false;
this.authenticatedSignedWrites = false;
this.reliableWrite = false;
this.writableAuxiliaries = false;
properties.forEach(val => {
if (this.hasOwnProperty(val))
this[val] = true;
else
throw `Invalid member '${val}'`;
});
}
}
function assert_properties_equal(properties, expected_properties) {
for (let key in expected_properties) {
assert_equals(properties[key], expected_properties[key]);
}
}
class EventCatcher {
constructor(object, event) {
this.eventFired = false;
let event_listener = () => {
object.removeEventListener(event, event_listener);
this.eventFired = true;
};
object.addEventListener(event, event_listener);
}
}
// Returns a function that when called returns a promise that resolves when
// the device has disconnected. Example:
// device.gatt.connect()
// .then(gatt => get_request_disconnection(gatt))
// .then(requestDisconnection => requestDisconnection())
// .then(() => // device is now disconnected)
function get_request_disconnection(gattServer) {
return gattServer.getPrimaryService(request_disconnection_service_uuid)
.then(service => service.getCharacteristic(request_disconnection_characteristic_uuid))
.then(characteristic => {
return () => assert_promise_rejects_with_message(
characteristic.writeValue(new Uint8Array([0])),
new DOMException(
'GATT Server is disconnected. Cannot perform GATT operations. ' +
'(Re)connect first with `device.gatt.connect`.',
'NetworkError'));
});
}
function generateRequestDeviceArgsWithServices(services = ['heart_rate']) {
return [{
filters: [{ services: services }]
}, {
filters: [{ services: services, name: 'Name' }]
}, {
filters: [{ services: services, namePrefix: 'Pre' }]
}, {
filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }]
}, {
filters: [{ services: services }],
optionalServices: ['heart_rate']
}, {
filters: [{ services: services, name: 'Name' }],
optionalServices: ['heart_rate']
}, {
filters: [{ services: services, namePrefix: 'Pre' }],
optionalServices: ['heart_rate']
}, {
filters: [{ services: services, name: 'Name', namePrefix: 'Pre' }],
optionalServices: ['heart_rate']
}];
}
// Simulates a pre-connected device with |address|, |name| and
// |knownServiceUUIDs|.
function setUpPreconnectedDevice({
address = '00:00:00:00:00:00', name = 'LE Device', knownServiceUUIDs = []}) {
return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
.then(fake_central => fake_central.simulatePreconnectedPeripheral({
address: address,
name: name,
knownServiceUUIDs: knownServiceUUIDs,
}));
}
// Returns a FakePeripheral that corresponds to a simulated pre-connected device
// called 'Health Thermometer'. The device has two known serviceUUIDs:
// 'generic_access' and 'health_thermometer'.
function setUpHealthThermometerDevice() {
return setUpPreconnectedDevice({
address: '09:09:09:09:09:09',
name: 'Health Thermometer',
knownServiceUUIDs: ['generic_access', 'health_thermometer'],
});
}
// Returns an array containing two FakePeripherals corresponding
// to the simulated devices.
function setUpHealthThermometerAndHeartRateDevices() {
return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
.then(fake_central => Promise.all([
fake_central.simulatePreconnectedPeripheral({
address: '09:09:09:09:09:09',
name: 'Health Thermometer',
knownServiceUUIDs: ['generic_access', 'health_thermometer'],
}),
fake_central.simulatePreconnectedPeripheral({
address: '08:08:08:08:08:08',
name: 'Heart Rate',
knownServiceUUIDs: ['generic_access', 'heart_rate'],
})]));
}
// Returns the same fake peripheral as setUpHealthThermometerDevice() except
// that connecting to the peripheral will succeed.
function setUpConnectableHealthThermometerDevice() {
let fake_peripheral;
return setUpHealthThermometerDevice()
.then(_ => fake_peripheral = _)
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => fake_peripheral);
}
// Returns an object containing a BluetoothDevice discovered using |options|,
// its corresponding FakePeripheral and FakeRemoteGATTServices.
// The simulated device is called 'Health Thermometer' it has two known service
// UUIDs: 'generic_access' and 'health_thermometer' which correspond to two
// services with the same UUIDs. The 'health thermometer' service contains three
// characteristics:
// - 'temperature_measurement' (indicate),
// - 'temperature_type' (read),
// - 'measurement_interval' (read, write, indicate)
// The 'measurement_interval' characteristic contains a
// 'gatt.client_characteristic_configuration' descriptor and a
// 'characteristic_user_description' descriptor.
// The device has been connected to and its attributes are ready to be
// discovered.
function getHealthThermometerDevice(options) {
let result;
return getConnectedHealthThermometerDevice(options)
.then(_ => result = _)
.then(() => result.fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS,
}))
.then(() => result);
}
// Similar to getHealthThermometerDevice except that the peripheral has
// two 'health_thermometer' services.
function getTwoHealthThermometerServicesDevice(options) {
let device;
let fake_peripheral;
let fake_generic_access;
let fake_health_thermometer1;
let fake_health_thermometer2;
return getConnectedHealthThermometerDevice(options)
.then(result => {
({
device,
fake_peripheral,
fake_generic_access,
fake_health_thermometer: fake_health_thermometer1,
} = result);
})
.then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
.then(s => fake_health_thermometer2 = s)
.then(() => fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS}))
.then(() => ({
device: device,
fake_peripheral: fake_peripheral,
fake_generic_access: fake_generic_access,
fake_health_thermometer1: fake_health_thermometer1,
fake_health_thermometer2: fake_health_thermometer2
}));
}
// Returns an object containing a Health Thermometer BluetoothRemoteGattService
// and its corresponding FakeRemoteGATTService.
function getHealthThermometerService() {
let result;
return getHealthThermometerDevice()
.then(r => result = r)
.then(() => result.device.gatt.getPrimaryService('health_thermometer'))
.then(service => Object.assign(result, {
service,
fake_service: result.fake_health_thermometer,
}));
}
// Returns an object containing a Measurement Interval
// BluetoothRemoteGATTCharacteristic and its corresponding
// FakeRemoteGATTCharacteristic.
function getMeasurementIntervalCharacteristic() {
let result;
return getHealthThermometerService()
.then(r => result = r)
.then(() => result.service.getCharacteristic('measurement_interval'))
.then(characteristic => Object.assign(result, {
characteristic,
fake_characteristic: result.fake_measurement_interval,
}));
}
function getUserDescriptionDescriptor() {
let result;
return getMeasurementIntervalCharacteristic()
.then(r => result = r)
.then(() => result.characteristic.getDescriptor(
'gatt.characteristic_user_description'))
.then(descriptor => Object.assign(result, {
descriptor,
fake_descriptor: result.fake_user_description,
}));
}
// Populates a fake_peripheral with various fakes appropriate for a health
// thermometer. This resolves to an associative array composed of the fakes,
// including the |fake_peripheral|.
function populateHealthThermometerFakes(fake_peripheral) {
let fake_generic_access, fake_health_thermometer, fake_measurement_interval,
fake_user_description, fake_cccd, fake_temperature_measurement,
fake_temperature_type;
return fake_peripheral.addFakeService({uuid: 'generic_access'})
.then(_ => fake_generic_access = _)
.then(() => fake_peripheral.addFakeService({
uuid: 'health_thermometer',
}))
.then(_ => fake_health_thermometer = _)
.then(() => fake_health_thermometer.addFakeCharacteristic({
uuid: 'measurement_interval',
properties: ['read', 'write', 'indicate'],
}))
.then(_ => fake_measurement_interval = _)
.then(() => fake_measurement_interval.addFakeDescriptor({
uuid: 'gatt.characteristic_user_description',
}))
.then(_ => fake_user_description = _)
.then(() => fake_measurement_interval.addFakeDescriptor({
uuid: 'gatt.client_characteristic_configuration',
}))
.then(_ => fake_cccd = _)
.then(() => fake_health_thermometer.addFakeCharacteristic({
uuid: 'temperature_measurement',
properties: ['indicate'],
}))
.then(_ => fake_temperature_measurement = _)
.then(() => fake_health_thermometer.addFakeCharacteristic({
uuid: 'temperature_type',
properties: ['read'],
}))
.then(_ => fake_temperature_type = _)
.then(() => ({
fake_peripheral,
fake_generic_access,
fake_health_thermometer,
fake_measurement_interval,
fake_cccd,
fake_user_description,
fake_temperature_measurement,
fake_temperature_type,
}));
}
// Similar to getHealthThermometerDevice except the GATT discovery
// response has not been set yet so more attributes can still be added.
function getConnectedHealthThermometerDevice(options) {
let device, fake_peripheral, fakes;
return getDiscoveredHealthThermometerDevice(options)
.then(_ => ({device, fake_peripheral} = _))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => populateHealthThermometerFakes(fake_peripheral))
.then(_ => fakes = _)
.then(() => device.gatt.connect())
.then(() => Object.assign({device}, fakes));
}
// Returns the same device and fake peripheral as getHealthThermometerDevice()
// after another frame (an iframe we insert) discovered the device,
// connected to it and discovered its services.
function getHealthThermometerDeviceWithServicesDiscovered(options) {
let device, fake_peripheral, fakes;
let iframe = document.createElement('iframe');
return setUpConnectableHealthThermometerDevice()
.then(_ => fake_peripheral = _)
.then(() => populateHealthThermometerFakes(fake_peripheral))
.then(_ => fakes = _)
.then(() => fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS,
}))
.then(() => new Promise(resolve => {
iframe.src = '../../../resources/bluetooth/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
.then(() => new Promise((resolve, reject) => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'DiscoverServices',
options: options
}, '*');
});
function messageHandler(messageEvent) {
if (messageEvent.data == 'DiscoveryComplete') {
window.removeEventListener('message', messageHandler);
resolve();
} else {
reject(new Error(`Unexpected message: ${messageEvent.data}`));
}
}
window.addEventListener('message', messageHandler);
}))
.then(() => requestDeviceWithTrustedClick(options))
.then(_ => device = _)
.then(device => device.gatt.connect())
.then(_ => Object.assign({device}, fakes));
}
// Similar to getHealthThermometerDevice() except the device has no services,
// characteristics, or descriptors.
function getEmptyHealthThermometerDevice(options) {
return getDiscoveredHealthThermometerDevice(options)
.then(({device, fake_peripheral}) => {
return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})
.then(() => device.gatt.connect())
.then(() => fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS}))
.then(() => ({
device: device,
fake_peripheral: fake_peripheral
}));
});
}
// Similar to getHealthThermometerService() except the service has no
// characteristics or included services.
function getEmptyHealthThermometerService(options) {
let device;
let fake_peripheral;
let fake_health_thermometer;
return getDiscoveredHealthThermometerDevice(options)
.then(result => ({device, fake_peripheral} = result))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(() => fake_peripheral.addFakeService({uuid: 'health_thermometer'}))
.then(s => fake_health_thermometer = s)
.then(() => fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS}))
.then(() => device.gatt.getPrimaryService('health_thermometer'))
.then(service => ({
service: service,
fake_health_thermometer: fake_health_thermometer,
}));
}
// Returns a BluetoothDevice discovered using |options| and its
// corresponding FakePeripheral.
// The simulated device is called 'HID Device' it has three known service
// UUIDs: 'generic_access', 'device_information', 'human_interface_device'.
// The primary service with 'device_information' UUID has a characteristics
// with UUID 'serial_number_string'. The device has been connected to and its
// attributes are ready to be discovered.
// TODO(crbug.com/719816): Add descriptors.
function getHIDDevice(options) {
return setUpPreconnectedDevice({
address: '10:10:10:10:10:10',
name: 'HID Device',
knownServiceUUIDs: [
'generic_access',
'device_information',
'human_interface_device'
],
})
.then(fake_peripheral => {
return requestDeviceWithTrustedClick(options)
.then(device => {
return fake_peripheral
.setNextGATTConnectionResponse({
code: HCI_SUCCESS})
.then(() => device.gatt.connect())
.then(() => fake_peripheral.addFakeService({
uuid: 'generic_access'}))
.then(() => fake_peripheral.addFakeService({
uuid: 'device_information'}))
// Blocklisted Characteristic:
// https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt
.then(dev_info => dev_info.addFakeCharacteristic({
uuid: 'serial_number_string', properties: ['read']}))
.then(() => fake_peripheral.addFakeService({
uuid: 'human_interface_device'}))
.then(() => fake_peripheral.setNextGATTDiscoveryResponse({
code: HCI_SUCCESS}))
.then(() => ({
device: device,
fake_peripheral: fake_peripheral
}));
});
});
}
// Similar to getHealthThermometerDevice() except the device
// is not connected and thus its services have not been
// discovered.
function getDiscoveredHealthThermometerDevice(
options = {filters: [{services: ['health_thermometer']}]}) {
return setUpHealthThermometerDevice()
.then(fake_peripheral => {
return requestDeviceWithTrustedClick(options)
.then(device => ({
device: device,
fake_peripheral: fake_peripheral
}));
});
}

Просмотреть файл

@ -33,3 +33,14 @@ function getAudioURI(base)
return base + extension; return base + extension;
} }
function getMediaContentType(url) {
var extension = new URL(url, location).pathname.split(".").pop();
var map = {
"mp4": "video/mp4",
"ogv": "video/ogg",
"mp3": "audio/mp3",
"oga": "audio/ogg",
};
return map[extension];
}

Просмотреть файл

@ -4,9 +4,9 @@
<title>ARIA Tree Example</title> <title>ARIA Tree Example</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta http-equiv="Content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="./css/treesimple.css" type="text/css"> <link rel="stylesheet" href="./css/treesimple.css" type="text/css">
<script type="text/javascript" src="./js/prototype.js"></script> <script src="./js/prototype.js"></script>
<script type="text/javascript" src="./js/aria.js"></script> <script src="./js/aria.js"></script>
<script type="text/javascript" src="./js/init.js"></script> <script src="./js/init.js"></script>
</head> </head>
<body> <body>

Просмотреть файл

@ -4,9 +4,9 @@
<title>ARIA Tree Example</title> <title>ARIA Tree Example</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta http-equiv="Content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="./css/treebox.css" type="text/css"> <link rel="stylesheet" href="./css/treebox.css" type="text/css">
<script type="text/javascript" src="./js/prototype.js"></script> <script src="./js/prototype.js"></script>
<script type="text/javascript" src="./js/aria.js"></script> <script src="./js/aria.js"></script>
<script type="text/javascript" src="./js/init.js"></script> <script src="./js/init.js"></script>
</head> </head>
<body> <body>

Просмотреть файл

@ -15,7 +15,7 @@
After the onload event completes a child DOM text node is added to the element with After the onload event completes a child DOM text node is added to the element with
the aria-live attribute.</p> the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addTextNode() { function addTextNode() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -15,7 +15,7 @@
After the onload event completes a child DOM text node is added to the element After the onload event completes a child DOM text node is added to the element
with the aria-live attribute.</p> with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addTextNode() { function addTextNode() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -16,7 +16,7 @@
value 'assertive' is added to the element and a child DOM text value 'assertive' is added to the element and a child DOM text
node is added to the element.</p> node is added to the element.</p>
<script type="text/javascript"> <script>
function addLiveRegion() { function addLiveRegion() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -16,7 +16,7 @@
value 'assertive' is added to the document and a child element and text value 'assertive' is added to the document and a child element and text
node is added to the element with the aria-live attribute.</p> node is added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addElement() { function addElement() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -17,7 +17,7 @@
After the onload event completes a child DOM element node with text content has the After the onload event completes a child DOM element node with text content has the
CSS dsiplay property changed to display="block".</p> CSS dsiplay property changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -18,7 +18,7 @@
a child DOM element node with text content has the CSS dsiplay property a child DOM element node with text content has the CSS dsiplay property
changed to display="block".</p> changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -20,7 +20,7 @@
After the onload event completes a child DOM element node with text content has the After the onload event completes a child DOM element node with text content has the
CSS dsiplay property changed to visibility="visible".</p> CSS dsiplay property changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -19,7 +19,7 @@
After the onload event completes a child DOM element node with text content has the CSS dsiplay After the onload event completes a child DOM element node with text content has the CSS dsiplay
property changed to visibility="visible".</p> property changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -15,7 +15,7 @@
event with the value="polite". After the onload event completes a child DOM text node is added event with the value="polite". After the onload event completes a child DOM text node is added
to the element with the aria-live attribute.</p> to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildTextNode() { function addChildTextNode() {
var node = document.getElementById('TEST_ID'); var node = document.getElementById('TEST_ID');

Просмотреть файл

@ -15,7 +15,7 @@
event with the value="assertive". After the onload event completes a child DOM text node is event with the value="assertive". After the onload event completes a child DOM text node is
added to the element with the aria-live attribute.</p> added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildTextNode() { function addChildTextNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -15,7 +15,7 @@
event with the value="polite". After the onload event completes a child DOM element node is event with the value="polite". After the onload event completes a child DOM element node is
added to the element with the aria-live attribute.</p> added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildElementNode() { function addChildElementNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -15,7 +15,7 @@
the onload event with the value="assertive". After the onload event completes a the onload event with the value="assertive". After the onload event completes a
child DOM element node is added to the element with the aria-live attribute.</p> child DOM element node is added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildElementNode() { function addChildElementNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
that is hidden using CSS display="none". After the onload event completes a child DOM element that is hidden using CSS display="none". After the onload event completes a child DOM element
node with text content has the CSS display property changed to display="block".</p> node with text content has the CSS display property changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -16,7 +16,7 @@
that is hidden using CSS display="none". After the onload event completes a child DOM element that is hidden using CSS display="none". After the onload event completes a child DOM element
node with text content has the CSS display property changed to display="block".</p> node with text content has the CSS display property changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -17,7 +17,7 @@
event completes a child DOM element node with text content has the CSS display property event completes a child DOM element node with text content has the CSS display property
changed to visibility="visible".</p> changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -17,7 +17,7 @@
After the onload event completes a child DOM element node with text content After the onload event completes a child DOM element node with text content
has the CSS display property changed to visibility="visible".</p> has the CSS display property changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -15,7 +15,7 @@
onload event completes with the value="polite". After the aria-live attribute is added, onload event completes with the value="polite". After the aria-live attribute is added,
a child DOM text node is added to the element with the aria-live attribute.</p> a child DOM text node is added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildTextNode() { function addChildTextNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -15,7 +15,7 @@
the onload event completes with the value="assertive". After the aria-live attribute the onload event completes with the value="assertive". After the aria-live attribute
is added, a child DOM text node is added to the element with the aria-live attribute.</p> is added, a child DOM text node is added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildTextNode() { function addChildTextNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
attribute is added, a child DOM element node is added to the element with attribute is added, a child DOM element node is added to the element with
the aria-live attribute.</p> the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildElementNode() { function addChildElementNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -15,7 +15,7 @@
the onload event completes with the value="assertive". After the aria-live attribute the onload event completes with the value="assertive". After the aria-live attribute
is added, a child DOM element node is added to the element with the aria-live attribute.</p> is added, a child DOM element node is added to the element with the aria-live attribute.</p>
<script type="text/javascript"> <script>
function addChildElementNode() { function addChildElementNode() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -17,7 +17,7 @@
aria-live attribute is added, the child DOM element node with text content has the aria-live attribute is added, the child DOM element node with text content has the
CSS display property changed to display="block".</p> CSS display property changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -17,7 +17,7 @@
the aria-live attribute is added, the child DOM element node with text content has the aria-live attribute is added, the child DOM element node with text content has
the CSS display property changed to display="block".</p> the CSS display property changed to display="block".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -17,7 +17,7 @@
visibility="hidden". After the aria-live attribute is added, the child DOM visibility="hidden". After the aria-live attribute is added, the child DOM
element node with text content has the CSS display property changed to visibility="visible".</p> element node with text content has the CSS display property changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_3'); var node = document.getElementById('TEST_ID_3');

Просмотреть файл

@ -18,7 +18,7 @@
the aria-live attribute is added, the child DOM element node with text content has the aria-live attribute is added, the child DOM element node with text content has
the CSS display property changed to visibility="visible".</p> the CSS display property changed to visibility="visible".</p>
<script type="text/javascript"> <script>
function showElement() { function showElement() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
has a child DOM text node with content. After the onload event completes the child has a child DOM text node with content. After the onload event completes the child
DOM text node is deleted.</p> DOM text node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
has a child DOM text node with content. After the onload event completes the child DOM has a child DOM text node with content. After the onload event completes the child DOM
text node is deleted.</p> text node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
has a child DOM element node that contains text content. After the onload event completes has a child DOM element node that contains text content. After the onload event completes
the child DOM element node is deleted.</p> the child DOM element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
value="assertive" has a child DOM element node that contains text content. value="assertive" has a child DOM element node that contains text content.
After the onload event completes the child DOM element node is deleted.</p> After the onload event completes the child DOM element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -17,7 +17,7 @@
content. After the onload event completes the CSS 'display' property content. After the onload event completes the CSS 'display' property
of the child DOM element node is changed to display="none".</p> of the child DOM element node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
has a child DOM element node that contains text content. After the onload event completes has a child DOM element node that contains text content. After the onload event completes
the CSS 'display' property of the child DOM element node is changed to display="none".</p> the CSS 'display' property of the child DOM element node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -17,7 +17,7 @@
completes the CSS 'visibility' property of the child DOM element node is changed completes the CSS 'visibility' property of the child DOM element node is changed
to visibility="hidden".</p> to visibility="hidden".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
has a child DOM element node that contains text content. After the onload event completes has a child DOM element node that contains text content. After the onload event completes
the CSS 'visibility' property of the child DOM element node is changed to visibility="hidden".</p> the CSS 'visibility' property of the child DOM element node is changed to visibility="hidden".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -16,7 +16,7 @@
text node with content. After the onload event completes the child DOM text text node with content. After the onload event completes the child DOM text
node is deleted.</p> node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -15,7 +15,7 @@
event with the value="assertive" and the element has a child DOM text node with content. After event with the value="assertive" and the element has a child DOM text node with content. After
the onload event completes the child DOM text node is deleted.</p> the onload event completes the child DOM text node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
DOM element node that contains text content. After the onload event completes DOM element node that contains text content. After the onload event completes
the child DOM element node is deleted.</p> the child DOM element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
node that contains text content. After the onload event completes the child DOM node that contains text content. After the onload event completes the child DOM
element node is deleted.</p> element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {

Просмотреть файл

@ -16,7 +16,7 @@
that contains text content. After the onload event completes the CSS 'display' that contains text content. After the onload event completes the CSS 'display'
property of the child DOM element node is changed to display="none".</p> property of the child DOM element node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {

Просмотреть файл

@ -16,7 +16,7 @@
node that contains text content. After the onload event completes the CSS 'display' node that contains text content. After the onload event completes the CSS 'display'
property of the child DOM element node is changed to display="none".</p> property of the child DOM element node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {

Просмотреть файл

@ -17,7 +17,7 @@
the CSS 'visibility' property of the child DOM element node is changed the CSS 'visibility' property of the child DOM element node is changed
to visibility="hidden".</p> to visibility="hidden".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {

Просмотреть файл

@ -17,7 +17,7 @@
event completes the CSS 'visibility' property of the child DOM element event completes the CSS 'visibility' property of the child DOM element
node is changed to visibility="hidden".</p> node is changed to visibility="hidden".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {

Просмотреть файл

@ -16,7 +16,7 @@
the element has a child DOM text node with content. After the the element has a child DOM text node with content. After the
aria-live attribute is added, the child DOM text node is deleted.</p> aria-live attribute is added, the child DOM text node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {

Просмотреть файл

@ -16,7 +16,7 @@
and the element has a child DOM text node with content. After the and the element has a child DOM text node with content. After the
aria-live attribute is added, the child DOM text node is deleted.</p> aria-live attribute is added, the child DOM text node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -16,7 +16,7 @@
a child DOM element node that contains text content. After the aria-live a child DOM element node that contains text content. After the aria-live
attribute is added, the child DOM element node is deleted.</p> attribute is added, the child DOM element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -17,7 +17,7 @@
a child DOM element node that contains text content. After the aria-live a child DOM element node that contains text content. After the aria-live
attribute is added, the child DOM element node is deleted.</p> attribute is added, the child DOM element node is deleted.</p>
<script type="text/javascript"> <script>
function deleteChildNodes() { function deleteChildNodes() {
var node = document.getElementById('TEST_ID_1'); var node = document.getElementById('TEST_ID_1');

Просмотреть файл

@ -17,7 +17,7 @@
attribute is added, the CSS 'display' property of the child DOM element attribute is added, the CSS 'display' property of the child DOM element
node is changed to display="none".</p> node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Просмотреть файл

@ -17,7 +17,7 @@
attribute is added, the CSS 'display' property of the child DOM element attribute is added, the CSS 'display' property of the child DOM element
node is changed to display="none".</p> node is changed to display="none".</p>
<script type="text/javascript"> <script>
function hideElement() { function hideElement() {
var node = document.getElementById('TEST_ID_2'); var node = document.getElementById('TEST_ID_2');

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше