Update web-platform-tests to revision 9a5d71b326166e12784bdd9d161772e20f87c1fd

This commit is contained in:
WPT Sync Bot 2018-09-07 21:37:42 -04:00
parent f7630dad87
commit 4ae3d09ff3
86 changed files with 2739 additions and 640 deletions

View file

@ -1,5 +1,4 @@
[url-in-tags-revoke.window.html] [url-in-tags-revoke.window.html]
expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe.] [Fetching a blob URL immediately before revoking it works in an iframe.]
expected: FAIL expected: FAIL
@ -15,6 +14,3 @@
[Opening a blob URL in a new window by clicking an <a> tag works immediately before revoking the URL.] [Opening a blob URL in a new window by clicking an <a> tag works immediately before revoking the URL.]
expected: FAIL expected: FAIL
[Fetching a blob URL immediately before revoking it works in <script> tags.]
expected: TIMEOUT

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
[registered-property-type.https.html]
expected: FAIL

View file

@ -14,9 +14,6 @@
[word-spacing intermediate] [word-spacing intermediate]
expected: FAIL expected: FAIL
[outline-width intermediate]
expected: FAIL
[vertical-align intermediate] [vertical-align intermediate]
expected: FAIL expected: FAIL
@ -71,3 +68,15 @@
[bottom intermediate] [bottom intermediate]
expected: FAIL expected: FAIL
[outline-offset end]
expected: FAIL
[border-bottom-width end]
expected: FAIL
[padding-bottom intermediate]
expected: FAIL
[padding-bottom end]
expected: FAIL

View file

@ -0,0 +1,4 @@
[traverse_the_history_1.html]
[Multiple history traversals from the same task]
expected: FAIL

View file

@ -0,0 +1,4 @@
[traverse_the_history_2.html]
[Multiple history traversals, last would be aborted]
expected: FAIL

View file

@ -0,0 +1,4 @@
[composed.window.html]
[Focus events are composed]
expected: FAIL

View file

@ -0,0 +1,4 @@
[document-level-apis.html]
[When a child browsing context is focused, its browsing context container is also focused]
expected: FAIL

View file

@ -0,0 +1,22 @@
[focus-fixup-rule-one-no-dialogs.html]
[Disabling contenteditable]
expected: FAIL
[Hiding the active element]
expected: FAIL
[Disabling the active element (making it expressly inert)]
expected: FAIL
[Changing the first legend element in disabled <fieldset>]
expected: FAIL
[Disabling <fieldset> affects its descendants]
expected: FAIL
[Removing the tabindex attribute from a div]
expected: FAIL
[Removing the active element from the DOM]
expected: FAIL

View file

@ -0,0 +1,19 @@
[preventScroll.html]
[Sanity test]
expected: FAIL
[elm.focus({preventScroll: false})]
expected: FAIL
[elm.focus(null)]
expected: FAIL
[elm.focus(undefined)]
expected: FAIL
[elm.focus({})]
expected: FAIL
[elm.focus() without arguments]
expected: FAIL

View file

@ -0,0 +1,7 @@
[focus-tabindex-default-value.html]
[The default value of tabIndex attribute must be 0 for elements that are focusable]
expected: FAIL
[The default value of tabIndex attribute must be -1 for elements that are not focusable]
expected: FAIL

View file

