Update web-platform-tests to revision d3cf77a7b8c20c678b725238eaa8a72eca3787ae

This commit is contained in:
WPT Sync Bot 2019-04-25 22:18:37 -04:00
parent 880f3b8b7a
commit efca990ffe
541 changed files with 8000 additions and 2276 deletions

View file

@ -2,6 +2,7 @@
*.py[co]
.cache/
.coverage*
.mypy_cache/
.pytest_cache/
.tox/
.virtualenv/

View file

@ -10,6 +10,9 @@ requirements:
- tools/requirements_flake8.txt:
update: all
pin: True
- tools/requirements_mypy.txt:
update: all
pin: True
- tools/wpt/requirements.txt:
update: all
pin: True

View file

@ -55,9 +55,7 @@ function parseQueryString(urlStr) {
};
*/
// In RTCIdentityProviderGlobalScope, global is self
const global = self;
const query = parseQueryString(global.location);
const query = parseQueryString(location);
// Generate a naive identity assertion. The result assertion
// is a JSON string that report the various parameters
@ -73,8 +71,8 @@ function generateAssertion(contents, origin, options) {
};
const env = {
origin: global.origin,
location: global.location
origin,
location
};
const assertion = {
@ -84,11 +82,6 @@ function generateAssertion(contents, origin, options) {
query
};
const idp = {
domain: global.location.host,
protocol: 'mock-idp.js'
};
const assertionStr = JSON.stringify(assertion);
const { generatorAction } = query;
@ -100,7 +93,7 @@ function generateAssertion(contents, origin, options) {
} else if(generatorAction === 'require-login') {
const err = new RTCError('idp-need-login');
err.idpLoginUrl = `${self.origin}/login`;
err.idpLoginUrl = `${origin}/login`;
err.idpErrorInfo = 'login required';
throw err;
@ -120,7 +113,10 @@ function generateAssertion(contents, origin, options) {
} else {
return {
idp,
idp: {
domain: location.host,
protocol: 'mock-idp.js'
},
assertion: assertionStr
};
}
@ -141,8 +137,8 @@ function generateAssertion(contents, origin, options) {
function validateAssertion(assertionStr, origin) {
const assertion = JSON.parse(assertionStr);
const { param, query } = assertion;
const { contents, options } = param;
const { args, query } = assertion;
const { contents, options } = args;
const identity = options.usernameHint;
@ -188,10 +184,10 @@ function validateAssertion(assertionStr, origin) {
};
*/
// if global.rtcIdentityProvider is defined, and the caller do not ask
// if rtcIdentityProvider is defined, and the caller do not ask
// to not register through query string, register our assertion callbacks.
if(global.rtcIdentityProvider && query.action !== 'do-not-register') {
global.rtcIdentityProvider.register({
if(rtcIdentityProvider && query.action !== 'do-not-register') {
rtcIdentityProvider.register({
generateAssertion,
validateAssertion
});

View file

@ -5,9 +5,9 @@
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
<script src="/common/namespaces.js"></script>
<script src="/common/canvas-tests.js"></script>
<div id=log></div>
<script>
const crossOriginImageUrl = "http://{{domains[www1]}}:{{ports[http][0]}}/images/red.png";
function assert_origin_unclean_getImageData(bitmap) {
const context = document.createElement("canvas").getContext("2d");
@ -31,92 +31,9 @@ function assert_origin_unclean_transferFromImageBitmap(bitmap) {
assert_throws('SecurityError', () => canvas.toDataURL());
}
function makeImage() {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = crossOriginImageUrl;
});
}
const arguments = [
{
name: "cross-origin HTMLImageElement",
factory: makeImage,
},
{
name: "cross-origin SVGImageElement",
factory: () => {
return new Promise((resolve, reject) => {
const image = document.createElementNS(NAMESPACES.svg, "image");
image.onload = () => resolve(image);
image.onerror = reject;
image.setAttribute("externalResourcesRequired", "true");
image.setAttributeNS(NAMESPACES.xlink, 'xlink:href', crossOriginImageUrl);
document.body.appendChild(image);
});
},
},
{
name: "cross-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = getVideoURI("http://{{domains[www1]}}:{{ports[http][0]}}/media/movie_300");
});
},
},
{
name: "redirected to cross-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = "/common/redirect.py?location=" + getVideoURI("http://{{domains[www1]}}:{{ports[http][0]}}/media/movie_300");
});
},
},
{
name: "redirected to same-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = "http://{{domains[www1]}}:{{ports[http][0]}}/common/redirect.py?location=" + getVideoURI("http://{{domains[]}}:{{ports[http][0]}}/media/movie_300");
});
},
},
{
name: "unclean HTMLCanvasElement",
factory: () => {
return makeImage().then(image => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
return canvas;
});
},
},
{
name: "unclean ImageBitmap",
factory: () => {
return makeImage().then(createImageBitmap);
},
},
];
for (let { name, factory } of arguments) {
forEachCanvasSource("http://{{domains[www1]}}:{{ports[http][0]}}",
"http://{{domains[]}}:{{ports[http][0]}}",
(name, factory) => {
promise_test(function() {
return factory().then(createImageBitmap).then(assert_origin_unclean_getImageData);
}, `${name}: origin unclear getImageData`);
@ -126,5 +43,5 @@ for (let { name, factory } of arguments) {
promise_test(function() {
return factory().then(createImageBitmap).then(assert_origin_unclean_transferFromImageBitmap);
}, `${name}: origin unclear bitmaprenderer.transferFromImageBitmap`);
}
});
</script>

View file

@ -1,32 +1,4 @@
Grant of License
----------------
By contributing to this repository, you and the company you represent, if the
company holds any copyrights in the contribution, grant to the W3C a perpetual,
non-exclusive, royalty-free, world-wide right and license under all of your
copyrights in this contribution to copy, publish, use, and modify the
contribution and to distribute the contribution under a BSD License or one with
more restrictive terms, as well as a right and license of the same scope to any
derivative works prepared by the W3C and based on or incorporating all or part
of the contribution. You further agree that any derivative works of this
contribution prepared by the W3C shall be solely owned by the W3C.
You state, to the best of your knowledge, that you, or the company you
represent, have all rights necessary to contribute the materials.
W3C will retain attribution of initial authorship to you. The W3C makes no
a-priori commitment to support or distribute contributions.
Disclaimer
----------
All content from this repository is provided as is, and W3C makes no
representations or warranties, express or implied, including, but not limited
to, warranties of merchantability, fitness for a particular purpose,
non-infringement, or title; nor that the contents of this repository are
suitable for any purpose. We make no representations, express or implied, that
the content of this repository or the use thereof indicates conformance to a
specification. All content is provided as-is to help reach interoperability.
All contributions are licensed under the terms of the LICENSE.md file.
Documentation
-------------

View file

@ -1,33 +1,11 @@
# Dual-License for W3C Test Suites
# The 3-Clause BSD License
All documents in this Repository are licensed by contributors to be distributed under both the [W3C Test Suite License](#w3c-test-suite-license) and the [W3C 3-clause BSD License](#w3c-3-clause-bsd-license), reproduced below. The choice of license is up to the licensee. For more information, see [Licenses for W3C Test Suites](https://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html)
# W3C Test Suite License
This document, Test Suites and other documents that link to this statement are provided by the copyright holders under the following license: By using and/or copying this document, or the W3C document from which this statement is linked, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
Permission to copy, and distribute the contents of this document, or the W3C document from which this statement is linked, in any medium for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the document, or portions thereof, that you use:
* A link or URL to the original W3C document.
* The pre-existing copyright notice of the original author, or if it doesn't exist, a notice (hypertext is preferred, but a textual representation is permitted) of the form: "Copyright © [$date-of-document] World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) and others. All Rights Reserved. http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html"
* If it exists, the STATUS of the W3C document.
When space permits, inclusion of the full text of this NOTICE should be provided. We request that authorship attribution be provided in any software, documents, or other items or products that you create pursuant to the implementation of the contents of this document, or any portion thereof.
No right to create modifications or derivatives of W3C documents is granted pursuant to this license. However, if additional requirements (documented in the Copyright FAQ) are satisfied, the right to create modifications or derivatives is sometimes granted by the W3C to individuals complying with those requirements.
If a Test Suite distinguishes the test harness (or, framework for navigation) and the actual tests, permission is given to remove or alter the harness or navigation if the Test Suite in question allows to do so. The tests themselves shall NOT be changed in any way.
The name and trademarks of W3C and other copyright holders may NOT be used in advertising or publicity pertaining to this document or other documents that link to this statement without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. Permission is given to use the trademarked string "W3C" within claims of performance concerning W3C Specifications or features described therein, and there only, if the test suite so authorizes.
THIS WORK IS PROVIDED BY W3C, MIT, ERCIM, KEIO, BEIHANG, THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL W3C, MIT, ERCIM, KEIO, BEIHANG, THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# W3C 3-clause BSD License
Copyright 2019 web-platform-tests contributors
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of works must retain the original copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the original copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the W3C nor the names of its contributors may be used to endorse or promote products derived from this work without specific prior written permission.
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -107,3 +107,94 @@ function addCrossOriginRedirectYellowImage()
get_host_info().HTTP_REMOTE_ORIGIN + "/images/yellow.png";
document.body.appendChild(img);
}
function forEachCanvasSource(crossOriginUrl, sameOriginUrl, callback) {
function makeImage() {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = crossOriginUrl + "/images/red.png";
});
}
const arguments = [
{
name: "cross-origin HTMLImageElement",
factory: makeImage,
},
{
name: "cross-origin SVGImageElement",
factory: () => {
return new Promise((resolve, reject) => {
const image = document.createElementNS(NAMESPACES.svg, "image");
image.onload = () => resolve(image);
image.onerror = reject;
image.setAttribute("externalResourcesRequired", "true");
image.setAttributeNS(NAMESPACES.xlink, 'xlink:href', crossOriginUrl + "/images/red.png");
document.body.appendChild(image);
});
},
},
{
name: "cross-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = getVideoURI(crossOriginUrl + "/media/movie_300");
});
},
},
{
name: "redirected to cross-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = "/common/redirect.py?location=" + getVideoURI(crossOriginUrl + "/media/movie_300");
});
},
},
{
name: "redirected to same-origin HTMLVideoElement",
factory: () => {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.oncanplaythrough = () => resolve(video);
video.onerror = reject;
video.src = crossOriginUrl + "/common/redirect.py?location=" + getVideoURI(sameOriginUrl + "/media/movie_300");
});
},
},
{
name: "unclean HTMLCanvasElement",
factory: () => {
return makeImage().then(image => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
return canvas;
});
},
},
{
name: "unclean ImageBitmap",
factory: () => {
return makeImage().then(createImageBitmap);
},
},
];
for (let { name, factory } of arguments) {
callback(name, factory);
}
}

View file

@ -2,3 +2,12 @@ This directory contains the common infrastructure for the following tests.
- referrer-policy/
- mixed-content/
- upgrade-insecure-requests/
Subdirectories:
- `subresource`:
Serves subresources, with support for redirects, stash, etc.
The subresource paths are managed by `subresourceMap` and
fetched in `requestVia*()` functions in `resources/common.js`.
- `scope`:
Serves nested contexts, such as iframe documents or workers.
Used from `invokeFrom*()` functions in `resources/common.js`.

View file

