Update web-platform-tests to revision 74bae78af4b95a2f0ca3a81df9c7fe3143f24bbc

This commit is contained in:
WPT Sync Bot 2019-01-17 20:37:38 -05:00
parent fb95f9df9c
commit 02c1eed999
150 changed files with 2395 additions and 829 deletions

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<style>
@ -47,7 +48,7 @@ async_test(t => {
animation.play();
assert_equals(data, '0.4');
waitTwoAnimationFrames(t.step_func_done(() => {
waitForAsyncAnimationFrames(1).then(t.step_func_done(() => {
assert_equals(getComputedStyle(target).opacity, '0.5');
}));
});

View file

@ -8,26 +8,25 @@ function registerPassthroughAnimator() {
`);
}
function registerConstantLocalTimeAnimator(localTime) {
return runInAnimationWorklet(`
registerAnimator('constant_time', class {
animate(currentTime, effect) { effect.localTime = ${localTime}; }
});
`);
}
function runInAnimationWorklet(code) {
return CSS.animationWorklet.addModule(
URL.createObjectURL(new Blob([code], {type: 'text/javascript'}))
);
}
function waitForAnimationFrames(count, callback) {
function rafCallback() {
if (count <= 0) {
callback();
} else {
count -= 1;
window.requestAnimationFrame(rafCallback);
}
}
rafCallback();
};
// Wait for two main thread frames to guarantee that compositor has produced
// at least one frame. Note that this is a Chrome-only concept.
function waitTwoAnimationFrames(callback) {
waitForAnimationFrames(2, callback);
};
function waitForAsyncAnimationFrames(count) {
// In Chrome, waiting for N+1 main thread frames guarantees that compositor has produced
// at least N frames.
// TODO(majidvp): re-evaluate this choice once other browsers have implemented
// AnimationWorklet.
return waitForAnimationFrames(count + 1);
}

View file

@ -6,6 +6,7 @@
background-color: #00ff00;
}
</style>
<script src="/web-animations/testcommon.js"></script>
<script src="../common.js"></script>
<script id="iframe_worklet" type="text/worklet">
@ -32,7 +33,7 @@ runInAnimationWorklet(
const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
const animation = new WorkletAnimation('iframe_animator', effect);
animation.play();
waitTwoAnimationFrames( _ => {
waitForAnimationFrames(2).then(_ => {
window.parent.postMessage(getComputedStyle(target).opacity, '*');
});
});

View file

@ -3,15 +3,9 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<script id="worklet_code" type="text/worklet">
registerAnimator("test_animator", class {
animate(currentTime, effect) {
effect.localTime = currentTime;
}
});
</script>
<script>
// Creates a DOM structure like:
@ -63,15 +57,14 @@ function createAndPlayTestAnimation(elements, timeline_orientation) {
timeRange: 1000,
orientation: timeline_orientation
});
const animation = new WorkletAnimation('test_animator', effect, timeline);
const animation = new WorkletAnimation('passthrough', effect, timeline);
animation.play();
}
setup(setupAndRegisterTests, {explicit_done: true});
function setupAndRegisterTests() {
const worklet_code = document.getElementById('worklet_code').textContent;
runInAnimationWorklet(worklet_code).then(() => {
registerPassthroughAnimator().then(() => {
// Note that block horizontal-tb is tested implicitly in the basic
// ScrollTimeline tests (as it is the default).
async_test(
@ -104,7 +97,7 @@ function block_vertical_lr(t) {
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
@ -120,7 +113,7 @@ function block_vertical_rl(t) {
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
@ -136,7 +129,7 @@ function inline_horizontal_tb_rtl(t) {
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
@ -151,7 +144,7 @@ function inline_vertical_writing_mode_ltr(t) {
elements.scroller.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
@ -167,7 +160,7 @@ function inline_vertical_writing_mode_rtl(t) {
elements.scroller.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
waitForAsyncAnimationFrames(2).then(t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<style>
@ -15,33 +16,21 @@
<script>
function CreateTest(target, effect, verify, test_name) {
async_test(t => {
runInAnimationWorklet(
document.getElementById('simple_animate').textContent
).then(_ => {
const animation = new WorkletAnimation('test_animator', effect);
promise_test(async function() {
await registerConstantLocalTimeAnimator(2000);
const animation = new WorkletAnimation('constant_time', effect);
animation.play();
waitTwoAnimationFrames(() => {
// waitTwoAnimationFrames guarantees a compositor frame that could update
// the opacity value in the worklet. Meanwhile, getComputedStyle needs an
// extra frame to fetch the updated value.
window.requestAnimationFrame(t.step_func_done(() => {
verify();
animation.cancel();
}));
});
});
await waitForAsyncAnimationFrames(1);
// waitTwoAnimationFrames guarantees a compositor frame that could update
// the opacity value in the worklet. Meanwhile, getComputedStyle needs an
// extra frame to fetch the updated value.
await waitForNextFrame();
verify();
animation.cancel();
}, test_name);
}
</script>
<script id="simple_animate" type="text/worklet">
registerAnimator("test_animator", class {
animate(currentTime, effect) {
effect.localTime = 2000;
}
});
</script>
<div id="target1" class='target'></div>
<div id="target2" class='target'></div>

View file

@ -3,6 +3,7 @@
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<script src="common.js"></script>
<style>
@ -17,8 +18,8 @@
<script>
'use strict';
test(function() {
registerPassthroughAnimator();
promise_test(async function() {
await registerPassthroughAnimator();
let playFunc = function() {
let effect = new KeyframeEffect(
document.getElementById('target'),

View file

@ -8,19 +8,22 @@
'use strict';
const test_desc = 'HeartRate device properties';
bluetooth_test(() => getHealthThermometerService()
.then(({service}) => Promise.all([
service.getCharacteristic('temperature_measurement'),
service.getCharacteristic('measurement_interval')]))
.then(([temperature_measurement, measurement_interval]) => {
let tm_expected_properties =
new TestCharacteristicProperties(['indicate']);
assert_properties_equal(temperature_measurement.properties,
tm_expected_properties);
bluetooth_test(
() => getHealthThermometerService()
.then(({service}) => Promise.all([
service.getCharacteristic('temperature_measurement'),
service.getCharacteristic('measurement_interval')
]))
.then(([temperature_measurement, measurement_interval]) => {
let tm_expected_properties =
new TestCharacteristicProperties(['indicate']);
assert_properties_equal(
temperature_measurement.properties, tm_expected_properties);
let mi_expected_properties =
new TestCharacteristicProperties(['read', 'write', 'indicate']);
assert_properties_equal(measurement_interval.properties,
mi_expected_properties);
}), test_desc);
let mi_expected_properties = new TestCharacteristicProperties(
['read', 'write', 'indicate']);
assert_properties_equal(
measurement_interval.properties, mi_expected_properties);
}),
test_desc);
</script>

View file

@ -8,12 +8,14 @@
'use strict';
const test_desc = 'Same parent service returned from multiple characteristics.';
bluetooth_test(() => getHealthThermometerService()
.then(({service}) => Promise.all([
service.getCharacteristic('measurement_interval'),
service.getCharacteristic('temperature_measurement')
]))
.then(characteristics =>
assert_equals(characteristics[0].service, characteristics[1].service)),
bluetooth_test(
() => getHealthThermometerService()
.then(({service}) => Promise.all([
service.getCharacteristic('measurement_interval'),
service.getCharacteristic('temperature_measurement')
]))
.then(
characteristics => assert_equals(
characteristics[0].service, characteristics[1].service)),
test_desc);
</script>

View file

@ -7,10 +7,11 @@
<script>
'use strict';
const test_desc = '[SameObject] test for BluetoothRemoteGATTCharacteristic ' +
'service.';
'service.';
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(({characteristic}) =>
assert_equals(characteristic.service, characteristic.service)),
bluetooth_test(
() => getMeasurementIntervalCharacteristic().then(
({characteristic}) =>
assert_equals(characteristic.service, characteristic.service)),
test_desc);
</script>

View file

@ -7,10 +7,12 @@
const test_desc = 'Bluetooth IDL test';
test(() => {
assert_throws(new TypeError(), () => new Bluetooth(),
'the constructor should not be callable with "new"');
assert_throws(new TypeError(), () => Bluetooth(),
'the constructor should not be callable');
assert_throws(
new TypeError(), () => new Bluetooth(),
'the constructor should not be callable with "new"');
assert_throws(
new TypeError(), () => Bluetooth(),
'the constructor should not be callable');
// Bluetooth implements BluetoothDiscovery;
assert_true('requestDevice' in navigator.bluetooth);

View file

@ -9,23 +9,28 @@
const test_desc_idl = 'BluetoothDevice IDL test.';
test(() => {
assert_throws(new TypeError(), () => new BluetoothDevice(),
assert_throws(
new TypeError(), () => new BluetoothDevice(),
'the constructor should not be callable with "new"');
assert_throws(new TypeError(), () => BluetoothDevice(),
assert_throws(
new TypeError(), () => BluetoothDevice(),
'the constructor should not be callable');
}, test_desc_idl);
const test_desc_attr = 'BluetoothDevice attributes.';
let device;
bluetooth_test(() => getConnectedHealthThermometerDevice()
.then(({device}) => {
assert_equals(device.constructor.name, 'BluetoothDevice');
var old_device_id = device.id;
assert_throws(new TypeError(), () => device.id = 'overwritten',
'the device id should not be writable');
assert_throws(new TypeError(), () => device.name = 'overwritten',
'the device name should not be writable');
assert_equals(device.id, old_device_id);
assert_equals(device.name, 'Health Thermometer');
}), test_desc_attr);
bluetooth_test(
() => getConnectedHealthThermometerDevice().then(({device}) => {
assert_equals(device.constructor.name, 'BluetoothDevice');
var old_device_id = device.id;
assert_throws(
new TypeError(), () => device.id = 'overwritten',
'the device id should not be writable');
assert_throws(
new TypeError(), () => device.name = 'overwritten',
'the device name should not be writable');
assert_equals(device.id, old_device_id);
assert_equals(device.name, 'Health Thermometer');
}),
test_desc_attr);
</script>

View file

@ -19,22 +19,25 @@ test(() => {
assert_equals(BluetoothUUID.getDescriptor(NaN), base_uuid);
}, 'NaN returns basic uuid');
test(() => {
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
let nine_digits = 0xfffffffff;
let thirteen_digits = 0xfffffffffffff;
let fourteen_digits = 0xffffffffffffff;
assert_equals(BluetoothUUID.getService(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getService(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
}, 'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
'should return max UUID');
test(
() => {
let max_uuid = 'ffffffff-0000-1000-8000-00805f9b34fb';
let nine_digits = 0xfffffffff;
let thirteen_digits = 0xfffffffffffff;
let fourteen_digits = 0xffffffffffffff;
assert_equals(BluetoothUUID.getService(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(nine_digits), max_uuid);
assert_equals(BluetoothUUID.getService(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getCharacteristic(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getDescriptor(thirteen_digits), max_uuid);
assert_equals(BluetoothUUID.getService(fourteen_digits), base_uuid);
assert_equals(
BluetoothUUID.getCharacteristic(fourteen_digits), base_uuid);
assert_equals(BluetoothUUID.getDescriptor(fourteen_digits), base_uuid);
},
'Values between 0xfffffffff (8 digits) and 0xffffffffffffff (14 digits)' +
'should return max UUID');
test(() => {
assert_equals(BluetoothUUID.getService(Infinity), base_uuid);
@ -54,7 +57,8 @@ test(() => {
let adeadbeef_alias = 0xADEADBEEF;
let adeadbeef_uuid = 'deadbeef-0000-1000-8000-00805f9b34fb';
assert_equals(BluetoothUUID.getService(adeadbeef_alias), adeadbeef_uuid);
assert_equals(BluetoothUUID.getCharacteristic(adeadbeef_alias), adeadbeef_uuid);
assert_equals(
BluetoothUUID.getCharacteristic(adeadbeef_alias), adeadbeef_uuid);
assert_equals(BluetoothUUID.getDescriptor(adeadbeef_alias), adeadbeef_uuid);
}, 'Only first 32bits should be used.');
@ -68,31 +72,40 @@ test(() => {
test(() => {
let all_caps_uuid = '1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D';
assert_throws(TypeError(), () => BluetoothUUID.getService(all_caps_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
assert_throws(
TypeError(), () => BluetoothUUID.getCharacteristic(all_caps_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(all_caps_uuid));
}, 'A UUID String with uppercase letters is an invalid UUID.');
test(() => {
let string_alias = 'deadbeef';
assert_throws(TypeError(), () => BluetoothUUID.getService(string_alias));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
assert_throws(
TypeError(), () => BluetoothUUID.getCharacteristic(string_alias));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(string_alias));
}, 'A 32bit *String* alias is invalid.');
test(() => {
let invalid_character_uuid = '0000000g-0000-1000-8000-00805f9b34fb';
assert_throws(TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getCharacteristic(invalid_character_uuid));
assert_throws(TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
assert_throws(
TypeError(), () => BluetoothUUID.getService(invalid_character_uuid));
assert_throws(
TypeError(),
() => BluetoothUUID.getCharacteristic(invalid_character_uuid));
assert_throws(
TypeError(), () => BluetoothUUID.getDescriptor(invalid_character_uuid));
}, 'A UUID with invalid characters is an invalid UUID.');
test(() => {
assert_equals(BluetoothUUID.getService('alert_notification'),
'00001811-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
'00002a7e-0000-1000-8000-00805f9b34fb');
assert_equals(BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
'00002900-0000-1000-8000-00805f9b34fb');
assert_equals(
BluetoothUUID.getService('alert_notification'),
'00001811-0000-1000-8000-00805f9b34fb');
assert_equals(
BluetoothUUID.getCharacteristic('aerobic_heart_rate_lower_limit'),
'00002a7e-0000-1000-8000-00805f9b34fb');
assert_equals(
BluetoothUUID.getDescriptor('gatt.characteristic_extended_properties'),
'00002900-0000-1000-8000-00805f9b34fb');
}, 'A valid UUID from a name.');
test(() => {
@ -136,7 +149,8 @@ test(() => {
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(undefined));
assert_equals(BluetoothUUID.canonicalUUID(null), base_uuid);
assert_equals(BluetoothUUID.canonicalUUID(false), base_uuid);
assert_equals(BluetoothUUID.canonicalUUID(true), BluetoothUUID.canonicalUUID(1));
assert_equals(
BluetoothUUID.canonicalUUID(true), BluetoothUUID.canonicalUUID(1));
assert_throws(new TypeError, () => BluetoothUUID.canonicalUUID(NaN));
// getService

View file

@ -6,8 +6,7 @@
const test_desc = '[SameObject] test for navigator.bluetooth';
test(() => {
assert_true('bluetooth' in navigator,
'navigator.bluetooth exists.');
assert_true('bluetooth' in navigator, 'navigator.bluetooth exists.');
}, 'navigator.bluetooth IDL test');
test(() => {

View file

@ -9,8 +9,10 @@
const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' +
'found if acceptAllDevices is true.';
bluetooth_test(() => setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, '')),
bluetooth_test(
() =>
setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, '')),
test_desc);
</script>

View file

@ -5,12 +5,15 @@
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
const test_desc = 'A device with name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.';
const test_desc =
'A device with name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.';
const name = 'LE Device';
bluetooth_test(() => setUpPreconnectedDevice({name: name})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, name)),
bluetooth_test(
() =>
setUpPreconnectedDevice({name: name})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => assert_equals(device.name, name)),
test_desc);
</script>

View file

@ -10,13 +10,14 @@ const test_desc = 'requestDevice called with acceptAllDevices: true and ' +
'with no optionalServices. Should not get access to any services.';
const expected = new DOMException(
'Origin is not allowed to access any service. ' +
'Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
'Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError');
bluetooth_test(() => getConnectedHealthThermometerDevice({acceptAllDevices: true})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.getPrimaryServices(),
expected)),
bluetooth_test(
() => getConnectedHealthThermometerDevice({acceptAllDevices: true})
.then(
({device}) => assert_promise_rejects_with_message(
device.gatt.getPrimaryServices(), expected)),
test_desc);
</script>

View file

@ -7,20 +7,23 @@
<script>
'use strict';
const test_desc = 'requestDevice called with acceptAllDevices: true and with ' +
'optionalServices. Should get access to services.';
'optionalServices. Should get access to services.';
bluetooth_test(() => getTwoHealthThermometerServicesDevice()
.then(() => requestDeviceWithTrustedClick({
acceptAllDevices: true,
optionalServices: ['health_thermometer']
}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryServices())
.then(services => {
assert_equals(services.length, 2);
services.forEach(service => {
assert_equals(service.uuid,
BluetoothUUID.getService('health_thermometer'));
});
}), test_desc);
bluetooth_test(
() => getTwoHealthThermometerServicesDevice()
.then(() => requestDeviceWithTrustedClick({
acceptAllDevices: true,
optionalServices: ['health_thermometer']
}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryServices())
.then(services => {
assert_equals(services.length, 2);
services.forEach(service => {
assert_equals(
service.uuid,
BluetoothUUID.getService('health_thermometer'));
});
}),
test_desc);
</script>

View file

@ -10,16 +10,16 @@ const test_desc = 'Reject with SecurityError if requesting a blocklisted ' +
'service.';
const expected = new DOMException(
'requestDevice() called with a filter containing a blocklisted UUID. ' +
'https://goo.gl/4NeimX',
'https://goo.gl/4NeimX',
'SecurityError');
bluetooth_test(() => setUpPreconnectedDevice({
knownServiceUUIDs: ['human_interface_device']
})
.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({
filters: [{services: ['human_interface_device']}]
}),
expected, 'Requesting blocklisted service rejects.')),
bluetooth_test(
() =>
setUpPreconnectedDevice({knownServiceUUIDs: ['human_interface_device']})
.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(
{filters: [{services: ['human_interface_device']}]}),
expected, 'Requesting blocklisted service rejects.')),
test_desc);
</script>

View file

@ -8,26 +8,30 @@
'use strict';
const test_desc = 'Blocklisted UUID in optionalServices is removed and ' +
'access not granted.';
const expected = new DOMException('Origin is not allowed to access the ' +
'service. Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
const expected = new DOMException(
'Origin is not allowed to access the ' +
'service. Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError');
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['human_interface_device']
})
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(() => Promise.all([
assert_promise_rejects_with_message(
device.gatt.getPrimaryService('human_interface_device'),
expected, 'Blocklisted service not accessible.'),
assert_promise_rejects_with_message(
device.gatt.getPrimaryServices('human_interface_device'),
expected, 'Blocklisted services not accessible.')])),
bluetooth_test(
() => getDiscoveredHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['human_interface_device']
})
.then(_ => ({device, fake_peripheral} = _))
.then(
() => fake_peripheral.setNextGATTConnectionResponse(
{code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(() => Promise.all([
assert_promise_rejects_with_message(
device.gatt.getPrimaryService('human_interface_device'),
expected, 'Blocklisted service not accessible.'),
assert_promise_rejects_with_message(
device.gatt.getPrimaryServices('human_interface_device'),
expected, 'Blocklisted services not accessible.')
])),
test_desc);
</script>

View file

@ -10,10 +10,11 @@ const test_desc = 'A device name between 29 and 248 bytes is valid.';
const DEVICE_NAME = 'a_device_name_that_is_longer_than_29_bytes_but_' +
'shorter_than_248_bytes';
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithTrustedClick({
filters: [{name: DEVICE_NAME}]
}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
bluetooth_test(
() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc);
</script>

View file

@ -9,8 +9,8 @@
const test_desc = 'A filter must restrict the devices in some way.';
const expected = new TypeError();
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{}]}),
expected),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{}]}), expected),
test_desc);
</script>

View file

@ -7,12 +7,13 @@
<script>
'use strict';
const test_desc = 'An empty |filters| member should result in a TypeError';
const expected = new DOMException('Failed to execute \'requestDevice\' on ' +
'\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
const expected = new DOMException(
'Failed to execute \'requestDevice\' on ' +
'\'Bluetooth\': \'filters\' member must be non-empty to find any devices.',
new TypeError());
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: []}),
expected),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: []}), expected),
test_desc);
</script>

View file

@ -9,36 +9,29 @@
const test_desc = 'requestDevice with empty namePrefix. ' +
'Should reject with TypeError.';
const expected = new TypeError();
const test_specs = [{
filters: [{ namePrefix: ''}]
}, {
filters: [{ namePrefix: '', name: 'Name'}]
}, {
filters: [{ namePrefix: '', services: ['heart_rate']}]
}, {
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}]
}, {
filters: [{ namePrefix: ''}],
optionalServices: ['heart_rate']
}, {
filters: [{ namePrefix: '', name: 'Name'}],
optionalServices: ['heart_rate']
}, {
filters: [{ namePrefix: '', services: ['heart_rate']}],
optionalServices: ['heart_rate']
}, {
filters: [{ namePrefix: '', name: 'Name', services: ['heart_rate']}],
optionalServices: ['heart_rate']
}];
const test_specs = [
{filters: [{namePrefix: ''}]}, {filters: [{namePrefix: '', name: 'Name'}]},
{filters: [{namePrefix: '', services: ['heart_rate']}]},
{filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}]},
{filters: [{namePrefix: ''}], optionalServices: ['heart_rate']},
{filters: [{namePrefix: '', name: 'Name'}], optionalServices: ['heart_rate']},
{
filters: [{namePrefix: '', services: ['heart_rate']}],
optionalServices: ['heart_rate']
},
{
filters: [{namePrefix: '', name: 'Name', services: ['heart_rate']}],
optionalServices: ['heart_rate']
}
];
bluetooth_test(() => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises
.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args),
expected));
});
return test_promises;
}, test_desc);
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), expected));
});
return test_promises;
}, test_desc);
</script>

View file

@ -10,14 +10,12 @@ const test_desc = 'Services member must contain at least one service.';
const expected = new TypeError();
bluetooth_test(() => {
let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices([]).forEach(args => {
test_promises = test_promises.then(() =>
assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args),
expected,
'Services member must contain at least one service'))
});
return test_promises;
}, test_desc);
let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices([]).forEach(
args => {test_promises = test_promises.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), expected,
'Services member must contain at least one service'))});
return test_promises;
}, test_desc);
</script>

View file

@ -6,28 +6,24 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = "RequestDeviceOptions should have exactly one of " +
"'filters' or 'acceptAllDevices:true'. Reject with TypeError if not.";
const test_desc = 'RequestDeviceOptions should have exactly one of ' +
'\'filters\' or \'acceptAllDevices:true\'. Reject with TypeError if not.';
const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " +
"Either 'filters' should be present or " +
"'acceptAllDevices' should be true, but not both.",
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
'Either \'filters\' should be present or ' +
'\'acceptAllDevices\' should be true, but not both.',
new TypeError());
const test_specs = [
{},
{optionalServices: ['heart_rate']},
{filters: [], acceptAllDevices: true},
{}, {optionalServices: ['heart_rate']}, {filters: [], acceptAllDevices: true},
{filters: [], acceptAllDevices: true, optionalServices: ['heart_rate']}
];
bluetooth_test(() => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises
.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args),
expected))
});
return test_promises;
}, test_desc);
let test_promises = Promise.resolve();
test_specs.forEach(
args => {test_promises = test_promises.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), expected))});
return test_promises;
}, test_desc);
</script>

View file

@ -9,15 +9,16 @@
const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
'bytes in \'name\' must throw TypeError.';
const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " +
"A device name can't be longer than 248 bytes.",
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
'A device name can\'t be longer than 248 bytes.',
new TypeError());
// \u2764's UTF-8 respresentation is 3 bytes long.
// 83 chars * 3 bytes/char = 249 bytes
const unicode_name = '\u2764'.repeat(83);
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}),
expected),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: unicode_name}]}),
expected),
test_desc);
</script>

View file

@ -8,14 +8,14 @@
'use strict';
const test_desc = 'A device name longer than 248 must reject.';
const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': A device " +
"name can't be longer than 248 bytes.",
'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
'name can\'t be longer than 248 bytes.',
new TypeError());
const name_too_long = 'a'.repeat(249);
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}),
expected,
'Device name longer than 248'),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{name: name_too_long}]}),
expected, 'Device name longer than 248'),
test_desc);
</script>

View file

@ -9,15 +9,16 @@
const test_desc = 'Unicode string with utf8 representation longer than 248 ' +
'bytes in \'namePrefix\' must throw NotFoundError.';
const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': " +
"A device name can't be longer than 248 bytes.",
'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
'A device name can\'t be longer than 248 bytes.',
new TypeError());
// \u2764's UTF-8 respresentation is 3 bytes long.
// 83 chars * 3 bytes/char = 249 bytes
const unicode_name = '\u2764'.repeat(83);
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}),
expected),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: unicode_name}]}),
expected),
test_desc);
</script>

View file

@ -8,14 +8,14 @@
'use strict';
const test_desc = 'A device name prefix longer than 248 must reject.';
const expected = new DOMException(
"Failed to execute 'requestDevice' on 'Bluetooth': A device " +
"name can't be longer than 248 bytes.",
'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
'name can\'t be longer than 248 bytes.',
new TypeError());
const name_too_long = 'a'.repeat(249);
bluetooth_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}),
expected,
'Device name longer than 248'),
bluetooth_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({filters: [{namePrefix: name_too_long}]}),
expected, 'Device name longer than 248'),
test_desc);
</script>

View file

@ -11,8 +11,11 @@ const test_desc = 'A unicode device name of 248 bytes is valid.';
// 124 chars * 2 bytes/char = 248 bytes
const DEVICE_NAME = '\u00A1'.repeat(124);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
bluetooth_test(
() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc);
</script>

View file

@ -9,8 +9,11 @@
const test_desc = 'A device name of 248 bytes is valid.';
const DEVICE_NAME = 'a'.repeat(248);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithTrustedClick({ filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
bluetooth_test(
() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc);
</script>

View file

@ -11,10 +11,11 @@ const test_desc = 'A unicode device namePrefix of 248 bytes is valid.';
// 124 chars * 2 bytes/char = 248 bytes
const DEVICE_NAME = '\u00A1'.repeat(124);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithTrustedClick({
filters: [{namePrefix: DEVICE_NAME}]
}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
bluetooth_test(
() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{namePrefix: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc);
</script>

View file

@ -9,10 +9,11 @@
const test_desc = 'A device namePrefix of 248 bytes is valid.';
const DEVICE_NAME = 'a'.repeat(248);
bluetooth_test(() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithTrustedClick({
filters: [{namePrefix: DEVICE_NAME}]
}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
bluetooth_test(
() => setUpPreconnectedDevice({name: DEVICE_NAME})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{namePrefix: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME)),
test_desc);
</script>

View file

@ -10,8 +10,8 @@
const test_desc = 'requestDevice() requires an argument.';
const expected = new TypeError();
promise_test(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(),
expected),
promise_test(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(), expected),
test_desc);
</script>

View file

@ -12,10 +12,11 @@ const test_desc = 'A name containing unicode characters whose utf8 length ' +
// 9 chars * 3 bytes/char = 27 bytes
const valid_unicode_name = '\u2764'.repeat(9);
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name})
.then(() => requestDeviceWithTrustedClick({
filters: [{name: valid_unicode_name}]
}))
.then(device => assert_equals(device.name, valid_unicode_name)),
bluetooth_test(
() => setUpPreconnectedDevice({name: valid_unicode_name})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{name: valid_unicode_name}]}))
.then(device => assert_equals(device.name, valid_unicode_name)),
test_desc);
</script>

View file

@ -6,16 +6,17 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'A namePrefix containing unicode characters whose utf8 ' +
const test_desc = 'A namePrefix containing unicode characters whose utf8 ' +
'length is less than 30 must not throw an error.';
// \u2764's UTF-8 representation is 3 bytes long.
// 9 chars * 3 bytes/char = 27 bytes
const valid_unicode_name = '\u2764'.repeat(9);
bluetooth_test(() => setUpPreconnectedDevice({name: valid_unicode_name})
.then(() => requestDeviceWithTrustedClick({
filters: [{namePrefix: valid_unicode_name}]
}))
.then(device => assert_equals(device.name, valid_unicode_name)),
bluetooth_test(
() => setUpPreconnectedDevice({name: valid_unicode_name})
.then(
() => requestDeviceWithTrustedClick(
{filters: [{namePrefix: valid_unicode_name}]}))
.then(device => assert_equals(device.name, valid_unicode_name)),
test_desc);
</script>

View file

@ -8,37 +8,34 @@
'use strict';
const test_desc = 'Invalid optional service must reject the promise.';
const expected = new TypeError();
const test_specs = [{
optionalServices: ['wrong_service'],
filters: [{services: ['heart_rate']}]
}, {
optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], name: 'Name'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], namePrefix: 'Pre'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ name: 'Name'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ name: 'Name', namePrefix: 'Pre'}]
}, {
optionalServices: ['wrong_service'],
filters: [{ namePrefix: 'Pre'}]
}];
const test_specs = [
{optionalServices: ['wrong_service'], filters: [{services: ['heart_rate']}]},
{
optionalServices: ['wrong_service'],
filters: [{services: ['heart_rate'], name: 'Name'}]
},
{
optionalServices: ['wrong_service'],
filters: [{services: ['heart_rate'], namePrefix: 'Pre'}]
},
{
optionalServices: ['wrong_service'],
filters: [{services: ['heart_rate'], name: 'Name', namePrefix: 'Pre'}]
},
{optionalServices: ['wrong_service'], filters: [{name: 'Name'}]}, {
optionalServices: ['wrong_service'],
filters: [{name: 'Name', namePrefix: 'Pre'}]
},
{optionalServices: ['wrong_service'], filters: [{namePrefix: 'Pre'}]}
];
bluetooth_test(() => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises =
test_promises.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args),
expected));
});
return test_promises;
}, test_desc);
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), expected));
});
return test_promises;
}, test_desc);
</script>

View file

@ -10,13 +10,12 @@ const test_desc = 'Invalid service must reject the promise.';
const expected = new TypeError();
bluetooth_test(() => {
let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
test_promises = test_promises.then(() =>
assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args),
expected));
});
return test_promises;
}, test_desc);
let test_promises = Promise.resolve();
generateRequestDeviceArgsWithServices(['wrong_service']).forEach(args => {
test_promises = test_promises.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(args), expected));
});
return test_promises;
}, test_desc);
</script>

View file

@ -13,26 +13,29 @@ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
'/bluetooth/resources/health-thermometer-iframe.html'
let iframe = document.createElement('iframe');
bluetooth_test(() => setUpHealthThermometerDevice()
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.src = cross_origin_src;
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Request the device from the iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestDevice'
}, '*');
});
bluetooth_test(
() => setUpHealthThermometerDevice()
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.src = cross_origin_src;
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Request the device from the iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage(
{type: 'RequestDevice'}, '*');
});
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'SecurityError: requestDevice() ' +
'called from cross-origin iframe.');
resolve();
}
})), test_desc);
window.onmessage = messageEvent => {
assert_equals(
messageEvent.data,
'SecurityError: requestDevice() ' +
'called from cross-origin iframe.');
resolve();
}
})),
test_desc);
</script>
</body>

View file

@ -8,21 +8,28 @@
'use strict';
const test_desc = 'Discover a device using alias, name, or UUID.';
bluetooth_test(() => getConnectedHealthThermometerDevice()
// Chrome will always close the previous chooser in the process of handling
// a user gesture for the next request, so these need to be done
// sequentially.
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [health_thermometer.alias]}]
}))
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [health_thermometer.name]}]
}))
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [health_thermometer.uuid]}]
}))
.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')),
bluetooth_test(
() => getConnectedHealthThermometerDevice()
// Chrome will always close the previous chooser in the process of
// handling a user gesture for the next request, so these need to
// be done sequentially.
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [health_thermometer.alias]}]}))
.then(
device =>
assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [health_thermometer.name]}]}))
.then(
device =>
assert_equals(device.constructor.name, 'BluetoothDevice'))
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [health_thermometer.uuid]}]}))
.then(
device => assert_equals(
device.constructor.name, 'BluetoothDevice')),
test_desc);
</script>

View file

@ -8,17 +8,21 @@
'use strict';
const test_desc = 'requestDevice calls do not consume user gestures.';
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
.then(() => callWithTrustedClick(() => {
let first = navigator.bluetooth.requestDevice({
filters: [{services: ['heart_rate']}]});
let second = navigator.bluetooth.requestDevice({
filters: [{services: ['heart_rate']}]});
return Promise.all([
first.then(device => assert_equals(
device.constructor.name, 'BluetoothDevice')),
second.then(device => assert_equals(
device.constructor.name, 'BluetoothDevice')),
]);
})), test_desc);
bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices().then(
() => callWithTrustedClick(() => {
let first = navigator.bluetooth.requestDevice(
{filters: [{services: ['heart_rate']}]});
let second = navigator.bluetooth.requestDevice(
{filters: [{services: ['heart_rate']}]});
return Promise.all([
first.then(
device =>
assert_equals(device.constructor.name, 'BluetoothDevice')),
second.then(
device =>
assert_equals(device.constructor.name, 'BluetoothDevice')),
]);
})),
test_desc);
</script>

View file

@ -11,57 +11,55 @@ let matching_services = [health_thermometer.uuid];
let matching_name = 'Health Thermometer';
let matching_namePrefix = 'Health';
let test_specs = [{
filters: [{
services: matching_services,
}]
}, {
filters: [{
services: matching_services,
name: matching_name,
}]
}, {
filters: [{
services: matching_services,
namePrefix: matching_namePrefix
}]
}, {
filters: [{
name: matching_name,
}],
optionalServices: matching_services
}, {
filters: [{
name: matching_name,
namePrefix: matching_namePrefix
}],
optionalServices: matching_services
}, {
filters: [{
namePrefix: matching_namePrefix
}],
optionalServices: matching_services
}, {
filters: [{
services: matching_services,
name: matching_name,
namePrefix: matching_namePrefix
}]
}];
let test_specs = [
{
filters: [{
services: matching_services,
}]
},
{
filters: [{
services: matching_services,
name: matching_name,
}]
},
{filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, {
filters: [{
name: matching_name,
}],
optionalServices: matching_services
},
{
filters: [{name: matching_name, namePrefix: matching_namePrefix}],
optionalServices: matching_services
},
{
filters: [{namePrefix: matching_namePrefix}],
optionalServices: matching_services
},
{
filters: [{
services: matching_services,
name: matching_name,
namePrefix: matching_namePrefix
}]
}
];
bluetooth_test(() => setUpHealthThermometerDevice()
.then(() => {
bluetooth_test(
() => setUpHealthThermometerDevice().then(() => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises
.then(() => requestDeviceWithTrustedClick(args))
.then(device => {
// We always have access to the services in matching_services
// because we include them in a filter or in optionalServices.
assert_equals(device.name, matching_name);
assert_true(device.name.startsWith(matching_namePrefix));
});
test_promises =
test_promises.then(() => requestDeviceWithTrustedClick(args))
.then(device => {
// We always have access to the services in matching_services
// because we include them in a filter or in optionalServices.
assert_equals(device.name, matching_name);
assert_true(device.name.startsWith(matching_namePrefix));
});
});
return test_promises;
}), test_desc);
}),
test_desc);
</script>

View file

@ -7,12 +7,13 @@
<script>
'use strict';
const test_desc = 'Reject with NotFoundError if Bluetooth is not supported.';
const expected = new DOMException('Bluetooth Low Energy not available.',
'NotFoundError');
const expected =
new DOMException('Bluetooth Low Energy not available.', 'NotFoundError');
bluetooth_test(() => navigator.bluetooth.test.setLESupported(false)
.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({acceptAllDevices: true}),
expected, 'Bluetooth Low Energy is not supported.')),
bluetooth_test(
() => navigator.bluetooth.test.setLESupported(false).then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({acceptAllDevices: true}), expected,
'Bluetooth Low Energy is not supported.')),
test_desc);
</script>

View file

@ -8,8 +8,10 @@
'use strict';
const test_desc = 'An empty name device can be obtained by empty name filter.'
bluetooth_test(() => setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
.then(device => assert_equals(device.name, '')),
bluetooth_test(
() =>
setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({filters: [{name: ''}]}))
.then(device => assert_equals(device.name, '')),
test_desc);
</script>

View file

@ -11,9 +11,11 @@ const expected = new DOMException(
'Must be handling a user gesture to show a permission request.',
'SecurityError');
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
.then(() => assert_promise_rejects_with_message(
navigator.bluetooth.requestDevice({filters:[{services:['heart_rate']}]}),
expected, 'User gesture is required')),
bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices().then(
() => assert_promise_rejects_with_message(
navigator.bluetooth.requestDevice(
{filters: [{services: ['heart_rate']}]}),
expected, 'User gesture is required')),
test_desc);
</script>

View file

@ -7,14 +7,15 @@
<script>
'use strict';
const test_desc = 'Reject with NotFoundError if there is no BT radio present.';
const expected = new DOMException('Bluetooth adapter not available.',
'NotFoundError');
const expected =
new DOMException('Bluetooth adapter not available.', 'NotFoundError');
bluetooth_test(() => navigator.bluetooth.test.simulateCentral({state: 'absent'})
.then(() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick({
filters: [{services: ['generic_access']}]
}),
expected, 'Bluetooth adapter is not present.')),
bluetooth_test(
() => navigator.bluetooth.test.simulateCentral({state: 'absent'})
.then(
() => assert_promise_rejects_with_message(
requestDeviceWithTrustedClick(
{filters: [{services: ['generic_access']}]}),
expected, 'Bluetooth adapter is not present.')),
test_desc);
</script>

View file

@ -12,32 +12,36 @@ for (let i = 0; i < 5; i++) {
iframes.push(document.createElement('iframe'));
}
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
// 1. Load the iframes.
.then(() => {
let promises = [];
for (let iframe of iframes) {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
promises.push(new Promise(resolve =>
iframe.addEventListener('load', resolve)));
}
return Promise.all(promises);
})
// 2. Request the device from the iframes.
.then(() => new Promise(async (resolve) => {
let numMessages = 0;
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'Success');
if (++numMessages === iframes.length) {
resolve();
}
}
bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices()
// 1. Load the iframes.
.then(() => {
let promises = [];
for (let iframe of iframes) {
iframe.src =
'/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
promises.push(new Promise(
resolve => iframe.addEventListener('load', resolve)));
}
return Promise.all(promises);
})
// 2. Request the device from the iframes.
.then(() => new Promise(async (resolve) => {
let numMessages = 0;
window.onmessage =
messageEvent => {
assert_equals(messageEvent.data, 'Success');
if (++numMessages === iframes.length) {
resolve();
}
}
for (let iframe of iframes) {
await callWithTrustedClick(() => iframe.contentWindow.postMessage({
type: 'RequestDevice'
}, '*'));
}
})), test_desc);
for (let iframe of iframes) {
await callWithTrustedClick(
() => iframe.contentWindow.postMessage(
{type: 'RequestDevice'}, '*'));
}
})),
test_desc);
</script>

View file

@ -14,26 +14,28 @@ const expected = 'SecurityError: requestDevice() called from cross-origin ' +
let iframe = document.createElement('iframe');
bluetooth_test(() => getConnectedHealthThermometerDevice()
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.sandbox.add('allow-scripts');
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Request the device from the iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestDevice'
}, '*');
});
bluetooth_test(
() => getConnectedHealthThermometerDevice()
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.sandbox.add('allow-scripts');
iframe.src =
'/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Request the device from the iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage(
{type: 'RequestDevice'}, '*');
});
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, expected);
resolve();
}
})), test_desc);
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, expected);
resolve();
}
})),
test_desc);
</script>
</body>

View file

@ -10,21 +10,23 @@ const test_desc = 'Returned device should always be the same.';
let devices = [];
let push = device => devices.push(device);
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [heart_rate.alias]}]
}))
.then(push)
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [heart_rate.name]}]
}))
.then(push)
.then(() => requestDeviceWithTrustedClick({
filters: [{services: [heart_rate.uuid]}]
}))
.then(push)
.then(() => {
assert_equals(devices[0], devices[1]);
assert_equals(devices[1], devices[2]);
}), test_desc);
bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices()
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [heart_rate.alias]}]}))
.then(push)
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [heart_rate.name]}]}))
.then(push)
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: [heart_rate.uuid]}]}))
.then(push)
.then(() => {
assert_equals(devices[0], devices[1]);
assert_equals(devices[1], devices[2]);
}),
test_desc);
</script>

View file

@ -8,10 +8,11 @@
'use strict';
const test_desc = 'Simple filter selects matching device.';
bluetooth_test(() => setUpHealthThermometerAndHeartRateDevices()
.then(() => requestDeviceWithTrustedClick({
filters: [{services: ['health_thermometer']}]
}))
.then(device => assert_equals(device.name, 'Health Thermometer')),
bluetooth_test(
() => setUpHealthThermometerAndHeartRateDevices()
.then(
() => requestDeviceWithTrustedClick(
{filters: [{services: ['health_thermometer']}]}))
.then(device => assert_equals(device.name, 'Health Thermometer')),
test_desc);
</script>

View file

@ -3,24 +3,24 @@
let device, gatt;
function requestDeviceWithOptionsAndConnect(options) {
return navigator.bluetooth.requestDevice(options)
.then(device => device.gatt.connect());
return navigator.bluetooth.requestDevice(options).then(
device => device.gatt.connect());
}
window.addEventListener('message', (messageEvent) => {
switch (messageEvent.data.type) {
case 'RequestDevice':
navigator.bluetooth.requestDevice({
filters: [{services: ['generic_access']}]
})
navigator.bluetooth
.requestDevice({filters: [{services: ['generic_access']}]})
.then(device => {
if (device.constructor.name === 'BluetoothDevice') {
parent.postMessage('Success', '*');
} else {
parent.postMessage(
`FAIL: requestDevice in iframe returned ${device.name}`, '*');
}}).catch(err => parent.postMessage(`${err.name}: ${err.message}`,
'*'));
}
})
.catch(err => parent.postMessage(`${err.name}: ${err.message}`, '*'));
break;
case 'RequestAndConnect':
requestDeviceWithOptionsAndConnect(messageEvent.data.options)
@ -28,7 +28,8 @@ window.addEventListener('message', (messageEvent) => {
gatt = _;
device = gatt.device;
parent.postMessage('Connected', '*');
}).catch(err => {
})
.catch(err => {
parent.postMessage(`FAIL: ${err}`, '*');
});
break;
@ -50,8 +51,8 @@ window.addEventListener('message', (messageEvent) => {
.catch(err => parent.postMessage(`FAIL: ${err}`, '*'));
break;
default:
parent.postMessage(`FAIL: Bad message type: ${messageEvent.data.type}`,
'*');
parent.postMessage(
`FAIL: Bad message type: ${messageEvent.data.type}`, '*');
}
});
</script>

View file

@ -9,11 +9,13 @@
const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.';
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(gatt => assert_equals(gatt.device, gatt.device)),
bluetooth_test(
() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(
() => fake_peripheral.setNextGATTConnectionResponse(
{code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(gatt => assert_equals(gatt.device, gatt.device)),
test_desc);
</script>

View file

@ -8,11 +8,14 @@
'use strict';
const test_desc = 'Same parent device returned from multiple services.';
bluetooth_test(() => getTwoHealthThermometerServicesDevice({
filters: [{services: ['health_thermometer']}]
})
.then(({device}) => device.gatt.getPrimaryServices('health_thermometer'))
.then(([service1, service2]) =>
assert_equals(service1.device, service2.device)),
bluetooth_test(
() => getTwoHealthThermometerServicesDevice(
{filters: [{services: ['health_thermometer']}]})
.then(
({device}) =>
device.gatt.getPrimaryServices('health_thermometer'))
.then(
([service1, service2]) =>
assert_equals(service1.device, service2.device)),
test_desc);
</script>

View file

@ -8,10 +8,12 @@
'use strict';
const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.';
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(({device}) => device.gatt.getPrimaryService('health_thermometer'))
.then(service => assert_equals(service.device, service.device)),
bluetooth_test(
() => getHealthThermometerDevice(
{filters: [{services: ['health_thermometer']}]})
.then(
({device}) =>
device.gatt.getPrimaryService('health_thermometer'))
.then(service => assert_equals(service.device, service.device)),
test_desc);
</script>

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Background Test: Large images with one auto size are correctly sized</title>
<link rel="author" title="schenney" href="mailto:schenney@chromium.org">
<link rel="help" href="http://www.w3.org/TR/css3-background">
<link rel="match" href="reference/background-image-large-with-auto-ref.html">
<style>
.wide-div {
background-image: url(support/green-1000x10.png);
background-repeat: no-repeat;
background-size: 10000px auto;
width: 1000px;
height: 100px;
border: 1px solid black;
}
.high-div {
background-image: url(support/green-10x1000.png);
background-repeat: no-repeat;
background-size: auto 10000px;
width: 100px;
height: 1000px;
border: 1px solid black;
}
</style>
</head>
<body>
<div class='wide-div'></div>
<div class='high-div'></div>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Background Test Reference</title>
<link rel="author" title="schenney" href="mailto:schenney@chromium.org">
<style>
.wide-div {
background-image: url(../support/green-1000x10.png);
background-repeat: no-repeat;
background-size: 10000px 100px;
width: 1000px;
height: 100px;
border: 1px solid black;
}
.high-div {
background-image: url(../support/green-10x1000.png);
background-repeat: no-repeat;
background-size: 100px 10000px;
width: 100px;
height: 1000px;
border: 1px solid black;
}
</style>
</head>
<body>
<div class='wide-div'></div>
<div class='high-div'></div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

View file

@ -147,6 +147,8 @@
{ value: "oblique 20deg", isValid: true, expectedValue: "oblique", description: "'oblique' followed by default 20deg angle" },
{ value: "oblique 90deg", isValid: true, description: "'oblique' followed by maxumum 90 degree angle" },
{ value: "oblique -90deg", isValid: true, description: "'oblique' followed by minimum -90 degree angle" },
{ value: "oblique calc(91deg)", isValid: true, expectedValue: "oblique 90deg", description: "'oblique' followed by calc with out of range value (should be clamped)" },
{ value: "oblique calc(-91deg)", isValid: true, expectedValue: "oblique -90deg", description: "'oblique' followed by calc with out of range value (should be clamped)" },
{ value: "oblique 0rad", isValid: true, expectedValue: "oblique 0deg", description: "'oblique' followed by angle in radians" },
{ value: "oblique 20", isValid: false, description: "'oblique' followed by unit-less number" },
{ value: "oblique 20px", isValid: false, description: "'oblique' followed by non-angle" },

View file

@ -7,43 +7,54 @@
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="test"></div>
<script>
var testFontStyle = [
{ style: "italic", expectedResult: true, message: "'italic' is valid" },
{ style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" },
{ style: "italic a", expectedResult: false, message: "'italic' followed by non-number is invalid" },
{ style: "oblique", expectedResult: true, message: "'oblique' is valid" },
{ style: "oblique 0deg", expectedResult: true, message: "'oblique' followed by zero degrees is valid" },
{ style: "oblique 20deg", expectedResult: true, message: "'oblique' followed by positive angle in degrees is valid" },
{ style: "oblique 0.5rad", expectedResult: true, message: "'oblique' followed by positive angle in radians is valid" },
{ style: "oblique 20grad", expectedResult: true, message: "'oblique' followed by positive angle in gradians is valid" },
{ style: "oblique 0.1turn", expectedResult: true, message: "'oblique' followed by positive angle in turns is valid" },
{ style: "oblique 20px", expectedResult: false, message: "'oblique' followed by number with invalid unit type is in valid" },
{ style: "oblique -20deg", expectedResult: true, message: "'oblique' followed by negative angle is valid" },
{ style: "oblique 20.1deg", expectedResult: true, message: "'oblique' followed by fractional angle is valid" },
{ style: "oblique 90deg", expectedResult: true, message: "'oblique' followed by maxumum 90 degree angle is valid" },
{ style: "oblique -90deg", expectedResult: true, message: "'oblique' followed by minimum -90 degree angle is valid" },
{ style: "oblique 90.01deg", expectedResult: false, message: "'oblique' followed by positive out of range angle is in invalid" },
{ style: "oblique -90.01deg", expectedResult: false, message: "'oblique' followed by negative out of range angle is in invalid" },
{ style: "oblique 10", expectedResult: false, message: "'oblique' followed by unit-less value is invalid" },
{ style: "oblique 20deg ", expectedResult: true, message: "'oblique' followed by positive angle is valid" },
{ style: "oblique a", expectedResult: false, message: "'oblique' followed by non-number is invalid" },
{ style: "oblique 20deg a", expectedResult: false, message: "'oblique' and angle followed by non-number is invalid" },
{ style: "oblique -", expectedResult: false, message: "'oblique' followed by isolated minus is invalid" },
{ style: "oblique - 20deg", expectedResult: false, message: "'oblique' followed by minus and angle separated by space is invalid" },
{ style: "oblique -a", expectedResult: false, message: "'oblique' followed by minus and non-number is invalid" },
{ style: "oblique calc(50deg)", expectedResult: true, message: "'oblique' followed by calc is valid" },
{ style: "oblique calc(-120deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (no computation)" },
{ style: "oblique calc(6 * 20deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (with computation)" },
{ style: "oblique calc(0.1rad + 1deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it mixes units (with computation)" }
{ style: "italic", expectedResult: true, message: "'italic' is valid" },
{ style: "italic 20deg", expectedResult: false, message: "'italic' followed by angle is invalid" },
{ style: "italic a", expectedResult: false, message: "'italic' followed by non-number is invalid" },
{ style: "oblique", expectedResult: true, message: "'oblique' is valid" },
{ style: "oblique 0deg", expectedResult: true, message: "'oblique' followed by zero degrees is valid" },
{ style: "oblique 20deg", expectedResult: true, message: "'oblique' followed by positive angle in degrees is valid" },
{ style: "oblique 0.5rad", expectedResult: true, message: "'oblique' followed by positive angle in radians is valid", expectedValue: "oblique 28.6479deg" },
{ style: "oblique 20grad", expectedResult: true, message: "'oblique' followed by positive angle in gradians is valid", expectedValue: "oblique 18deg" },
{ style: "oblique 0.1turn", expectedResult: true, message: "'oblique' followed by positive angle in turns is valid", expectedValue: "oblique 36deg" },
{ style: "oblique 20px", expectedResult: false, message: "'oblique' followed by number with invalid unit type is in valid" },
{ style: "oblique -20deg", expectedResult: true, message: "'oblique' followed by negative angle is valid" },
{ style: "oblique 20.5deg", expectedResult: true, message: "'oblique' followed by fractional angle is valid" },
{ style: "oblique 90deg", expectedResult: true, message: "'oblique' followed by maxumum 90 degree angle is valid" },
{ style: "oblique -90deg", expectedResult: true, message: "'oblique' followed by minimum -90 degree angle is valid" },
{ style: "oblique 90.01deg", expectedResult: false, message: "'oblique' followed by positive out of range angle is in invalid" },
{ style: "oblique -90.01deg", expectedResult: false, message: "'oblique' followed by negative out of range angle is in invalid" },
{ style: "oblique 10", expectedResult: false, message: "'oblique' followed by unit-less value is invalid" },
{ style: "oblique 30deg", expectedResult: true, message: "'oblique' followed by positive angle is valid" },
{ style: "oblique a", expectedResult: false, message: "'oblique' followed by non-number is invalid" },
{ style: "oblique 20deg a", expectedResult: false, message: "'oblique' and angle followed by non-number is invalid" },
{ style: "oblique -", expectedResult: false, message: "'oblique' followed by isolated minus is invalid" },
{ style: "oblique - 20deg", expectedResult: false, message: "'oblique' followed by minus and angle separated by space is invalid" },
{ style: "oblique -a", expectedResult: false, message: "'oblique' followed by minus and non-number is invalid" },
{ style: "oblique calc(50deg)", expectedResult: true, message: "'oblique' followed by calc is valid", expectedValue: "oblique 50deg" },
{ style: "oblique calc(-120deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (no computation)", expectedValue: "oblique -90deg" },
{ style: "oblique calc(6 * 20deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it must be clamped (with computation)", expectedValue: "oblique 90deg" },
{ style: "oblique calc(10grad + 5deg)", expectedResult: true, message: "'oblique' followed by calc is valid even if it mixes units (with computation)", expectedValue: "oblique 14deg" }
];
testFontStyle.forEach(function (testCase) {
test(() => { assert_equals(window.CSS.supports("font-style", testCase.style), testCase.expectedResult, "Font-style: " + testCase.message); }, "Font-style: " + testCase.message);
test(() => {
assert_equals(window.CSS.supports("font-style", testCase.style), testCase.expectedResult, "Font-style supports: " + testCase.message);
}, "Font-style (supports): " + testCase.message);
});
testFontStyle.forEach(function (testCase) {
if (testCase.expectedResult) {
test(() => {
let element = document.getElementById("test");
element.style = "font-style: " + testCase.style;
let expectedValue = (testCase.expectedValue) ? testCase.expectedValue : testCase.style;
assert_equals(window.getComputedStyle(element).fontStyle, expectedValue, "Font-style computed style: " + testCase.message);
}, "Font-style (computed): " + testCase.message);
}
});
</script>
</body>
</html>
</html>

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test Reference: Test column-span:all when the body tag is the multi-column container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
body {
column-count: 1;
column-rule: 6px solid;
width: 400px;
outline: 1px solid black;
}
h3 {
/* column-count: 1 makes this behave like a real spanner. */
outline: 1px solid blue;
}
</style>
<body>
<div>block1</div>
<div>
<h3>spanner</h3>
</div>
<div>block2</div>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test column-span:all when the body tag is the multi-column container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
<link rel="match" href="multicol-span-all-007-ref.html">
<meta name="assert" content="This test checks a column-span:all element is working if the body tag is the multi-column container.">
<style>
body {
column-count: 3;
column-rule: 6px solid;
width: 400px;
outline: 1px solid black;
}
h3 {
column-span: all;
outline: 1px solid blue;
}
</style>
<body>
<div>block1</div>
<div>
<h3>spanner</h3> <!-- Put spanner in a subtree deliberately -->
</div>
<div>block2</div>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test Reference: Append a block containing a spanner kid. The spanner kid should correctly span across all columns.</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<style>
#column {
column-count: 3;
column-rule: 6px solid;
width: 400px;
outline: 1px solid black;
}
h3 {
column-span: all;
outline: 1px solid blue;
}
</style>
<body>
<article id="column">
<div>block1</div>
<div><h3>spanner</h3>block2</div>
</article>
</body>
</html>

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Append a block containing a spanner kid. The spanner kid should correctly span across all columns.</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
<link rel="match" href="multicol-span-all-dynamic-add-010-ref.html">
<meta name="assert" content="This test checks appending a block containing 'column-span' element should be rendered correctly.">
<script>
function runTest() {
document.body.offsetHeight;
// Create a subtree like the following, and append it to columns.
// <div>
// <h3>spanner</h3>
// block2
// </div>
var spanner = document.createElement("h3");
var spannerText = document.createTextNode("spanner");
spanner.appendChild(spannerText);
var block2 = document.createElement("div");
var block2Text = document.createTextNode("block2");
block2.appendChild(spanner);
block2.appendChild(block2Text)
var column = document.getElementById("column");
column.appendChild(block2);
document.documentElement.removeAttribute("class");
}
</script>
<style>
#column {
column-count: 3;
column-rule: 6px solid;
width: 400px;
outline: 1px solid black;
}
h3 {
column-span: all;
outline: 1px solid blue;
}
</style>
<body onload="runTest();">
<article id="column">
<div>block1</div>
</article>
</body>
</html>

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Inheritance of CSS Overflow properties</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#property-index">
<meta name="assert" content="Properties inherit or not according to the spec.">
<meta name="assert" content="Properties have initial values according to the spec.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/inheritance-testcommon.js"></script>
</head>
<body>
<div id="container">
<div id="target"></div>
</div>
<script>
assert_inherited('block-ellipsis', 'none', 'auto');
assert_not_inherited('continue', 'auto', 'discard');
assert_not_inherited('max-lines', 'none', '2');
assert_not_inherited('overflow-block', 'visible', 'scroll');
assert_not_inherited('overflow-inline', 'visible', 'scroll');
assert_not_inherited('overflow-x', 'visible', 'scroll');
assert_not_inherited('overflow-y', 'visible', 'scroll');
assert_not_inherited('text-overflow', 'clip', 'ellipsis');
</script>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing block-ellipsis with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-block-ellipsis">
<meta name="assert" content="block-ellipsis supports only the grammar 'none | auto | <string>'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("block-ellipsis", 'hidden');
test_invalid_value("block-ellipsis", 'none auto');
test_invalid_value("block-ellipsis", 'auto "string"');
test_invalid_value("block-ellipsis", '"string" none');
test_invalid_value("block-ellipsis", '"first" "second"');
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing block-ellipsis with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-block-ellipsis">
<meta name="assert" content="block-ellipsis supports the full grammar 'none | auto | <string>'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("block-ellipsis", 'none');
test_valid_value("block-ellipsis", 'auto');
test_valid_value("block-ellipsis", '" etc., etc. "');
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing continue with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-continue">
<meta name="assert" content="continue supports only the grammar 'auto | discard'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("continue", 'none');
test_invalid_value("continue", 'auto discard');
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing continue with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-continue">
<meta name="assert" content="continue supports the full grammar 'auto | discard'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("continue", 'auto');
test_valid_value("continue", 'discard');
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing line-clamp with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-line-clamp">
<meta name="assert" content="line-clamp supports only the grammar 'none | <integer> <block-ellipsis>?'.">
<meta name="assert" content="Zero or negative max-lines integers are invalid.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("line-clamp", 'auto');
test_invalid_value("line-clamp", '0');
test_invalid_value("line-clamp", '-5');
test_invalid_value("line-clamp", '" etc., etc. "');
test_invalid_value("line-clamp", 'none 2');
test_invalid_value("line-clamp", '3 none');
test_invalid_value("line-clamp", 'auto 4');
</script>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing line-clamp with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-line-clamp">
<meta name="assert" content="line-clamp supports the full grammar 'none | <integer> <block-ellipsis>?'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("line-clamp", 'none');
test_valid_value("line-clamp", '1');
test_valid_value("line-clamp", '6');
test_valid_value("line-clamp", '7 none');
test_valid_value("line-clamp", '8 auto', '8');
test_valid_value("line-clamp", '9 " etc., etc. "');
</script>
</body>
</html>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing max-lines with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-max-lines">
<meta name="assert" content="max-lines supports only the grammar 'none | <integer>'.">
<meta name="assert" content="Zero or negative integers are invalid.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("max-lines", 'auto');
test_invalid_value("max-lines", '0');
test_invalid_value("max-lines", '-5');
test_invalid_value("max-lines", 'none none');
test_invalid_value("max-lines", '1 none');
test_invalid_value("max-lines", 'none 2');
test_invalid_value("max-lines", '3 4');
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing max-lines with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-max-lines">
<meta name="assert" content="max-lines supports the full grammar 'none | <integer>'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("max-lines", 'none');
test_valid_value("max-lines", '1');
test_valid_value("max-lines", '6');
</script>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: getComputedValue().overflow</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
<meta name="assert" content="visible/clip compute to auto/hidden (respectively) if one of overflow-x or overflow-y is neither visible nor clip.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("overflow", 'visible');
test_computed_value("overflow", 'hidden');
test_computed_value("overflow", 'clip');
test_computed_value("overflow", 'scroll');
test_computed_value("overflow", 'auto');
test_computed_value("overflow", 'auto auto', 'auto');
test_computed_value("overflow", 'auto clip', 'auto hidden');
test_computed_value("overflow", 'auto visible', 'auto');
test_computed_value("overflow", 'clip auto', 'hidden auto');
test_computed_value("overflow", 'clip clip', 'clip');
test_computed_value("overflow", 'clip hidden', 'hidden');
test_computed_value("overflow", 'clip scroll', 'hidden scroll')
test_computed_value("overflow", 'hidden clip', 'hidden');
test_computed_value("overflow", 'hidden visible', 'hidden auto');
test_computed_value("overflow", 'scroll auto');
test_computed_value("overflow", 'scroll clip', 'scroll hidden');
test_computed_value("overflow", 'scroll visible', 'scroll auto');
test_computed_value("overflow", 'visible auto', 'auto');
test_computed_value("overflow", 'visible hidden', 'auto hidden');
test_computed_value("overflow", 'visible scroll', 'auto scroll');
test_computed_value("overflow", 'visible visible', 'visible');
test_computed_value("overflow-x", 'scroll');
test_computed_value("overflow-x", 'hidden');
test_computed_value("overflow-x", 'visible');
test_computed_value("overflow-y", 'clip');
test_computed_value("overflow-y", 'auto');
test_computed_value("overflow-y", 'visible');
test_computed_value("overflow-block", 'hidden');
test_computed_value("overflow-block", 'clip');
test_computed_value("overflow-block", 'visible');
test_computed_value("overflow-inline", 'scroll');
test_computed_value("overflow-inline", 'visible');
</script>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing overflow with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
<meta name="assert" content="overflow supports only the grammar '[ visible | hidden | clip | scroll | auto ]{1,2}'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("overflow", 'none');
test_invalid_value("overflow", 'visible clip auto');
test_invalid_value("overflow-x", 'visible clip');
test_invalid_value("overflow-y", 'clip hidden');
test_invalid_value("overflow-block", 'hidden scroll');
test_invalid_value("overflow-inline", 'scroll auto');
</script>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing overflow with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-overflow">
<meta name="assert" content="overflow supports the full grammar '[ visible | hidden | clip | scroll | auto ]{1,2}'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("overflow", 'visible');
test_valid_value("overflow", 'hidden');
test_valid_value("overflow", 'clip');
test_valid_value("overflow", 'scroll');
test_valid_value("overflow", 'auto');
test_valid_value("overflow", 'visible visible', 'visible');
test_valid_value("overflow", 'hidden visible');
test_valid_value("overflow", 'clip clip', 'clip');
test_valid_value("overflow", 'scroll auto');
test_valid_value("overflow", 'auto auto', 'auto');
test_valid_value("overflow-x", 'visible');
test_valid_value("overflow-x", 'scroll');
test_valid_value("overflow-y", 'clip');
test_valid_value("overflow-y", 'auto');
test_valid_value("overflow-block", 'hidden');
test_valid_value("overflow-block", 'clip');
test_valid_value("overflow-inline", 'scroll');
test_valid_value("overflow-inline", 'visible');
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: getComputedValue().textOverflow</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("text-overflow", 'clip');
test_computed_value("text-overflow", 'ellipsis');
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing text-overflow with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
<meta name="assert" content="text-overflow supports only the grammar 'clip | ellipsis'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("text-overflow", 'auto');
test_invalid_value("text-overflow", 'clip ellipsis clip');
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing text-overflow with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#propdef-text-overflow">
<meta name="assert" content="text-overflow supports the full grammar 'clip | ellipsis'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("text-overflow", 'clip');
test_valid_value("text-overflow", 'ellipsis');
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#scroller {
overflow: scroll;
width: 300px;
height: 300px;
}
#before { height: 50px; }
#content { margin-top: 100px; margin-bottom: 600px; }
.no { overflow-anchor: none; }
</style>
<div id="scroller">
<div id="before"></div>
<div id="content">content</div>
</div>
<script>
// Tests that dynamic styling 'overflow-anchor' on a scrolling element has the
// same effect as initial styling
test(() => {
let scroller = document.querySelector("#scroller");
let before = document.querySelector("#before");
// Scroll down so that #content is the first element in the viewport
scroller.scrollTop = 100;
// Change the height of #before to trigger a scroll adjustment. This ensures
// that #content was selected as a scroll anchor
before.style.height = "100px";
assert_equals(scroller.scrollTop, 150);
// Now set 'overflow-anchor: none' on #scroller. This should invalidate the
// scroll anchor, and #scroller shouldn't be able to select an anchor anymore
scroller.className = 'no';
// Change the height of #before and make sure we don't adjust. This ensures
// that #content is not a scroll anchor
before.style.height = "150px";
assert_equals(scroller.scrollTop, 150);
}, "Dynamically styling 'overflow-anchor: none' on the scroller element should prevent scroll anchoring");
</script>

View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#scroller {
overflow: scroll;
width: 300px;
height: 300px;
}
#before { height: 50px; }
#content { margin-top: 100px; margin-bottom: 600px; }
.no { overflow-anchor: none; }
</style>
<div id="scroller">
<div id="before"></div>
<div id="content">content</div>
</div>
<script>
// Tests that dynamic styling 'overflow-anchor' on an anchor node has the
// same effect as initial styling
test(() => {
let scroller = document.querySelector("#scroller");
let before = document.querySelector("#before");
let content = document.querySelector("#content");
// Scroll down so that #content is the first element in the viewport
scroller.scrollTop = 100;
// Change the height of #before to trigger a scroll adjustment. This ensures
// that #content was selected as a scroll anchor
before.style.height = "100px";
assert_equals(scroller.scrollTop, 150);
// Now set 'overflow-anchor: none' on #content. This should invalidate the
// scroll anchor, and #scroller should recalculate its anchor. There are no
// other valid anchors in the viewport, so there should be no anchor.
content.className = 'no';
// Change the height of #before and make sure we don't adjust. This ensures
// that #content was not selected as a scroll anchor
before.style.height = "150px";
assert_equals(scroller.scrollTop, 150);
}, "Dynamically styling 'overflow-anchor: none' on the anchor node should prevent scroll anchoring");
</script>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Shadow Parts - Interaction with placeholder</title>
<meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly">
<link href="http://www.google.com/" rel="author" title="Google">
<link href="https://drafts.csswg.org/css-shadow-parts/" rel="help">
</head>
<body>
<style>
#placeholder-i::placeholder { color: green; }
</style>
<div>
The following text should be green:
<input id="placeholder-i" part="placeholder-p" placeholder="this text"></input>
</div>
</body>
</html>

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Shadow Parts - Interaction with placeholder</title>
<!-- This reftest exists because getComputedStyle for
::placeholder is not implemented everywhere --!>
<meta href="mailto:fergal@chromium.org" rel="author" title="Fergal Daly">
<link href="http://www.google.com/" rel="author" title="Google">
<link href="https://drafts.csswg.org/css-shadow-parts/" rel="help">
<link href="interaction-with-placeholder-ref.html" rel="match">
<script src="support/shadow-helper.js"></script>
</head>
<body>
<style>
#c-e::part(placeholder-p)::placeholder { color: green; }
</style>
<script>installCustomElement("custom-element", "custom-element-template");</script>
<template id="custom-element-template">
<style>
#placeholder-i::placeholder { color: red; }
</style>
<div>
The following text should be green:
<input id="placeholder-i" part="placeholder-p" placeholder="this text"></input>
</div>
</template>
<custom-element id="c-e"></custom-element>
</body>
</html>

View file

@ -501,15 +501,18 @@ test(() => {
span.shadowRoot.adoptedStyleSheets = [sheet];
assert_equals(getComputedStyle(shadowDiv).color, "rgb(255, 0, 0)");
document.adoptNode(span);
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
iframe.contentDocument.adoptNode(span);
iframe.contentDocument.body.appendChild(span);
assert_not_equals(span.shadowRoot, null);
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 1);
assert_equals(span.shadowRoot.adoptedStyleSheets[0], sheet);
assert_equals(span.shadowRoot.adoptedStyleSheets.length, 0);
assert_equals(getComputedStyle(shadowDiv).color, "rgb(0, 0, 0)");
}, 'Adopting a shadow host will move adoptedStyleSheets but it is not applied');
}, 'Adopting a shadow host will empty adoptedStyleSheets if adopting to a different document');
</script>

View file

@ -14,6 +14,11 @@
<td>x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: 50%">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td>x</td>

View file

@ -11,6 +11,11 @@
<td style="width: calc(500px)">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: calc(50% + 1px)">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: calc(50%)">x</td>

View file

@ -19,6 +19,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
<td>x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: 50%">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td>x</td>

View file

@ -16,6 +16,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
<td style="width: calc(500px)">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: calc(50% + 1px)">x</td>
<td style="width: 100px">y</td>
</table>
<table border>
<tr>
<td style="width: calc(50%)">x</td>

View file

@ -8,7 +8,7 @@ The tests make a number of assumptions of the user agent, and new
tests can freely rely on these assumptions being true:
* The device is a full-color device.
* The device has a viewport width of at least 800px.
* The device has a viewport width of at least 600px.
* The UA imposes no minimum font size.
* The `medium` `font-size` computes to 16px.
* The canvas background is `white`.

View file

@ -90,7 +90,7 @@ headers.
### Be Short
Tests should be as short as possible. For reftests in particular
scrollbars at 800&#xD7;600px window size must be avoided unless scrolling
scrollbars at 600&#xD7;600px window size must be avoided unless scrolling
behavior is specifically being tested. For all tests extraneous
elements on the page should be avoided so it is clear what is part of
the test (for a typical testharness test, the only content on the page

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
var saw_link_onerror = false;
var t = async_test("Check if the stylesheet's error event is fired before the " +
"pending parsing-blocking script is unblocked");
</script>
<link href="nonexistent.css" rel="stylesheet" id="style_test"
onload="t.unreached_func('Sheet should fail to load')"
onerror="t.step(function() { saw_link_onerror = true; })">
<script>
t.step(function() {
assert_true(saw_link_onerror, "The pending parsing-blocking script should " +
"only run after the last element that " +
"contributes a script-blocking style " +
"sheet's error event is fired if the sheet " +
"fails to load.");
});
t.done();
</script>
</head>
</html>

View file

@ -11,7 +11,7 @@ window.addEventListener('load', t.step_func_done(function() {
}));
</script>
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test"
onload="t.step(function() { saw_link_onload = true; });"
onerror="t.step(function() { assert_unreached('Sheet should load OK'); });"></link>
onload="t.step(function() { saw_link_onload = true; })"
onerror="t.unreached_func('Sheet should load OK')">
</head>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
var saw_link_onload = false;
var t = async_test("Check if the stylesheet's load event is fired before the " +
"pending parsing-blocking script is unblocked");
</script>
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test"
onload="t.step(function() { saw_link_onload = true; })"
onerror="t.unreached_func('Sheet should load OK')">
<script>
t.step(function() {
assert_true(saw_link_onload, "The pending parsing-blocking script should " +
"only run after the last element that " +
"contributes a script-blocking style " +
"sheet's load event is fired.");
});
t.done();
</script>
</head>
</html>

View file

@ -0,0 +1,3 @@
body {
background-color: gray;
}

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<link rel="author" title="Dom Farolino" href="mailto:dom@chromium.org">
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link href="style.css?pipe=trickle(d3)" rel="stylesheet" id="style_test">
<script>
test(function() {
assert_true(document.styleSheets.length === 1 &&
document.styleSheets[0].href.includes("style.css"),
"The style sheet 'style.css' must be available to scripts");
style_test.href = "resources/neutral.css?pipe=trickle(d3)";
assert_true(document.styleSheets.length === 1 &&
document.styleSheets[0].href.includes("style.css"),
"The style sheet 'style.css' must remain accessible to " +
"scripts until its replacement has finished loading");
}, "Check that a style sheet loaded by a <link> is available until its successor is loaded");
</script>
</head>
</html>

View file

@ -0,0 +1,2 @@
<!doctype html>
<p>innerWidth x innerHeight: <span>600x600</span></p>

View file

@ -0,0 +1,6 @@
<!doctype html>
<link rel=match href=size-ref.html>
<p>innerWidth x innerHeight: <span id=size></span></p>
<script>
document.querySelector("#size").textContent = window.innerWidth + "x" + window.innerHeight;
</script>

View file

@ -262,7 +262,7 @@ interface SVGSVGElement : SVGGraphicsElement {
DOMMatrix createSVGMatrix();
DOMRect createSVGRect();
SVGTransform createSVGTransform();
SVGTransform createSVGTransformFromMatrix(DOMMatrixReadOnly matrix);
SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix);
Element getElementById(DOMString elementId);
@ -367,7 +367,7 @@ interface SVGTransform {
[SameObject] readonly attribute DOMMatrix matrix;
readonly attribute float angle;
void setMatrix(DOMMatrixReadOnly matrix);
void setMatrix(optional DOMMatrix2DInit matrix);
void setTranslate(float tx, float ty);
void setScale(float sx, float sy);
void setRotate(float angle, float cx, float cy);
@ -391,7 +391,7 @@ interface SVGTransformList {
setter void (unsigned long index, SVGTransform newItem);
// Additional methods not common to other list interfaces.
SVGTransform createSVGTransformFromMatrix(DOMMatrixReadOnly matrix);
SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix);
SVGTransform? consolidate();
};

View file

@ -164,16 +164,18 @@ function userIsShownErrorsFields(button) {
function abortTheUpdate(button) {
button.disabled = true;
promise_test(async t => {
const { response, request } = await getPaymentRequestResponse({ requestShipping: true });
// causes "abort the update" to run
const shippingChangedPromise = new Promise(resolve => {
request.onshippingoptionchange = () => {
event.updateWith({ total: { amount: { currency: "USD", value: "INVALID" } }});
const { response, request } = await getPaymentRequestResponse({
requestShipping: true,
});
const shipOptionChangePromise = new Promise(resolve => {
request.onshippingoptionchange = event => {
// causes "abort the update" to run
event.updateWith({ total: "error!" });
resolve();
};
});
const retryPromise = response.retry();
await shippingChangedPromise;
await shipOptionChangePromise;
await promise_rejects(
t,
new TypeError(),
@ -265,7 +267,9 @@ function callingRetryReturnsUniquePromise(button){
</li>
<li>
<p>
When shown the payment sheet, hit pay once. Then retry once.
When shown the payment sheet, hit pay once.
Then, change the shipping option.
Select to pay again.
</p>
<button onclick="abortTheUpdate(this);">
When "abort the update" occurs because of an update error,

View file

@ -2,16 +2,21 @@
<meta charset="utf-8">
<title>iframe for xhr tests</title>
<script>
async function xhr(url) {
async function xhr(url, options) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const opts = options ? options : {};
xhr.onload = () => {
resolve(xhr);
};
xhr.onerror = () => {
reject('xhr failed');
};
xhr.open('GET', url);
if (opts.responseType) {
xhr.responseType = opts.responseType;
}
xhr.send();
});
}

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