@ -0,0 +1,13 @@
[tabindex-focus-flag.html]
[a should not be focusable by default.]
expected: FAIL
[#summary-first should be focusable by default.]
expected: FAIL
[input[type="hidden"\] should not be focusable by default.]
expected: FAIL
[[contenteditable\] should be focusable by default.]
expected: FAIL

View file

@ -2,15 +2,21 @@
[request.formData() with input: a&b&c] [request.formData() with input: a&b&c]
expected: FAIL expected: FAIL
[response.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL
[request.formData() with input: a=b&c=d&]
expected: FAIL
[request.formData() with input: a=b&c=d] [request.formData() with input: a=b&c=d]
expected: FAIL expected: FAIL
[request.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[response.formData() with input: a=b&c=d&]
expected: FAIL
[response.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[response.formData() with input: a=b&c=d]
expected: FAIL
[urlencoded-parser.any.worker.html] [urlencoded-parser.any.worker.html]
[response.formData() with input: a&b&c] [response.formData() with input: a&b&c]
@ -19,18 +25,12 @@
[request.formData() with input: a&b&c] [request.formData() with input: a&b&c]
expected: FAIL expected: FAIL
[request.formData() with input: &&&a=b&&&&c=d&]
expected: FAIL
[response.formData() with input: a=b&c=d&]
expected: FAIL
[request.formData() with input: a=b&c=d]
expected: FAIL
[request.formData() with input: _charset_=windows-1252&test=%C2x] [request.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL expected: FAIL
[response.formData() with input: _charset_=windows-1252&test=%C2x] [response.formData() with input: _charset_=windows-1252&test=%C2x]
expected: FAIL expected: FAIL
[response.formData() with input: a=b&c=d]
expected: FAIL

View file

@ -0,0 +1,13 @@
[buffer-resampling.html]
[< [interpolate\] 2 out of 2 assertions were failed.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL
[X SNR (0.000 dB) is not greater than or equal to 37.17. Got 0.]
expected: FAIL
[X Interpolated sine wave does not equal [0,0.05756402388215065,0.11493714898824692,0.17192909121513367,0.22835086286067963,0.28401535749435425,0.3387379050254822,0.3923371136188507,0.44463518261909485,0.4954586327075958,0.5446390509605408,0.5920131802558899,0.6374239921569824,0.680720865726471,0.7217602133750916,0.760405957698822...\] with an element-wise tolerance of {"absoluteThreshold":0.090348,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[2\]\t0.0000000000000000e+0\t1.1493714898824692e-1\t1.1493714898824692e-1\t1.0000000000000000e+0\t9.0347999999999998e-2\n\t[3\]\t0.0000000000000000e+0\t1.7192909121513367e-1\t1.7192909121513367e-1\t1.0000000000000000e+0\t9.0347999999999998e-2\n\t[4\]\t0.0000000000000000e+0\t2.2835086286067963e-1\t2.2835086286067963e-1\t1.0000000000000000e+0\t9.0347999999999998e-2\n\t[5\]\t0.0000000000000000e+0\t2.8401535749435425e-1\t2.8401535749435425e-1\t1.0000000000000000e+0\t9.0347999999999998e-2\n\t[6\]\t0.0000000000000000e+0\t3.3873790502548218e-1\t3.3873790502548218e-1\t1.0000000000000000e+0\t9.0347999999999998e-2\n\t...and 476 more errors.\n\tMax AbsError of 1.0000000000000000e+0 at index of 300.\n\t[300\]\t0.0000000000000000e+0\t-1.0000000000000000e+0\t1.0000000000000000e+0\t1.0000000000000000e+0\t9.0347999999999998e-2\n\tMax RelError of 1.0000000000000000e+0 at index of 2.\n]
expected: FAIL

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Containment Test: contain is not animatable</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
<link rel="help" href="https://drafts.csswg.org/css-contain/#contain-property">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<meta name=assert content="the contain property is not animatable">
<style>
div {
border: 50px solid green;
background: red;
position: absolute; /* for shrinkwrap */
contain: strict;
animation-duration: 1s;
animation-name: bad;
animation-play-state: paused;
font-size: 100px;
}
@keyframes bad {
from {
contain: none;
}
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div>&nbsp;</div>

View file

@ -0,0 +1,31 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CSS-contain test: layout containment and baselines</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
<meta name=assert content="With contain:layout, for the purpose of the vertical-align property, the containing element is treated as having no baseline.">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
<meta name="flags" content="">
<style>
#red {
position: absolute;
background: red;
width: 100px;
height: 100px;
z-index: -1;
}
.green {
display: inline-block;
height: 100px;
background: green;
width: 50px;
contain: layout;
color: transparent;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id=red></div>
<div class=green></div><div class=green>a</div>

View file

@ -0,0 +1,24 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CSS-contain test: paint containment and baselines</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
<meta name=assert content="contain:paint does not suppress baseline alignment">
<link rel="match" href="reference/contain-baseline-ref.html">
<link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
<meta name="flags" content="">
<style>
div {
display: inline-block;
height: 5px;
background: blue;
width: 50px;
contain: paint;
color: transparent;
font-size: 100px;
}
</style>
<p>Test passes if there are two, not one, blue lines below.</p>
<div></div><div>a</div>

View file

@ -0,0 +1,24 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CSS-contain test: size containment and baselines</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
<meta name=assert content="contain:size does not suppress baseline alignment">
<link rel="match" href="reference/contain-baseline-ref.html">
<link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-size">
<meta name="flags" content="">
<style>
div {
display: inline-block;
height: 5px;
background: blue;
width: 50px;
contain: size;
color: transparent;
font-size: 100px;
}
</style>
<p>Test passes if there are two, not one, blue lines below.</p>
<div></div><div>a</div>

View file

@ -0,0 +1,24 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CSS-contain test: style containment and baselines</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
<meta name=assert content="contain:style does not suppress baseline alignment">
<link rel="match" href="reference/contain-baseline-ref.html">
<link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-style">
<meta name="flags" content="">
<style>
div {
display: inline-block;
height: 5px;
background: blue;
width: 50px;
contain: style;
color: transparent;
font-size: 100px;
}
</style>
<p>Test passes if there are two, not one, blue lines below.</p>
<div></div><div>a</div>

View file

@ -0,0 +1,18 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CSS test reference</title>
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
<style>
div {
display: inline-block;
height: 5px;
background: blue;
width: 50px;
color: transparent;
font-size: 100px;
}
</style>
<p>Test passes if there are two, not one, blue lines below.</p>
<div></div><div>a</div>

View file

@ -1,67 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel="match" href="parse-input-arguments-ref.html">
<style>
.container {
width: 100px;
height: 100px;
--length: 10px;
--number: 10;
}
#canvas-geometry {
background-image: paint(geometry);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
<script id="code" type="text/worklet">
registerPaint('geometry', class {
static get inputProperties() {
return [
'--length',
'--length-initial',
'--number',
];
}
paint(ctx, geom, styleMap) {
const properties = [...styleMap.keys()].sort();
var serializedStrings = [];
for (let i = 0; i < properties.length; i++) {
const value = styleMap.get(properties[i]);
let serialized;
if (value)
serialized = properties[i].toString() + ': [' + value.constructor.name + '=' + value.toString() + ']';
else
serialized = properties[i].toString() + ': [null]';
serializedStrings.push(serialized);
}
ctx.strokeStyle = 'green';
if (serializedStrings[0] != "--length: [CSSUnitValue=10px]")
ctx.strokeStyle = 'red';
if (serializedStrings[1] != "--length-initial: [CSSUnitValue=20px]")
ctx.strokeStyle = 'blue';
if (serializedStrings[2] != "--number: [CSSUnitValue=10]")
ctx.strokeStyle = 'yellow';
ctx.lineWidth = 4;
ctx.strokeRect(0, 0, geom.width, geom.height);
}
});
</script>
<script>
try {
CSS.registerProperty({name: '--length', syntax: '<length>', initialValue: '0px', inherits: false});
CSS.registerProperty({name: '--length-initial', syntax: '<length>', initialValue: '20px', inherits: false});
CSS.registerProperty({name: '--number', syntax: '<number>', initialValue: '0', inherits: false});
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
} catch(e) {
document.body.textContent = e;
takeScreenshot();
}
</script>
</body>
</html>

View file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel="help" href="https://www.w3.org/TR/css-paint-api-1/#examples">
<link rel="match" href="parse-input-arguments-ref.html">
<style>
.container {
width: 100px;
height: 100px;
}
#canvas-geometry {
background-image: paint(geometry);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="canvas-geometry" class="container"></div>
<script id="code" type="text/worklet">
// Globals that must be prepended to this script:
// - debugLog: A function that logs errors.
// - props: Test data.
registerPaint('geometry', class {
static get inputProperties() { return props.map(p => p.name); }
paint(ctx, geom, styleMap) {
ctx.strokeStyle = 'green';
for (let prop of props) {
let first = styleMap.get(prop.name);
let all = styleMap.getAll(prop.name);
let serialize = v => v.constructor.name + '=' + v.toString()
let actual = all.map(serialize).join(',');
let expected = prop.expected.join(',');
let pass = actual === expected
&& serialize(first) === prop.expected[0];
if (!pass)
ctx.strokeStyle = 'red';
debugLog(pass ? 'PASS' : 'FAIL', prop.syntax, actual, expected);
}
ctx.lineWidth = 4;
ctx.strokeRect(0, 0, geom.width, geom.height);
}
});
</script>
<script>
// A copy of this array (automatically enriched with 'name' and 'expected')
// is also available in the worklet.
let props = [
// Initial values.
{ syntax: '*', initialValue: 'if(){}' },
{ syntax: '<angle>', initialValue: '42deg' },
{ syntax: '<color>', initialValue: '#fefefe' },
{ syntax: '<custom-ident>', initialValue: 'none' },
{ syntax: '<image>', initialValue: 'linear-gradient(red, red)' },
{ syntax: '<image>', initialValue: 'url(http://a.com/a)' },
{ syntax: '<integer>', initialValue: '42' },
{ syntax: '<length-percentage>', initialValue: '10%' },
{ syntax: '<length-percentage>', initialValue: '10px' },
{ syntax: '<length-percentage>', initialValue: 'calc(10px + 10%)' },
{ syntax: '<length>', initialValue: '1337px' },
{ syntax: '<number>', initialValue: '42.5' },
{ syntax: '<percentage>', initialValue: '42%' },
{ syntax: '<resolution>', initialValue: '300dpi' },
{ syntax: '<time>', initialValue: '3600s' },
{ syntax: '<url>', initialValue: 'url(http://a.com/a)' },
{ syntax: 'thing', initialValue: 'thing' },
{ syntax: '<length> | <angle>', initialValue: '1337px' },
{ syntax: '<angle> | <image>', initialValue: '1turn' },
{ syntax: '<length>+', initialValue: '1337px' },
{ syntax: '<length>+', initialValue: '1337px 1338px', count: 2 },
{ syntax: '<length>#', initialValue: '1337px' },
{ syntax: '<length>#', initialValue: '1337px, 1338px', count: 2 },
// Non-initial values:
{ syntax: '*', initialValue: 'fail', value: 'if(){}' },
{ syntax: '<angle> | fail', initialValue: 'fail', value: '42deg' },
{ syntax: '<color> | fail', initialValue: 'fail', value: '#fefefe' },
{ syntax: '<custom-ident> | fail', initialValue: 'fail', value: 'none' },
{ syntax: '<image> | fail', initialValue: 'fail', value: 'linear-gradient(red, red)' },
{ syntax: '<image> | fail', initialValue: 'fail', value: 'url(http://a.com/a)' },
{ syntax: '<integer> | fail', initialValue: 'fail', value: '42' },
{ syntax: '<length-percentage> | fail', initialValue: 'fail', value: '10%' },
{ syntax: '<length-percentage> | fail', initialValue: 'fail', value: '10px' },
{ syntax: '<length-percentage> | fail', initialValue: 'fail', value: 'calc(10px + 10%)' },
{ syntax: '<length> | fail', initialValue: 'fail', value: '1337px' },
{ syntax: '<number> | fail', initialValue: 'fail', value: '42.5' },
{ syntax: '<percentage> | fail', initialValue: 'fail', value: '42%' },
{ syntax: '<resolution> | fail', initialValue: 'fail', value: '300dpi' },
{ syntax: '<time> | fail', initialValue: 'fail', value: '3600s' },
{ syntax: '<url> | fail', initialValue: 'fail', value: 'url(http://a.com/a)' },
{ syntax: 'thing | fail', initialValue: 'fail', value: 'thing' },
{ syntax: '<length>+ | fail', initialValue: 'fail', value: '1337px' },
{ syntax: '<length>+ | fail', initialValue: 'fail', value: '1337px 1338px', count: 2 },
{ syntax: '<length># | fail', initialValue: 'fail', value: '1337px' },
{ syntax: '<length># | fail', initialValue: 'fail', value: '1337px, 1338px', count: 2 },
];
try {
let target = document.getElementById('canvas-geometry');
let pid = 1;
for (let p of props) {
p.name = `--prop-${++pid}`;
CSS.registerProperty({
name: p.name,
syntax: p.syntax,
initialValue: p.initialValue,
inherits: (typeof p.inherits !== 'undefined') ? p.inherits : false
});
if (typeof p.value !== 'undefined')
target.style.setProperty(p.name, p.value);
if (typeof p.count === 'undefined')
p.count = 1;
let getValue = p => (typeof p.value !== 'undefined') ? p.value : p.initialValue;
let serialize = v => v.constructor.name + '=' + v.toString();
let parse = function (p) {
if (p.count == 1)
return [CSSStyleValue.parse(p.name, getValue(p))];
return CSSStyleValue.parseAll(p.name, getValue(p));
};
// Generate expected value. We assume that CSSStyleValue.parse/All
// returns the correct CSSStyleValue subclass and value.
p.expected = parse(p).map(serialize);
}
// Adding '?debug' to the URL will cause this test to emit
// test results to console.log.
let debugMode = document.location.href.endsWith('?debug');
let code = [
`const props = ${JSON.stringify(props)};`,
`const debugLog = ${debugMode ? 'console.log' : 'function(){}'};`,
document.getElementById('code').textContent
].join('\n');
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, code);
} catch(e) {
document.body.textContent = e;
takeScreenshot();
}
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>CSS Reference</title>
<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<style>
textarea {
overflow: hidden;
white-space: pre;
}
</style>
<textarea cols="10" rows="10"></textarea>
<script>
let textarea = document.querySelector("textarea");
textarea.value = ('X'.repeat(100) + '\n').repeat(100);
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>CSS Test: scrollbar-width should apply on &lt;textarea&gt;</title>
<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width">
<link rel="match" href="textarea-scrollbar-width-none-ref.html">
<style>
textarea {
scrollbar-width: none;
white-space: pre;
}
</style>
<textarea cols="10" rows="10"></textarea>
<script>
let textarea = document.querySelector("textarea");
textarea.value = ('X'.repeat(100) + '\n').repeat(100);
</script>

View file

@ -16,25 +16,25 @@ test_valid_value("offset", "100px none auto 90deg", "100px center none auto 90de
test_valid_value("offset", "100px", "100px center"); test_valid_value("offset", "100px", "100px center");
test_valid_value("offset", "auto none reverse"); test_valid_value("offset", "auto none reverse");
test_valid_value("offset", "auto"); test_valid_value("offset", "auto");
test_valid_value("offset", "center bottom path('M 1 2 V 3 Z')"); test_valid_value("offset", "center bottom path(\"M 1 2 V 3 Z\")");
test_valid_value("offset", "center center path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z') 100% 90deg / left bottom"); test_valid_value("offset", "center center path(\"M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z\") 100% 90deg / left bottom");
test_valid_value("offset", "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom"); test_valid_value("offset", "left bottom ray(0rad closest-side) 10px auto 30deg / right bottom");
test_valid_value("offset", "left top"); test_valid_value("offset", "left top");
test_valid_value("offset", "none 30deg reverse", "none reverse 30deg"); test_valid_value("offset", "none 30deg reverse", "none reverse 30deg");
test_valid_value("offset", "none 50px reverse 30deg"); test_valid_value("offset", "none 50px reverse 30deg");
test_valid_value("offset", "none calc(10px + 20%) auto"); test_valid_value("offset", "none calc(10px + 20%) auto");
test_valid_value("offset", "none reverse"); test_valid_value("offset", "none reverse");
test_valid_value("offset", "path('M 0 0 H 1') -200% auto"); test_valid_value("offset", "path(\"M 0 0 H 1\") -200% auto");
test_valid_value("offset", "path('M 0 0 H 1') -200%"); test_valid_value("offset", "path(\"M 0 0 H 1\") -200%");
test_valid_value("offset", "path('M 0 0 H 1') 50px"); test_valid_value("offset", "path('M 0 0 H 1') 50px", "path(\"M 0 0 H 1\") 50px");
test_valid_value("offset", "path('M 0 0 H 1') auto"); test_valid_value("offset", "path(\"M 0 0 H 1\") auto");
test_valid_value("offset", "path('M 0 0 H 1') reverse 30deg 50px", "path('M 0 0 H 1') 50px reverse 30deg"); test_valid_value("offset", "path('M 0 0 H 1') reverse 30deg 50px", "path(\"M 0 0 H 1\") 50px reverse 30deg");
test_valid_value("offset", "path('M 0 0 H 1')"); test_valid_value("offset", "path(\"M 0 0 H 1\")");
test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px / auto", "path('m 0 0 h 100') 8px -7rad / auto"); test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px / auto", "path(\"m 0 0 h 100\") 8px -7rad / auto");
test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px / left top", "path('m 0 0 h 100') 8px -7rad / left top"); test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px / left top", "path(\"m 0 0 h 100\") 8px -7rad / left top");
test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px", "path('m 0 0 h 100') 8px -7rad"); test_valid_value("offset", "path('m 0 0 h 100') -7rad 8px", "path(\"m 0 0 h 100\") 8px -7rad");
test_valid_value("offset", "path('m 0 0 h 100') 100px 0deg"); test_valid_value("offset", "path(\"m 0 0 h 100\") 100px 0deg");
test_valid_value("offset", "path('m 1 2 v 3 Z')"); test_valid_value("offset", "path('m 1 2 v 3 Z')", "path(\"m 1 2 v 3 Z\")");
test_valid_value("offset", "ray(farthest-corner 90deg) 1%", "ray(90deg farthest-corner) 1%"); test_valid_value("offset", "ray(farthest-corner 90deg) 1%", "ray(90deg farthest-corner) 1%");
test_valid_value("offset", "ray(sides 0deg) 50% 90deg auto", "ray(0deg sides) 50% auto 90deg"); test_valid_value("offset", "ray(sides 0deg) 50% 90deg auto", "ray(0deg sides) 50% auto 90deg");
test_valid_value("offset", "right bottom / left top"); test_valid_value("offset", "right bottom / left top");

View file

@ -0,0 +1,17 @@
<!doctype html>
<title>legend focusable</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
const t = async_test();
</script>
<fieldset>
<legend tabindex=0 onfocus="t.step(() => { t.done(); })">
legend
<input onfocus="t.unreached_func('input in legend was focused')();">
</legend>
<input onfocus="t.unreached_func('input after legend was focused')();">
</fieldset>
<script>
document.querySelector('legend').focus();
</script>

View file

@ -0,0 +1,20 @@
<!doctype html>
<title>legend</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
const t = async_test();
</script>
<fieldset>
<legend onfocus="t.unreached_func('legend was focused')()">
legend
<input onfocus="t.unreached_func('input in legend was focused')();">
</legend>
<input onfocus="t.unreached_func('input after legend was focused')();">
</fieldset>
<script>
document.querySelector('legend').focus();
t.step_timeout(() => {
t.done();
}, 500);
</script>

View file

@ -0,0 +1,27 @@
<!doctype html>
<title>legend align does not map to text-align</title>
<!-- See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1488228 -->
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
legend { width: 13em }
</style>
<fieldset><legend>foo bar abcdefghijklmnopqrstuvwxyz</legend></fieldset>
<fieldset><legend align=left>foo bar abcdefghijklmnopqrstuvwxyz</legend></fieldset>
<fieldset><legend align=center>foo bar abcdefghijklmnopqrstuvwxyz</legend></fieldset>
<fieldset><legend align=right>foo bar abcdefghijklmnopqrstuvwxyz</legend></fieldset>
<fieldset><legend align=justify>foo bar abcdefghijklmnopqrstuvwxyz</legend></fieldset>
<script>
function test_align(selectorTest, expectedAlign) {
const testElm = document.querySelector(selectorTest);
test(() => {
assert_equals(getComputedStyle(testElm).textAlign, expectedAlign);
}, selectorTest);
}
test_align('legend', 'start');
for (const val of ['left', 'center', 'right', 'justify']) {
test_align(`legend[align=${val}]`, 'start');
}
</script>

View file

@ -5,6 +5,7 @@
<fieldset><legend align=left>x</legend></fieldset> <fieldset><legend align=left>x</legend></fieldset>
<fieldset><legend align=center>x</legend></fieldset> <fieldset><legend align=center>x</legend></fieldset>
<fieldset><legend align=right>x</legend></fieldset> <fieldset><legend align=right>x</legend></fieldset>
<fieldset><legend align=justify>x</legend></fieldset>
<div align=left> <div align=left>
<fieldset><legend>x</legend></fieldset> <fieldset><legend>x</legend></fieldset>
</div> </div>
@ -14,6 +15,9 @@
<div align=right> <div align=right>
<fieldset><legend>x</legend></fieldset> <fieldset><legend>x</legend></fieldset>
</div> </div>
<div align=justify>
<fieldset><legend>x</legend></fieldset>
</div>
<div style="text-align: center"> <div style="text-align: center">
<fieldset><legend>x</legend></fieldset> <fieldset><legend>x</legend></fieldset>
</div> </div>
@ -33,12 +37,12 @@ function test_align(selectorTest, selectorRef) {
}, selectorTest); }, selectorTest);
} }
for (const val of ['left', 'center', 'right']) { for (const val of ['left', 'center', 'right', 'justify']) {
test_align(`div[align=${val}] legend`, `legend[align=${val}]`); test_align(`div[align=${val}] legend`, `legend[align=left]`);
} }
test_align(`div[style="text-align: center"] legend`, `legend[align=left]`); test_align(`div[style="text-align: center"] legend`, `legend[align=left]`);
test_align(`div[style="text-align: center"][align=center] legend`, `legend[align=center]`); test_align(`div[style="text-align: center"][align=center] legend`, `legend[align=left]`);
test_align(`legend[style="margin: 0 auto"]`, `legend[align=center]`); test_align(`legend[style="margin: 0 auto"]`, `legend[align=center]`);
test_align(`legend[style="margin: 0 0 0 auto"]`, `legend[align=right]`); test_align(`legend[style="margin: 0 0 0 auto"]`, `legend[align=right]`);
test_align(`fieldset[dir=rtl] legend`, `legend[align=right]`); test_align(`fieldset[dir=rtl] legend`, `legend[align=right]`);

View file

@ -0,0 +1,36 @@
setup({explicit_done: true, explicit_timeout: true});
const NOTRUN = 3;
let status = NOTRUN;
function notrun() {
return status === NOTRUN;
}
add_completion_callback(tests => {
status = tests[0].status;
});
function pass() {
// Wait a couple of frames in case fail() is also called.
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (notrun()) {
test(() => {});
done();
}
});
});
}
function fail(msg) {
if (notrun()) {
test(() => { assert_unreached(msg); });
done();
}
}
document.addEventListener('DOMContentLoaded', () => {
const accessKeyElement = document.querySelector('[accesskey]');
if (accessKeyElement.accessKeyLabel) {
document.querySelector('kbd').textContent = accessKeyElement.accessKeyLabel;
}
});

View file

@ -0,0 +1,10 @@
<!doctype html>
<title>First input after the legend</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<legend accesskey=a>legend</legend>
<input onfocus="pass()">
</fieldset>

View file

@ -0,0 +1,13 @@
<!doctype html>
<title>First input before the legend</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<input onfocus="pass()">
<legend accesskey=a>legend
<input onfocus="fail('input in legend was focused')">
</legend>
<input onfocus="fail('input after legend was focused')">
</fieldset>

View file

@ -0,0 +1,12 @@
<!doctype html>
<title>First input inside the legend</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<legend accesskey=a>legend
<input onfocus="pass()">
</legend>
<input onfocus="fail('input after legend was focused')">
</fieldset>

View file

@ -0,0 +1,14 @@
<!doctype html>
<title>Focusable legend</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<legend tabindex=0 onclick="fail('unexpected click event on legend')"
onfocus="fail('legend was focused')" accesskey=a>
legend
<input onfocus="pass()">
</legend>
<input onfocus="fail('input after legend was focused')">
</fieldset>

View file

@ -0,0 +1,17 @@
<!doctype html>
<title>Focusable legend sibling</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<legend accesskey=a>first legend</legend>
<legend tabindex=0 onfocus="fail('sibling legend was focused')">second legend</legend>
</fieldset>
<script>
onkeyup = e => {
if (e.keyCode === 65) {
pass();
}
}
</script>

View file

@ -0,0 +1,17 @@
<!doctype html>
<title>Input outside fieldset</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<fieldset>
<legend accesskey=a>legend</legend>
</fieldset>
<input onfocus="fail('input outside fieldset was focused')">
<script>
onkeyup = e => {
if (e.keyCode === 65) {
pass();
}
}
</script>

View file

@ -0,0 +1,18 @@
<!doctype html>
<title>Label sibling</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<input id=x onfocus="fail('input associated with the label was focused')">
<fieldset>
<legend accesskey=a>legend</legend>
<label for=x onclick="fail('label received a click event')">label</label>
</fieldset>
<script>
onkeyup = e => {
if (e.keyCode === 65) {
pass();
}
}
</script>

View file

@ -0,0 +1,18 @@
<!doctype html>
<title>No fieldset parent</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=../common/accesskey.js></script>
<p>Press the access key combination for "a". <kbd></kbd></p>
<legend accesskey=a>
legend
<input onfocus="fail('input in legend was focused')">
</legend>
<input onfocus="fail('input after legend was focused')">
<script>
onkeyup = e => {
if (e.keyCode === 65) {
pass();
}
}
</script>

View file