@ -5,6 +5,133 @@
* method's JSDoc.
*/
// ===============================================================
// Types
// ===============================================================
// Objects of the following types are used to represent what kind of
// subresource requests should be sent with what kind of policies,
// from what kind of possibly nested source contexts.
// The objects are represented as JSON objects (not JavaScript/Python classes
// in a strict sense) to be passed between JavaScript/Python code.
// Note: So far this document covers:
// - resources/common.js : client-side test infra code
// - scope/ - server-side scripts that serves nested source contexts
// but doesn't cover:
// - tools/ - generator scripts that generates top-level HTML documents.
// There are some policies only handled by generators (e.g. mixed-content
// opt-ins) and not yet covered by the docs here.
/**
@typedef PolicyDelivery
@type {object}
Referrer policy etc. can be applied/delivered in several ways.
A PolicyDelivery object specifies what policy is delivered and how.
@property {string} deliveryType
Specifies how the policy is delivered.
The valid deliveryType are:
"attr"
[A] DOM attributes e.g. referrerPolicy.
"rel-noref"
[A] <link rel="noreferrer"> (referrer-policy only).
"http-rp"
[B] HTTP response headers.
"meta"
[B] <meta> elements.
@property {string} key
@property {string} value
Specifies what policy to be delivered. The valid keys are:
"referrerPolicy"
Referrer Policy
https://w3c.github.io/webappsec-referrer-policy/
Valid values are those listed in
https://w3c.github.io/webappsec-referrer-policy/#referrer-policy
(except that "" is represented as null/None)
A PolicyDelivery can be specified in several ways:
- (for [A]) Associated with an individual subresource request and
specified in `Subresource.policies`,
e.g. referrerPolicy attributes of DOM elements.
This is handled in invokeRequest().
- (for [B]) Associated with an nested environmental settings object and
specified in `SourceContext.policies`,
e.g. HTTP referrer-policy response headers of HTML/worker scripts.
This is handled in server-side under /common/security-features/scope/.
- (for [B]) Associated with the top-level HTML document.
This is handled by the generators.d
*/
/**
@typedef Subresource
@type {object}
A Subresource represents how a subresource request is sent.
@property{SubresourceType} subresourceType
How the subresource request is sent,
e.g. "img-tag" for sending a request via <img src>.
See the keys of `subresourceMap` for valid values.
@property{string} url
subresource's URL.
Typically this is constructed by getRequestURLs() below.
@property{PolicyDelivery} policyDeliveries
Policies delivered specific to the subresource request.
*/
/**
@typedef SourceContext
@type {object}
Requests can be possibly sent from various kinds of source contexts, i.e.
fetch client's environment settings objects:
top-level windows, iframes, or workers.
A SourceContext object specifies one environment settings object, and
an Array<SourceContext> specifies a possibly nested context,
from the outer-most to inner-most environment settings objects.
For example:
[{sourceContextType: "srcdoc"}, {sourceContextType: "classic-worker"}]
means that a subresource request is to be sent from
a classic dedicated worker created from <iframe srcdoc>
inside the top-level HTML document.
Note: the top-level document is not included in the array and
is assumed implicitly.
SourceContext (or Array<SourceContext>) is set based on
the fetch client's settings object that is used for the subresource request,
NOT on module map settings object, and
NOT on the inner-most settings object that appears in the test.
For example, Array<SourceContext> is `[]` (indicating the top Window)
for `worker.js`
- When it is the root worker script: `new Worker('worker.js')`, or
- When it is imported from the root worker script:
`new Worker('top.js', {type: 'module'})`
where `top.js` has `import 'worker.js'`.
because the request for `worker.js` uses the Window as its fetch client's
settings object, while a WorkerGlobalScope is created though.
@property {string} sourceContextType
Kind of the source context to be used.
Valid values are the keys of `sourceContextMap` below.
@property {Array<PolicyDelivery>} policyDeliveries
A list of PolicyDelivery applied to the source context.
*/
// ===============================================================
// General utility functions
// ===============================================================
function timeoutPromise(t, ms) {
return new Promise(resolve => { t.step_timeout(resolve, ms); });
}
@ -70,8 +197,16 @@ function xhrRequest(url, responseType) {
*/
function setAttributes(el, attrs) {
attrs = attrs || {}
for (var attr in attrs)
el.setAttribute(attr, attrs[attr]);
for (var attr in attrs) {
if (attr !== 'src')
el.setAttribute(attr, attrs[attr]);
}
// Workaround for Chromium: set <img>'s src attribute after all other
// attributes to ensure the policy is applied.
for (var attr in attrs) {
if (attr === 'src')
el.setAttribute(attr, attrs[attr]);
}
}
/**
@ -202,52 +337,79 @@ function wrapResult(server_data) {
}
}
// `requestVia*()` functions return promises that are resolved on successful
// requests with objects with the following keys:
// - `headers`: HTTP request headers sent to server.
// - `referrer`: Referrer.
// - `location`: The URL of the subresource.
//
// Category 1:
// `headers`: set.
// `referrer`: set via `document.referrer`.
// `location`: set via `document.location`.
// See `template/document.html.template`.
// Category 2:
// `headers`: set.
// `referrer`: set to `headers.referer` by `wrapResult()`.
// `location`: not set.
// Category 3:
// All the keys listed above are NOT set.
//
// -------------------------------- -------- --------------------------
// Function name Category Used in
// -------- ------- ---------
// referrer mixed- upgrade-
// policy content insecure-
// policy content request
// -------------------------------- -------- -------- ------- ---------
// requestViaAnchor 1 Y Y -
// requestViaArea 1 Y Y -
// requestViaAudio 3 - Y -
// requestViaDedicatedWorker 2 Y Y Y
// requestViaFetch 2 Y Y -
// requestViaForm 3 - Y -
// requestViaIframe 1 Y Y -
// requestViaImage 3 - Y -
// requestViaImageForReferrerPolicy 2 Y - -
// requestViaLinkPrefetch 3 - Y -
// requestViaLinkStylesheet 3 - Y -
// requestViaObject 3 - Y -
// requestViaPicture 3 - Y -
// requestViaScript 2 Y Y -
// requestViaSendBeacon 3 - Y -
// requestViaSharedWorker 2 Y - -
// requestViaVideo 3 - Y -
// requestViaWebSocket 3 - Y -
// requestViaWorklet 3 - Y Y
// requestViaXhr 2 Y Y -
// -------------------------------- -------- -------- ------- ---------
// ===============================================================
// Subresources
// ===============================================================
/**
@typedef RequestResult
@type {object}
Represents the result of sending an request.
All properties are optional. See the comments for
requestVia*() and invokeRequest() below to see which properties are set.
@property {Array<Object<string, string>>} headers
HTTP request headers sent to server.
@property {string} referrer - Referrer.
@property {string} location - The URL of the subresource.
@property {string} sourceContextUrl
the URL of the global object where the actual request is sent.
*/
/**
requestVia*(url, additionalAttributes) functions send a subresource
request from the current environment settings object.
@param {string} url
The URL of the subresource.
@param {Object<string, string>} additionalAttributes
Additional attributes set to DOM elements
(element-initiated requests only).
@returns {Promise} that are resolved with a RequestResult object
on successful requests.
- Category 1:
`headers`: set.
`referrer`: set via `document.referrer`.
`location`: set via `document.location`.
See `template/document.html.template`.
- Category 2:
`headers`: set.
`referrer`: set to `headers.referer` by `wrapResult()`.
`location`: not set.
- Category 3:
All the keys listed above are NOT set.
`sourceContextUrl` is not set here.
-------------------------------- -------- --------------------------
Function name Category Used in
-------- ------- ---------
referrer mixed- upgrade-
policy content insecure-
policy content request
-------------------------------- -------- -------- ------- ---------
requestViaAnchor 1 Y Y -
requestViaArea 1 Y Y -
requestViaAudio 3 - Y -
requestViaDedicatedWorker 2 Y Y Y
requestViaFetch 2 Y Y -
requestViaForm 3 - Y -
requestViaIframe 1 Y Y -
requestViaImage 2 Y Y -
requestViaLinkPrefetch 3 - Y -
requestViaLinkStylesheet 3 - Y -
requestViaObject 3 - Y -
requestViaPicture 3 - Y -
requestViaScript 2 Y Y -
requestViaSendBeacon 3 - Y -
requestViaSharedWorker 2 Y - -
requestViaVideo 3 - Y -
requestViaWebSocket 3 - Y -
requestViaWorklet 3 - Y Y
requestViaXhr 2 Y Y -
-------------------------------- -------- -------- ------- ---------
*/
/**
* Creates a new iframe, binds load and error events, sets the src attribute and
@ -274,40 +436,23 @@ function requestViaIframe(url, additionalAttributes) {
* @param {string} url The src for the image.
* @return {Promise} The promise for success/error events.
*/
function requestViaImage(url) {
return createRequestViaElement("img", {"src": url}, document.body);
function requestViaImage(url, additionalAttributes) {
const img = createElement(
"img",
// crossOrigin attribute is added to read the pixel data of the response.
Object.assign({"src": url, "crossOrigin": "Anonymous"}, additionalAttributes),
document.body, true);
return img.eventPromise.then(() => wrapResult(decodeImageData(img)));
}
// Helpers for requestViaImageForReferrerPolicy().
function loadImageInWindow(src, attributes, w) {
return new Promise((resolve, reject) => {
var image = new w.Image();
image.crossOrigin = "Anonymous";
image.onload = function() {
resolve(image);
};
// Helper for requestViaImage().
function decodeImageData(img) {
var canvas = document.createElement("canvas");
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var imgData = context.getImageData(0, 0, img.clientWidth, img.clientHeight);
const rgba = imgData.data;
// Extend element with attributes. (E.g. "referrerPolicy" or "rel")
if (attributes) {
for (var attr in attributes) {
image[attr] = attributes[attr];
}
}
image.src = src;
w.document.body.appendChild(image)
});
}
function extractImageData(img) {
var canvas = document.createElement("canvas");
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var imgData = context.getImageData(0, 0, img.clientWidth, img.clientHeight);
return imgData.data;
}
function decodeImageData(rgba) {
let decodedBytes = new Uint8ClampedArray(rgba.length);
let decodedLength = 0;
@ -349,62 +494,6 @@ function decodeImageData(rgba) {
return JSON.parse(string_data);
}
// A variant of requestViaImage for referrer policy tests.
// This tests many patterns of <iframe>s to test referrer policy inheritance.
// TODO(https://crbug.com/906850): Merge this into requestViaImage().
// <iframe>-related code should be moved outside requestViaImage*().
function requestViaImageForReferrerPolicy(url, attributes, referrerPolicy) {
// For images, we'll test:
// - images in a `srcdoc` frame to ensure that it uses the referrer
// policy of its parent,
// - images in a top-level document,
// - and images in a `srcdoc` frame with its own referrer policy to
// override its parent.
var iframeWithoutOwnPolicy = document.createElement('iframe');
var noSrcDocPolicy = new Promise((resolve, reject) => {
iframeWithoutOwnPolicy.srcdoc = "Hello, world.";
iframeWithoutOwnPolicy.onload = resolve;
document.body.appendChild(iframeWithoutOwnPolicy);
})
.then(() => {
var nextUrl = url + "&cache_destroyer2=" + (new Date()).getTime();
return loadImageInWindow(nextUrl, attributes,
iframeWithoutOwnPolicy.contentWindow);
})
.then(function (img) {
return decodeImageData(extractImageData(img));
});
// Give a srcdoc iframe a referrer policy different from the top-level page's policy.
var iframePolicy = (referrerPolicy === "no-referrer") ? "unsafe-url" : "no-referrer";
var iframeWithOwnPolicy = document.createElement('iframe');
var srcDocPolicy = new Promise((resolve, reject) => {
iframeWithOwnPolicy.srcdoc = "<meta name='referrer' content='" + iframePolicy + "'>Hello world.";
iframeWithOwnPolicy.onload = resolve;
document.body.appendChild(iframeWithOwnPolicy);
})
.then(() => {
var nextUrl = url + "&cache_destroyer3=" + (new Date()).getTime();
return loadImageInWindow(nextUrl, null,
iframeWithOwnPolicy.contentWindow);
})
.then(function (img) {
return decodeImageData(extractImageData(img));
});
var pagePolicy = loadImageInWindow(url, attributes, window)
.then(function (img) {
return decodeImageData(extractImageData(img));
});
return Promise.all([noSrcDocPolicy, srcDocPolicy, pagePolicy]).then(values => {
assert_equals(values[0].headers.referer, values[2].headers.referer, "Referrer inside 'srcdoc' without its own policy should be the same as embedder's referrer.");
assert_equals((iframePolicy === "no-referrer" ? undefined : document.location.href), values[1].headers.referer, "Referrer inside 'srcdoc' should use the iframe's policy if it has one");
return wrapResult(values[2]);
});
}
/**
* Initiates a new XHR GET request to provided URL.
* @param {string} url The endpoint URL for the XHR.
@ -745,6 +834,14 @@ function requestViaWebSocket(url) {
});
}
/**
@typedef SubresourceType
@type {string}
Represents how a subresource is sent.
The keys of `subresourceMap` below are the valid values.
*/
// Subresource paths and invokers.
const subresourceMap = {
"a-tag": {
@ -778,7 +875,6 @@ const subresourceMap = {
"img-tag": {
path: "/common/security-features/subresource/image.py",
invoker: requestViaImage,
invokerForReferrerPolicy: requestViaImageForReferrerPolicy,
},
"link-css-tag": {
path: "/common/security-features/subresource/empty.py",
@ -854,6 +950,35 @@ for (const workletType of ['animation', 'audio', 'layout', 'paint']) {
};
}
/**
@typedef RedirectionType
@type {string}
Represents what redirects should occur to the subresource request
after initial request.
See preprocess_redirection() in
/common/security-features/subresource/subresource.py for valid values.
*/
/**
Construct subresource (and related) URLs.
@param {SubresourceType} subresourceType
@param {OriginType} originType
@param {RedirectionType} redirectionType
@returns {object} with following properties:
{string} testUrl
The subresource request URL.
{string} announceUrl
{string} assertUrl
The URLs to be used for detecting whether `testUrl` is actually sent
to the server.
1. Fetch `announceUrl` first,
2. then possibly fetch `testUrl`, and
3. finally fetch `assertUrl`.
The fetch result of `assertUrl` should indicate whether
`testUrl` is actually sent to the server or not.
*/
function getRequestURLs(subresourceType, originType, redirectionType) {
const key = guid();
const value = guid();
@ -875,6 +1000,122 @@ function getRequestURLs(subresourceType, originType, redirectionType) {
};
}
// ===============================================================
// Source Context
// ===============================================================
// Requests can be sent from several source contexts,
// such as the main documents, iframes, workers, or so,
// possibly nested, and possibly with <meta>/http headers added.
// invokeRequest() and invokeFrom*() functions handles
// SourceContext-related setup in client-side.
/**
invokeRequest() invokes a subresource request
(specified as `subresource`)
from a (possibly nested) environment settings object
(specified as `sourceContextList`).
For nested contexts, invokeRequest() calls an invokeFrom*() function
that creates a nested environment settings object using
/common/security-features/scope/, which calls invokeRequest()
again inside the nested environment settings object.
This cycle continues until all specified
nested environment settings object are created, and
finally invokeRequest() calls a requestVia*() function to start the
subresource request from the inner-most environment settings object.
@param {Subresource} subresource
@param {Array<SourceContext>} sourceContextList
@returns {Promise} A promise that is resolved with an RequestResult object.
`sourceContextUrl` is always set. For whether other properties are set,
see the comments for requestVia*() above.
*/
function invokeRequest(subresource, sourceContextList) {
if (sourceContextList.length === 0) {
// No further nested global objects. Send the subresource request here.
const additionalAttributes = {};
/** @type {PolicyDelivery} policyDelivery */
for (const policyDelivery of (subresource.policyDeliveries || [])) {
// Depending on the delivery method, extend the subresource element with
// these attributes.
if (policyDelivery.deliveryType === "attr") {
additionalAttributes[policyDelivery.key] = policyDelivery.value;
} else if (policyDelivery.deliveryType === "rel-noref") {
additionalAttributes["rel"] = "noreferrer";
}
}
return subresourceMap[subresource.subresourceType].invoker(
subresource.url,
additionalAttributes)
.then(result => Object.assign(
{sourceContextUrl: location.toString()},
result));
}
// Defines invokers for each valid SourceContext.sourceContextType.
const sourceContextMap = {
"srcdoc": { // <iframe srcdoc></iframe>
invoker: invokeFromIframe,
},
"iframe": { // <iframe src="same-origin-URL"></iframe>
invoker: invokeFromIframe,
},
};
return sourceContextMap[sourceContextList[0].sourceContextType].invoker(
subresource, sourceContextList);
}
/**
invokeFrom*() functions are helper functions with the same parameters
and return values as invokeRequest(), that are tied to specific types
of top-most environment settings objects.
For example, invokeFromIframe() is the helper function for the cases where
sourceContextList[0] is an iframe.
*/
function invokeFromIframe(subresource, sourceContextList) {
const currentSourceContext = sourceContextList.shift();
const frameUrl =
"/common/security-features/scope/document.py?policyDeliveries=" +
encodeURIComponent(JSON.stringify(
currentSourceContext.policyDeliveries || []));
let promise;
if (currentSourceContext.sourceContextType === 'srcdoc') {
promise = fetch(frameUrl)
.then(r => r.text())
.then(srcdoc => {
return createElement("iframe", {srcdoc: srcdoc}, document.body, true);
});
} else if (currentSourceContext.sourceContextType === 'iframe') {
promise = Promise.resolve(
createElement("iframe", {src: frameUrl}, document.body, true));
}
return promise
.then(iframe => {
return iframe.eventPromise
.then(() => {
const promise = bindEvents2(
window, "message", iframe, "error", window, "error");
iframe.contentWindow.postMessage(
{subresource: subresource,
sourceContextList: sourceContextList},
"*");
return promise;
})
.then(event => {
if (event.data.error)
return Promise.reject(event.data.error);
return event.data;
});
});
}
// SanityChecker does nothing in release mode. See sanity-checker.js for debug
// mode.
function SanityChecker() {}

View file

@ -0,0 +1,35 @@
import os, sys, json
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import util
def main(request, response):
policyDeliveries = json.loads(request.GET.first("policyDeliveries", "[]"))
maybe_additional_headers = {}
meta = ''
error = ''
for delivery in policyDeliveries:
if delivery['deliveryType'] == 'meta':
if delivery['key'] == 'referrerPolicy':
meta += '<meta name="referrer" content="%s">' % delivery['value']
else:
error = 'invalid delivery key'
elif delivery['deliveryType'] == 'http-rp':
if delivery['key'] == 'referrerPolicy':
maybe_additional_headers['Referrer-Policy'] = delivery['value']
else:
error = 'invalid delivery key'
else:
error = 'invalid deliveryType'
handler = lambda: util.get_template("document.html.template") % ({
"meta": meta,
"error": error
})
util.respond(
request,
response,
payload_generator=handler,
content_type="text/html",
maybe_additional_headers=maybe_additional_headers)

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
%(meta)s
<script src="/common/security-features/resources/common.js"></script>
<script>
// Receive a message from the parent and start the test.
function onMessageFromParent(event) {
// Because this window might receive messages from child iframe during
// tests, we first remove the listener here before staring the test.
window.removeEventListener('message', onMessageFromParent);
const configurationError = "%(error)s";
if (configurationError.length > 0) {
parent.postMessage({error: configurationError}, "*");
return;
}
invokeRequest(event.data.subresource,
event.data.sourceContextList)
.then(result => parent.postMessage(result, "*"))
.catch(e => {
const message = (e.error && e.error.stack) || e.message || "Error";
parent.postMessage({error: message}, "*");
});
}
window.addEventListener('message', onMessageFromParent);
</script>
</head>
</html>

View file

@ -0,0 +1,42 @@
import os
def get_template(template_basename):
script_directory = os.path.dirname(os.path.abspath(__file__))
template_directory = os.path.abspath(
os.path.join(script_directory, "template"))
template_filename = os.path.join(template_directory, template_basename)
with open(template_filename, "r") as f:
return f.read()
def __noop(request, response):
return ""
def respond(request,
response,
status_code=200,
content_type="text/html",
payload_generator=__noop,
cache_control="no-cache; must-revalidate",
access_control_allow_origin="*",
maybe_additional_headers=None):
response.add_required_headers = False
response.writer.write_status(status_code)
if access_control_allow_origin != None:
response.writer.write_header("access-control-allow-origin",
access_control_allow_origin)
response.writer.write_header("content-type", content_type)
response.writer.write_header("cache-control", cache_control)
additional_headers = maybe_additional_headers or {}
for header, value in additional_headers.items():
response.writer.write_header(header, value)
response.writer.end_headers()
payload = payload_generator()
response.writer.write(payload)

View file

@ -0,0 +1,189 @@
from __future__ import print_function
import copy
import os, sys, json
import spec_validator
import argparse
import util
def expand_pattern(expansion_pattern, test_expansion_schema):
expansion = {}
for artifact_key in expansion_pattern:
artifact_value = expansion_pattern[artifact_key]
if artifact_value == '*':
expansion[artifact_key] = test_expansion_schema[artifact_key]
elif isinstance(artifact_value, list):
expansion[artifact_key] = artifact_value
elif isinstance(artifact_value, dict):
# Flattened expansion.
expansion[artifact_key] = []
values_dict = expand_pattern(artifact_value,
test_expansion_schema[artifact_key])
for sub_key in values_dict.keys():
expansion[artifact_key] += values_dict[sub_key]
else:
expansion[artifact_key] = [artifact_value]
return expansion
def permute_expansion(expansion, artifact_order, selection = {}, artifact_index = 0):
assert isinstance(artifact_order, list), "artifact_order should be a list"
if artifact_index >= len(artifact_order):
yield selection
return
artifact_key = artifact_order[artifact_index]
for artifact_value in expansion[artifact_key]:
selection[artifact_key] = artifact_value
for next_selection in permute_expansion(expansion,
artifact_order,
selection,
artifact_index + 1):
yield next_selection
def generate_selection(config, selection, spec, test_html_template_basename):
# TODO: Refactor out this referrer-policy-specific part.
if 'referrer_policy' in spec:
# Oddball: it can be None, so in JS it's null.
selection['referrer_policy'] = spec['referrer_policy']
test_parameters = json.dumps(selection, indent=2, separators=(',', ':'))
# Adjust the template for the test invoking JS. Indent it to look nice.
indent = "\n" + " " * 8
test_parameters = test_parameters.replace("\n", indent)
selection['test_js'] = '''
%s(
%s,
document.querySelector("meta[name=assert]").content,
new SanityChecker()
).start();
''' % (config.test_case_name, test_parameters)
selection['spec_name'] = spec['name']
selection['test_page_title'] = config.test_page_title_template % spec['title']
selection['spec_description'] = spec['description']
selection['spec_specification_url'] = spec['specification_url']
selection['helper_js'] = config.helper_js
selection['sanity_checker_js'] = config.sanity_checker_js
selection['spec_json_js'] = config.spec_json_js
test_filename = os.path.join(config.spec_directory, config.test_file_path_pattern % selection)
test_headers_filename = test_filename + ".headers"
test_directory = os.path.dirname(test_filename)
test_html_template = util.get_template(test_html_template_basename)
disclaimer_template = util.get_template('disclaimer.template')
html_template_filename = os.path.join(util.template_directory,
test_html_template_basename)
generated_disclaimer = disclaimer_template \
% {'generating_script_filename': os.path.relpath(__file__,
util.test_root_directory),
'html_template_filename': os.path.relpath(html_template_filename,
util.test_root_directory)}
# Adjust the template for the test invoking JS. Indent it to look nice.
selection['generated_disclaimer'] = generated_disclaimer.rstrip()
selection['test_description'] = config.test_description_template % selection
selection['test_description'] = \
selection['test_description'].rstrip().replace("\n", "\n" + " " * 33)
# Directory for the test files.
try:
os.makedirs(test_directory)
except:
pass
delivery = config.handleDelivery(selection, spec)
if len(delivery['headers']) > 0:
with open(test_headers_filename, "w") as f:
for header in delivery['headers']:
f.write(header)
f.write('\n')
selection['meta_delivery_method'] = delivery['meta']
# Obey the lint and pretty format.
if len(selection['meta_delivery_method']) > 0:
selection['meta_delivery_method'] = "\n " + \
selection['meta_delivery_method']
# Write out the generated HTML file.
util.write_file(test_filename, test_html_template % selection)
def generate_test_source_files(config, spec_json, target):
test_expansion_schema = spec_json['test_expansion_schema']
specification = spec_json['specification']
spec_json_js_template = util.get_template('spec_json.js.template')
generated_spec_json_filename = os.path.join(config.spec_directory, "spec_json.js")
util.write_file(generated_spec_json_filename,
spec_json_js_template % {'spec_json': json.dumps(spec_json)})
# Choose a debug/release template depending on the target.
html_template = "test.%s.html.template" % target
artifact_order = test_expansion_schema.keys() + ['name']
artifact_order.remove('expansion')
# Create list of excluded tests.
exclusion_dict = {}
for excluded_pattern in spec_json['excluded_tests']:
excluded_expansion = \
expand_pattern(excluded_pattern, test_expansion_schema)
for excluded_selection in permute_expansion(excluded_expansion,
artifact_order):
excluded_selection_path = config.selection_pattern % excluded_selection
exclusion_dict[excluded_selection_path] = True
for spec in specification:
# Used to make entries with expansion="override" override preceding
# entries with the same |selection_path|.
output_dict = {}
for expansion_pattern in spec['test_expansion']:
expansion = expand_pattern(expansion_pattern, test_expansion_schema)
for selection in permute_expansion(expansion, artifact_order):
selection_path = config.selection_pattern % selection
if not selection_path in exclusion_dict:
if selection_path in output_dict:
if expansion_pattern['expansion'] != 'override':
print("Error: %s's expansion is default but overrides %s" % (selection['name'], output_dict[selection_path]['name']))
sys.exit(1)
output_dict[selection_path] = copy.deepcopy(selection)
else:
print('Excluding selection:', selection_path)
for selection_path in output_dict:
selection = output_dict[selection_path]
generate_selection(config,
selection,
spec,
html_template)
def main(config):
parser = argparse.ArgumentParser(description='Test suite generator utility')
parser.add_argument('-t', '--target', type = str,
choices = ("release", "debug"), default = "release",
help = 'Sets the appropriate template for generating tests')
parser.add_argument('-s', '--spec', type = str, default = None,
help = 'Specify a file used for describing and generating the tests')
# TODO(kristijanburnik): Add option for the spec_json file.
args = parser.parse_args()
if args.spec:
config.spec_directory = args.spec
spec_filename = os.path.join(config.spec_directory, "spec.src.json")
spec_json = util.load_spec_json(spec_filename)
spec_validator.assert_valid_spec_json(spec_json)
generate_test_source_files(config, spec_json, args.target)

View file

@ -2,15 +2,20 @@
%(generated_disclaimer)s
<html>
<head>
<title>Referrer-Policy: %(spec_title)s</title>
<meta name="description" content="%(spec_description)s">%(meta_delivery_method)s
<title>%(test_page_title)s</title>
<meta charset='utf-8'>
<meta name="description" content="%(spec_description)s">
<link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
<link rel="help" href="%(spec_specification_url)s">
<meta name="assert" content="%(test_description)s">
<meta name="assert" content="%(test_description)s">%(meta_delivery_method)s
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/security-features/resources/common.js"></script>
<script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
<!-- The original specification JSON for validating the scenario. -->
<script src="%(spec_json_js)s"></script>
<!-- Internal checking of the tests -->
<script src="%(sanity_checker_js)s"></script>
<script src="%(helper_js)s"></script>
</head>
<body>
<script>%(test_js)s</script>

View file

@ -2,16 +2,16 @@
%(generated_disclaimer)s
<html>
<head>
<title>Mixed-Content: %(spec_title)s</title>
<title>%(test_page_title)s</title>
<meta charset='utf-8'>
<meta name="description" content="%(spec_description)s">
<link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
<link rel="help" href="%(spec_specification_url)s">
<meta name="assert" content="%(test_description)s">%(meta_opt_in)s
<meta name="assert" content="%(test_description)s">%(meta_delivery_method)s
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/security-features/resources/common.js"></script>
<script src="/mixed-content/generic/mixed-content-test-case.js?pipe=sub"></script>
<script src="%(helper_js)s"></script>
</head>
<body>
<script>%(test_js)s</script>

View file

@ -3,27 +3,11 @@ from __future__ import print_function
import os, sys, json, re
script_directory = os.path.dirname(os.path.abspath(__file__))
generic_directory = os.path.abspath(os.path.join(script_directory, '..'))
template_directory = os.path.abspath(os.path.join(script_directory,
'..',
'template'))
spec_directory = os.path.abspath(os.path.join(script_directory, '..', '..'))
test_root_directory = os.path.abspath(os.path.join(script_directory,
'..', '..', '..'))
spec_filename = os.path.join(spec_directory, "spec.src.json")
generated_spec_json_filename = os.path.join(spec_directory, "spec_json.js")
selection_pattern = '%(delivery_method)s/' + \
'%(origin)s/' + \
'%(source_protocol)s-%(target_protocol)s/' + \
'%(subresource)s/' + \
'%(redirection)s/'
test_file_path_pattern = '%(spec_name)s/' + selection_pattern + \
'%(name)s.%(source_protocol)s.html'
def get_template(basename):
with open(os.path.join(template_directory, basename), "r") as f:
@ -42,10 +26,7 @@ def read_nth_line(fp, line_number):
return line
def load_spec_json(path_to_spec = None):
if path_to_spec is None:
path_to_spec = spec_filename
def load_spec_json(path_to_spec):
re_error_location = re.compile('line ([0-9]+) column ([0-9]+)')
with open(path_to_spec, "r") as f:
try:

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#flow-control">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="position: absolute; width: 100px; height: 100px; background: red;"></div>
<div style="position: absolute; width: 100px;">
<div>
<div style="float:left; width:100px; height:50px; background: green;"></div>
<div style="clear:both;">
<div style="float:left; width:10px; height:10px;"></div>
<div style="margin-top:100px; height:50px; background: green;"></div>
</div>
</div>
</div>
</div>

View file

@ -1,18 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reference: Green 'canadian syllabics chi sign' punctuation character</title>
<style type="text/css">
span
{
color: green;
font-size: 36px;
line-height: 2;
}
</style>
</head>
<body>
<p>Test passes if the "T" and surrounding punctuation below are green.</p>
<div><span>&#x166D;T&#x166D;</span>est</div>
</body>
</html>

View file

@ -1,23 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: First-letter with the 'canadian syllabics chi sign' punctuation character</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="http://www.w3.org/TR/CSS21/selector.html#first-letter" />
<link rel="match" href="first-letter-punctuation-184-ref.xht" />
<meta name="flags" content="" />
<meta name="assert" content="Punctuation characters defined in Unicode [UNICODE] in (Ps),(Pe),(Pi),(Pf) and (Po) punctuation classes that precede or follow the first letter are included in first-letter selection - 'canadian syllabics chi sign'." />
<style type="text/css">
div:first-letter
{
color: green;
font-size: 36px;
line-height: 2;
}
</style>
</head>
<body>
<p>Test passes if the "T" and surrounding punctuation below are green.</p>
<div>&#x166D;T&#x166D;est</div>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test Reference</title>
<style type="text/css">
#test
{
outline: solid blue 10px;
height: 1in;
width: 1in;
}
#table
{
display: table;
}
</style>
</head>
<body>
<p>Test passes if there is a blue box below.</p>
<div id="table">
<img id="test"></img>
</div>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Outline applied to replaced element with display table-column-group</title>
<link rel="help" href="http://www.w3.org/TR/CSS21/ui.html#propdef-outline" />
<link rel="help" href="http://www.w3.org/TR/CSS21/ui.html#dynamic-outlines" />
<link rel="match" href="outline-applies-to-016-ref.xht"/>
<meta name="flags" content="" />
<meta name="assert" content="The 'outline' property applies to replaced elements with a display of table-column-group." />
<style type="text/css">
#test
{
display: table-column-group;
outline: solid blue 10px;
height: 1in;
width: 1in;
}
#table
{
display: table;
}
</style>
</head>
<body>
<p>Test passes if there is a blue box below.</p>
<div id="table">
<img id="test"></img>
</div>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Outline applied to replaced element with display table-column</title>
<link rel="help" href="http://www.w3.org/TR/CSS21/ui.html#propdef-outline" />
<link rel="help" href="http://www.w3.org/TR/CSS21/ui.html#dynamic-outlines" />
<link rel="match" href="outline-applies-to-016-ref.xht"/>
<meta name="flags" content="" />
<meta name="assert" content="The 'outline' property applies to replaced elements with a display of table-column." />
<style type="text/css">
#test
{
display: table-column;
outline: solid blue 10px;
height: 1in;
width: 1in;
}
#table
{
display: table;
}
</style>
</head>
<body>
<p>Test passes if there is a blue box below.</p>
<div id="table">
<img id="test"></img>
</div>
</body>
</html>

View file

@ -18,12 +18,6 @@
@keyframes animRight {
to { right: 100px }
}
::before {
content: ''
}
::after {
content: ''
}
</style>
<div id="log"></div>
<script>
@ -251,34 +245,77 @@ test(t => {
}, 'CSS Animations canceled and restarted via the API are returned');
test(t => {
addStyle(t, { '#parent::after': 'animation: animLeft 10s;',
'#parent::before': 'animation: animRight 10s;' });
// create two divs with these arrangement:
// Create two divs with the following arrangement:
//
// parent
// (::marker,)
// ::before,
// ::after
// |
// child
const parent = addDiv(t, { 'id': 'parent' });
addStyle(t, {
'#parent::after': "content: ''; animation: animLeft 100s;",
'#parent::before': "content: ''; animation: animRight 100s;",
});
const supportsMarkerPseudos = CSS.supports('selector(::marker)');
if (supportsMarkerPseudos) {
addStyle(t, {
'#parent': 'display: list-item;',
'#parent::marker': "content: ''; animation: animLeft 100s;",
});
}
const parent = addDiv(t, { id: 'parent' });
const child = addDiv(t);
parent.appendChild(child);
for (const div of [parent, child]) {
div.setAttribute('style', 'animation: animBottom 10s');
div.setAttribute('style', 'animation: animBottom 100s');
}
const anims = document.getAnimations();
assert_equals(anims.length, 4,
'CSS animations on both pseudo-elements and elements ' +
'are returned');
assert_equals(anims[0].effect.target, parent,
'The animation targeting the parent element comes first');
assert_equals(anims[1].effect.target.type, '::before',
'The animation targeting the ::before element comes second');
assert_equals(anims[2].effect.target.type, '::after',
'The animation targeting the ::after element comes third');
assert_equals(anims[3].effect.target, child,
'The animation targeting the child element comes last');
}, 'CSS Animations targetting (pseudo-)elements should have correct order ' +
'after sorting');
const expectedAnimations = [
[parent, undefined],
[parent, '::marker'],
[parent, '::before'],
[parent, '::after'],
[child, undefined],
];
if (!supportsMarkerPseudos) {
expectedAnimations.splice(1, 1);
}
const animations = document.getAnimations();
assert_equals(
animations.length,
expectedAnimations.length,
'CSS animations on both pseudo-elements and elements are returned'
);
for (const [index, expected] of expectedAnimations.entries()) {
const [element, pseudo] = expected;
const actual = animations[index];
if (pseudo) {
assert_equals(
actual.effect.target.element,
element,
`Animation #${index + 1} has expected target`
);
assert_equals(
actual.effect.target.type,
pseudo,
`Animation #${index + 1} has expected pseudo type`
);
} else {
assert_equals(
actual.effect.target,
element,
`Animation #${index + 1} has expected target`
);
}
}
}, 'CSS Animations targetting (pseudo-)elements should have correct order '
+ 'after sorting');
</script>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Animations Test: AnimationEvent pseudoElement</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<link rel="help" href="https://drafts.csswg.org/css-animations/#interface-animationevent">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#target::marker {
content: "";
animation: move 1s;
}
@keyframes move {
to { transform: translate(100px); }
}
#target {
display: list-item;
list-style-position: inside;
}
</style>
<div id='target'></div>
<script>
async_test(function(t) {
var target = document.getElementById('target');
target.addEventListener("animationstart", t.step_func(function(evt) {
assert_true(evt instanceof window.AnimationEvent);
assert_equals(evt.pseudoElement, "::marker");
t.done();
}), true);
}, "AnimationEvent should have the correct pseudoElement memeber");
</script>

View file

@ -6,10 +6,14 @@
<script src="/resources/testharnessreport.js"></script>
<script src="support/testcommon.js"></script>
<style>
@keyframes anim {
from { margin-left: 0px; }
to { margin-left: 100px; }
}
@keyframes anim {
from { margin-left: 0px; }
to { margin-left: 100px; }
}
@keyframes color-anim {
from { color: red; }
to { color: green; }
}
</style>
<div id="log"></div>
<script type='text/javascript'>
@ -20,38 +24,69 @@
* @param actualEvents An array of the received AnimationEvent objects.
* @param expectedEvents A series of array objects representing the expected
* events, each having the form:
* [ event type, target element, elapsed time ]
* [ event type, target element, [pseudo type], elapsed time ]
*/
const checkEvents = (actualEvents, ...expectedEvents) => {
assert_equals(actualEvents.length, expectedEvents.length,
`Number of actual events (${actualEvents.length}: \
${actualEvents.map(event => event.type).join(', ')}) should match expected \
events (${expectedEvents.map(event => event.type).join(', ')})`);
const actualTypeSummary = actualEvents.map(event => event.type).join(', ');
const expectedTypeSummary = expectedEvents.map(event => event[0]).join(', ');
actualEvents.forEach((actualEvent, i) => {
assert_equals(expectedEvents[i][0], actualEvent.type,
'Event type should match');
assert_equals(expectedEvents[i][1], actualEvent.target,
'Event target should match');
assert_equals(expectedEvents[i][2], actualEvent.elapsedTime,
'Event\'s elapsed time should match');
});
assert_equals(
actualEvents.length,
expectedEvents.length,
`Number of events received (${actualEvents.length}) \
should match expected number (${expectedEvents.length}) \
(expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
);
for (const [index, actualEvent] of actualEvents.entries()) {
const expectedEvent = expectedEvents[index];
const [type, target] = expectedEvent;
const pseudoElement = expectedEvent.length === 4 ? expectedEvent[2] : '';
const elapsedTime = expectedEvent[expectedEvent.length - 1];
assert_equals(
actualEvent.type,
type,
`Event #${index + 1} types should match \
(expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
);
assert_equals(
actualEvent.target,
target,
`Event #${index + 1} targets should match`
);
assert_equals(
actualEvent.pseudoElement,
pseudoElement,
`Event #${index + 1} pseudoElements should match`
);
assert_equals(
actualEvent.elapsedTime,
elapsedTime,
`Event #${index + 1} elapsedTimes should match`
);
}
};
const setupAnimation = (t, animationStyle, receiveEvents) => {
const div = addDiv(t, { style: "animation: " + animationStyle });
const div = addDiv(t, { style: 'animation: ' + animationStyle });
for (const name of ['start', 'iteration', 'end']) {
div['onanimation' + name] = evt => {
receiveEvents.push({ type: evt.type,
target: evt.target,
elapsedTime: evt.elapsedTime });
receiveEvents.push({
type: evt.type,
target: evt.target,
pseudoElement: evt.pseudoElement,
elapsedTime: evt.elapsedTime,
});
};
}
const watcher = new EventWatcher(t, div, [ 'animationstart',
'animationiteration',
'animationend' ]);
const watcher = new EventWatcher(t, div, [
'animationstart',
'animationiteration',
'animationend',
]);
const animation = div.getAnimations()[0];
@ -92,7 +127,64 @@ promise_test(async t => {
checkEvents(events, ['animationend', div1, 200],
['animationend', div2, 200]);
}, 'Test same events are ordered by elements.');
}, 'Same events are ordered by elements');
promise_test(async t => {
// Setup a hierarchy as follows:
//
// parent
// |
// (::marker, ::before, ::after)
// |
// child
const parentDiv = addDiv(t, { style: 'animation: anim 100s' });
parentDiv.id = 'parent-div';
addStyle(t, {
'#parent-div::after': "content: ''; animation: anim 100s",
'#parent-div::before': "content: ''; animation: anim 100s",
});
if (CSS.supports('selector(::marker)')) {
parentDiv.style.display = 'list-item';
addStyle(t, {
'#parent-div::marker': "content: ''; animation: color-anim 100s",
});
}
const childDiv = addDiv(t, { style: 'animation: anim 100s' });
parentDiv.append(childDiv);
// Setup event handlers
let events = [];
for (const name of ['start', 'iteration', 'end', 'cancel']) {
parentDiv['onanimation' + name] = evt => {
events.push({
type: evt.type,
target: evt.target,
pseudoElement: evt.pseudoElement,
elapsedTime: evt.elapsedTime,
});
};
}
// Wait a couple of frames for the events to be dispatched
await waitForFrame();
await waitForFrame();
const expectedEvents = [
['animationstart', parentDiv, 0],
['animationstart', parentDiv, '::marker', 0],
['animationstart', parentDiv, '::before', 0],
['animationstart', parentDiv, '::after', 0],
['animationstart', childDiv, 0],
];
if (!CSS.supports('selector(::marker)')) {
expectedEvents.splice(1, 1);
}
checkEvents(events, ...expectedEvents);
}, 'Same events on pseudo-elements follow the prescribed order');
promise_test(async t => {
let events = [];
@ -113,7 +205,7 @@ promise_test(async t => {
checkEvents(events, ['animationiteration', div2, 300],
['animationstart', div1, 0]);
}, 'Test start and iteration events are ordered by time.');
}, 'Start and iteration events are ordered by time');
promise_test(async t => {
let events = [];
@ -135,7 +227,7 @@ promise_test(async t => {
checkEvents(events, ['animationiteration', div2, 100],
['animationend', div1, 150]);
}, 'Test iteration and end events are ordered by time.');
}, 'Iteration and end events are ordered by time');
promise_test(async t => {
let events = [];
@ -156,6 +248,6 @@ promise_test(async t => {
['animationstart', div1, 0],
['animationend', div1, 100],
['animationend', div2, 200]);
}, 'Test start and end events are sorted correctly when fired simultaneously');
}, 'Start and end events are sorted correctly when fired simultaneously');
</script>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Reference: CSS display:contents; in Shadow DOM</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=907396">
<style>
html,body {
color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
}
span { color:blue; }
</style>
</head>
<body>
<div>X 1 c</div>
<div>a 2 c</div>
<div>a 3 Y</div>
<div>X 4 Y</div>
<div>a 5 Y</div>
<div>X <span>6</span> c</div>
<div>a <span>7</span> c</div>
<div>a <span>8</span> Y</div>
<div>X <span>9</span> Y</div>
<div>a <span>A</span> Y</div>
<div>a <span>1 2</span> B</div>
<div>A <span>a 1 2 c</span> B</div>
<div>A <span>a 1 a 2 ca 3 c</span> B</div>
<div>A <span>a 1 c a 2 c</span> B</div>
<div>X <span>a 1 c a 2 c</span> B</div>
<div><span>1a 2 c</span></div>
<div><span>a 1 c2</span></div>
<div>A<span>b</span>c</div>
<div>A<span>b</span>c</div>
<div><span>b c</span>d</div>
<div><span>a </span>b</div>
<div><b>One</b><i>Two</i></div>
<div><b>One</b><i>Two</i></div>
<div><b>One</b><i>Two</i></div>
<div><b>One</b><i>Two</i></div>
<b style="color:blue">One</b><i style="color:blue">Two</i>Three
<div></div>
<b style="color:green">V</b>
</body>
</html>

View file

@ -0,0 +1,221 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html class="reftest-wait" lang="en-US">
<head>
<meta charset="utf-8">
<title>CSS Test: CSS display:contents; in Shadow DOM</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=907396">
<link rel="help" href="https://drafts.csswg.org/css-display/">
<link rel="match" href="display-contents-shadow-dom-1-ref.html">
<style>
html,body {
color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
}
.before::before, ::slotted(.before)::before {content: "a ";}
.after::after, ::slotted(.after)::after {content: " c";}
div.before::before {content: "X ";}
div.after::after {content: " Y";}
.b, .c, ::slotted(.b), ::slotted(.c) { display:contents; }
</style>
</head>
<body>
<div id="host1" class="before"></div>
<span id="host2"></span>
<div id="host3" class="after"></div>
<div id="host4" class="before after"></div>
<div id="host5" class="after"></div>
<div id="host6" class="before"></div>
<div id="host7"></div>
<div id="host8" class="after"></div>
<div id="host9" class="before after"></div>
<div id="hostA" class="after"></div>
<div id="hostB"></div>
<div id="hostC"></div>
<div id="hostD"></div>
<div id="hostE"></div>
<div id="hostF" class="before"></div>
<div id="hostG"></div>
<span id="hostH"></span>
<div id="hostI"></div>
<div id="hostJ"></div>
<span id="hostK"></span>
<div id="hostL"></div>
<div id="hostM"><i slot=i>Two</i><b slot=b>One</b></div>
<div id="hostN"><i slot=i class="c">Two</i><b slot=b>One</b></div>
<div id="hostO"><i slot=i>Two</i><b slot=b class="c">One</b></div>
<div id="hostP"><i slot=i class="c">Two</i><b slot=b class="c">One</b></div>
<div id="hostQ" class="c" style="color:blue"><i slot=i class="c">Two</i><b slot=b class="c">One</b></div>Three
<div id="hostS" class="c"><span class="c">S</span></div>
<div id="hostT" class="c">T</div>
<div id="hostU"><span slot="c">U</span></div>
<div id="hostV" class="c" style="color:red"><b slot="b" class="c" style="color:inherit">V</b></div>
<script>
function shadow(id) {
return document.getElementById(id).attachShadow({mode:"open"});
}
function span(s) {
var e = document.createElement("span");
var t = document.createTextNode(s);
e.appendChild(t);
return e;
}
function text(s) {
return document.createTextNode(s);
}
function contents(n, slotName) {
var e = document.createElement("z");
e.style.display = "contents";
e.style.color = "blue";
if (n) e.appendChild(n);
if (slotName) e.setAttribute("slot", slotName);
return e;
}
function run() {
document.body.offsetHeight;
shadow("host1").innerHTML = '<slot style="display:inline"></slot> c';
shadow("host2").innerHTML = 'a <slot style="display:contents"></slot> c';
shadow("host3").innerHTML = 'a <slot style="display:contents"></slot>';
shadow("host4").innerHTML = '<slot style="display:contents"></slot>';
shadow("host5").innerHTML = 'a <slot style="display:contents"></slot>';
shadow("host6").innerHTML = '<z style="color:blue; display:contents"><slot style="display:inline"></slot></z> c';
shadow("host7").innerHTML = 'a <slot style="display:contents"></slot> c';
shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><slot style="display:contents"></z></slot>';
shadow("host9").innerHTML = '<slot style="display:contents"></slot>';
shadow("hostA").innerHTML = 'a <slot style="display:contents"></slot>';
shadow("hostB").innerHTML = 'a <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
shadow("hostC").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
shadow("hostD").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B <slot name="b"></slot>';
shadow("hostE").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
shadow("hostF").innerHTML = '<slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
shadow("hostG").innerHTML = '<slot name="b" style="display:contents"></slot>';
shadow("hostH").innerHTML = '<slot name="b" style="display:contents"></slot>';
shadow("hostI").innerHTML = 'A<slot name="b" style="display:contents"></slot>';
shadow("hostJ").innerHTML = 'A<slot name="b" style="display:contents"></slot>';
shadow("hostK").innerHTML = '<slot name="b" style="display:contents"></slot>';
shadow("hostL").innerHTML = '<slot name="b" style="display:contents"></slot>';
shadow("hostM").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
shadow("hostN").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
shadow("hostO").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
shadow("hostP").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
shadow("hostQ").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
}
function tweak() {
document.body.offsetHeight;
host1.appendChild(span("1"));
host2.appendChild(text("2"));
host3.appendChild(span("3"));
host4.appendChild(text("4"));
var e = span("5");
e.style.display = "contents";
host5.appendChild(e);
host6.appendChild(span("6"));
host7.appendChild(contents(text("7")));
host8.appendChild(contents(span("8")));
host9.appendChild(contents(text("9")));
var e = contents(span("A"));
hostA.appendChild(e);
var e = contents(text("2"), "b");
hostB.appendChild(e);
var e = contents(text("1"), "c");
hostB.appendChild(e);
var e = contents(text("2"), "b");
e.className = "after";
hostC.appendChild(e);
var e = contents(text("1"), "c");
e.className = "before";
hostC.appendChild(e);
var e = contents(text("2"), "b");
e.className = "before after";
hostD.appendChild(e);
var e = contents(text(" 3"), "b");
e.className = "before after";
hostD.appendChild(e);
var e = contents(text("1"), "c");
e.className = "before";
hostD.appendChild(e);
var e = contents(contents(text("2")), "b");
e.className = "before after";
hostE.appendChild(e);
var e2 = contents(text("1"), "c");
e2.className = "before after";
hostE.insertBefore(e2, e);
var e = contents(text("2"), "b");
e.className = "before after";
hostF.appendChild(e);
var e2 = contents(text("1"), "c");
e2.className = "before after";
hostF.insertBefore(e2, e);
var e = contents(contents(text("1")), "b");
hostG.appendChild(e);
var e = contents(text("2"), "b");
e.className = "before after";
hostG.appendChild(e);
var e = contents(contents(text("2")), "b");
hostH.appendChild(e);
var e2 = contents(text("1"), "b");
e2.className = "before after";
hostH.insertBefore(e2, e);
var e = contents(text("b"), "b");
hostI.appendChild(e);
var e = span("c");
e.setAttribute("slot", "b");
hostI.appendChild(e);
var e = contents(contents(text("b")), "b");
hostJ.appendChild(e);
var e = span("c");
e.setAttribute("slot", "b");
hostJ.appendChild(e);
var inner = span("b");
inner.className = "after";
var e = contents(contents(inner), "b");
hostK.appendChild(e);
var e = span("d");
e.setAttribute("slot", "b");
hostK.appendChild(e);
var inner = contents(null);
inner.className = "before";
var e = contents(inner, "b");
hostL.appendChild(e);
var e = span("b");
e.setAttribute("slot", "b");
hostL.appendChild(e);
document.body.offsetHeight;
setTimeout(function() {
shadow("hostS");
shadow("hostT");
shadow("hostU");
shadow("hostV").innerHTML = '<z style="color:green"><slot name="b"></slot></z>';
document.body.offsetHeight;
document.documentElement.removeAttribute("class");
},0);
}
run();
setTimeout(tweak, 0);
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset=utf-8>
<title>CSS Reference: quoted font-family names must not be treated as generics</title>
<link rel="author" title="Jonathan Kew" href="mailto:jfkthame@gmail.com"/>
<style>
body { font-size: 36px; }
.test1 { font-family: serif; }
.test2 { font-family: sans-serif; }
.test3 { font-family: monospace; }
</style>
<body>
<p>The following lines should be rendered with the generic font-families as named:</p>
<div class="test1">serif</div>
<div class="test2">sans-serif</div>
<div class="test3">monospace</div>
<div class="test1">serif</div>
<div class="test2">sans-serif</div>
<div class="test3">monospace</div>

View file

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset=utf-8>
<title>CSS Test: quoted font-family names must not be treated as generics</title>
<link rel="author" title="Jonathan Kew" href="mailto:jfkthame@gmail.com"/>
<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-family-prop"/>
<link rel="match" href="quoted-generic-ignored-ref.html"/>
<meta name="assert" content="Font family names that happen to be the same as keyword value must be quoted to prevent confusion with the keywords with the same names"/>
<style>
body { font-size: 36px; }
/* Note that this test assumes that the system does not have an actual
font named "Fantasy" or "Cursive" installed! */
.fantasy-test1 { font-family: "fantasy", serif; }
.fantasy-test2 { font-family: "fantasy", sans-serif; }
.fantasy-test3 { font-family: "fantasy", monospace; }
.cursive-test1 { font-family: "cursive", serif; }
.cursive-test2 { font-family: "cursive", sans-serif; }
.cursive-test3 { font-family: "cursive", monospace; }
</style>
</head>
<body>
<p>The following lines should be rendered with the generic font-families as named:</p>
<div class="fantasy-test1">serif</div>
<div class="fantasy-test2">sans-serif</div>
<div class="fantasy-test3">monospace</div>
<div class="cursive-test1">serif</div>
<div class="cursive-test2">sans-serif</div>
<div class="cursive-test3">monospace</div>

View file

@ -142,8 +142,8 @@
initial: 'row',
'row': ['row', 'row'],
'column': ['column', 'column'],
'dense': ['dense', 'row dense'],
'row dense': ['row dense', 'row dense'],
'dense': ['dense', 'dense'],
'row dense': ['dense', 'dense'],
'column dense': ['column dense', 'column dense'],
'reset': ['row', 'row'],
},

View file

@ -13,13 +13,13 @@
<script>
test_computed_value("grid-auto-flow", "row");
test_computed_value("grid-auto-flow", "column");
test_computed_value("grid-auto-flow", "row dense");
test_computed_value("grid-auto-flow", "row dense", "dense");
test_computed_value("grid-auto-flow", "column dense");
test_computed_value("grid-auto-flow", "dense row", "row dense");
test_computed_value("grid-auto-flow", "dense row", "dense");
test_computed_value("grid-auto-flow", "dense column", "column dense");
test_computed_value("grid-auto-flow", "dense", "row dense");
test_computed_value("grid-auto-flow", "dense", "dense");
</script>
</body>
</html>

View file

@ -14,11 +14,11 @@
<script>
test_valid_value("grid-auto-flow", "row");
test_valid_value("grid-auto-flow", "column");
test_valid_value("grid-auto-flow", "row dense");
test_valid_value("grid-auto-flow", "row dense", "dense");
test_valid_value("grid-auto-flow", "dense row", "dense");
test_valid_value("grid-auto-flow", "dense");
test_valid_value("grid-auto-flow", "column dense");
test_valid_value("grid-auto-flow", "dense column", "column dense");
// Blink/WebKit "dense", Edge/Firefox "row dense"
test_valid_value("grid-auto-flow", "dense", ["dense", "row dense"]);
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!doctype html>
<title>Magic list-item counter-increment shouldn't be visible from computed style</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#declaring-a-list-item">
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item-counter">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<li data-expected="none">No explicit counter.
<li><span style="counter-increment:inherit" data-expected="none">Inherited
<li value="10" data-expected="none">Value attribute.
<li style="counter-increment: list-item 10" data-expected="list-item 10">Explicit list-item counter.
<li style="counter-increment: list-item 1" data-expected="list-item 1">Explicit and redundant list-item counter.
<li style="counter-increment: foo 10" data-expected="foo 10">Other counter.
<script>
test(function() {
for (const element of document.querySelectorAll("[data-expected]"))
assert_equals(getComputedStyle(element).counterIncrement, element.getAttribute("data-expected"), element.innerText);
}, "list-item counter-increment shouldn't be visible from computed style");
</script>