@ -7,12 +7,19 @@
<script> <script>
var worker = 'resources/fetch-event-test-worker.js'; var worker = 'resources/fetch-event-test-worker.js';
function do_test(referrer, value, expected, name)
{
test(() => {
assert_equals(value, expected);
}, name + (referrer ? " - Custom Referrer" : " - Default Referrer"));
}
function run_referrer_policy_tests(frame, referrer, href, origin) { function run_referrer_policy_tests(frame, referrer, href, origin) {
return frame.contentWindow.fetch('resources/simple.html?referrerFull', return frame.contentWindow.fetch('resources/simple.html?referrerFull',
{method: "GET", referrer: referrer}) {method: "GET", referrer: referrer})
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -24,7 +31,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -34,7 +41,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -46,7 +53,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -56,7 +63,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: origin', 'ReferrerPolicy: origin',
@ -68,7 +75,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: origin', 'ReferrerPolicy: origin',
@ -78,7 +85,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: origin-when-cross-origin', 'ReferrerPolicy: origin-when-cross-origin',
@ -90,7 +97,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: origin-when-cross-origin', 'ReferrerPolicy: origin-when-cross-origin',
@ -100,7 +107,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -112,7 +119,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: no-referrer-when-downgrade', 'ReferrerPolicy: no-referrer-when-downgrade',
@ -123,7 +130,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: unsafe-url', 'ReferrerPolicy: unsafe-url',
@ -133,7 +140,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: no-referrer', 'ReferrerPolicy: no-referrer',
@ -143,7 +150,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: same-origin', 'ReferrerPolicy: same-origin',
@ -155,7 +162,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: same-origin', 'ReferrerPolicy: same-origin',
@ -167,7 +174,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: strict-origin', 'ReferrerPolicy: strict-origin',
@ -177,7 +184,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: strict-origin', 'ReferrerPolicy: strict-origin',
@ -189,7 +196,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: strict-origin', 'ReferrerPolicy: strict-origin',
@ -199,7 +206,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + href + '\n' + 'Referrer: ' + href + '\n' +
'ReferrerPolicy: strict-origin-when-cross-origin', 'ReferrerPolicy: strict-origin-when-cross-origin',
@ -211,7 +218,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: ' + origin + '/' + '\n' + 'Referrer: ' + origin + '/' + '\n' +
'ReferrerPolicy: strict-origin-when-cross-origin', 'ReferrerPolicy: strict-origin-when-cross-origin',
@ -223,7 +230,7 @@ function run_referrer_policy_tests(frame, referrer, href, origin) {
}) })
.then(function(response) { return response.text(); }) .then(function(response) { return response.text(); })
.then(function(response_text) { .then(function(response_text) {
assert_equals( do_test(referrer,
response_text, response_text,
'Referrer: \n' + 'Referrer: \n' +
'ReferrerPolicy: strict-origin-when-cross-origin', 'ReferrerPolicy: strict-origin-when-cross-origin',
@ -241,17 +248,16 @@ async_test(function(t) {
.then(function() { return with_iframe(scope); }) .then(function() { return with_iframe(scope); })
.then(function(f) { .then(function(f) {
frame = f; frame = f;
assert_equals( test(() => {
frame.contentDocument.body.textContent, assert_equals(frame.contentDocument.body.textContent, 'ReferrerPolicy: no-referrer-when-downgrade');
'ReferrerPolicy: no-referrer-when-downgrade', }, 'Service Worker should respond to fetch with the default referrer policy');
'Service Worker should respond to fetch with the default referrer policy');
// First, run the referrer policy tests without passing a referrer in RequestInit. // First, run the referrer policy tests without passing a referrer in RequestInit.
return run_referrer_policy_tests(frame, undefined, frame.contentDocument.location.href, return run_referrer_policy_tests(frame, undefined, frame.contentDocument.location.href,
frame.contentDocument.location.origin); frame.contentDocument.location.origin);
}) })
.then(function() { .then(function() {
// Now, run the referrer policy tests while passing a referrer in RequestInit. // Now, run the referrer policy tests while passing a referrer in RequestInit.
var referrer = get_host_info()['HTTPS_ORIGIN'] + base_path() + 'fake-referrer'; var referrer = get_host_info()['HTTPS_ORIGIN'] + base_path() + 'resources/fake-referrer';
return run_referrer_policy_tests(frame, 'fake-referrer', referrer, return run_referrer_policy_tests(frame, 'fake-referrer', referrer,
frame.contentDocument.location.origin); frame.contentDocument.location.origin);
}) })

View file

@ -17,27 +17,27 @@
// Distinct number of path segments // Distinct number of path segments
test_no_interpolation({ test_no_interpolation({
property: 'd', property: 'd',
from: "path('M 0 0 H 1 H 2')", from: 'path("M 0 0 H 1 H 2")',
to: "path('M 0 0 H 3')" to: 'path("M 0 0 H 3")'
}); });
test_no_interpolation({ test_no_interpolation({
property: 'd', property: 'd',
from: "path('M 1 2 L 3 4 Z')", from: 'path("M 1 2 L 3 4 Z")',
to: "none" to: "none"
}); });
// Distinct segment types // Distinct segment types
test_no_interpolation({ test_no_interpolation({
property: 'd', property: 'd',
from: "path('M 10 0 H 11')", from: 'path("M 10 0 H 11")',
to: "path('M 20 0 V 2')" to: 'path("M 20 0 V 2")'
}); });
test_no_interpolation({ test_no_interpolation({
property: 'd', property: 'd',
from: "path('M 1 2 L 4 6 Z')", from: 'path("M 1 2 L 4 6 Z")',
to: "path('M 1 2 H 4 V 6')" to: 'path("M 1 2 H 4 V 6")'
}); });
]]></script> ]]></script>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -17,106 +17,106 @@
// Mix relative and non-relative // Mix relative and non-relative
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')", from: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")',
to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 300 100 z')" to: 'path("M 0 0 L 100 100 m 0 100 l 100 0 z l 300 100 z")'
}, [ }, [
{at: -1, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 0 -100 Z')"}, {at: -1, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 0 -100 Z")'},
{at: 0, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 0, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 0.125, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 225 125 Z')"}, {at: 0.125, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 225 125 Z")'},
{at: 0.875, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 375 275 Z')"}, {at: 0.875, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 375 275 Z")'},
{at: 1, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 400 300 Z')"}, {at: 1, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 400 300 Z")'},
{at: 2, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 600 500 Z')"}, {at: 2, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 600 500 Z")'},
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')", from: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")',
to: "path('M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z')" to: 'path("M 0 0 L 100 100 m 0 100 l 100 0 z l 100 -100 z")'
}, [ }, [
{at: -1, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: -1, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 0, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 0, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 0.125, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 0.125, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 0.875, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 0.875, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 1, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 1, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
{at: 2, expect: "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z')"}, {at: 2, expect: 'path("M 0 0 L 100 100 M 100 200 L 200 200 Z L 200 100 Z")'},
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 l 40 50 z l 40 60 z m 60 70 l 90 60 z t 70 130')", from: 'path("m 10 20 l 40 50 z l 40 60 z m 60 70 l 90 60 z t 70 130")',
to: "path('M 210 220 L 170 190 Z L 90 120 Z M 110 130 L 200 230 Z T 220 220')" to: 'path("M 210 220 L 170 190 Z L 90 120 Z M 110 130 L 200 230 Z T 220 220")'
}, [ }, [
{at: -1, expect: "path('M -190 -180 L -70 -50 Z L 10 40 Z M 30 50 L 120 70 Z T 60 220')"}, {at: -1, expect: 'path("M -190 -180 L -70 -50 Z L 10 40 Z M 30 50 L 120 70 Z T 60 220")'},
{at: 0, expect: "path('M 10 20 L 50 70 Z L 50 80 Z M 70 90 L 160 150 Z T 140 220')"}, {at: 0, expect: 'path("M 10 20 L 50 70 Z L 50 80 Z M 70 90 L 160 150 Z T 140 220")'},
{at: 0.125, expect: "path('M 35 45 L 65 85 Z L 55 85 Z M 75 95 L 165 160 Z T 150 220')"}, {at: 0.125, expect: 'path("M 35 45 L 65 85 Z L 55 85 Z M 75 95 L 165 160 Z T 150 220")'},
{at: 0.875, expect: "path('M 185 195 L 155 175 Z L 85 115 Z M 105 125 L 195 220 Z T 210 220')"}, {at: 0.875, expect: 'path("M 185 195 L 155 175 Z L 85 115 Z M 105 125 L 195 220 Z T 210 220")'},
{at: 1, expect: "path('M 210 220 L 170 190 Z L 90 120 Z M 110 130 L 200 230 Z T 220 220')"}, {at: 1, expect: 'path("M 210 220 L 170 190 Z L 90 120 Z M 110 130 L 200 230 Z T 220 220")'},
{at: 2, expect: "path('M 410 420 L 290 310 Z L 130 160 Z M 150 170 L 240 310 Z T 300 220')"} {at: 2, expect: 'path("M 410 420 L 290 310 Z L 130 160 Z M 150 170 L 240 310 Z T 300 220")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 c 40 50 30 60 80 70 c 120 130 170 140 110 160')", from: 'path("m 10 20 c 40 50 30 60 80 70 c 120 130 170 140 110 160")',
to: "path('M 130 100 C 130 150 120 160 210 170 C 290 300 340 310 320 330')" to: 'path("M 130 100 C 130 150 120 160 210 170 C 290 300 340 310 320 330")'
}, [ }, [
{at: -1, expect: "path('M -110 -60 C -30 -10 -40 0 -30 10 C 130 140 180 150 80 170')"}, {at: -1, expect: 'path("M -110 -60 C -30 -10 -40 0 -30 10 C 130 140 180 150 80 170")'},
{at: 0, expect: "path('M 10 20 C 50 70 40 80 90 90 C 210 220 260 230 200 250')"}, {at: 0, expect: 'path("M 10 20 C 50 70 40 80 90 90 C 210 220 260 230 200 250")'},
{at: 0.125, expect: "path('M 25 30 C 60 80 50 90 105 100 C 220 230 270 240 215 260')"}, {at: 0.125, expect: 'path("M 25 30 C 60 80 50 90 105 100 C 220 230 270 240 215 260")'},
{at: 0.875, expect: "path('M 115 90 C 120 140 110 150 195 160 C 280 290 330 300 305 320')"}, {at: 0.875, expect: 'path("M 115 90 C 120 140 110 150 195 160 C 280 290 330 300 305 320")'},
{at: 1, expect: "path('M 130 100 C 130 150 120 160 210 170 C 290 300 340 310 320 330')"}, {at: 1, expect: 'path("M 130 100 C 130 150 120 160 210 170 C 290 300 340 310 320 330")'},
{at: 2, expect: "path('M 250 180 C 210 230 200 240 330 250 C 370 380 420 390 440 410')"} {at: 2, expect: 'path("M 250 180 C 210 230 200 240 330 250 C 370 380 420 390 440 410")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 q 30 60 40 50 q 110 80 90 80')", from: 'path("m 10 20 q 30 60 40 50 q 110 80 90 80")',
to: "path('M 130 100 Q 120 160 130 150 Q 200 150 180 190')" to: 'path("M 130 100 Q 120 160 130 150 Q 200 150 180 190")'
}, [ }, [
{at: -1, expect: "path('M -110 -60 Q -40 0 -30 -10 Q 120 150 100 110')"}, {at: -1, expect: 'path("M -110 -60 Q -40 0 -30 -10 Q 120 150 100 110")'},
{at: 0, expect: "path('M 10 20 Q 40 80 50 70 Q 160 150 140 150')"}, {at: 0, expect: 'path("M 10 20 Q 40 80 50 70 Q 160 150 140 150")'},
{at: 0.125, expect: "path('M 25 30 Q 50 90 60 80 Q 165 150 145 155')"}, {at: 0.125, expect: 'path("M 25 30 Q 50 90 60 80 Q 165 150 145 155")'},
{at: 0.875, expect: "path('M 115 90 Q 110 150 120 140 Q 195 150 175 185')"}, {at: 0.875, expect: 'path("M 115 90 Q 110 150 120 140 Q 195 150 175 185")'},
{at: 1, expect: "path('M 130 100 Q 120 160 130 150 Q 200 150 180 190')"}, {at: 1, expect: 'path("M 130 100 Q 120 160 130 150 Q 200 150 180 190")'},
{at: 2, expect: "path('M 250 180 Q 200 240 210 230 Q 240 150 220 230')"} {at: 2, expect: 'path("M 250 180 Q 200 240 210 230 Q 240 150 220 230")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 s 30 60 40 50 s 110 60 90 70')", from: 'path("m 10 20 s 30 60 40 50 s 110 60 90 70")',
to: "path('M 130 140 S 120 160 130 150 S 200 170 140 180')" to: 'path("M 130 140 S 120 160 130 150 S 200 170 140 180")'
}, [ }, [
{at: -1, expect: "path('M -110 -100 S -40 0 -30 -10 S 120 90 140 100')"}, {at: -1, expect: 'path("M -110 -100 S -40 0 -30 -10 S 120 90 140 100")'},
{at: 0, expect: "path('M 10 20 S 40 80 50 70 S 160 130 140 140')"}, {at: 0, expect: 'path("M 10 20 S 40 80 50 70 S 160 130 140 140")'},
{at: 0.125, expect: "path('M 25 35 S 50 90 60 80 S 165 135 140 145')"}, {at: 0.125, expect: 'path("M 25 35 S 50 90 60 80 S 165 135 140 145")'},
{at: 0.875, expect: "path('M 115 125 S 110 150 120 140 S 195 165 140 175')"}, {at: 0.875, expect: 'path("M 115 125 S 110 150 120 140 S 195 165 140 175")'},
{at: 1, expect: "path('M 130 140 S 120 160 130 150 S 200 170 140 180')"}, {at: 1, expect: 'path("M 130 140 S 120 160 130 150 S 200 170 140 180")'},
{at: 2, expect: "path('M 250 260 S 200 240 210 230 S 240 210 140 220')"} {at: 2, expect: 'path("M 250 260 S 200 240 210 230 S 240 210 140 220")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 h 30 v 60 h 10 v -10 l 110 60 Z')", from: 'path("m 10 20 h 30 v 60 h 10 v -10 l 110 60 Z")',
to: "path('M 130 140 H 120 V 160 H 130 V 150 L 200 170 Z')" to: 'path("M 130 140 H 120 V 160 H 130 V 150 L 200 170 Z")'
}, [ }, [
{at: -1, expect: "path('M -110 -100 H -40 V 0 H -30 V -10 L 120 90 Z')"}, {at: -1, expect: 'path("M -110 -100 H -40 V 0 H -30 V -10 L 120 90 Z")'},
{at: 0, expect: "path('M 10 20 H 40 V 80 H 50 V 70 L 160 130 Z')"}, {at: 0, expect: 'path("M 10 20 H 40 V 80 H 50 V 70 L 160 130 Z")'},
{at: 0.125, expect: "path('M 25 35 H 50 V 90 H 60 V 80 L 165 135 Z')"}, {at: 0.125, expect: 'path("M 25 35 H 50 V 90 H 60 V 80 L 165 135 Z")'},
{at: 0.875, expect: "path('M 115 125 H 110 V 150 H 120 V 140 L 195 165 Z')"}, {at: 0.875, expect: 'path("M 115 125 H 110 V 150 H 120 V 140 L 195 165 Z")'},
{at: 1, expect: "path('M 130 140 H 120 V 160 H 130 V 150 L 200 170 Z')"}, {at: 1, expect: 'path("M 130 140 H 120 V 160 H 130 V 150 L 200 170 Z")'},
{at: 2, expect: "path('M 250 260 H 200 V 240 H 210 V 230 L 240 210 Z')"} {at: 2, expect: 'path("M 250 260 H 200 V 240 H 210 V 230 L 240 210 Z")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50')", from: 'path("m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50")',
to: "path('M 18 12 A 50 100 70 0 1 90 110 A 150 160 70 0 1 70 80')" to: 'path("M 18 12 A 50 100 70 0 1 90 110 A 150 160 70 0 1 70 80")'
}, [ }, [
{at: -1, expect: "path('M 2 28 A -30 -60 -10 1 0 10 30 A 70 80 -10 1 1 310 160')"}, {at: -1, expect: 'path("M 2 28 A -30 -60 -10 1 0 10 30 A 70 80 -10 1 1 310 160")'},
{at: 0, expect: "path('M 10 20 A 10 20 30 1 0 50 70 A 110 120 30 1 1 190 120')"}, {at: 0, expect: 'path("M 10 20 A 10 20 30 1 0 50 70 A 110 120 30 1 1 190 120")'},
{at: 0.125, expect: "path('M 11 19 A 15 30 35 1 0 55 75 A 115 125 35 1 1 175 115')"}, {at: 0.125, expect: 'path("M 11 19 A 15 30 35 1 0 55 75 A 115 125 35 1 1 175 115")'},
{at: 0.875, expect: "path('M 17 13 A 45 90 65 0 1 85 105 A 145 155 65 0 1 85 85')"}, {at: 0.875, expect: 'path("M 17 13 A 45 90 65 0 1 85 105 A 145 155 65 0 1 85 85")'},
{at: 1, expect: "path('M 18 12 A 50 100 70 0 1 90 110 A 150 160 70 0 1 70 80')"}, {at: 1, expect: 'path("M 18 12 A 50 100 70 0 1 90 110 A 150 160 70 0 1 70 80")'},
{at: 2, expect: "path('M 26 4 A 90 180 110 0 1 130 150 A 190 200 110 0 1 -50 40')"} {at: 2, expect: 'path("M 26 4 A 90 180 110 0 1 130 150 A 190 200 110 0 1 -50 40")'}
]); ]);
]]></script> ]]></script>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Before After
Before After