View file

@ -8,4 +8,7 @@
<img style="display: list-item" alt="Foo">
<li value="4">Foo
<li>Bar
<div style="display: list-item"><div style="display: list-item">Before</div>WithBefore</div>
<div style="display: list-item">WithAfter<div style="display: list-item">After</div></div>
<li value="10">Baz
</ol>

View file

@ -1,15 +1,27 @@
<!doctype html>
<title>The definition of what a list-item is only depends on the display value, and doesn't account for pseudo-elements</title>
<title>The definition of what a list-item is only depends on the display value</title>
<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543758">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="match" href="list-item-definition-ref.html">
<!-- TODO: Test pseudo-elements, see https://github.com/w3c/csswg-drafts/issues/3766 -->
<style>
.before::before, .after::after {
display: list-item;
content: "Before";
}
.after::after {
content: "After";
}
</style>
<ol>
<svg style="display: list-item"></svg>
<img style="display: list-item">
<img style="display: list-item" alt="Foo">
<div style="display: list-item">Foo</div>
<li>Bar
<li class="before">WithBefore
<li class="after">WithAfter
<li>Baz
</ol>

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test Reference: Test a multi-column container with percentage height children</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
article {
width: 400px;
height: 200px;
outline: 1px solid black;
}
div {
height: 25%;
}
div.spanner {
outline: 1px solid blue;
height: 50%;
}
</style>
<article>
<div>block1</div>
<div class="spanner">spanner</div>
<div>block2</div>
</article>
</html>

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test a multi-column container with percentage height children</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
<link rel="match" href="multicol-span-all-children-height-001-ref.html">
<meta name="assert" content="This test checks the the percentage height children under multicol container is rendered correctly.">
<style>
article {
column-count: 2;
width: 400px;
height: 200px;
outline: 1px solid black;
}
div {
height: 50%; /* Spread evenly into two colums, each 25%. */
}
div.spanner {
column-span: all;
outline: 1px solid blue;
height: 50%;
}
</style>
<article>
<div>block1</div>
<div class="spanner">spanner</div>
<div>block2</div>
</article>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -2ch; }
.v m { writing-mode: vertical-lr; width:0; position:relative; left: -1em; height:0; text-indent:-2ch; }
.lr { writing-mode: vertical-lr; }
.big { font-size:xx-large; }
.big-marker m { font-size:xx-large; }
li { display: block; }
</style>
</head><body>
<ol class="h">
<li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
<li><div></div><div class="big"><m style="font-size:initial">AB</m>C<br>D</div>
</li>
</ol>
<ol class="big-marker h">
<li><div><m>AB</m>C<br>D</div></li>
<li><div></div><div><m>AB</m>C<br>D</div></li>
</ol>
<ol class="v">
<li><div><m>AB</m>C<br>D</div></li>
<li><div></div><div><m>AB</m>C<br>D</div></li>
<li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
</ol>
<ol class="v big-marker">
<li><div><m>AB</m>C<br>D</div></li>
</ol>
</body></html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<link rel="match" href="marker-content-009-ref.html">
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
li::marker { content: 'AB'; }
.v > li::marker { writing-mode: vertical-lr; }
.lr { writing-mode: vertical-lr; }
.big { font-size:xx-large; }
.big-marker > li::marker { font-size:xx-large; }
f { float: left; margin-right: 20px; }
</style>
</head><body>
<ol>
<li><div class="big">C<br>D</div></li>
<li><div></div><div class="big">C<br>D</div>
</li>
</ol>
<ol class="big-marker">
<li><div>C<br>D</div></li>
<li><div></div><div>C<br>D</div></li>
</ol>
<ol class=v>
<li><div>C<br>D</div></li>
<li><div></div><div>C<br>D</div></li>
<li><div class="big">C<br>D</div></li>
</ol>
<ol class="v big-marker">
<li><div>C<br>D</div></li>
</ol>
</body></html>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -3ch; }
.big { font-size:xx-large; }
.big-marker m { font-size:xx-large; }
li { display: block; }
</style>
</head><body>
<ol class="h">
<li><div class="big"><m style="font-size:initial">1.</m>C<br>D</div></li>
<li><div></div><div class="big"><m style="font-size:initial">2.</m>C<br>D</div>
</li>
</ol>
<ol class="big-marker h">
<li><div><m>1.</m>C<br>D</div></li>
<li><div></div><div><m>2.</m>C<br>D</div></li>
</ol>
</body></html>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<link rel="match" href="marker-content-010-ref.html">
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
.big { font-size:xx-large; }
.big-marker > li::marker { font-size:xx-large; }
</style>
</head><body>
<ol>
<li><div class="big">C<br>D</div></li>
<li><div></div><div class="big">C<br>D</div>
</li>
</ol>
<ol class="big-marker">
<li><div>C<br>D</div></li>
<li><div></div><div>C<br>D</div></li>
</ol>
</body></html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -3ch; }
.v m { writing-mode: vertical-lr; width:0; position:relative; left: -2em; height:0; text-indent:-3ch; }
.lr { writing-mode: vertical-lr; }
.big { font-size:xx-large; }
.big-marker m { font-size:xx-large; }
li { display: block; }
</style>
</head><body>
<ol class="h">
<li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
<li><div></div><div class="big"><m style="font-size:initial">AB</m>C<br>D</div>
</li>
</ol>
<ol class="big-marker h">
<li><div><m>AB</m>C<br>D</div></li>
<li><div></div><div><m>AB</m>C<br>D</div></li>
</ol>
<ol class="v">
<li><div><m>AB</m>C<br>D</div></li>
<li><div></div><div><m>AB</m>C<br>D</div></li>
<li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
</ol>
<ol class="v big-marker">
<li><div><m>AB</m>C<br>D</div></li>
</ol>
</body></html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
<link rel="match" href="marker-content-011-ref.html">
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<style>
html,body {
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
}
body { margin-left: 40px; }
li::marker { content: 'AB'; margin-bottom: 1ch; margin-right: 1ch; }
.v > li::marker { writing-mode: vertical-lr; margin-right: 1em; }
.lr { writing-mode: vertical-lr; }
.big { font-size:xx-large; }
.big-marker > li::marker { font-size:xx-large; }
f { float: left; margin-right: 20px; }
</style>
</head><body>
<ol>
<li><div class="big">C<br>D</div></li>
<li><div></div><div class="big">C<br>D</div>
</li>
</ol>
<ol class="big-marker">
<li><div>C<br>D</div></li>
<li><div></div><div>C<br>D</div></li>
</ol>
<ol class=v>
<li><div>C<br>D</div></li>
<li><div></div><div>C<br>D</div></li>
<li><div class="big">C<br>D</div></li>
</ol>
<ol class="v big-marker">
<li><div>C<br>D</div></li>
</ol>
</body></html>