View file

@ -17,229 +17,229 @@
// Exercise each segment type // Exercise each segment type
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 20 70')", from: 'path("M 20 70")',
to: "path('M 100 30')" to: 'path("M 100 30")'
}, [ }, [
{at: -1, expect: "path('M -60 110')"}, {at: -1, expect: 'path("M -60 110")'},
{at: 0, expect: "path('M 20 70')"}, {at: 0, expect: 'path("M 20 70")'},
{at: 0.125, expect: "path('M 30 65')"}, {at: 0.125, expect: 'path("M 30 65")'},
{at: 0.875, expect: "path('M 90 35')"}, {at: 0.875, expect: 'path("M 90 35")'},
{at: 1, expect: "path('M 100 30')"}, {at: 1, expect: 'path("M 100 30")'},
{at: 2, expect: "path('M 180 -10')"} {at: 2, expect: 'path("M 180 -10")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 20 70')", from: 'path("m 20 70")',
to: "path('m 100 30')" to: 'path("m 100 30")'
}, [ }, [
{at: -1, expect: "path('M -60 110')"}, {at: -1, expect: 'path("M -60 110")'},
{at: 0, expect: "path('M 20 70')"}, {at: 0, expect: 'path("M 20 70")'},
{at: 0.125, expect: "path('M 30 65')"}, {at: 0.125, expect: 'path("M 30 65")'},
{at: 0.875, expect: "path('M 90 35')"}, {at: 0.875, expect: 'path("M 90 35")'},
{at: 1, expect: "path('M 100 30')"}, {at: 1, expect: 'path("M 100 30")'},
{at: 2, expect: "path('M 180 -10')"} {at: 2, expect: 'path("M 180 -10")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 100 200 L 120 270')", from: 'path("m 100 200 L 120 270")',
to: "path('m 100 200 L 200 230')" to: 'path("m 100 200 L 200 230")'
}, [ }, [
{at: -1, expect: "path('M 100 200 L 40 310')"}, {at: -1, expect: 'path("M 100 200 L 40 310")'},
{at: 0, expect: "path('M 100 200 L 120 270')"}, {at: 0, expect: 'path("M 100 200 L 120 270")'},
{at: 0.125, expect: "path('M 100 200 L 130 265')"}, {at: 0.125, expect: 'path("M 100 200 L 130 265")'},
{at: 0.875, expect: "path('M 100 200 L 190 235')"}, {at: 0.875, expect: 'path("M 100 200 L 190 235")'},
{at: 1, expect: "path('M 100 200 L 200 230')"}, {at: 1, expect: 'path("M 100 200 L 200 230")'},
{at: 2, expect: "path('M 100 200 L 280 190')"} {at: 2, expect: 'path("M 100 200 L 280 190")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 100 200 l 20 70')", from: 'path("m 100 200 l 20 70")',
to: "path('m 100 200 l 100 30')" to: 'path("m 100 200 l 100 30")'
}, [ }, [
{at: -1, expect: "path('M 100 200 L 40 310')"}, {at: -1, expect: 'path("M 100 200 L 40 310")'},
{at: 0, expect: "path('M 100 200 L 120 270')"}, {at: 0, expect: 'path("M 100 200 L 120 270")'},
{at: 0.125, expect: "path('M 100 200 L 130 265')"}, {at: 0.125, expect: 'path("M 100 200 L 130 265")'},
{at: 0.875, expect: "path('M 100 200 L 190 235')"}, {at: 0.875, expect: 'path("M 100 200 L 190 235")'},
{at: 1, expect: "path('M 100 200 L 200 230')"}, {at: 1, expect: 'path("M 100 200 L 200 230")'},
{at: 2, expect: "path('M 100 200 L 280 190')"} {at: 2, expect: 'path("M 100 200 L 280 190")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 20 10 C 32 42 52 62 120 2200')", from: 'path("M 20 10 C 32 42 52 62 120 2200")',
to: "path('M 20 10 C 40 50 60 70 200 3000')", to: 'path("M 20 10 C 40 50 60 70 200 3000")',
}, [ }, [
{at: -1, expect: "path('M 20 10 C 24 34 44 54 40 1400')"}, {at: -1, expect: 'path("M 20 10 C 24 34 44 54 40 1400")'},
{at: 0, expect: "path('M 20 10 C 32 42 52 62 120 2200')"}, {at: 0, expect: 'path("M 20 10 C 32 42 52 62 120 2200")'},
{at: 0.125, expect: "path('M 20 10 C 33 43 53 63 130 2300')"}, {at: 0.125, expect: 'path("M 20 10 C 33 43 53 63 130 2300")'},
{at: 0.875, expect: "path('M 20 10 C 39 49 59 69 190 2900')"}, {at: 0.875, expect: 'path("M 20 10 C 39 49 59 69 190 2900")'},
{at: 1, expect: "path('M 20 10 C 40 50 60 70 200 3000')"}, {at: 1, expect: 'path("M 20 10 C 40 50 60 70 200 3000")'},
{at: 2, expect: "path('M 20 10 C 48 58 68 78 280 3800')"} {at: 2, expect: 'path("M 20 10 C 48 58 68 78 280 3800")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 20 10 c 12 32 32 52 100 2190')", from: 'path("m 20 10 c 12 32 32 52 100 2190")',
to: "path('m 20 10 c 20 40 40 60 180 2990')" to: 'path("m 20 10 c 20 40 40 60 180 2990")'
}, [ }, [
{at: -1, expect: "path('M 20 10 C 24 34 44 54 40 1400')"}, {at: -1, expect: 'path("M 20 10 C 24 34 44 54 40 1400")'},
{at: 0, expect: "path('M 20 10 C 32 42 52 62 120 2200')"}, {at: 0, expect: 'path("M 20 10 C 32 42 52 62 120 2200")'},
{at: 0.125, expect: "path('M 20 10 C 33 43 53 63 130 2300')"}, {at: 0.125, expect: 'path("M 20 10 C 33 43 53 63 130 2300")'},
{at: 0.875, expect: "path('M 20 10 C 39 49 59 69 190 2900')"}, {at: 0.875, expect: 'path("M 20 10 C 39 49 59 69 190 2900")'},
{at: 1, expect: "path('M 20 10 C 40 50 60 70 200 3000')"}, {at: 1, expect: 'path("M 20 10 C 40 50 60 70 200 3000")'},
{at: 2, expect: "path('M 20 10 C 48 58 68 78 280 3800')"} {at: 2, expect: 'path("M 20 10 C 48 58 68 78 280 3800")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 20 10 Q 32 42 120 2200')", from: 'path("M 20 10 Q 32 42 120 2200")',
to: "path('M 20 10 Q 40 50 200 3000')" to: 'path("M 20 10 Q 40 50 200 3000")'
}, [ }, [
{at: -1, expect: "path('M 20 10 Q 24 34 40 1400')"}, {at: -1, expect: 'path("M 20 10 Q 24 34 40 1400")'},
{at: 0, expect: "path('M 20 10 Q 32 42 120 2200')"}, {at: 0, expect: 'path("M 20 10 Q 32 42 120 2200")'},
{at: 0.125, expect: "path('M 20 10 Q 33 43 130 2300')"}, {at: 0.125, expect: 'path("M 20 10 Q 33 43 130 2300")'},
{at: 0.875, expect: "path('M 20 10 Q 39 49 190 2900')"}, {at: 0.875, expect: 'path("M 20 10 Q 39 49 190 2900")'},
{at: 1, expect: "path('M 20 10 Q 40 50 200 3000')"}, {at: 1, expect: 'path("M 20 10 Q 40 50 200 3000")'},
{at: 2, expect: "path('M 20 10 Q 48 58 280 3800')"} {at: 2, expect: 'path("M 20 10 Q 48 58 280 3800")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 20 10 q 12 32 100 2190')", from: 'path("m 20 10 q 12 32 100 2190")',
to: "path('m 20 10 q 20 40 180 2990')" to: 'path("m 20 10 q 20 40 180 2990")'
}, [ }, [
{at: -1, expect: "path('M 20 10 Q 24 34 40 1400')"}, {at: -1, expect: 'path("M 20 10 Q 24 34 40 1400")'},
{at: 0, expect: "path('M 20 10 Q 32 42 120 2200')"}, {at: 0, expect: 'path("M 20 10 Q 32 42 120 2200")'},
{at: 0.125, expect: "path('M 20 10 Q 33 43 130 2300')"}, {at: 0.125, expect: 'path("M 20 10 Q 33 43 130 2300")'},
{at: 0.875, expect: "path('M 20 10 Q 39 49 190 2900')"}, {at: 0.875, expect: 'path("M 20 10 Q 39 49 190 2900")'},
{at: 1, expect: "path('M 20 10 Q 40 50 200 3000')"}, {at: 1, expect: 'path("M 20 10 Q 40 50 200 3000")'},
{at: 2, expect: "path('M 20 10 Q 48 58 280 3800')"} {at: 2, expect: 'path("M 20 10 Q 48 58 280 3800")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 100 400 A 10 20 30 1 0 140 450')", from: 'path("M 100 400 A 10 20 30 1 0 140 450")',
to: "path('M 300 200 A 50 60 70 0 1 380 290')" to: 'path("M 300 200 A 50 60 70 0 1 380 290")'
}, [ }, [
{at: -1, expect: "path('M -100 600 A -30 -20 -10 1 0 -100 610')"}, {at: -1, expect: 'path("M -100 600 A -30 -20 -10 1 0 -100 610")'},
{at: 0, expect: "path('M 100 400 A 10 20 30 1 0 140 450')"}, {at: 0, expect: 'path("M 100 400 A 10 20 30 1 0 140 450")'},
{at: 0.125, expect: "path('M 125 375 A 15 25 35 1 0 170 430')"}, {at: 0.125, expect: 'path("M 125 375 A 15 25 35 1 0 170 430")'},
{at: 0.875, expect: "path('M 275 225 A 45 55 65 0 1 350 310')"}, {at: 0.875, expect: 'path("M 275 225 A 45 55 65 0 1 350 310")'},
{at: 1, expect: "path('M 300 200 A 50 60 70 0 1 380 290')"}, {at: 1, expect: 'path("M 300 200 A 50 60 70 0 1 380 290")'},
{at: 2, expect: "path('M 500 0 A 90 100 110 0 1 620 130')"} {at: 2, expect: 'path("M 500 0 A 90 100 110 0 1 620 130")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 100 400 a 10 20 30 1 0 40 50')", from: 'path("m 100 400 a 10 20 30 1 0 40 50")',
to: "path('m 300 200 a 50 60 70 0 1 80 90')" to: 'path("m 300 200 a 50 60 70 0 1 80 90")'
}, [ }, [
{at: -1, expect: "path('M -100 600 A -30 -20 -10 1 0 -100 610')"}, {at: -1, expect: 'path("M -100 600 A -30 -20 -10 1 0 -100 610")'},
{at: 0, expect: "path('M 100 400 A 10 20 30 1 0 140 450')"}, {at: 0, expect: 'path("M 100 400 A 10 20 30 1 0 140 450")'},
{at: 0.125, expect: "path('M 125 375 A 15 25 35 1 0 170 430')"}, {at: 0.125, expect: 'path("M 125 375 A 15 25 35 1 0 170 430")'},
{at: 0.875, expect: "path('M 275 225 A 45 55 65 0 1 350 310')"}, {at: 0.875, expect: 'path("M 275 225 A 45 55 65 0 1 350 310")'},
{at: 1, expect: "path('M 300 200 A 50 60 70 0 1 380 290')"}, {at: 1, expect: 'path("M 300 200 A 50 60 70 0 1 380 290")'},
{at: 2, expect: "path('M 500 0 A 90 100 110 0 1 620 130')"} {at: 2, expect: 'path("M 500 0 A 90 100 110 0 1 620 130")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 50 60 H 70')", from: 'path("M 50 60 H 70")',
to: "path('M 10 140 H 270')" to: 'path("M 10 140 H 270")'
}, [ }, [
{at: -1, expect: "path('M 90 -20 H -130')"}, {at: -1, expect: 'path("M 90 -20 H -130")'},
{at: 0, expect: "path('M 50 60 H 70')"}, {at: 0, expect: 'path("M 50 60 H 70")'},
{at: 0.125, expect: "path('M 45 70 H 95')"}, {at: 0.125, expect: 'path("M 45 70 H 95")'},
{at: 0.875, expect: "path('M 15 130 H 245')"}, {at: 0.875, expect: 'path("M 15 130 H 245")'},
{at: 1, expect: "path('M 10 140 H 270')"}, {at: 1, expect: 'path("M 10 140 H 270")'},
{at: 2, expect: "path('M -30 220 H 470')"} {at: 2, expect: 'path("M -30 220 H 470")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 50 60 h 20')", from: 'path("m 50 60 h 20")',
to: "path('m 10 140 h 260')" to: 'path("m 10 140 h 260")'
}, [ }, [
{at: -1, expect: "path('M 90 -20 H -130')"}, {at: -1, expect: 'path("M 90 -20 H -130")'},
{at: 0, expect: "path('M 50 60 H 70')"}, {at: 0, expect: 'path("M 50 60 H 70")'},
{at: 0.125, expect: "path('M 45 70 H 95')"}, {at: 0.125, expect: 'path("M 45 70 H 95")'},
{at: 0.875, expect: "path('M 15 130 H 245')"}, {at: 0.875, expect: 'path("M 15 130 H 245")'},
{at: 1, expect: "path('M 10 140 H 270')"}, {at: 1, expect: 'path("M 10 140 H 270")'},
{at: 2, expect: "path('M -30 220 H 470')"} {at: 2, expect: 'path("M -30 220 H 470")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 50 60 V 70')", from: 'path("M 50 60 V 70")',
to: "path('M 10 140 V 270')" to: 'path("M 10 140 V 270")'
}, [ }, [
{at: -1, expect: "path('M 90 -20 V -130')"}, {at: -1, expect: 'path("M 90 -20 V -130")'},
{at: 0, expect: "path('M 50 60 V 70')"}, {at: 0, expect: 'path("M 50 60 V 70")'},
{at: 0.125, expect: "path('M 45 70 V 95')"}, {at: 0.125, expect: 'path("M 45 70 V 95")'},
{at: 0.875, expect: "path('M 15 130 V 245')"}, {at: 0.875, expect: 'path("M 15 130 V 245")'},
{at: 1, expect: "path('M 10 140 V 270')"}, {at: 1, expect: 'path("M 10 140 V 270")'},
{at: 2, expect: "path('M -30 220 V 470')"} {at: 2, expect: 'path("M -30 220 V 470")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 50 60 v 10')", from: 'path("m 50 60 v 10")',
to: "path('m 10 140 v 130')" to: 'path("m 10 140 v 130")'
}, [ }, [
{at: -1, expect: "path('M 90 -20 V -130')"}, {at: -1, expect: 'path("M 90 -20 V -130")'},
{at: 0, expect: "path('M 50 60 V 70')"}, {at: 0, expect: 'path("M 50 60 V 70")'},
{at: 0.125, expect: "path('M 45 70 V 95')"}, {at: 0.125, expect: 'path("M 45 70 V 95")'},
{at: 0.875, expect: "path('M 15 130 V 245')"}, {at: 0.875, expect: 'path("M 15 130 V 245")'},
{at: 1, expect: "path('M 10 140 V 270')"}, {at: 1, expect: 'path("M 10 140 V 270")'},
{at: 2, expect: "path('M -30 220 V 470')"} {at: 2, expect: 'path("M -30 220 V 470")'}
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 12 34 S 45 67 89 123')", from: 'path("M 12 34 S 45 67 89 123")',
to: "path('M 20 26 S 61 51 113 99')" to: 'path("M 20 26 S 61 51 113 99")'
}, [ }, [
{at: -1, expect: "path('M 4 42 S 29 83 65 147')"}, {at: -1, expect: 'path("M 4 42 S 29 83 65 147")'},
{at: 0, expect: "path('M 12 34 S 45 67 89 123')"}, {at: 0, expect: 'path("M 12 34 S 45 67 89 123")'},
{at: 0.125, expect: "path('M 13 33 S 47 65 92 120')"}, {at: 0.125, expect: 'path("M 13 33 S 47 65 92 120")'},
{at: 0.875, expect: "path('M 19 27 S 59 53 110 102')"}, {at: 0.875, expect: 'path("M 19 27 S 59 53 110 102")'},
{at: 1, expect: "path('M 20 26 S 61 51 113 99')"}, {at: 1, expect: 'path("M 20 26 S 61 51 113 99")'},
{at: 2, expect: "path('M 28 18 S 77 35 137 75')"}, {at: 2, expect: 'path("M 28 18 S 77 35 137 75")'},
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 12 34 s 33 33 77 89')", from: 'path("m 12 34 s 33 33 77 89")',
to: "path('m 20 26 s 41 25 93 73')" to: 'path("m 20 26 s 41 25 93 73")'
}, [ }, [
{at: -1, expect: "path('M 4 42 S 29 83 65 147')"}, {at: -1, expect: 'path("M 4 42 S 29 83 65 147")'},
{at: 0, expect: "path('M 12 34 S 45 67 89 123')"}, {at: 0, expect: 'path("M 12 34 S 45 67 89 123")'},
{at: 0.125, expect: "path('M 13 33 S 47 65 92 120')"}, {at: 0.125, expect: 'path("M 13 33 S 47 65 92 120")'},
{at: 0.875, expect: "path('M 19 27 S 59 53 110 102')"}, {at: 0.875, expect: 'path("M 19 27 S 59 53 110 102")'},
{at: 1, expect: "path('M 20 26 S 61 51 113 99')"}, {at: 1, expect: 'path("M 20 26 S 61 51 113 99")'},
{at: 2, expect: "path('M 28 18 S 77 35 137 75')"}, {at: 2, expect: 'path("M 28 18 S 77 35 137 75")'},
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('M 12 34 T 45 67')", from: 'path("M 12 34 T 45 67")',
to: "path('M 20 26 T 61 51')" to: 'path("M 20 26 T 61 51")'
}, [ }, [
{at: -1, expect: "path('M 4 42 T 29 83')"}, {at: -1, expect: 'path("M 4 42 T 29 83")'},
{at: 0, expect: "path('M 12 34 T 45 67')"}, {at: 0, expect: 'path("M 12 34 T 45 67")'},
{at: 0.125, expect: "path('M 13 33 T 47 65')"}, {at: 0.125, expect: 'path("M 13 33 T 47 65")'},
{at: 0.875, expect: "path('M 19 27 T 59 53')"}, {at: 0.875, expect: 'path("M 19 27 T 59 53")'},
{at: 1, expect: "path('M 20 26 T 61 51')"}, {at: 1, expect: 'path("M 20 26 T 61 51")'},
{at: 2, expect: "path('M 28 18 T 77 35')"}, {at: 2, expect: 'path("M 28 18 T 77 35")'},
]); ]);
test_interpolation({ test_interpolation({
property: 'd', property: 'd',
from: "path('m 12 34 t 33 33')", from: 'path("m 12 34 t 33 33")',
to: "path('m 20 26 t 41 25')" to: 'path("m 20 26 t 41 25")'
}, [ }, [
{at: -1, expect: "path('M 4 42 T 29 83')"}, {at: -1, expect: 'path("M 4 42 T 29 83")'},
{at: 0, expect: "path('M 12 34 T 45 67')"}, {at: 0, expect: 'path("M 12 34 T 45 67")'},
{at: 0.125, expect: "path('M 13 33 T 47 65')"}, {at: 0.125, expect: 'path("M 13 33 T 47 65")'},
{at: 0.875, expect: "path('M 19 27 T 59 53')"}, {at: 0.875, expect: 'path("M 19 27 T 59 53")'},
{at: 1, expect: "path('M 20 26 T 61 51')"}, {at: 1, expect: 'path("M 20 26 T 61 51")'},
{at: 2, expect: "path('M 28 18 T 77 35')"}, {at: 2, expect: 'path("M 28 18 T 77 35")'},
]); ]);
]]></script> ]]></script>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Before After
Before After

View file

@ -39,14 +39,14 @@
var p6 = document.getElementById('p6'); var p6 = document.getElementById('p6');
var p7 = document.getElementById('p7'); var p7 = document.getElementById('p7');
assert_equals(getComputedStyle(g0).d, "none"); assert_equals(getComputedStyle(g0).d, 'none');
assert_equals(getComputedStyle(p1).d, "none"); assert_equals(getComputedStyle(p1).d, 'none');
assert_equals(getComputedStyle(p2).d, "path('M 10 2 H 20')"); assert_equals(getComputedStyle(p2).d, 'path("M 10 2 H 20")');
assert_equals(getComputedStyle(p3).d, "path('M 10 3 H 30')"); assert_equals(getComputedStyle(p3).d, 'path("M 10 3 H 30")');
assert_equals(getComputedStyle(p4).d, "path('M 10 4 H 40')"); assert_equals(getComputedStyle(p4).d, 'path("M 10 4 H 40")');
assert_equals(getComputedStyle(g5).d, "path('M 10 5 H 50')"); assert_equals(getComputedStyle(g5).d, 'path("M 10 5 H 50")');
assert_equals(getComputedStyle(p6).d, "path('M 10 5 H 50')"); assert_equals(getComputedStyle(p6).d, 'path("M 10 5 H 50")');
assert_equals(getComputedStyle(p7).d, "none"); assert_equals(getComputedStyle(p7).d, 'none');
}); });
]]></script> ]]></script>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

@ -1,6 +1,8 @@
#!/bin/bash #!/bin/bash
set -ex
./wpt manifest-download # This is allowed to fail
./wpt manifest-download || echo
if [ $1 == "firefox" ]; then if [ $1 == "firefox" ]; then
./wpt run firefox --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --this-chunk=$4 --total-chunks=$5 --test-type=$3 -y --install-browser --channel=$2 --no-pause --no-restart-on-unexpected --reftest-internal --install-fonts --no-fail-on-unexpected ./wpt run firefox --log-tbpl=../artifacts/log_tbpl.log --log-tbpl-level=info --log-wptreport=../artifacts/wpt_report.json --log-mach=- --this-chunk=$4 --total-chunks=$5 --test-type=$3 -y --install-browser --channel=$2 --no-pause --no-restart-on-unexpected --reftest-internal --install-fonts --no-fail-on-unexpected

View file