View file

@ -33,7 +33,7 @@ assert_not_inherited('scroll-padding-right', 'auto', '10px');
assert_not_inherited('scroll-padding-top', 'auto', '10px');
assert_not_inherited('scroll-snap-align', 'none', 'start end');
assert_not_inherited('scroll-snap-stop', 'normal', 'always');
assert_not_inherited('scroll-snap-type', 'none', 'inline proximity');
assert_not_inherited('scroll-snap-type', 'none', 'inline');
</script>
</body>
</html>

View file

@ -20,7 +20,7 @@ test_valid_value("scroll-snap-type", "inline");
test_valid_value("scroll-snap-type", "both");
test_valid_value("scroll-snap-type", "y mandatory");
test_valid_value("scroll-snap-type", "inline proximity");
test_valid_value("scroll-snap-type", "inline proximity", "inline"); // The shortest serialization is preferable
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
div {
position: absolute;
margin: 0px;
}
#scroller {
height: 500px;
width: 500px;
overflow: hidden;
scroll-snap-type: both mandatory;
}
#target {
width: 300px;
height: 300px;
background-color: blue;
}
</style>
<div id="scroller">
<div style="width: 2000px; height: 2000px;"></div>
<div id="target"></div>
</div>
<script>
test(() => {
scroller.style.scrollPadding = "100px";
target.style.scrollSnapAlign = "start";
target.style.left = "300px";
target.style.top = "300px";
scroller.scrollTo(0, 0);
// `target position (300px, 300px)` - `padding (100px, 100px)`.
assert_equals(scroller.scrollLeft, 200);
assert_equals(scroller.scrollTop, 200);
target.style.scrollSnapAlign = "end";
// `target position (300px, 300px)` + `target size (300px, 300px) +
// `padding (100px, 100px) - `scroller size (500px, 500px)`.
scroller.scrollTo(0, 0);
assert_equals(scroller.scrollLeft, 200);
assert_equals(scroller.scrollTop, 200);
}, "Snaps to the positions adjusted by scroll-padding");
</script>

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type"/>
<link rel="help" href="https://drafts.csswg.org/css-writing-modes-4/#principal-flow"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
html {
height: 3000px;
scroll-snap-type: inline mandatory;
}
#target {
position: absolute;
background-color: blue;
top: 1000px;
width: 100%;
height: 100px;
}
</style>
<div id="target"></div>
<script>
const documentHeight = document.documentElement.clientHeight;
test(() => {
target.style.scrollSnapAlign = "end start";
window.scrollTo(0, 1000);
// `target y (1000px)` + `target height (100px)` - document height.
assert_equals(document.scrollingElement.scrollTop, 1100 - documentHeight);
target.style.scrollSnapAlign = "";
window.scrollTo(0, 0);
}, "The scroll-snap-type on the root element is applied");
test(() => {
document.body.style.writingMode = "vertical-rl";
target.style.scrollSnapAlign = "start end";
window.scrollTo(0, 1000);
// `target y (1000px)` + `target height (100px)` - document height.
assert_equals(document.scrollingElement.scrollTop, 1100 - documentHeight);
}, "The writing-mode on the body is used");
</script>

View file

@ -3,7 +3,7 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
html {
margin: 0px;
overflow: scroll;
scroll-snap-type: both mandatory;
@ -23,8 +23,8 @@ div {
.space {
left: 0px;
top: 0px;
width: 2100px;
height: 2100px;
width: 4000px;
height: 4000px;
}
.target {
width: 600px;
@ -151,9 +151,9 @@ var viewport = document.scrollingElement;
window.scrollTo(0, 0);
assert_equals(window.scrollX, 0);
assert_equals(window.scrollY, 0);
window.scrollTo(input);
window.scrollBy(input);
assert_equals(window.scrollX, expectedX);
assert_equals(window.scrollY, expectedY);
}, `scrollBy(${format_dict(input)}) on window lands on (${expectedX}, ${expectedY})`);
});
</script>
</script>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
div {
position: absolute;
}
#scroller {
overflow: hidden; /* TODO: Use scrollbar-width: none */
scroll-snap-type: x mandatory;
width: 500px;
height: 500px;
}
.space {
width: 2000px;
height: 2000px;
}
#target {
height: 200px;
width: 200px;
left: 50px;
background-color: blue;
}
</style>
<div id="scroller">
<div class="space"></div>
<div id="target"></div>
</div>
<script>
test(() => {
target.style.scrollSnapAlign = "start";
target.style.transform = "translateX(300px)";
scroller.scrollTo(10, 0);
assert_equals(scroller.scrollLeft, 350 /* left + translateX(300px) */);
assert_equals(scroller.scrollTop, 0);
}, "Snaps to the transformed snap start position");
test(() => {
target.style.scrollSnapAlign = "end";
target.style.transform = "translateX(300px)";
scroller.scrollTo(10, 0);
assert_equals(scroller.scrollLeft,
50 /* left + width + translateX(300px) - scroller.width */);
assert_equals(scroller.scrollTop, 0);
}, "Snaps to the transformed snap end position");
test(() => {
target.style.scrollSnapAlign = "start";
target.style.transform = "translateX(-100px)";
scroller.scrollTo(10, 0);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 0);
}, "Snaps to visible top left position of the transformed box");
</script>

View file

@ -40,12 +40,20 @@ div {
top: 800px;
}
#right-bottom {
left: 1800px;
top: 1800px;
scroll-margin-top: 1000px;
scroll-margin-left: 1000px;
}
</style>
<div id="scroller">
<div id="space"></div>
<div id="left-top" class="snap"></div>
<div id="right-top" class="snap"></div>
<div id="left-bottom" class="snap"></div>
<div id="right-bottom" class="snap"></div>
</div>
<script>
var scroller = document.getElementById("scroller");
@ -66,4 +74,13 @@ test(() => {
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 800);
}, 'Only snap to visible area on Y axis, even when the non-visible ones are closer');
test(() => {
scroller.scrollTo(0, 0);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 0);
scroller.scrollTo(300, 300);
assert_equals(scroller.scrollLeft, 800);
assert_equals(scroller.scrollTop, 800);
}, 'snap to snap area inflated by scroll-margin, even when the non-visible ones are closer');
</script>

View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#unreachable" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
div {
position: absolute;
margin: 0px;
}
#scroller {
height: 500px;
width: 500px;
overflow: hidden;
scroll-snap-type: both mandatory;
}
#unreachable {
width: 300px;
height: 300px;
top: -100px;
left: -100px;
background-color: blue;
scroll-snap-align: start;
}
#reachable {
width: 300px;
height: 300px;
top: 400px;
left: 400px;
background-color: blue;
scroll-snap-align: start;
}
</style>
<div id="scroller">
<div style="width: 2000px; height: 2000px;"></div>
<div id="unreachable"></div>
<div id="reachable"></div>
</div>
<script>
test(() => {
// Firstly move to the reachable snap position.
scroller.scrollTo(400, 400);
assert_equals(scroller.scrollLeft, 400);
assert_equals(scroller.scrollTop, 400);
// Then move to a position between the unreachable snap position and the
// reachable position but closer to the unreachable one.
scroller.scrollTo(100, 100);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 0);
}, "Snaps to the positions defined by the element as much as possible");
</script>

View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Shadow Parts - Multiple parts</title>
<meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly">
<link href="http://www.google.com/" rel="author" title="Google">
<link href="https://drafts.csswg.org/css-shadow-parts/" rel="help">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/shadow-helper.js"></script>
</head>
<body>
<style>#c-e::part(partp1 partp2) { color: green; }</style>
<script>installCustomElement("custom-element", "custom-element-template");</script>
<template id="custom-element-template">
<style>
.red { color: red; }
.blue { color: blue; }
</style>
<span id="greenpart" class="red" part="partp1 partp2">green</span>
<span id="bluepart1" class="blue" part="partp1">blue</span>
<span id="bluepart2" class="blue" part="partp2">blue</span>
</template>
The following text should match its stated colour:
<custom-element id="c-e"></custom-element>
<script>
"use strict";
const colorBlue = "rgb(0, 0, 255)";
const colorGreen = "rgb(0, 128, 0)";
test(function() {
const el = getElementByShadowIds(document, ["c-e", "greenpart"]);
assert_equals(window.getComputedStyle(el).color, colorGreen);
}, "Double-part in selected host is styled");
test(function() {
const el = getElementByShadowIds(document, ["c-e", "bluepart1"]);
assert_equals(window.getComputedStyle(el).color, colorBlue);
}, "Single-part-1 in selected host is not styled");
test(function() {
const el = getElementByShadowIds(document, ["c-e", "bluepart2"]);
assert_equals(window.getComputedStyle(el).color, colorBlue);
}, "Single-part-2 in selected host is not styled");
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — line breaking at element boundaries</title>
<meta name=assert content="An empty inline element should not introduce a line-break opportunity">
<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
<link rel=match href="reference/line-breaking-015-ref.html">
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; width: 0; line-height: 2; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">un<span></span>bro<b></b>ken</div>
</body>
</html>

View file