@ -18,14 +18,14 @@ test_infrastructure() {
} }
main() { main() {
PRODUCTS=( "firefox" "chrome" ) PRODUCTS=( "firefox" "chrome" "chrome_webdriver" )
for PRODUCT in "${PRODUCTS[@]}"; do for PRODUCT in "${PRODUCTS[@]}"; do
if [ "$PRODUCT" != "firefox" ]; then if [ "$PRODUCT" != "firefox" ]; then
# Firefox is expected to work using pref settings for DNS # Firefox is expected to work using pref settings for DNS
# Don't adjust the hostnames in that case to ensure this keeps working # Don't adjust the hostnames in that case to ensure this keeps working
hosts_fixup hosts_fixup
fi fi
if [ "$PRODUCT" == "chrome" ]; then if [[ "$PRODUCT" == "chrome"* ]]; then
install_chrome unstable install_chrome unstable
test_infrastructure "--binary=$(which google-chrome-unstable)" test_infrastructure "--binary=$(which google-chrome-unstable)"
else else

View file

@ -6,8 +6,10 @@ class WebDriverException(Exception):
http_status = None http_status = None
status_code = None status_code = None
def __init__(self, message=None, stacktrace=None): def __init__(self, http_status=None, status_code=None, message=None, stacktrace=None):
super(WebDriverException, self) super(WebDriverException, self)
self.http_status = http_status
self.status_code = status_code
self.message = message self.message = message
self.stacktrace = stacktrace self.stacktrace = stacktrace
@ -171,6 +173,8 @@ def from_response(response):
""" """
if response.status == 200: if response.status == 200:
raise UnknownErrorException( raise UnknownErrorException(
response.status,
None,
"Response is not an error:\n" "Response is not an error:\n"
"%s" % json.dumps(response.body)) "%s" % json.dumps(response.body))
@ -178,6 +182,8 @@ def from_response(response):
value = response.body["value"] value = response.body["value"]
else: else:
raise UnknownErrorException( raise UnknownErrorException(
response.status,
None,
"Expected 'value' key in response body:\n" "Expected 'value' key in response body:\n"
"%s" % json.dumps(response.body)) "%s" % json.dumps(response.body))
@ -187,7 +193,7 @@ def from_response(response):
stack = value["stacktrace"] or None stack = value["stacktrace"] or None
cls = get(code) cls = get(code)
return cls(message, stacktrace=stack) return cls(response.status, code, message, stacktrace=stack)
def get(error_code): def get(error_code):

View file

@ -486,6 +486,12 @@ class ChromeAndroid(Browser):
def version(self, binary): def version(self, binary):
return None return None
class ChromeWebDriver(Chrome):
"""Chrome-specific interface for chrome without using selenium.
Includes webdriver installation.
"""
product = "chrome_webdriver"
class Opera(Browser): class Opera(Browser):
"""Opera-specific interface. """Opera-specific interface.
@ -582,6 +588,10 @@ class Edge(Browser):
return None return None
class EdgeWebDriver(Edge):
product = "edge_webdriver"
class InternetExplorer(Browser): class InternetExplorer(Browser):
"""Internet Explorer-specific interface.""" """Internet Explorer-specific interface."""
@ -629,6 +639,10 @@ class Safari(Browser):
return None return None
class SafariWebDriver(Safari):
product = "safari_webdriver"
class Servo(Browser): class Servo(Browser):
"""Servo-specific interface.""" """Servo-specific interface."""

View file

@ -273,6 +273,10 @@ class ChromeAndroid(BrowserSetup):
else: else:
raise WptrunError("Unable to locate or install chromedriver binary") raise WptrunError("Unable to locate or install chromedriver binary")
class ChromeWebDriver(Chrome):
name = "chrome_webdriver"
browser_cls = browser.ChromeWebDriver
class Opera(BrowserSetup): class Opera(BrowserSetup):
name = "opera" name = "opera"
@ -318,6 +322,11 @@ https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
kwargs["webdriver_binary"] = webdriver_binary kwargs["webdriver_binary"] = webdriver_binary
class EdgeWebDriver(Edge):
name = "edge_webdriver"
browser_cls = browser.EdgeWebDriver
class InternetExplorer(BrowserSetup): class InternetExplorer(BrowserSetup):
name = "ie" name = "ie"
browser_cls = browser.InternetExplorer browser_cls = browser.InternetExplorer
@ -356,6 +365,11 @@ class Safari(BrowserSetup):
kwargs["webdriver_binary"] = webdriver_binary kwargs["webdriver_binary"] = webdriver_binary
class SafariWebDriver(Safari):
name = "safari_webdriver"
browser_cls = browser.SafariWebDriver
class Sauce(BrowserSetup): class Sauce(BrowserSetup):
name = "sauce" name = "sauce"
browser_cls = browser.Sauce browser_cls = browser.Sauce
@ -402,9 +416,12 @@ product_setup = {
"firefox": Firefox, "firefox": Firefox,
"chrome": Chrome, "chrome": Chrome,
"chrome_android": ChromeAndroid, "chrome_android": ChromeAndroid,
"chrome_webdriver": ChromeWebDriver,
"edge": Edge, "edge": Edge,
"edge_webdriver": EdgeWebDriver,
"ie": InternetExplorer, "ie": InternetExplorer,
"safari": Safari, "safari": Safari,
"safari_webdriver": SafariWebDriver,
"servo": Servo, "servo": Servo,
"sauce": Sauce, "sauce": Sauce,
"opera": Opera, "opera": Opera,

View file

@ -101,9 +101,6 @@ def main(prog=None, argv=None):
main_args, command_args = parse_args(argv, commands) main_args, command_args = parse_args(argv, commands)
if not(len(argv) and argv[0] in commands):
sys.exit(1)
command = main_args.command command = main_args.command
props = commands[command] props = commands[command]
venv = None venv = None

View file

@ -24,11 +24,14 @@ module global scope.
product_list = ["chrome", product_list = ["chrome",
"chrome_android", "chrome_android",
"chrome_webdriver",
"edge", "edge",
"edge_webdriver",
"fennec", "fennec",
"firefox", "firefox",
"ie", "ie",
"safari", "safari",
"safari_webdriver",
"sauce", "sauce",
"servo", "servo",
"servodriver", "servodriver",

View file

@ -2,12 +2,32 @@ import os
import platform import platform
import socket import socket
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from copy import deepcopy
from ..wptcommandline import require_arg # noqa: F401 from ..wptcommandline import require_arg # noqa: F401
here = os.path.split(__file__)[0] here = os.path.split(__file__)[0]
def inherit(super_module, child_globals, product_name):
super_wptrunner = super_module.__wptrunner__
child_globals["__wptrunner__"] = child_wptrunner = deepcopy(super_wptrunner)
child_wptrunner["product"] = product_name
for k in ("check_args", "browser", "browser_kwargs", "executor_kwargs",
"env_extras", "env_options"):
attr = super_wptrunner[k]
child_globals[attr] = getattr(super_module, attr)
for v in super_module.__wptrunner__["executor"].values():
child_globals[v] = getattr(super_module, v)
if "run_info_extras" in super_wptrunner:
attr = super_wptrunner["run_info_extras"]
child_globals[attr] = getattr(super_module, attr)
def cmd_arg(name, value=None): def cmd_arg(name, value=None):
prefix = "-" if platform.system() == "Windows" else "--" prefix = "-" if platform.system() == "Windows" else "--"
rv = prefix + name rv = prefix + name

View file

@ -0,0 +1,50 @@
from .base import inherit
from . import chrome
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401
WebDriverRefTestExecutor) # noqa: F401
inherit(chrome, globals(), "chrome_webdriver")
# __wptrunner__ magically appears from inherit, F821 is undefined name
__wptrunner__["executor_kwargs"] = "executor_kwargs" # noqa: F821
__wptrunner__["executor"]["testharness"] = "WebDriverTestharnessExecutor" # noqa: F821
__wptrunner__["executor"]["reftest"] = "WebDriverRefTestExecutor" # noqa: F821
def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
**kwargs):
executor_kwargs = base_executor_kwargs(test_type, server_config,
cache_manager, run_info_data,
**kwargs)
executor_kwargs["close_after_done"] = True
capabilities = {
"browserName": "chrome",
"platform": "ANY",
"version": "",
"goog:chromeOptions": {
"prefs": {
"profile": {
"default_content_setting_values": {
"popups": 1
}
}
},
"w3c": True
}
}
for (kwarg, capability) in [("binary", "binary"), ("binary_args", "args")]:
if kwargs[kwarg] is not None:
capabilities["goog:chromeOptions"][capability] = kwargs[kwarg]
if test_type == "testharness":
capabilities["goog:chromeOptions"]["useAutomationExtension"] = False
capabilities["goog:chromeOptions"]["excludeSwitches"] = ["enable-automation"]
executor_kwargs["capabilities"] = capabilities
return executor_kwargs

View file

@ -0,0 +1,12 @@
from .base import inherit
from . import edge
from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401
WebDriverRefTestExecutor) # noqa: F401
inherit(edge, globals(), "edge_webdriver")
# __wptrunner__ magically appears from inherit, F821 is undefined name
__wptrunner__["executor"]["testharness"] = "WebDriverTestharnessExecutor" # noqa: F821
__wptrunner__["executor"]["reftest"] = "WebDriverRefTestExecutor" # noqa: F821

View file

@ -0,0 +1,12 @@
from .base import inherit
from . import safari
from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401
WebDriverRefTestExecutor) # noqa: F401
inherit(safari, globals(), "safari_webdriver")
# __wptrunner__ magically appears from inherit, F821 is undefined name
__wptrunner__["executor"]["testharness"] = "WebDriverTestharnessExecutor" # noqa: F821
__wptrunner__["executor"]["reftest"] = "WebDriverRefTestExecutor" # noqa: F821

View file

@ -95,14 +95,14 @@ class SeleniumTestharnessProtocolPart(TestharnessProtocolPart):
def get_test_window(self, window_id, parent): def get_test_window(self, window_id, parent):
test_window = None test_window = None
if window_id: try:
try: # Try using the JSON serialization of the WindowProxy object,
# Try this, it's in Level 1 but nothing supports it yet # it's in Level 1 but nothing supports it yet
win_s = self.webdriver.execute_script("return window['%s'];" % self.window_id) win_s = self.webdriver.execute_script("return window['%s'];" % window_id)
win_obj = json.loads(win_s) win_obj = json.loads(win_s)
test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"] test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
except Exception: except Exception:
pass pass
if test_window is None: if test_window is None:
after = self.webdriver.window_handles after = self.webdriver.window_handles
@ -296,7 +296,7 @@ class SeleniumTestharnessExecutor(TestharnessExecutor):
parent_window = protocol.testharness.close_old_windows() parent_window = protocol.testharness.close_old_windows()
# Now start the test harness # Now start the test harness
protocol.base.execute_script(self.script % format_map) protocol.base.execute_script(self.script % format_map)
test_window = protocol.testharness.get_test_window(webdriver, parent_window) test_window = protocol.testharness.get_test_window(self.window_id, parent_window)
handler = CallbackHandler(self.logger, protocol, test_window) handler = CallbackHandler(self.logger, protocol, test_window)
while True: while True:

View file

@ -0,0 +1,373 @@
import json
import os
import socket
import threading
import traceback
import urlparse
import uuid
from .base import (CallbackHandler,
RefTestExecutor,
RefTestImplementation,
TestharnessExecutor,
extra_timeout,
strip_server)
from .protocol import (BaseProtocolPart,
TestharnessProtocolPart,
Protocol,
SelectorProtocolPart,
ClickProtocolPart,
SendKeysProtocolPart,
TestDriverProtocolPart)
from ..testrunner import Stop
import webdriver as client
here = os.path.join(os.path.split(__file__)[0])
class WebDriverBaseProtocolPart(BaseProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def execute_script(self, script, async=False):
method = self.webdriver.execute_async_script if async else self.webdriver.execute_script
return method(script)
def set_timeout(self, timeout):
try:
self.webdriver.timeouts.script = timeout
except client.WebDriverException:
# workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2057
body = {"type": "script", "ms": timeout * 1000}
self.webdriver.send_session_command("POST", "timeouts", body)
@property
def current_window(self):
return self.webdriver.window_handle
def set_window(self, handle):
self.webdriver.window_handle = handle
def wait(self):
while True:
try:
self.webdriver.execute_async_script("")
except client.TimeoutException:
pass
except (socket.timeout, client.NoSuchWindowException,
client.UnknownErrorException, IOError):
break
except Exception as e:
self.logger.error(traceback.format_exc(e))
break
class WebDriverTestharnessProtocolPart(TestharnessProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def load_runner(self, url_protocol):
url = urlparse.urljoin(self.parent.executor.server_url(url_protocol),
"/testharness_runner.html")
self.logger.debug("Loading %s" % url)
self.webdriver.url = url
self.webdriver.execute_script("document.title = '%s'" %
threading.current_thread().name.replace("'", '"'))
def close_old_windows(self):
exclude = self.webdriver.window_handle
handles = [item for item in self.webdriver.handles if item != exclude]
for handle in handles:
try:
self.webdriver.window_handle = handle
self.webdriver.close()
except client.NoSuchWindowException:
pass
self.webdriver.window_handle = exclude
return exclude
def get_test_window(self, window_id, parent):
test_window = None
try:
# Try using the JSON serialization of the WindowProxy object,
# it's in Level 1 but nothing supports it yet
win_s = self.webdriver.execute_script("return window['%s'];" % window_id)
win_obj = json.loads(win_s)
test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
except Exception:
pass
if test_window is None:
after = self.webdriver.handles
if len(after) == 2:
test_window = next(iter(set(after) - set([parent])))
elif after[0] == parent and len(after) > 2:
# Hope the first one here is the test window
test_window = after[1]
else:
raise Exception("unable to find test window")
assert test_window != parent
return test_window
class WebDriverSelectorProtocolPart(SelectorProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def elements_by_selector(self, selector):
return self.webdriver.find.css(selector)
class WebDriverClickProtocolPart(ClickProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def element(self, element):
return element.click()
class WebDriverSendKeysProtocolPart(SendKeysProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def send_keys(self, element, keys):
try:
return element.send_keys(keys)
except client.UnknownErrorException as e:
# workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=1999
if (e.http_status != 500 or
e.status_code != "unknown error"):
raise
return element.send_element_command("POST", "value", {"value": list(keys)})
class WebDriverTestDriverProtocolPart(TestDriverProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
def send_message(self, message_type, status, message=None):
obj = {
"type": "testdriver-%s" % str(message_type),
"status": str(status)
}
if message:
obj["message"] = str(message)
self.webdriver.execute_script("window.postMessage(%s, '*')" % json.dumps(obj))
class WebDriverProtocol(Protocol):
implements = [WebDriverBaseProtocolPart,
WebDriverTestharnessProtocolPart,
WebDriverSelectorProtocolPart,
WebDriverClickProtocolPart,
WebDriverSendKeysProtocolPart,
WebDriverTestDriverProtocolPart]
def __init__(self, executor, browser, capabilities, **kwargs):
super(WebDriverProtocol, self).__init__(executor, browser)
self.capabilities = capabilities
self.url = browser.webdriver_url
self.webdriver = None
def connect(self):
"""Connect to browser via WebDriver."""
self.logger.debug("Connecting to WebDriver on URL: %s" % self.url)
host, port = self.url.split(":")[1].strip("/"), self.url.split(':')[-1].strip("/")
capabilities = {"alwaysMatch": self.capabilities}
self.webdriver = client.Session(host, port, capabilities=capabilities)
self.webdriver.start()
def after_conect(self):
pass
def teardown(self):
self.logger.debug("Hanging up on WebDriver session")
try:
self.webdriver.quit()
except Exception:
pass
del self.webdriver
def is_alive(self):
try:
# Get a simple property over the connection
self.webdriver.window_handle
except (socket.timeout, client.UnknownErrorException):
return False
return True
def after_connect(self):
self.testharness.load_runner(self.executor.last_environment["protocol"])
class WebDriverRun(object):
def __init__(self, func, protocol, url, timeout):
self.func = func
self.result = None
self.protocol = protocol
self.url = url
self.timeout = timeout
self.result_flag = threading.Event()
def run(self):
timeout = self.timeout
try:
self.protocol.base.set_timeout((timeout + extra_timeout))
except client.UnknownErrorException:
self.logger.error("Lost WebDriver connection")
return Stop
executor = threading.Thread(target=self._run)
executor.start()
flag = self.result_flag.wait(timeout + 2 * extra_timeout)
if self.result is None:
assert not flag
self.result = False, ("EXTERNAL-TIMEOUT", None)
return self.result
def _run(self):
try:
self.result = True, self.func(self.protocol, self.url, self.timeout)
except client.TimeoutException:
self.result = False, ("EXTERNAL-TIMEOUT", None)
except (socket.timeout, client.UnknownErrorException):
self.result = False, ("CRASH", None)
except Exception as e:
if (isinstance(e, client.WebDriverException) and
e.http_status == 408 and
e.status_code == "asynchronous script timeout"):
# workaround for https://bugs.chromium.org/p/chromedriver/issues/detail?id=2001
self.result = False, ("EXTERNAL-TIMEOUT", None)
else:
message = getattr(e, "message", "")
if message:
message += "\n"
message += traceback.format_exc(e)
self.result = False, ("ERROR", message)
finally:
self.result_flag.set()
class WebDriverTestharnessExecutor(TestharnessExecutor):
supports_testdriver = True
def __init__(self, browser, server_config, timeout_multiplier=1,
close_after_done=True, capabilities=None, debug_info=None,
**kwargs):
"""WebDriver-based executor for testharness.js tests"""
TestharnessExecutor.__init__(self, browser, server_config,
timeout_multiplier=timeout_multiplier,
debug_info=debug_info)
self.protocol = WebDriverProtocol(self, browser, capabilities)
with open(os.path.join(here, "testharness_webdriver.js")) as f:
self.script = f.read()
with open(os.path.join(here, "testharness_webdriver_resume.js")) as f:
self.script_resume = f.read()
self.close_after_done = close_after_done
self.window_id = str(uuid.uuid4())
def is_alive(self):
return self.protocol.is_alive()
def on_environment_change(self, new_environment):
if new_environment["protocol"] != self.last_environment["protocol"]:
self.protocol.testharness.load_runner(new_environment["protocol"])
def do_test(self, test):
url = self.test_url(test)
success, data = WebDriverRun(self.do_testharness,
self.protocol,
url,
test.timeout * self.timeout_multiplier).run()
if success:
return self.convert_result(test, data)
return (test.result_cls(*data), [])
def do_testharness(self, protocol, url, timeout):
format_map = {"abs_url": url,
"url": strip_server(url),
"window_id": self.window_id,
"timeout_multiplier": self.timeout_multiplier,
"timeout": timeout * 1000}
parent_window = protocol.testharness.close_old_windows()
# Now start the test harness
protocol.base.execute_script(self.script % format_map)
test_window = protocol.testharness.get_test_window(self.window_id, parent_window)
handler = CallbackHandler(self.logger, protocol, test_window)
while True:
result = protocol.base.execute_script(
self.script_resume % format_map, async=True)
done, rv = handler(result)
if done:
break
return rv
class WebDriverRefTestExecutor(RefTestExecutor):
def __init__(self, browser, server_config, timeout_multiplier=1,
screenshot_cache=None, close_after_done=True,
debug_info=None, capabilities=None, **kwargs):
"""WebDriver-based executor for reftests"""
RefTestExecutor.__init__(self,
browser,
server_config,
screenshot_cache=screenshot_cache,
timeout_multiplier=timeout_multiplier,
debug_info=debug_info)
self.protocol = WebDriverProtocol(self, browser,
capabilities=capabilities)
self.implementation = RefTestImplementation(self)
self.close_after_done = close_after_done
self.has_window = False
with open(os.path.join(here, "reftest.js")) as f:
self.script = f.read()
with open(os.path.join(here, "reftest-wait_webdriver.js")) as f:
self.wait_script = f.read()
def is_alive(self):
return self.protocol.is_alive()
def do_test(self, test):
self.protocol.webdriver.window.size = (600, 600)
result = self.implementation.run_test(test)
return self.convert_result(test, result)
def screenshot(self, test, viewport_size, dpi):
# https://github.com/w3c/wptrunner/issues/166
assert viewport_size is None
assert dpi is None
return WebDriverRun(self._screenshot,
self.protocol,
self.test_url(test),
test.timeout).run()
def _screenshot(self, protocol, url, timeout):
webdriver = protocol.webdriver
webdriver.url = url
webdriver.execute_async_script(self.wait_script)
screenshot = webdriver.screenshot()
# strip off the data:img/png, part of the url
if screenshot.startswith("data:image/png;base64,"):
screenshot = screenshot.split(",", 1)[1]
return screenshot

View file

@ -96,8 +96,12 @@ class LogHandler(reader.LogHandler):
duration = data["time"] - test.pop("start_time") duration = data["time"] - test.pop("start_time")
test["longest_duration"][data["status"]] = max( test["longest_duration"][data["status"]] = max(
duration, test["longest_duration"][data["status"]]) duration, test["longest_duration"][data["status"]])
# test_timeout is in seconds; convert it to ms. try:
test["timeout"] = data["extra"]["test_timeout"] * 1000 # test_timeout is in seconds; convert it to ms.
test["timeout"] = data["extra"]["test_timeout"] * 1000
except KeyError:
# If a test is skipped, it won't have extra info.
pass
def is_inconsistent(results_dict, iterations): def is_inconsistent(results_dict, iterations):
@ -118,6 +122,8 @@ def find_slow_status(test):
A result status produced by a run that almost times out; None, if no A result status produced by a run that almost times out; None, if no
runs almost time out. runs almost time out.
""" """
if "timeout" not in test:
return None
threshold = test["timeout"] * FLAKY_THRESHOLD threshold = test["timeout"] * FLAKY_THRESHOLD
for status in ['PASS', 'FAIL', 'OK', 'ERROR']: for status in ['PASS', 'FAIL', 'OK', 'ERROR']:
if (status in test["longest_duration"] and if (status in test["longest_duration"] and

View file

@ -17,7 +17,9 @@ if "CURRENT_TOX_ENV" in os.environ:
current_tox_env_split = os.environ["CURRENT_TOX_ENV"].split("-") current_tox_env_split = os.environ["CURRENT_TOX_ENV"].split("-")
tox_env_extra_browsers = { tox_env_extra_browsers = {
"chrome": {"chrome_android"}, "chrome": {"chrome_android", "chrome_webdriver"},
"edge": {"edge_webdriver"},
"safari": {"safari_webdriver"},
"servo": {"servodriver"}, "servo": {"servodriver"},
} }

View file

@ -29,3 +29,5 @@ def test_find_slow_status():
assert stability.find_slow_status({ assert stability.find_slow_status({
"longest_duration": {"TIMEOUT": 10, "FAIL": 81}, "longest_duration": {"TIMEOUT": 10, "FAIL": 81},
"timeout": 100}) == "FAIL" "timeout": 100}) == "FAIL"
assert stability.find_slow_status({
"longest_duration": {"SKIP": 0}}) is None

View file

@ -96,11 +96,38 @@ class UpdateMetadata(Step):
runner.run() runner.run()
class RemoveObsolete(Step):
"""Remove metadata files that don't corespond to an existing test file"""
def create(self, state):
if not state.kwargs["remove_obsolete"]:
return
paths = state.kwargs["test_paths"]
state.tests_path = state.paths["/"]["tests_path"]
state.metadata_path = state.paths["/"]["metadata_path"]
for url_paths in paths.itervalues():
tests_path = url_paths["tests_path"]
metadata_path = url_paths["metadata_path"]
for dirpath, dirnames, filenames in os.walk(metadata_path):
for filename in filenames:
if filename == "__dir__.ini":
continue
if filename.endswith(".ini"):
full_path = os.path.join(dirpath, filename)
rel_path = os.path.relpath(full_path, metadata_path)
test_path = os.path.join(tests_path, rel_path[:-4])
if not os.path.exists(test_path):
os.unlink(full_path)
class UpdateRunner(StepRunner): class UpdateRunner(StepRunner):
"""Runner for doing an overall update.""" """Runner for doing an overall update."""
steps = [LoadConfig, steps = [LoadConfig,
LoadTrees, LoadTrees,
SyncFromUpstream, SyncFromUpstream,
RemoveObsolete,
UpdateMetadata] UpdateMetadata]

View file

@ -565,8 +565,14 @@ def create_parser_update(product_choices=None):
parser.add_argument("--stability", nargs="?", action="store", const="unstable", default=None, parser.add_argument("--stability", nargs="?", action="store", const="unstable", default=None,
help=("Reason for disabling tests. When updating test results, disable tests that have " help=("Reason for disabling tests. When updating test results, disable tests that have "
"inconsistent results across many runs with the given reason.")) "inconsistent results across many runs with the given reason."))
parser.add_argument("--continue", action="store_true", help="Continue a previously started run of the update script") parser.add_argument("--no-remove-obsolete", action="store_false", dest="remove_obsolete", default=True,
parser.add_argument("--abort", action="store_true", help="Clear state from a previous incomplete run of the update script") help=("Don't remove metadata files that no longer correspond to a test file"))
parser.add_argument("--no-store-state", action="store_false", dest="store_state",
help="Store state so that steps can be resumed after failure")
parser.add_argument("--continue", action="store_true",
help="Continue a previously started run of the update script")
parser.add_argument("--abort", action="store_true",
help="Clear state from a previous incomplete run of the update script")
parser.add_argument("--exclude", action="store", nargs="*", parser.add_argument("--exclude", action="store", nargs="*",
help="List of glob-style paths to exclude when syncing tests") help="List of glob-style paths to exclude when syncing tests")
parser.add_argument("--include", action="store", nargs="*", parser.add_argument("--include", action="store", nargs="*",

View file

@ -15,3 +15,59 @@ function assert_function_length(fn, length, description) {
assert_true(propdesc.configurable, "configurable", `${description} length should be configurable`); assert_true(propdesc.configurable, "configurable", `${description} length should be configurable`);
assert_equals(propdesc.value, length, `${description} length should be ${length}`); assert_equals(propdesc.value, length, `${description} length should be ${length}`);
} }
function assert_exported_function(fn, { name, length }, description) {
assert_equals(Object.getPrototypeOf(fn), Function.prototype,
`${description}: prototype`);
assert_function_name(fn, name, description);
assert_function_length(fn, length, description);
}
function assert_Instance(instance, expected_exports) {
assert_equals(Object.getPrototypeOf(instance), WebAssembly.Instance.prototype,
"prototype");
assert_true(Object.isExtensible(instance), "extensible");
assert_equals(instance.exports, instance.exports, "exports should be idempotent");
const exports = instance.exports;
assert_equals(Object.getPrototypeOf(exports), null, "exports prototype");
assert_false(Object.isExtensible(exports), "extensible exports");
for (const [key, expected] of Object.entries(expected_exports)) {
const property = Object.getOwnPropertyDescriptor(exports, key);
assert_equals(typeof property, "object", `${key} should be present`);
assert_false(property.writable, `${key}: writable`);
assert_true(property.enumerable, `${key}: enumerable`);
assert_false(property.configurable, `${key}: configurable`);
const actual = property.value;
assert_true(Object.isExtensible(actual), `${key}: extensible`);
switch (expected.kind) {
case "function":
assert_exported_function(actual, expected, `value of ${key}`);
break;
case "global":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Global.prototype,
`value of ${key}: prototype`);
assert_equals(actual.value, expected.value, `value of ${key}: value`);
assert_equals(actual.valueOf(), expected.value, `value of ${key}: valueOf()`);
break;
case "memory":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Memory.prototype,
`value of ${key}: prototype`);
assert_equals(Object.getPrototypeOf(actual.buffer), ArrayBuffer.prototype,
`value of ${key}: prototype of buffer`);
assert_equals(actual.buffer.byteLength, 0x10000 * expected.size, `value of ${key}: size of buffer`);
const array = new Uint8Array(actual.buffer);
assert_equals(array[0], 0, `value of ${key}: first element of buffer`);
assert_equals(array[array.byteLength - 1], 0, `value of ${key}: last element of buffer`);
break;
case "table":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype,
`value of ${key}: prototype`);
assert_equals(actual.length, expected.length, `value of ${key}: length of table`);
break;
}
}
}

View file

@ -0,0 +1,77 @@
// META: global=jsshell
// META: script=/wasm/jsapi/wasm-constants.js
// META: script=/wasm/jsapi/wasm-module-builder.js
function assert_Module(module) {
assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype,
"Prototype");
assert_true(Object.isExtensible(module), "Extensibility");
}
let emptyModuleBinary;
setup(() => {
emptyModuleBinary = new WasmModuleBuilder().toBuffer();
});
promise_test(t => {
return promise_rejects(t, new TypeError(), WebAssembly.compile());
}, "Missing argument");
promise_test(t => {
const invalidArguments = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
ArrayBuffer,
ArrayBuffer.prototype,
Array.from(emptyModuleBinary),
];
return Promise.all(invalidArguments.map(argument => {
return promise_rejects(t, new TypeError(), WebAssembly.compile(argument),
`compile(${format_value(argument)})`);
}));
}, "Invalid arguments");
promise_test(() => {
const fn = WebAssembly.compile;
const thisValues = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
WebAssembly,
];
return Promise.all(thisValues.map(thisValue => {
return fn.call(thisValue, emptyModuleBinary).then(assert_Module);
}));
}, "Branding");
test(() => {
const promise = WebAssembly.compile(emptyModuleBinary);
assert_equals(Object.getPrototypeOf(promise), Promise.prototype, "prototype");
assert_true(Object.isExtensible(promise), "extensibility");
}, "Promise type");
promise_test(t => {
const buffer = new Uint8Array();
return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.compile(buffer));
}, "Invalid code");
promise_test(() => {
return WebAssembly.compile(emptyModuleBinary).then(assert_Module);
}, "Result type");
promise_test(() => {
const buffer = new WasmModuleBuilder().toBuffer();
assert_equals(buffer[0], 0);
const promise = WebAssembly.compile(buffer);
buffer[0] = 1;
return promise.then(assert_Module);
}, "Changing the buffer");

View file

@ -0,0 +1,196 @@
// META: global=jsshell
// META: script=/wasm/jsapi/wasm-constants.js
// META: script=/wasm/jsapi/wasm-module-builder.js
// META: script=/wasm/jsapi/assertions.js
function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) {
assert_equals(Object.getPrototypeOf(actual), Object.prototype,
"Prototype");
assert_true(Object.isExtensible(actual), "Extensibility");
const module = Object.getOwnPropertyDescriptor(actual, "module");
assert_equals(typeof module, "object", "module: type of descriptor");
assert_true(module.writable, "module: writable");
assert_true(module.enumerable, "module: enumerable");
assert_true(module.configurable, "module: configurable");
assert_equals(Object.getPrototypeOf(module.value), WebAssembly.Module.prototype,
"module: prototype");
const instance = Object.getOwnPropertyDescriptor(actual, "instance");
assert_equals(typeof instance, "object", "instance: type of descriptor");
assert_true(instance.writable, "instance: writable");
assert_true(instance.enumerable, "instance: enumerable");
assert_true(instance.configurable, "instance: configurable");
assert_Instance(instance.value, expected_exports);
}
let emptyModuleBinary;
setup(() => {
emptyModuleBinary = new WasmModuleBuilder().toBuffer();
});
promise_test(t => {
return promise_rejects(t, new TypeError(), WebAssembly.instantiate());
}, "Missing arguments");
promise_test(() => {
const fn = WebAssembly.instantiate;
const thisValues = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
WebAssembly,
];
return Promise.all(thisValues.map(thisValue => {
return fn.call(thisValue, emptyModuleBinary).then(assert_WebAssemblyInstantiatedSource);
}));
}, "Branding");
promise_test(t => {
const invalidArguments = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
WebAssembly.Module,
WebAssembly.Module.prototype,
ArrayBuffer,
ArrayBuffer.prototype,
Array.from(emptyModuleBinary),
];
return Promise.all(invalidArguments.map(argument => {
return promise_rejects(t, new TypeError(), WebAssembly.instantiate(argument),
`instantiate(${format_value(argument)})`);
}));
}, "Invalid arguments");
test(() => {
const promise = WebAssembly.instantiate(emptyModuleBinary);
assert_equals(Object.getPrototypeOf(promise), Promise.prototype, "prototype");
assert_true(Object.isExtensible(promise), "extensibility");
}, "Promise type");
const createModule = () => {
const builder = new WasmModuleBuilder();
builder
.addFunction("fn", kSig_v_d)
.addBody([
kExprEnd
])
.exportFunc();
builder
.addFunction("fn2", kSig_v_v)
.addBody([
kExprEnd
])
.exportFunc();
builder.setFunctionTableLength(1);
builder.addExportOfKind("table", kExternalTable, 0);
builder.addGlobal(kWasmI32, true)
.exportAs("global")
.init = 7;
builder.addGlobal(kWasmF64, true)
.exportAs("global2")
.init = 1.2;
builder.addMemory(4, 8, true);
const buffer = builder.toBuffer();
const exports = {
"fn": { "kind": "function", "name": "0", "length": 1 },
"fn2": { "kind": "function", "name": "1", "length": 0 },
"table": { "kind": "table", "length": 1 },
"global": { "kind": "global", "value": 7 },
"global2": { "kind": "global", "value": 1.2 },
"memory": { "kind": "memory", "size": 4 },
};
return [buffer, exports];
}
promise_test(() => {
const [buffer, expected] = createModule();
return WebAssembly.instantiate(buffer).then(result => assert_WebAssemblyInstantiatedSource(result, expected));
}, "BufferSource argument");
promise_test(() => {
const [buffer, expected] = createModule();
const module = new WebAssembly.Module(buffer);
return WebAssembly.instantiate(module).then(instance => assert_Instance(instance, expected));
}, "Module argument");
const createModuleWithImports = () => {
const builder = new WasmModuleBuilder();
const index = builder.addImportedGlobal("module", "global", kWasmI32);
builder
.addFunction("fn", kSig_i_v)
.addBody([
kExprGetGlobal,
index,
kExprReturn,
kExprEnd,
])
.exportFunc();
const buffer = builder.toBuffer();
const expected = {
"fn": { "kind": "function", "name": "0", "length": 0 },
};
return [buffer, expected];
};
promise_test(() => {
const [buffer, expected] = createModuleWithImports();
const value = 102;
return WebAssembly.instantiate(buffer, {
"module": {
"global": value,
},
}).then(result => {
assert_WebAssemblyInstantiatedSource(result, expected)
assert_equals(result.instance.exports.fn(), value);
});
}, "exports and imports: buffer argument");
promise_test(() => {
const [buffer, expected] = createModuleWithImports();
const module = new WebAssembly.Module(buffer);
const value = 102;
return WebAssembly.instantiate(module, {
"module": {
"global": value,
},
}).then(instance => {
assert_Instance(instance, expected)
assert_equals(instance.exports.fn(), value);
});
}, "exports and imports: Module argument");
promise_test(t => {
const buffer = new Uint8Array();
return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.instantiate(buffer));
}, "Invalid code");
promise_test(() => {
const buffer = new WasmModuleBuilder().toBuffer();
assert_equals(buffer[0], 0);
const promise = WebAssembly.instantiate(buffer);
buffer[0] = 1;
return promise.then(assert_WebAssemblyInstantiatedSource);
}, "Changing the buffer");

View file

@ -0,0 +1,96 @@
// META: global=jsshell
// META: script=/wasm/jsapi/wasm-constants.js
// META: script=/wasm/jsapi/wasm-module-builder.js
let emptyModuleBinary;
setup(() => {
emptyModuleBinary = new WasmModuleBuilder().toBuffer();
});
test(() => {
assert_throws(new TypeError(), () => WebAssembly.validate());
}, "Missing argument");
test(() => {
const invalidArguments = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
ArrayBuffer,
ArrayBuffer.prototype,
Array.from(emptyModuleBinary),
];
for (const argument of invalidArguments) {
assert_throws(new TypeError(), () => WebAssembly.validate(argument),
`validate(${format_value(argument)})`);
}
}, "Invalid arguments");
test(() => {
const fn = WebAssembly.validate;
const thisValues = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
WebAssembly,
];
for (const thisValue of thisValues) {
assert_true(fn.call(thisValue, emptyModuleBinary), `this=${format_value(thisValue)}`);
}
}, "Branding");
const modules = [
// Incomplete header.
[[], false],
[[0x00], false],
[[0x00, 0x61], false],
[[0x00, 0x61, 0x73], false],
[[0x00, 0x61, 0x73, 0x6d], false],
[[0x00, 0x61, 0x73, 0x6d, 0x01], false],
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00], false],
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00], false],
// Complete header.
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00], true],
// Invalid version.
[[0x00, 0x61, 0x73, 0x6d, 0x00, 0x00, 0x00, 0x00], false],
[[0x00, 0x61, 0x73, 0x6d, 0x02, 0x00, 0x00, 0x00], false],
// Nameless custom section.
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00], false],
// Custom section with empty name.
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00], true],
// Custom section with name "a".
[[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x61], true],
];
const bufferTypes = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
];
for (const [module, expected] of modules) {
const name = module.map(n => n.toString(16)).join(" ");
for (const bufferType of bufferTypes) {
if (module.length % bufferType.BYTES_PER_ELEMENT === 0) {
test(() => {
const bytes = new Uint8Array(module);
const moduleBuffer = new bufferType(bytes.buffer);
assert_equals(WebAssembly.validate(moduleBuffer), expected);
}, `Validating module [${name}] in ${bufferType.name}`);
}
}
}