@ -0,0 +1,17 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — line breaking at element boundaries</title>
<meta name=assert content="An out-of-flow element should not introduce a line-break opportunity">
<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
<link rel=match href="reference/line-breaking-016-ref.html">
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; width: 0; }
.oof { position: absolute; left: 6em; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">un<span class="oof"></span>bro<b class="oof">absolute</b>ken</div>
</body>
</html>

View file

@ -0,0 +1,17 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — line breaking at element boundaries</title>
<meta name=assert content="An out-of-flow element should not introduce a line-break opportunity">
<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
<link rel=match href="reference/line-breaking-017-ref.html">
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; width: 0; }
.oof { float: left; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">un<span class="oof"></span>bro<b class="oof">float</b>ken</div>
</body>
</html>

View file

@ -0,0 +1,13 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — reference file for line-breaking test</title>
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; line-height: 2; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">unbroken</div>
</body>
</html>

View file

@ -0,0 +1,14 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — reference file for line-breaking test</title>
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; }
.oof { position: absolute; left: 6em; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">unbroken<b class="oof">absolute</b></div>
</body>
</html>

View file

@ -0,0 +1,13 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>CSS Text — reference file for line-breaking test</title>
<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
<style>
.test { margin: 1em 0; }
</style>
<body>
The word "unbroken" below should <b>not</b> be broken:
<div class="test">unbroken<br><b>float</b></div>
</body>
</html>

View file

@ -22,16 +22,20 @@ test_valid_value("text-transform", "full-size-kana");
test_valid_value("text-transform", "capitalize full-width");
test_valid_value("text-transform", "uppercase full-size-kana");
test_valid_value("text-transform", "full-width full-size-kana");
test_valid_value("text-transform", "full-width lowercase");
test_valid_value("text-transform", "full-size-kana capitalize");
test_valid_value("text-transform", "full-size-kana full-width");
// serialization canonicalizes the order of values: https://drafts.csswg.org/cssom/#serialize-a-css-value
test_valid_value("text-transform", "full-width lowercase", "lowercase full-width");
test_valid_value("text-transform", "full-size-kana capitalize", "capitalize full-size-kana");
test_valid_value("text-transform", "full-size-kana full-width", "full-width full-size-kana");
test_valid_value("text-transform", "capitalize full-width full-size-kana");
test_valid_value("text-transform", "full-width full-size-kana uppercase");
test_valid_value("text-transform", "full-size-kana lowercase full-width");
test_valid_value("text-transform", "lowercase full-size-kana full-width");
test_valid_value("text-transform", "full-width uppercase full-size-kana");
test_valid_value("text-transform", "full-size-kana full-width capitalize");
// serialization canonicalizes the order of values
test_valid_value("text-transform", "full-width full-size-kana uppercase", "uppercase full-width full-size-kana");
test_valid_value("text-transform", "full-size-kana lowercase full-width", "lowercase full-width full-size-kana");
test_valid_value("text-transform", "lowercase full-size-kana full-width", "lowercase full-width full-size-kana");
test_valid_value("text-transform", "full-width uppercase full-size-kana", "uppercase full-width full-size-kana");
test_valid_value("text-transform", "full-size-kana full-width capitalize", "capitalize full-width full-size-kana");
</script>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!doctype html>
<html lang="ja">
<meta charset=utf-8>
<title>text-transform with multiple values</title>
<body style="font-family:serif">
<h4>Each pair of lines should look identical:</h4>
<hr>
<div>  </div>
<div>  </div>
<hr>
<div>  </div>
<div>  </div>
<hr>
<div>  </div>
<div>  </div>
<hr>
<div>KATAKANA: アイウエオカクケシスツトヌ</div>
<div>KATAKANA: アイウエオカクケシスツトヌ</div>
<hr>
<div>hiragana: あいうえおかけつやゆよわ</div>
<div>hiragana: あいうえおかけつやゆよわ</div>
<hr>

View file

@ -0,0 +1,26 @@
<!doctype html>
<html lang="ja">
<meta charset=utf-8>
<title>text-transform with multiple values</title>
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
<link rel=match href="reference/text-transform-multiple-001-ref.html">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-transform-property">
<meta name="assert" content="case transforms can be combined with full-width and/or full-size-kana transforms">
<body style="font-family:serif">
<h4>Each pair of lines should look identical:</h4>
<hr>
<div style="text-transform:uppercase full-width">HELLO Transformed world</div>
<div>  </div>
<hr>
<div style="text-transform:lowercase full-width">HELLO Transformed world</div>
<div>  </div>
<hr>
<div style="text-transform:capitalize full-width">HELLO Transformed world</div>
<div>  </div>
<hr>
<div style="text-transform:uppercase full-size-kana">Katakana: ァィゥェォヵㇰヶㇱㇲッㇳㇴ</div>
<div>KATAKANA: アイウエオカクケシスツトヌ</div>
<hr>
<div style="text-transform:full-width full-size-kana lowercase">Hiragana: ぁぃぅぇぉゕゖっゃゅょゎ</div>
<div>hiragana: あいうえおかけつやゆよわ</div>
<hr>

View file

@ -8,7 +8,7 @@
<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-break-all">
<link rel="match" href="reference/white-space-break-spaces-005-ref.html">
<meta name="flags" content="ahem">
<meta name="assert" content="White spaces are preserved, honoring the 'white-space: break-spaces', which may lead to overfow. However, we can break before the first white-space after the word honoring the 'break-all' value.">
<meta name="assert" content="White spaces are preserved, honoring the 'white-space: break-spaces', which may lead to overfow. However, we can break before the las letter in the word honoring the 'break-all' value.">
<style>
div {
font: 25px/1 Ahem;
@ -29,6 +29,6 @@ span { color: green; }
</style>
<body>
<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
<div class="fail">XXXX<br><span>X</span>XX<span>X</span><br><span>XXXX</span><br><span>XXXX</span></div>
<div class="fail">XXX<span>X</span><br>X<span>X</span>XX<br><span>XXXX</span><br><span>XXXX</span></div>
<div class="test">XXXX XX</div>
</body>

View file

@ -36,47 +36,88 @@ test(t => {
}, 'getAnimations for CSS Transitions');
test(t => {
addStyle(t, { '.init::after': 'content: ""; width: 0px; ' +
'transition: all 100s;',
'.init::before': 'content: ""; width: 0px; ' +
'transition: all 10s;',
'.change::after': 'width: 100px;',
'.change::before': 'width: 100px;' });
// create two divs with these arrangement:
// Create two divs with the following arrangement:
//
// parent
// (::marker,)
// ::before,
// ::after
// |
// child
const parent = addDiv(t);
addStyle(t, {
'.init::after': 'content: ""; width: 0px; transition: all 100s;',
'.init::before': 'content: ""; width: 0px; transition: all 100s;',
'.change::after': 'width: 100px;',
'.change::before': 'width: 100px;',
});
const supportsMarkerPseudos = CSS.supports('selector(::marker)');
if (supportsMarkerPseudos) {
addStyle(t, {
'.init::marker': 'content: ""; color: red; transition: all 100s;',
'.change::marker': 'color: green;',
});
}
const parent = addDiv(t, { 'style': 'display: list-item' });
const child = addDiv(t);
parent.appendChild(child);
parent.style.left = '0px';
parent.style.transition = 'left 10s';
parent.style.transition = 'left 100s';
parent.classList.add('init');
child.style.left = '0px';
child.style.transition = 'left 10s';
child.style.transition = 'left 100s';
getComputedStyle(parent).left;
parent.style.left = '100px';
parent.classList.add('change');
child.style.left = '100px';
const anims = document.getAnimations();
assert_equals(anims.length, 4,
'CSS transition on both pseudo-elements and elements ' +
'are returned');
assert_equals(anims[0].effect.target, parent,
'The animation targeting the parent element comes first');
assert_equals(anims[1].effect.target.type, '::before',
'The animation targeting the ::before element comes second');
assert_equals(anims[2].effect.target.type, '::after',
'The animation targeting the ::after element comes third');
assert_equals(anims[3].effect.target, child,
'The animation targeting the child element comes last');
}, 'CSS Transitions targetting (pseudo-)elements should have correct order ' +
'after sorting');
const expectedTransitions = [
[parent, undefined],
[parent, '::marker'],
[parent, '::before'],
[parent, '::after'],
[child, undefined],
];
if (!supportsMarkerPseudos) {
expectedTransitions.splice(1, 1);
}
const transitions = document.getAnimations();
assert_equals(
transitions.length,
expectedTransitions.length,
'CSS transition on both pseudo-elements and elements are returned'
);
for (const [index, expected] of expectedTransitions.entries()) {
const [element, pseudo] = expected;
const actual = transitions[index];
if (pseudo) {
assert_equals(
actual.effect.target.element,
element,
`Transition #${index + 1} has expected target`
);
assert_equals(
actual.effect.target.type,
pseudo,
`Transition #${index + 1} has expected pseudo type`
);
} else {
assert_equals(
actual.effect.target,
element,
`Transition #${index + 1} has expected target`
);
}
}
}, 'CSS Transitions targetting (pseudo-)elements should have correct order '
+ 'after sorting');
promise_test(async t => {
const div = addDiv(t, { style: 'left: 0px; transition: all 50ms' });

View file

@ -56,7 +56,6 @@ the following suites test behavior that is not covered in CSS3 Transitions (as o
* `properties-value-003.html` - verify transitionable properties thus far not specified at all
* `properties-value-implicit-001.html` - verify behavior for `em` based `<length>` properties when `font-size` is changed
* `events-006.html` - expect `TransitionEnd` event to be triggered and `event.pseudoElement` to be set properly
* `before-DOMContentLoaded-001.html` - expect transitions to be performed before DOM is ready
* `before-load-001.html` - expect transitions to be performed before document is fully loaded
* `hidden-container-001.html` - expect transitions to NOT be performed if they happen within hidden elements
* `detached-container-001.html` - expect transitions to NOT be performed if they happen outside of the document

View file

@ -1,148 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: Transitioning before DOMContentLoaded event</title>
<meta name="assert" content="Test checks that transitions are run even before the document has left parsing mode">
<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<meta name="flags" content="dom">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/vendorPrefix.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
<script src="./support/generalParallelTest.js" type="text/javascript"></script>
<script src="./support/properties.js" type="text/javascript"></script>
<style type="text/css">
#offscreen {
position: absolute;
top: -100000px;
left: -100000px;
width: 100000px;
height: 100000px;
}
</style>
</head>
<body>
<!-- required by testharnessreport.js -->
<div id="log"></div>
<!-- elements used for testing -->
<div id="fixture" class="fixture">
<div class="container">
<div class="transition">Text sample</div>
</div>
</div>
<div id="offs-creen"></div>
<!--
SEE ./support/README.md for an abstract explanation of the test procedure
http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-->
<script>
// make sure a transition is run between DOMContentLoaded and load
var isDOMContentLoaded = false;
window.addEventListener('DOMContentLoaded', function() {
isDOMContentLoaded = true;
}, false);
// this test takes its time, give it a minute to run
var timeout = 60000;
setup({timeout: timeout});
var tests = [
{
name: "transition height from 10px to 100px",
property: 'height',
flags: {},
from: {'height': '10px'},
to: {'height': '100px'}
}
];
// general transition-duration
var duration = '0.5s';
runParallelAsyncHarness({
// array of test data
tests: tests,
// the number of tests to run in parallel
testsPerSlice: 1,
// milliseconds to wait before calling teardown and ending test
duration: parseFloat(duration) * 1000,
// prepare individual test
setup: function(data, options) {
var styles = {
'.fixture': {},
'.container': data.parentStyle,
'.container.to': {},
'.container.how': {},
'.transition': data.from,
'.transition.to' : data.to,
'.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
};
generalParallelTest.setup(data, options);
generalParallelTest.addStyles(data, options, styles);
},
// cleanup after individual test
teardown: generalParallelTest.teardown,
// invoked prior to running a slice of tests
sliceStart: function(options, tests) {
// inject styles into document
setStyle(options.styles);
},
// invoked after running a slice of tests
sliceDone: generalParallelTest.sliceDone,
// test cases, make them as granular as possible
cases: {
// test property values while transitioning
// values.start kicks off a transition
'values': {
// run actual test, assertions can be used here!
start: function(test, data, options) {
// identify initial and target values
generalParallelTest.getStyle(data);
// make sure values differ, if they don't, the property could most likely not be parsed
assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
// kick off the transition
generalParallelTest.startTransition(data);
// make sure we didn't get the target value immediately.
// If we did, there wouldn't be a transition!
var current = data.transition.computedStyle(data.property);
assert_not_equals(current, data.transition.to, "must not be target value after start");
},
done: function(test, data, options) {
// make sure the property's value were neither initial nor target while transitioning
test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
}
},
// test TransitionEnd events
'events': {
done: function(test, data, options) {
// make sure there were no events on parent
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
// make sure we got the event for the tested property only
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
test.step(function() {
assert_false(isDOMContentLoaded, "DOMContentLoaded may not have happened yet")
});
}
}
},
// called once all tests are done
done: generalParallelTest.done
});
</script>
<script src="/delay/?type=js&amp;delay=3000"></script>
</body>
</html>

View file

@ -1,150 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: Transitioning before load event</title>
<meta name="assert" content="Test checks that transitions are run even before all assets are loaded">
<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<meta name="flags" content="dom">
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: Transitioning before load event</title>
<meta name="assert" content="Test checks that transitions are run even before the load event fires">
<!-- NOTE: This test covers unspecified behavior and should probably be
removed. It this behavior *were* specified, it would probably be
specified here: -->
<link rel="help" title="5. Transition Events" href="https://drafts.csswg.org/css-transitions/#starting">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/vendorPrefix.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
<script src="./support/generalParallelTest.js" type="text/javascript"></script>
<script src="./support/properties.js" type="text/javascript"></script>
</head>
<body>
<style type="text/css">
#offscreen {
position: absolute;
top: -100000px;
left: -100000px;
width: 100000px;
height: 100000px;
}
</style>
</head>
<body>
<!-- required by testharnessreport.js -->
<div id="log"></div>
<!-- elements used for testing -->
<div id="fixture" class="fixture">
<div class="container">
<div class="transition">Text sample</div>
</div>
</div>
<div id="offs-creen"></div>
<script>
// Make sure a transition can run before the load event fires.
<!--
SEE ./support/README.md for an abstract explanation of the test procedure
http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-->
let loadEventFired = false;
window.addEventListener('load', () => {
loadEventFired = true;
}, false);
<script>
// make sure a transition is run between DOMContentLoaded and load
async_test(t => {
const div = addDiv(t, { style: 'transition: height .01s linear; ' +
'height: 1px' });
getComputedStyle(div).height;
div.style.height = '100px';
// this test takes its time, give it a minute to run
var timeout = 60000;
setup({timeout: timeout});
div.addEventListener('transitionrun', t.step_func_done(() => {
assert_false(
loadEventFired,
'load event should not have fired yet'
);
document.getElementById('cat').src = '';
}));
});
</script>
var isLoad = false;
window.addEventListener('load', function() {
isLoad = true;
}, false);
window.addEventListener('DOMContentLoaded', function() {
var tests = [
{
name: "transition height from 10px to 100px",
property: 'height',
flags: {},
from: {'height': '10px'},
to: {'height': '100px'}
}
];
// general transition-duration
var duration = '0.5s';
runParallelAsyncHarness({
// array of test data
tests: tests,
// the number of tests to run in parallel
testsPerSlice: 1,
// milliseconds to wait before calling teardown and ending test
duration: parseFloat(duration) * 1000,
// prepare individual test
setup: function(data, options) {
var styles = {
'.fixture': {},
'.container': data.parentStyle,
'.container.to': {},
'.container.how': {},
'.transition': data.from,
'.transition.to' : data.to,
'.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
};
generalParallelTest.setup(data, options);
generalParallelTest.addStyles(data, options, styles);
},
// cleanup after individual test
teardown: generalParallelTest.teardown,
// invoked prior to running a slice of tests
sliceStart: function(options, tests) {
// inject styles into document
setStyle(options.styles);
},
// invoked after running a slice of tests
sliceDone: generalParallelTest.sliceDone,
// test cases, make them as granular as possible
cases: {
// test property values while transitioning
// values.start kicks off a transition
'values': {
// run actual test, assertions can be used here!
start: function(test, data, options) {
// identify initial and target values
generalParallelTest.getStyle(data);
// make sure values differ, if they don't, the property could most likely not be parsed
assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
// kick off the transition
generalParallelTest.startTransition(data);
// make sure we didn't get the target value immediately.
// If we did, there wouldn't be a transition!
var current = data.transition.computedStyle(data.property);
assert_not_equals(current, data.transition.to, "must not be target value after start");
},
done: function(test, data, options) {
// make sure the property's value were neither initial nor target while transitioning
test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
}
},
// test TransitionEnd events
'events': {
done: function(test, data, options) {
// make sure there were no events on parent
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
// make sure we got the event for the tested property only
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
test.step(function() {
assert_false(isLoad, "load may not have happened yet")
});
}
}
},
// called once all tests are done
done: generalParallelTest.done
});
}, false);
</script>
<img src="/delay/?type=gif&amp;delay=3000" alt="dummy image">
</body>
<img src="support/cat.png?pipe=trickle(d100)" id="cat">
</body>
</html>

View file

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: behavior when transition-duration changes while transitioning</title>
<meta name="assert" content="Checks a change to the transition-duration
property does not affect an in-flight transition">
<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
// Start a 100s transition 50% of the way through
const div = addDiv(t, {
style: 'transition: height 100s -50s linear; height: 0px',
});
getComputedStyle(div).height;
div.style.height = '100px';
assert_equals(
getComputedStyle(div).height,
'50px',
'Transition should be initially 50% complete'
);
// Extend the transition-duration to 200s.
div.style.transitionDuration = '200s';
// If the change to the transition-duration was reflected, the
// computed height would now be '25px'.
assert_equals(
getComputedStyle(div).height,
'50px',
'Even after updating the transition-duration, the transition should be 50% complete'
);
// Wait a frame just to be sure that the changed duration is not later
// updated.
await waitForFrame();
assert_greater_than_equal(
parseInt(getComputedStyle(div).height),
50,
'Even in the next frame the updated transition-duration should not apply'
);
}, 'Changes to transition-duration should not affect in-flight transitions');
</script>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: behavior when transition-timing-function changes while transitioning</title>
<meta name="assert" content="Checks a change to the transition-timing-function
property does not affect an in-flight transition">
<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
// Start a transition 50% of the way through with a linear timing function
const div = addDiv(t, {
style: 'transition: height 100s -50s linear; height: 0px',
});
getComputedStyle(div).height;
div.style.height = '100px';
assert_equals(
getComputedStyle(div).height,
'50px',
'Transition should be initially 50% complete'
);
// Update the timing function
div.style.transitionTimingFunction = 'steps(1, end)';
// If the change to the transition-timing-function was reflected, the
// computed height would now be '0px'.
assert_equals(
getComputedStyle(div).height,
'50px',
'Even after updating the transition-timing-function, the transition should be 50% complete'
);
// Wait a frame just to be sure that the changed timing function is not later
// updated.
await waitForFrame();
assert_greater_than_equal(
parseInt(getComputedStyle(div).height),
50,
'Even in the next frame the updated transition-timing-function should not apply'
);
}, 'Changes to transition-timing-function should not affect in-flight transitions');
</script>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: behavior when transition-delay changes while transitioning</title>
<meta name="assert" content="Checks a change to the transition-delay
property does not affect an in-flight transition">
<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
// Start a 200s transition 50% of the way through
const div = addDiv(t, {
style: 'transition: height 200s -100s linear; height: 0px',
});
getComputedStyle(div).height;
div.style.height = '100px';
assert_equals(
getComputedStyle(div).height,
'50px',
'Transition should be initially 50% complete'
);
// Set the transition-delay to -50s.
div.style.transitionDelay = '-50s';
// If the change to the transition-delay was reflected, the
// computed height would now be '25px'.
assert_equals(
getComputedStyle(div).height,
'50px',
'Even after updating the transition-delay, the transition should be 50% complete'
);
// Wait a frame just to be sure that the changed delay is not later
// updated.
await waitForFrame();
assert_greater_than_equal(
parseInt(getComputedStyle(div).height),
50,
'Even in the next frame the updated transition-delay should not apply'
);
}, 'Changes to transition-delay should not affect in-flight transitions');
</script>
</body>
</html>

View file

@ -1,146 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: behavior when transition parameters change while transitioning</title>
<meta name="assert" content="Test checks that all transitions run properly when property or duration is changed mid-run">
<link rel="help" title="3. Starting of transitions" href="http://www.w3.org/TR/css3-transitions/#starting">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<meta name="flags" content="dom">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/vendorPrefix.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
<script src="./support/generalParallelTest.js" type="text/javascript"></script>
<style type="text/css">
#offscreen {
position: absolute;
top: -100000px;
left: -100000px;
width: 100000px;
height: 100000px;
}
</style>
</head>
<body>
<!-- required by testharnessreport.js -->
<div id="log"></div>
<!-- elements used for testing -->
<div id="fixture" class="fixture">
<div class="container">
<div class="transition">Text sample</div>
</div>
</div>
<div id="offscreen"></div>
<!--
SEE ./support/README.md for an abstract explanation of the test procedure
http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-->
<script>
// this test takes its time, give it a minute to run
var timeout = 60000;
setup({timeout: timeout});
var tests = [
{
name: "changing transition-duration",
property: 'padding-left',
transitions: 'padding-left .5s linear 0s',
from: {'padding-left': '1px'},
to: {'padding-left': '10px'},
then: {
'transition-duration': '0.1s'
},
expect: [
'padding-left:0.5s'
]
},
{
name: "changing transition-property",
property: 'padding-left',
transitions: 'padding-left .5s linear 0s',
from: {'padding-left': '1px'},
to: {'padding-left': '10px'},
then: {
'transition-property': 'margin-left'
},
expect: [
''
]
}
];
// general transition-duration
var duration = '0.5s';
runParallelAsyncHarness({
// array of test data
tests: tests,
// the number of tests to run in parallel
testsPerSlice: 50,
// milliseconds to wait before calling teardown and ending test
duration: parseFloat(duration) * 1000,
// prepare individual test
setup: function(data, options) {
var styles = {
'.fixture': {},
'.container': {},
'.container.to': {},
'.container.how': {},
'.transition': data.from,
'.transition.to' : data.to,
'.transition.how' : {transition: data.transitions},
'.transition.then' : data.then
};
generalParallelTest.setup(data, options);
generalParallelTest.addStyles(data, options, styles);
},
// cleanup after individual test
teardown: generalParallelTest.teardown,
// invoked prior to running a slice of tests
sliceStart: generalParallelTest.sliceStart,
// invoked after running a slice of tests
sliceDone: generalParallelTest.sliceDone,
// test cases, make them as granular as possible
cases: {
// test property values while transitioning
// values.start kicks off a transition
'values': {
// run actual test, assertions can be used here!
start: function(test, data, options) {
// identify initial and target values
generalParallelTest.getStyle(data);
// kick off the transition
generalParallelTest.startTransition(data);
setTimeout(function() {
data.transition.node.classList.add('then');
for (var property in data.then) {
var current = data.transition.computedStyle(property);
assert_equals(current, data.then[property], 'value of ' + property + ' changed');
}
}, 50);
},
done: function(test, data, options) {
// make sure we got the event for the tested property only
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', data.expect));
}
}
},
// called once all tests are done
done: generalParallelTest.done
});
</script>
</body>
</html>

View file

@ -1,39 +1,52 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<head>
<title>CSS Variables Allowed Syntax</title>
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
<link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
<link rel="help" href="http://www.w3.org/TR/css3-transitions/#animatable-types">
<!-- also see https://www.w3.org/Bugs/Public/show_bug.cgi?id=14605 -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style id="style"></style>
<meta charset=utf-8>
<title>CSS Transitions of currentcolor</title>
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
<link rel="author" title="Mozilla Corporation" href="https://mozilla.com/">
<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
<link rel="help" href="https://drafts.csswg.org/css-color/#resolving-color-values">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<div id="log"></div>
<div id="test"></div>
<script>
// Transition does not occur when the value is currentColor and color changes
test(function() {
var div = document.getElementById("test");
var cs = getComputedStyle(div, "");
div.style.color = "red";
div.style.backgroundColor = "currentcolor";
var force_flush = cs.backgroundColor;
div.style.transition = "background-color linear 50s -10s";
div.style.color = "blue";
var quarter_interpolated = cs.backgroundColor;
div.style.transition = "";
div.style.backgroundColor = "rgb(204, 0, 51)";
var quarter_reference = cs.backgroundColor;
div.style.backgroundColor = "blue";
var final_reference = cs.backgroundColor;
assert_true(quarter_interpolated != quarter_reference &&
quarter_interpolated == final_reference);
},
"currentcolortransition");
test(() => {
const div = document.getElementById('test');
const cs = getComputedStyle(div, '');
// Setup before-change style
div.style.color = 'red';
div.style.backgroundColor = 'currentcolor';
cs.backgroundColor; // Flush style
// Change color -- this should NOT trigger a transition because as per [1]
// the computed value of 'currentcolor' for properties other than 'color'
// is 'currentcolor' and transitions operate on computed values (not used
// values).
//
// [1] https://drafts.csswg.org/css-color/#resolving-color-values
div.style.transition = 'background-color linear 50s -10s';
div.style.color = 'blue';
const valueAfterUpdatingColor = cs.backgroundColor;
// Generate some reference values for comparing
div.style.transition = '';
div.style.backgroundColor = 'rgb(204, 0, 51)';
const quarterReference = cs.backgroundColor;
div.style.backgroundColor = 'blue';
const finalReference = cs.backgroundColor;
assert_true(
valueAfterUpdatingColor != quarterReference &&
valueAfterUpdatingColor == finalReference
);
}, 'Transition does not occur when the value is currentcolor and color changes');
</script>
</body>

View file

@ -1,131 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: Not Transitioning within detached element</title>
<meta name="assert" content="Test checks that transitions are NOT run within detached elements">
<link rel="help" title="2. Transitions" href="http://www.w3.org/TR/css3-transitions/#transitions">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<meta name="flags" content="dom">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/vendorPrefix.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
<script src="./support/generalParallelTest.js" type="text/javascript"></script>
<script src="./support/properties.js" type="text/javascript"></script>
<style type="text/css">
#offscreen {
position: absolute;
top: -100000px;
left: -100000px;
width: 100000px;
height: 100000px;
}
</style>
</head>
<body>
<!-- required by testharnessreport.js -->
<div id="log"></div>
<!-- elements used for testing -->
<div id="fixture" class="fixture">
<div class="container">
<div class="transition">Text sample</div>
</div>
</div>
<div id="off-screen"></div>
<!--
SEE ./support/README.md for an abstract explanation of the test procedure
http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-->
<script>
// this test takes its time, give it a minute to run
var timeout = 60000;
setup({timeout: timeout});
var tests = [
{
name: "transition within detached container",
property: 'background-color',
flags: {},
from: {'background-color': 'red'},
to: {'background-color': 'green'}
}
];
// general transition-duration
var duration = '0.5s';
runParallelAsyncHarness({
// array of test data
tests: tests,
// the number of tests to run in parallel
testsPerSlice: 1,
// milliseconds to wait before calling teardown and ending test
duration: parseFloat(duration) * 1000,
// prepare individual test
setup: function(data, options) {
var styles = {
'.fixture': {},
'.container': data.parentStyle,
'.container.to': {},
'.container.how': {},
'.transition': data.from,
'.transition.to' : data.to,
'.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
};
generalParallelTest.setup(data, options);
generalParallelTest.addStyles(data, options, styles);
},
// cleanup after individual test
teardown: generalParallelTest.teardown,
// invoked prior to running a slice of tests
sliceStart: generalParallelTest.sliceStart,
// invoked after running a slice of tests
sliceDone: generalParallelTest.sliceDone,
// test cases, make them as granular as possible
cases: {
// test property values while transitioning
// values.start kicks off a transition
'values': {
// run actual test, assertions can be used here!
start: function(test, data, options) {
// identify initial and target values
generalParallelTest.getStyle(data);
// make sure values differ, if they don't, the property could most likely not be parsed
assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
// detach transitioning elements
data.fixture.parentNode.removeChild(data.fixture);
// kick off the transition
generalParallelTest.startTransition(data);
},
done: function(test, data, options) {
// make sure there were no intermediate values
assert_equals(data.transition.values.length, 2, "no intermediate values");
}
},
// test TransitionEnd events
'events': {
done: function(test, data, options) {
// make sure there were no events on parent
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
// make sure we got the event for the tested property only
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
}
}
},
// called once all tests are done
done: generalParallelTest.done
});
</script>
</body>
</html>

View file

@ -0,0 +1,203 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: Transitions do not run for a disconnected element</title>
<meta name="assert" content="If an element is not in the document during that
style change event or was not in the document during the previous style change
event, then transitions are not started for that element in that style change
event.">
<meta name="assert" content="If an element is no longer in the document,
implementations must cancel any running transitions on it and remove transitions
on it from the completed transitions.">
<link rel="help" title="Starting transitions"
href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
// Create element but do not attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Set up after-change style
div.style.backgroundColor = 'green';
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(255, 0, 0)',
'No transition should run'
);
// Wait a frame just to be sure the UA does not start the transition on the
// next frame.
await waitForFrame();
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(255, 0, 0)',
'No transition should run even after waiting a frame'
);
}, 'Transitions do not run on an element not in the document');
test(t => {
// Create element but do not attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Add to document
document.documentElement.append(div);
// Set up after-change style
div.style.backgroundColor = 'green';
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(0, 128, 0)',
'No transition should run'
);
}, 'Transitions do not run for an element newly added to the document');
promise_test(async t => {
// Create element and attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
document.documentElement.append(div);
// Attach event listeners
div.addEventListener('transitionrun', t.step_func(() => {
assert_unreached('transitionrun event should not be fired');
}));
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Set up after-change style
div.style.backgroundColor = 'green';
// But remove the document before the next style change event
div.remove();
// There should be no events received for the triggered transition.
//
// (We can't verify the presence/absence of transitions by querying
// getComputedStyle for this case because it will return an empty string.)
await waitForFrame();
await waitForFrame();
}, 'Transitions do not run for an element newly removed from the document');
promise_test(async t => {
// Create element and attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
document.documentElement.append(div);
// Attach event listeners
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).backgroundColor;
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
await eventWatcher.wait_for('transitionrun');
// Remove the element from the document
div.remove();
await eventWatcher.wait_for('transitioncancel');
}, 'Transitions are canceled when an element is removed from the document');
promise_test(async t => {
// Create a container element. We'll need this later.
const container = addDiv(t);
document.documentElement.append(container);
// Create element and attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
document.documentElement.append(div);
// Attach event listeners
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).backgroundColor;
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
await eventWatcher.wait_for('transitionrun');
// Re-parent element
container.append(div);
await eventWatcher.wait_for('transitioncancel');
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(0, 128, 0)',
'There should be no transition after re-parenting'
);
}, 'Transitions are canceled when an element is re-parented');
promise_test(async t => {
// Create a container element. We'll need this later.
const container = addDiv(t);
document.documentElement.append(container);
// Create element and attach it to the document
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
document.documentElement.append(div);
// Attach event listeners
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).backgroundColor;
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
await eventWatcher.wait_for('transitionrun');
// Re-parent element to same container
document.documentElement.append(div);
await eventWatcher.wait_for('transitioncancel');
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(0, 128, 0)',
'There should be no transition after re-parenting'
);
}, 'Transitions are canceled when an element is re-parented to the same node');
</script>
</body>
</html>

View file

@ -1,125 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: Not Transitioning within hidden element</title>
<meta name="assert" content="Test checks that transitions are NOT run within hidden elements">
<link rel="help" title="2. Transitions" href="http://www.w3.org/TR/css3-transitions/#transitions">
<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
<meta name="flags" content="dom">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/vendorPrefix.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
<script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
<script src="./support/generalParallelTest.js" type="text/javascript"></script>
<script src="./support/properties.js" type="text/javascript"></script>
<style type="text/css">
#offscreen {
display: none;
}
</style>
</head>
<body>
<!-- required by testharnessreport.js -->
<div id="log"></div>
<!-- elements used for testing -->
<div id="fixture" class="fixture">
<div class="container">
<div class="transition">Text sample</div>
</div>
</div>
<div id="offscreen"></div>
<!--
SEE ./support/README.md for an abstract explanation of the test procedure
http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-->
<script>
// this test takes its time, give it a minute to run
var timeout = 60000;
setup({timeout: timeout});
var tests = [
{
name: "transition within display:none",
property: 'background-color',
flags: {},
from: {'background-color': 'red'},
to: {'background-color': 'green'}
}
];
// general transition-duration
var duration = '0.5s';
runParallelAsyncHarness({
// array of test data
tests: tests,
// the number of tests to run in parallel
testsPerSlice: 1,
// milliseconds to wait before calling teardown and ending test
duration: parseFloat(duration) * 1000,
// prepare individual test
setup: function(data, options) {
var styles = {
'.fixture': {},
'.container': data.parentStyle,
'.container.to': {},
'.container.how': {},
'.transition': data.from,
'.transition.to' : data.to,
'.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
};
generalParallelTest.setup(data, options);
generalParallelTest.addStyles(data, options, styles);
},
// cleanup after individual test
teardown: generalParallelTest.teardown,
// invoked prior to running a slice of tests
sliceStart: generalParallelTest.sliceStart,
// invoked after running a slice of tests
sliceDone: generalParallelTest.sliceDone,
// test cases, make them as granular as possible
cases: {
// test property values while transitioning
// values.start kicks off a transition
'values': {
// run actual test, assertions can be used here!
start: function(test, data, options) {
// identify initial and target values
generalParallelTest.getStyle(data);
// make sure values differ, if they don't, the property could most likely not be parsed
assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
// kick off the transition
generalParallelTest.startTransition(data);
},
done: function(test, data, options) {
// make sure there were no intermediate values
assert_equals(data.transition.values.length, 2, "no intermediate values");
}
},
// test TransitionEnd events
'events': {
done: function(test, data, options) {
// make sure there were no events on parent
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
// make sure we got the event for the tested property only
test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
}
}
},
// called once all tests are done
done: generalParallelTest.done
});
</script>
</body>
</html>

View file

@ -0,0 +1,127 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: Transitions do not run for an element that is not being rendered</title>
<link rel="help" title="Starting transitions"
href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
// Create element that is not rendered
const div = addDiv(t, {
style:
'transition: background-color 100s;' +
'background-color: red;' +
'display: none',
});
// Attach event listeners
div.addEventListener(
'transitionrun',
t.step_func(() => {
assert_unreached('transitionrun event should not be fired');
})
);
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Set up and resolve after-change style
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
// There should be no events received for the triggered transition.
await waitForFrame();
await waitForFrame();
}, 'Transitions do not run on an element not being rendered');
test(t => {
// Create element that is not rendered
const div = addDiv(t, {
style:
'transition: background-color 100s;' +
'background-color: red;' +
'display: none',
});
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Make it rendered
div.style.display = 'block';
// Set up and resolve after-change style
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
// We should have jumped immediately to the after-change style rather than
// transitioning to it.
assert_equals(
getComputedStyle(div).backgroundColor,
'rgb(0, 128, 0)',
'No transition should run'
);
}, 'Transitions do not run for an element newly rendered');
promise_test(async t => {
// Create element
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
// Attach event listeners
div.addEventListener('transitionrun', t.step_func(() => {
assert_unreached('transitionrun event should not be fired');
}));
// Resolve before-change style
getComputedStyle(div).backgroundColor;
// Set up after-change style
div.style.backgroundColor = 'green';
// But make the element non-rendered
div.style.display = 'none';
// There should be no events received for the triggered transition.
await waitForFrame();
await waitForFrame();
}, 'Transitions do not run for an element newly made not rendered');
promise_test(async t => {
// Create element
const div = addDiv(t, {
style: 'transition: background-color 100s; background-color: red',
});
// Attach event listeners
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).backgroundColor;
div.style.backgroundColor = 'green';
getComputedStyle(div).backgroundColor;
await eventWatcher.wait_for('transitionrun');
// Make the element no longer rendered
div.style.display = 'none';
await eventWatcher.wait_for('transitioncancel');
}, 'Transitions are canceled when an element is no longer rendered');
</script>
</body>
</html>

View file