View file

@ -3,62 +3,6 @@
// META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/wasm-module-builder.js
// META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/assertions.js
function assert_exported_function(fn, { name, length }, description) {
assert_equals(Object.getPrototypeOf(fn), Function.prototype,
`${description}: prototype`);
assert_function_name(fn, name, description);
assert_function_length(fn, length, description);
}
function assert_Instance(instance, expected_exports) {
assert_equals(Object.getPrototypeOf(instance), WebAssembly.Instance.prototype,
"prototype");
assert_true(Object.isExtensible(instance), "extensible");
assert_equals(instance.exports, instance.exports, "exports should be idempotent");
const exports = instance.exports;
assert_equals(Object.getPrototypeOf(exports), null, "exports prototype");
assert_false(Object.isExtensible(exports), "extensible exports");
for (const [key, expected] of Object.entries(expected_exports)) {
const property = Object.getOwnPropertyDescriptor(exports, key);
assert_equals(typeof property, "object", `${key} should be present`);
assert_false(property.writable, `${key}: writable`);
assert_true(property.enumerable, `${key}: enumerable`);
assert_false(property.configurable, `${key}: configurable`);
const actual = property.value;
assert_true(Object.isExtensible(actual), `${key}: extensible`);
switch (expected.kind) {
case "function":
assert_exported_function(actual, expected, `value of ${key}`);
break;
case "global":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Global.prototype,
`value of ${key}: prototype`);
assert_equals(actual.value, expected.value, `value of ${key}: value`);
assert_equals(actual.valueOf(), expected.value, `value of ${key}: valueOf()`);
break;
case "memory":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Memory.prototype,
`value of ${key}: prototype`);
assert_equals(Object.getPrototypeOf(actual.buffer), ArrayBuffer.prototype,
`value of ${key}: prototype of buffer`);
assert_equals(actual.buffer.byteLength, 0x10000 * expected.size, `value of ${key}: size of buffer`);
const array = new Uint8Array(actual.buffer);
assert_equals(array[0], 0, `value of ${key}: first element of buffer`);
assert_equals(array[array.byteLength - 1], 0, `value of ${key}: last element of buffer`);
break;
case "table":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype,
`value of ${key}: prototype`);
assert_equals(actual.length, expected.length, `value of ${key}: length of table`);
break;
}
}
}
let emptyModuleBinary; let emptyModuleBinary;
setup(() => { setup(() => {
emptyModuleBinary = new WasmModuleBuilder().toBuffer(); emptyModuleBinary = new WasmModuleBuilder().toBuffer();
@ -130,6 +74,8 @@ test(() => {
test(() => { test(() => {
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addImportedGlobal("module", "global1", kWasmI32); builder.addImportedGlobal("module", "global1", kWasmI32);
builder.addImportedGlobal("module2", "global3", kWasmI32);
builder.addImportedMemory("module", "memory", 0, 128);
builder.addImportedGlobal("module", "global2", kWasmI32); builder.addImportedGlobal("module", "global2", kWasmI32);
const buffer = builder.toBuffer(); const buffer = builder.toBuffer();
const module = new WebAssembly.Module(buffer); const module = new WebAssembly.Module(buffer);
@ -146,6 +92,19 @@ test(() => {
order.push("global2 getter"); order.push("global2 getter");
return 0; return 0;
}, },
get memory() {
order.push("memory getter");
return new WebAssembly.Memory({ "initial": 64, maximum: 128 });
},
}
},
get module2() {
order.push("module2 getter");
return {
get global3() {
order.push("global3 getter");
return 0;
},
} }
}, },
}; };
@ -153,6 +112,10 @@ test(() => {
const expected = [ const expected = [
"module getter", "module getter",
"global1 getter", "global1 getter",
"module2 getter",
"global3 getter",
"module getter",
"memory getter",
"module getter", "module getter",
"global2 getter", "global2 getter",
]; ];
@ -225,3 +188,34 @@ test(() => {
}; };
assert_Instance(instance, expected); assert_Instance(instance, expected);
}, "exports"); }, "exports");
test(() => {
const value = 102;
const builder = new WasmModuleBuilder();
builder.addImportedGlobal("module", "global", kWasmI32);
builder
.addFunction("fn", kSig_i_v)
.addBody([
kExprGetGlobal,
0,
kExprReturn,
kExprEnd,
])
.exportFunc();
const buffer = builder.toBuffer();
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module, {
"module": {
"global": value,
},
});
const expected = {
"fn": { "kind": "function", "name": "0", "length": 0 },
};
assert_Instance(instance, expected);
assert_equals(instance.exports.fn(), value);
}, "exports and imports");

View file

@ -0,0 +1,101 @@
<!doctype html>
<html>
<head>
<title>Test Extrapolation at end of AudibBuffer in an AudioBufferSourceNode</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webaudio/resources/audit-util.js"></script>
<script src="/webaudio/resources/audit.js"></script>
</head>
<body>
<script>
let audit = Audit.createTaskRunner();
const sampleRate = 48000;
// For testing we only need a few render quanta.
const renderSamples = 512
// Sample rate for our buffers. This is the lowest sample rate that is
// required to be supported.
const bufferRate = 8000;
// Number of samples in each AudioBuffer; this is fairly arbitrary but
// should be less than a render quantum.
const bufferLength = 30;
// Frequency of the sine wave for testing.
const frequency = 440;
audit.define(
{
label: 'interpolate',
description: 'Interpolation of AudioBuffers to context sample rate'
},
(task, should) => {
// The first channel is for the interpolated signal, and the second
// channel is for the reference signal from an oscillator.
let context = new OfflineAudioContext({
numberOfChannels: 2,
length: renderSamples,
sampleRate: sampleRate
});
let merger = new ChannelMergerNode(
context, {numberOfChannels: context.destination.channelCount});
merger.connect(context.destination);
// Create a set of AudioBuffers which are samples from a pure sine
// wave with frequency |frequency|.
const nBuffers = Math.floor(context.length / bufferLength);
const omega = 2 * Math.PI * frequency / bufferRate;
let frameNumber = 0;
let startTime = 0;
for (let k = 0; k < nBuffers; ++k) {
// let buffer = context.createBuffer(1, bufferLength,
// bufferRate);
let buffer = new AudioBuffer(
{length: bufferLength, sampleRate: bufferRate});
let data = buffer.getChannelData(0);
for (let n = 0; n < bufferLength; ++n) {
data[n] = Math.sin(omega * frameNumber);
++frameNumber;
}
// Create a source using this buffer and start it at the end of
// the previous buffer.
let src = new AudioBufferSourceNode(context, {buffer: buffer});
src.connect(merger, 0, 0);
src.start(startTime);
startTime += buffer.duration;
}
// Create the reference sine signal using an oscillator.
let osc = new OscillatorNode(
context, {type: 'sine', frequency: frequency});
osc.connect(merger, 0, 1);
osc.start(0);
context.startRendering()
.then(audioBuffer => {
let actual = audioBuffer.getChannelData(0);
let expected = audioBuffer.getChannelData(1);
should(actual, 'Interpolated sine wave')
.beCloseToArray(expected, {absoluteThreshold: 9.0348e-2});
// Compute SNR between them.
let snr = 10 * Math.log10(computeSNR(actual, expected));
should(snr, `SNR (${snr.toPrecision(4)} dB)`)
.beGreaterThanOrEqualTo(37.17);
})
.then(() => task.done());
});
audit.run();
</script>
</body>
</html>

View file

@ -13,7 +13,9 @@
window.onload = test.step_func(function() { window.onload = test.step_func(function() {
var client = new XMLHttpRequest(); var client = new XMLHttpRequest();
var abortFired = false; var abortFired = false;
var sync = true;
client.onabort = test.step_func(function (e) { client.onabort = test.step_func(function (e) {
assert_false(sync);
assert_equals(e.type, 'abort'); assert_equals(e.type, 'abort');
abortFired = true; abortFired = true;
}); });
@ -24,6 +26,7 @@
test.done(); test.done();
}, 200); }, 200);
window.stop(); window.stop();
sync = false;
}); });
</script> </script>
</body> </body>

View file

@ -9,27 +9,69 @@
<body> <body>
<div id="log"></div> <div id="log"></div>
<script> <script>
var test = async_test() test(function(t) {
test.step(function() {
var client = new XMLHttpRequest(), var client = new XMLHttpRequest(),
result = [], result = [],
expected = [1, 4, 1] // open() -> 1, expected = [
// abort() -> 4, open() -> 1 'readystatechange', 0, 1, // open()
client.onreadystatechange = function() { 'readystatechange', 2, 4, // abort()
test.step(function() { 'abort', 2, 4, // abort()
result.push(client.readyState) 'loadend', 2, 4, // abort()
}) 'readystatechange', 3, 1, // open()
} ]
var state = 0
client.onreadystatechange = t.step_func(function() {
result.push('readystatechange', state, client.readyState)
})
client.onabort = t.step_func(function() {
// abort event must be fired synchronously from abort().
assert_equals(state, 2)
// readystatechange should be fired before abort.
assert_array_equals(result, [
'readystatechange', 0, 1, // open()
'readystatechange', 2, 4, // abort()
])
// readyState should be set to unsent (0) at the very end of abort(),
// after this (and onloadend) is called.
assert_equals(client.readyState, 4)
result.push('abort', state, client.readyState)
})
client.onloadend = t.step_func(function() {
// abort event must be fired synchronously from abort().
assert_equals(state, 2)
// readystatechange should be fired before abort.
assert_array_equals(result, [
'readystatechange', 0, 1, // open()
'readystatechange', 2, 4, // abort()
'abort', 2, 4, // abort()
])
// readyState should be set to unsent (0) at the very end of abort(),
// after this is called.
assert_equals(client.readyState, 4)
result.push('loadend', state, client.readyState)
})
client.open("GET", "resources/well-formed.xml") client.open("GET", "resources/well-formed.xml")
assert_equals(client.readyState, 1) assert_equals(client.readyState, 1)
state = 1
client.send(null) client.send(null)
state = 2
client.abort() client.abort()
assert_equals(client.readyState, 0) assert_equals(client.readyState, 0)
state = 3
client.open("GET", "resources/well-formed.xml") client.open("GET", "resources/well-formed.xml")
assert_equals(client.readyState, 1) assert_equals(client.readyState, 1)
assert_array_equals(result, expected) assert_array_equals(result, expected)
}) })
test.done()
</script> </script>
</body> </body>
</html> </html>

View file

@ -0,0 +1,43 @@
// window.stop() below prevents the load event from firing, so wait until it is
// fired to start the test.
setup({explicit_done: true });
onload = () => {
async_test(function(t) {
const client = new XMLHttpRequest();
const result = [];
const expected = [
'readystatechange', 0, 1, // open()
];
let state = 0;
client.onreadystatechange = t.step_func(() => {
result.push('readystatechange', state, client.readyState);
});
client.onabort = t.unreached_func("abort should not be fired after window.stop() and open()");
client.onloadend = t.unreached_func("loadend should not be fired after window.stop() and open()");
client.open("GET", "resources/well-formed.xml");
assert_equals(client.readyState, 1);
state = 1;
client.send(null);
state = 2;
window.stop();
// Unlike client.abort(), window.stop() does not change readyState
// immediately, rather through a task...
assert_equals(client.readyState, 1);
state = 3;
// ... which is then canceled when we open a new request anyway.
client.open("GET", "resources/well-formed.xml");
assert_equals(client.readyState, 1);
assert_array_equals(result, expected);
// Give the abort and loadend events a chance to fire (erroneously) before
// calling this a success.
t.step_timeout(t.step_func_done(), 1000);
}, "open() after window.stop()");
done();
};