@ -0,0 +1,90 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>CSS Transitions Test: Transitions do not run for a pseudo-element that is not being rendered</title>
<link rel="help" title="Starting transitions"
href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
promise_test(async t => {
for (const pseudoType of ['before', 'after']) {
const style = addStyle(t, {
[`.init::${pseudoType}`]: 'content: ""; width: 0px; transition: width 100s;',
[`.change::${pseudoType}`]: 'width: 100px;',
[`.cancel::${pseudoType}`]: 'content: none',
});
// Create element (and pseudo-element) and attach event listeners
const div = addDiv(t);
div.classList.add('init');
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).width;
div.classList.add('change');
getComputedStyle(div).width;
await eventWatcher.wait_for('transitionrun');
// Make the pseudo-element no longer rendered
div.classList.add('cancel');
await eventWatcher.wait_for('transitioncancel');
div.remove();
style.remove();
}
}, 'Transitions on ::before/::after pseudo-elements are canceled when the'
+ ' content property is cleared');
promise_test(async t => {
if (!CSS.supports('selector(::marker)')) {
return;
}
addStyle(t, {
'.init::marker': 'content: ""; color: red; transition: color 100s;',
'.change::marker': 'color: green',
});
// Create element (and pseudo-element) and attach event listeners
const div = addDiv(t, { 'style': 'display: list-item' });
div.classList.add('init');
const eventWatcher = new EventWatcher(t, div, [
'transitionrun',
'transitioncancel',
]);
// Trigger transition
getComputedStyle(div).color;
div.classList.add('change');
getComputedStyle(div).color;
await eventWatcher.wait_for('transitionrun');
// Make the parent element no longer display: list-item so that the pseudo
// element no longer renders
div.style.display = 'block';
await eventWatcher.wait_for('transitioncancel');
}, 'Transitions on ::marker pseudo-elements are canceled when the'
+ ' parent display type is no longer list-item');
</script>
</body>
</html>

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Transitions Test: behavior when transition-property changes while transitioning</title>
<meta name="assert" content="Checks a change to the transition-duration
property does not affect an in-flight transition">
<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
<script src="/resources/testharness.js" type="text/javascript"></script>
<script src="/resources/testharnessreport.js" type="text/javascript"></script>
<script src="./support/helper.js" type="text/javascript"></script>
</head>
<body>
<div id="log"></div>
<script>
test(t => {
// Start a 100s transition 50% of the way through
const div = addDiv(t, {
style: 'transition: height 100s -50s linear; height: 0px',
});
getComputedStyle(div).height;
div.style.height = '100px';
assert_equals(
getComputedStyle(div).height,
'50px',
'Transition should be initially 50% complete'
);
// Change the transition-property and flush the style change
div.style.transitionProperty = 'width';
getComputedStyle(div).transitionProperty;
// The transition on the height property should have been canceled
assert_equals(
getComputedStyle(div).height,
'100px',
'Transition should have been canceled'
);
}, 'changes to transition-property should cancel in-flight transitions');
</script>
</body>
</html>

View file

@ -231,6 +231,7 @@ root.addStyle = (t, rules) => {
extraStyle.remove();
});
}
return extraStyle;
};
/**

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>CSS Test Reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<style>
#outer {
border: 10px solid transparent;
}
#inner {
border: 10px solid;
}
</style>
<div id="outer"><div id="inner"></div></div>

View file

@ -0,0 +1,21 @@
<!doctype html>
<title>CSS Test: Wide keyword can be used as a fallback variable value</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-variables/#substitute-a-var">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1544886">
<link rel="match" href="wide-keyword-fallback-ref.html">
<style>
/* Should see a 10px border of the initial color */
#outer {
color: transparent;
border: 10px solid;
}
#inner {
color: var(--unknown, initial);
border-width: 10px;
border-style: var(--unknown, inherit);
}
</style>
<div id="outer"><div id="inner"></div></div>

View file

@ -0,0 +1,19 @@
<!doctype html>
<title>CSS Test: matchMedia works on display: none iframes</title>
<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-window-matchmedia">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function frameLoaded(frame) {
test(function() {
assert_true(frame.contentWindow.matchMedia("all").matches);
}, "matchMedia should work in display: none iframes");
test(function() {
assert_true(frame.contentWindow.matchMedia("(min-width: 0)").matches);
assert_true(!frame.contentWindow.matchMedia("(min-width: 1px)").matches);
}, "matchMedia should assume a 0x0 viewport in display: none iframes");
}
</script>
<iframe style="display: none" onload="frameLoaded(this)"></iframe>

View file

@ -0,0 +1,35 @@
<!doctype html>
<title>CSS Tests: client* and scroll* APIs work as expected with outer SVG elements</title>
<link rel="help" href="https://drafts.csswg.org/cssom-view/#extension-to-the-element-interface">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874811">
<link rel="author" title="violet" href="mailto:violet.bugreport@gmail.com">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#u {
padding: 30px;
transform: translate(50px,60px) scale(2,3);
border: 5px solid lime;
width: 50px;
height: 100px;
}
</style>
<div style="width: 100px; height: 2000px; border: 1px solid blue"></div>
<svg id="u"></svg>
<script>
let u = document.getElementById("u");
test(function() {
assert_equals(u.clientTop, 5, "u.clientTop");
assert_equals(u.clientLeft, 5, "u.clientLeft");
assert_equals(u.clientWidth, 110, "u.clientWidth");
assert_equals(u.clientHeight, 160, "u.clientHeight");
}, "clientWidth, clientHeight, clientTop and clientLeft work on outer svg element");
test(function() {
assert_equals(u.scrollTop, 0, "u.scrollTop");
assert_equals(u.scrollLeft, 0, "u.scrollLeft");
assert_equals(u.scrollWidth, 110, "u.scrollWidth");
assert_equals(u.scrollHeight, 160, "u.scrollHeight");
}, "scrollWidth, scrollHeight, scrollTop and scrollLeft work on outer svg element");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset=utf-8>
<meta name="viewport" content="width=device-width">
<link rel="help" href="https://drafts.csswg.org/cssom-view/#run-the-resize-steps"/>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
promise_test(async t => {
let gotResizeEvent = false;
on_event(window, 'resize', () => gotResizeEvent = true);
await new Promise(resolve => requestAnimationFrame(resolve));
await new Promise(resolve => requestAnimationFrame(resolve));
assert_false(gotResizeEvent, 'resize event should not be fired');
}, 'resize events are not fired on the initial layout');
</script>

View file

@ -0,0 +1,45 @@
<!doctype html>
<title>&lt;link disabled&gt;, HTMLLinkElement.disabled and CSSStyleSheet.disabled interactions</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link title="alt" rel="stylesheet" disabled href="data:text/css,html { background: green }">
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
const link = document.querySelector("link[disabled]");
test(function() {
assert_equals(document.styleSheets.length, 0);
assert_applies(false);
}, "<link disabled> prevents the stylesheet from being in document.styleSheets (from parser)");
async_test(function(t) {
assert_true(link.disabled);
link.onload = t.step_func_done(function() {
assert_equals(document.styleSheets.length, 1);
let sheet = document.styleSheets[0];
assert_equals(sheet.ownerNode, link);
assert_applies(true);
link.disabled = true;
assert_equals(sheet.ownerNode, null);
assert_false(sheet.disabled);
assert_applies(false);
assert_true(link.hasAttribute("disabled"));
assert_equals(document.styleSheets.length, 0);
assert_applies(false);
});
link.disabled = false;
assert_true(!link.hasAttribute("disabled"));
assert_false(link.disabled);
}, "HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently");
</script>

View file

@ -0,0 +1,38 @@
<!doctype html>
<title>&lt;link disabled&gt;, HTMLLinkElement.disabled and CSSStyleSheet.disabled interactions (alternate)</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
const link = document.querySelector("link[disabled]");
async_test(function(t) {
assert_true(link.disabled);
link.onload = t.step_func_done(function() {
assert_equals(document.styleSheets.length, 1);
let sheet = document.styleSheets[0];
assert_equals(sheet.ownerNode, link);
assert_applies(true);
link.disabled = true;
assert_equals(sheet.ownerNode, null);
assert_false(sheet.disabled);
assert_applies(false);
assert_true(link.hasAttribute("disabled"));
assert_equals(document.styleSheets.length, 0);
});
link.disabled = false;
assert_true(!link.hasAttribute("disabled"));
assert_false(link.disabled);
}, "HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently, when the sheet is an alternate");
</script>

View file

@ -0,0 +1,32 @@
<!doctype html>
<title>&lt;link disabled&gt;'s "explicitly enabled" state persists after getting disconnected from the tree</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
const link = document.querySelector("link[disabled]");
async_test(function(t) {
assert_true(link.disabled);
link.disabled = false;
assert_false(link.disabled);
assert_true(!link.hasAttribute("disabled"));
link.remove();
link.onload = t.step_func_done(function() {
assert_equals(document.styleSheets.length, 1);
let sheet = document.styleSheets[0];
assert_equals(sheet.ownerNode, link);
assert_applies(true);
});
document.head.appendChild(link);
}, "HTMLLinkElement.disabled's explicitly enabled state persists when disconnected and connected again");
</script>

View file

@ -0,0 +1,40 @@
<!doctype html>
<title>&lt;link disabled&gt;'s "explicitly enabled" state doesn't persist for clones</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
const link = document.querySelector("link[disabled]");
async_test(function(t) {
link.remove();
link.disabled = false; // `link` is explicitly enabled.
let clonesLoaded = 0;
for (let shallow of [true, false]) {
const clone = link.cloneNode(shallow);
clone.onload = t.step_func(function() {
assert_false(link.disabled);
// Even though it's not disabled, it still doesn't apply, since it's an alternate.
assert_applies(false);
if (++clonesLoaded == 2) {
link.onload = t.step_func_done(function() {
assert_false(link.disabled);
assert_applies(true); // `link` is still explicitly enabled.
});
document.head.appendChild(link);
}
});
document.head.appendChild(clone);
}
}, "HTMLLinkElement.disabled's explicitly enabled state doesn't persist on clones");
</script>

View file

@ -0,0 +1,27 @@
<!doctype html>
<title>&lt;link disabled&gt;'s "explicitly enabled" persists across rel changes</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link title="alt" rel="yadayada" disabled href="data:text/css,html { background: green }">
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
const link = document.querySelector("link[disabled]");
async_test(function(t) {
link.onload = t.step_func_done(function() {
assert_applies(true);
link.setAttribute("rel", "alternate stylesheet");
assert_applies(true);
assert_false(link.disabled);
});
link.disabled = false;
link.setAttribute("rel", "stylesheet");
}, "HTMLLinkElement.disabled's explicitly enabled state persists regardless of rel");
</script>

View file

@ -0,0 +1,26 @@
<!doctype html>
<title>&lt;link disabled&gt;'s "explicitly enabled" state isn't magically set from the setter</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
async_test(function(t) {
const link = document.createElement("link");
link.setAttribute("rel", "alternate stylesheet");
link.setAttribute("title", "alt");
link.href = "data:text/css,html { background: green }";
link.disabled = false; // This should do nothing, and is the point of this test.
link.onload = t.step_func_done(function() {
assert_applies(false); // Should not apply, since it's an alternate that hasn't been enabled.
assert_false(link.disabled);
});
document.head.appendChild(link);
}, "HTMLLinkElement.disabled setter does nothing if the attribute isn't present already.");
</script>

View file

@ -0,0 +1,27 @@
<!doctype html>
<title>&lt;link disabled&gt;'s "explicitly enabled" state works when set explicitly back and forth</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function assert_applies(applies) {
(applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
}
async_test(function(t) {
const link = document.createElement("link");
link.setAttribute("rel", "alternate stylesheet");
link.setAttribute("title", "alt");
link.href = "data:text/css,html { background: green }";
link.disabled = true;
link.disabled = false; // This should make it "explicitly enabled".
link.onload = t.step_func_done(function() {
assert_applies(true); // Should apply, since it's explicitly enabled.
assert_false(link.disabled);
});
document.head.appendChild(link);
}, "HTMLLinkElement.disabled setter sets the explicitly enabled state if toggled back and forth.");
</script>

View file

@ -0,0 +1,7 @@
<!DOCTYPE html>
<title>CSS Test Reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<style>
html { background: green }
</style>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html class="reftest-wait">
<title>CSS Test: alternate stylesheets can be disabled by HTMLLinkElement.disabled if they have the disabled attribute already</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
<link rel="help" href="https://github.com/whatwg/html/issues/3840">
<link rel="match" href="HTMLLinkElement-disabled-alternate-ref.html">
<link title="alt" rel="alternate stylesheet" href="data:text/css,html { background: green }" disabled onload="document.documentElement.className = ''">
<script>
onload = function() {
const link = document.querySelector("link[rel='alternate stylesheet']");
link.disabled = false;
}
</script>

View file

@ -0,0 +1,13 @@
<!doctype html>
<title>CSS Test reference</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<svg width="200" height="100">
<defs>
<g id="p0">
<rect width="100" height="100" style="fill: blue" />
<rect x="100" y="0" width="100" height="100" style="fill: purple" />
</g>
</defs>
<use href="#p0" x="0" y="0" />
</svg>

View file

@ -0,0 +1,25 @@
<!doctype html>
<title>CSS Test: nth-of-type should work in an svg use subtree</title>
<link rel="help" href="https://drafts.csswg.org/selectors-4/#child-index">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1540385">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="match" href="sharing-in-svg-use-ref.html">
<style>
rect:nth-of-type(1) {
fill: blue;
}
rect:nth-of-type(2) {
fill: purple;
}
</style>
<!-- Should see two different colors -->
<svg width="200" height="100">
<defs>
<g id="p0">
<rect width="100" height="100" />
<rect x="100" y="0" width="100" height="100" />
</g>
</defs>
<use href="#p0" x="0" y="0" />
</svg>

View file

@ -75,6 +75,26 @@ var browserTests = [
"[foobarbaz]",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["[foo<span style=\"display: none\">bar</span>baz]",
[["stylewithcss","true"],["removeformat",""]],
"[foobarbaz]",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
["[foo<span style=\"display: none\">bar</span>baz]",
[["stylewithcss","false"],["removeformat",""]],
"[foobarbaz]",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]",
[["stylewithcss","true"],["removeformat",""]],
"[foobarbaz]",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
["[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]",
[["stylewithcss","false"],["removeformat",""]],
"[foobarbaz]",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["foo<span style=\"font-weight: bold\">b[a]r</span>baz",
[["stylewithcss","true"],["removeformat",""]],
"foo<span style=\"font-weight:bold\">b</span>[a]<span style=\"font-weight:bold\">r</span>baz",
@ -85,6 +105,26 @@ var browserTests = [
"foo<span style=\"font-weight:bold\">b</span>[a]<span style=\"font-weight:bold\">r</span>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["foo<span style=\"display: none\">b[a]r</span>baz",
[["stylewithcss","true"],["removeformat",""]],
"foo<span style=\"display:none\">b</span>[a]<span style=\"display:none\">r</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
["foo<span style=\"display: none\">b[a]r</span>baz",
[["stylewithcss","false"],["removeformat",""]],
"foo<span style=\"display:none\">b</span>[a]<span style=\"display:none\">r</span>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz",
[["stylewithcss","true"],["removeformat",""]],
"foo<span style=\"display:none; font-weight:bold\">b</span>[a]<span style=\"display:none; font-weight:bold\">r</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
["foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz",
[["stylewithcss","false"],["removeformat",""]],
"foo<span style=\"display:none; font-weight:bold\">b</span>[a]<span style=\"display:none; font-weight:bold\">r</span>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
["[foo<span style=\"font-variant: small-caps\">bar</span>baz]",
[["stylewithcss","true"],["removeformat",""]],
"[foobarbaz]",

View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Element Timing: observe image in shadow tree</title>
<style>
body {
margin: 0;
}
</style>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/element-timing-helpers.js"></script>
<div id='target'></div>
<script>
let beforeRender;
async_test(function (t) {
const observer = new PerformanceObserver(
t.step_func_done(function(entryList) {
assert_equals(entryList.getEntries().length, 1);
const entry = entryList.getEntries()[0];
const pathname = window.location.origin + '/element-timing/resources/square100.png';
checkElement(entry, pathname, 'my_image', 'my_id', beforeRender);
// Assume viewport has size at least 100, so the element is fully visible.
checkRect(entry, [0, 100, 0, 100]);
checkNaturalSize(entry, 100, 100);
})
);
observer.observe({entryTypes: ['element']});
// We add the image during onload to be sure that the observer is registered
// in time for it to observe the element timing.
window.onload = () => {
// Add image of width equal to 100 and height equal to 100.
const img = document.createElement('img');
img.src = 'resources/square100.png';
img.setAttribute('elementtiming', 'my_image');
img.setAttribute('id', 'my_id');
const shadowRoot = document.getElementById('target').attachShadow({mode: 'closed'});
shadowRoot.appendChild(img);
beforeRender = performance.now();
};
}, 'Image in shadow tree with elementtiming attribute is observable.');
</script>

View file

@ -23,9 +23,9 @@ promise_test(async t => {
{types: ['feature-policy-violation']}).observe();
});
try {
await navigator.xr.supportsSessionMode('inline');
await navigator.xr.supportsSession('inline');
} catch (err) {
// If no XR devices are available, supportsSessionMode() will reject with a
// If no XR devices are available, supportsSession() will reject with a
// NotSupportedError, but the report should be generated anyway.
assert_equals(err.name, 'NotSupportedError');
}

View file

@ -22,7 +22,7 @@ promise_test(async (t) => {
new ReportingObserver((reports, observer) => resolve([reports, observer]),
{types: ['feature-policy-violation']}).observe();
});
await promise_rejects(t, 'SecurityError', navigator.xr.supportsSessionMode('inline'),
await promise_rejects(t, 'SecurityError', navigator.xr.supportsSession('inline'),
"XR device access should not be allowed in this document.");
const [reports, observer] = await report;
check_report_format(reports, observer);

Some files were not shown because too many files have changed in this diff Show more