<icon src="icon.png" height="117" width="117"/>
<name>tct-mediacapture-w3c-tests</name>
<tizen:application id="w3cmediaca.WebAPIW3CMediacaptureTests" package="w3cmediaca" required_version="8.0"/>
+ <tizen:privilege name="http://tizen.org/privilege/internet"/>
+ <tizen:privilege name="http://tizen.org/privilege/tv.inputdevice"/>
+ <tizen:privilege name="http://tizen.org/privilege/recorder"/>
+ <tizen:privilege name="http://tizen.org/privilege/mediacapture"/>
+ <tizen:privilege name="http://tizen.org/privilege/filesystem.read"/>
+ <tizen:privilege name="http://developer.samsung.com/privilege/camera"/>
+ <tizen:privilege name="http://developer.samsung.com/privilege/microphone"/>
+ <tizen:privilege name="http://developer.samsung.com/privilege/hostedapp_deviceapi_allow"/>
<tizen:setting screen-orientation="landscape"/>
<tizen:setting pointing-device-support="enable"/>
</widget>
action_status = False
break
- # Do some special copy/delete... steps
- '''
- (return_code, output) = doRemoteCMD(
- "mkdir -p %s/tests" % PKG_SRC_DIR)
- if return_code != 0:
- action_status = False
-
- if not doRemoteCopy("specname/tests", "%s/tests" % PKG_SRC_DIR):
- action_status = False
- '''
+ for item in glob.glob("%s/*" % SCRIPT_DIR):
+ if item.endswith(".wgt"):
+ continue
+ elif item.endswith("inst.py"):
+ continue
+ else:
+ item_name = os.path.basename(item)
+ if not doRemoteCopy(item, "%s/%s" % (PKG_SRC_DIR, item_name)):
+ action_status = False
return action_status
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia: test that getUserMedia is present</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermedia">
+<meta name='assert' content='Check that the getUserMedia() method is present.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of the
+<code>navigator.mediaDevices.getUserMedia</code> method.</p>
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(function () {
+ assert_true(undefined !== navigator.mediaDevices && undefined !== navigator.mediaDevices.getUserMedia, "navigator.mediaDevices.getUserMedia exists");
+}, "mediaDevices.getUserMedia() is present on navigator");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia({}) rejects with TypeError</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia">
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that getUserMedia with no value in the
+options parameter raises a TypeError exception.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+promise_test(async () => {
+ try {
+ // Race a settled promise to check that the returned promise is already
+ // rejected.
+ await Promise.race([navigator.mediaDevices.getUserMedia({}),
+ Promise.resolve()]);
+ } catch (error) {
+ assert_throws_js(TypeError, () => { throw error });
+ assert_false('constraintName' in error,
+ "constraintName attribute not set as expected");
+ return;
+ }
+ assert_unreached("should have returned an already-rejected promise.");
+}, "Tests that getUserMedia is rejected with a TypeError when used with an empty options parameter");
+
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Trivial mandatory constraint in getUserMedia</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-NavigatorUserMediaError">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that setting an impossible mandatory
+constraint (width >=1G) in getUserMedia works</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ // Note - integer conversion is weird for +inf and numbers > 2^32, so we
+ // use a number less than 2^32 for testing.
+ try {
+ await navigator.mediaDevices.getUserMedia({video: {width: {min:100000000}}});
+ assert_unreached("a Video stream of width 100M cannot be created");
+
+ } catch (error) {
+ assert_equals(error.name, "OverconstrainedError", "An impossible constraint triggers a OverconstrainedError");
+ assert_equals(error.constraint, "width", "The name of the not satisfied error is given in error.constraint");
+ }
+}, "Tests that setting an impossible constraint in getUserMedia fails");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Invalid facingMode in getUserMedia</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#def-constraint-facingMode">
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that trying to set an empty facingMode
+ value in getUserMedia results in an OverconstrainedError.
+</p>
+
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ try {
+ await navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: ''}}});
+ assert_unreached("The empty string is not a valid facingMode");
+ } catch (error) {
+ assert_equals(error.name, "OverconstrainedError");
+ assert_equals(error.constraint, "facingMode");
+ };
+}, "Tests that setting an invalid facingMode constraint in getUserMedia fails");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>non-applicable constraint in getUserMedia</title>
+<link rel="author" title="Intel" href="http://www.intel.com"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#methods-5">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+
+<p class="instructions">When prompted, accept to share your audio and video stream.</p>
+
+<script>
+
+let video_only_valid_constraints = {
+ width: {min: 0},
+ height: {min: 0},
+ frameRate: {min: 0},
+ aspectRatio: {min: 0},
+ facingMode: {ideal: 'environment'},
+ resizeMode: {ideal: 'none'}
+}
+
+let video_only_invalid_constraints = {
+ width: {min: 100000000},
+ height: {min: 100000000},
+ frameRate: {min: 100000000},
+ aspectRatio: {min: 100000000},
+ facingMode: {exact: 'invalid'},
+ resizeMode: {exact: 'invalid'}
+}
+
+let audio_only_valid_constraints = {
+ volume: {min: 0},
+ sampleRate: {min: 0},
+ sampleSize: {min: 0},
+ echoCancellation: {ideal: true},
+ autoGainControl: {ideal: true},
+ noiseSuppression: {ideal: true},
+ latency: {min: 0},
+ channelCount: {min: 0}
+}
+
+let audio_only_invalid_constraints = {
+ volume: {min: 2},
+ sampleRate: {min: 100000000},
+ sampleSize: {min: 100000000},
+ echoCancellation: {exact: true},
+ autoGainControl: {exact: true},
+ noiseSuppression: {exact: true},
+ latency: {max: 0},
+ channelCount: {max: 0}
+}
+
+promise_test(async () => {
+ // Both permissions are needed at some point, asking for both at once
+ await setMediaPermission();
+ let stream = await navigator.mediaDevices.getUserMedia({audio: video_only_valid_constraints})
+ assert_equals(stream.getAudioTracks().length, 1, "the media stream has exactly one audio track");
+}, 'Test that setting video-only valid constraints inside of "audio" is simply ignored');
+
+promise_test(async () => {
+ let stream = await navigator.mediaDevices.getUserMedia({audio: video_only_invalid_constraints})
+ assert_equals(stream.getAudioTracks().length, 1, "the media stream has exactly one audio track");
+}, 'Test that setting video-only invalid constraints inside of "audio" is simply ignored');
+
+promise_test(async () => {
+ let stream = await navigator.mediaDevices.getUserMedia({video: audio_only_valid_constraints})
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+}, 'Test that setting audio-only valid constraints inside of "video" is simply ignored');
+
+promise_test(async () => {
+ let stream = await navigator.mediaDevices.getUserMedia({video: audio_only_invalid_constraints})
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+}, 'Test that setting audio-only invalid constraints inside of "video" is simply ignored');
+
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Optional constraint recognized as optional in getUserMedia</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that setting an optional constraint in
+getUserMedia is handled as optional</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({video: {advanced: [{width: {min:1024, max: 800}}]}});
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+ } catch (error) {
+ assert_unreached("an optional constraint can't stop us from obtaining a video stream");
+ }
+}, "Tests that setting an optional constraint in getUserMedia is handled as optional");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Ideal value in required constraint in getUserMedia</title>
+<link rel="author" title="Intel" href="http://www.intel.com"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dfn-fitness-distance">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that setting a required constraint
+with an ideal value in getUserMedia works</p>
+<div id='log'></div>
+<script>
+promise_test(async t => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: {width: {ideal: 320, min: 160}}});
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+ assert_equals(stream.getVideoTracks()[0].getSettings().width, 320, 'ideal width is selected for getUserMedia() video tracks');
+ const video = document.createElement('video');
+ video.srcObject = stream;
+ await video.play();
+ assert_equals(video.videoWidth, 320, 'video width equals to track width');
+ stream.getVideoTracks()[0].stop();
+}, "Tests that setting a required constraint with an ideal value in getUserMedia works");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Trivial mandatory constraint in getUserMedia</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that setting a trivial mandatory
+constraint (width >=0) in getUserMedia works</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission();
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({video: {width: {min:0}}})
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+ } catch (error) {
+ assert_unreached("a Video stream of minimally zero width can always be created");
+ }
+}, "Tests that setting a trivial mandatory constraint in getUserMedia works");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia({doesnotexist:true}) rejects with TypeError</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that getUserMedia with an unknown value
+in the constraints parameter rejects with a TypeError.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ try {
+ await navigator.mediaDevices.getUserMedia({doesnotexist:true})
+ assert_unreached("This should never be triggered since the constraints parameter only contains an unrecognized constraint");
+ } catch (error) {
+ assert_equals(error.name, "TypeError", "TypeError returned as expected");
+ assert_equals(error.constraintName, undefined, "constraintName attribute not set as expected");
+ }
+}, "Tests that getUserMedia is rejected with a TypeError when used with an unknown constraint");
+</script>
+</body>
+</html>
--- /dev/null
+spec: https://w3c.github.io/mediacapture-main/
+suggested_reviewers:
+ - alvestrand
+ - youennf
+ - jan-ivar
--- /dev/null
+<!doctype html>
+<title>Test promises from MediaDevices methods in a discarded browsing
+ context</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<body></body>
+<script>
+let devices;
+let child_DOMException;
+setup(() => {
+ const frame = document.createElement('iframe');
+ document.body.appendChild(frame);
+ devices = frame.contentWindow.navigator.mediaDevices;
+ child_DOMException = frame.contentWindow.DOMException;
+ frame.remove();
+});
+
+// https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia
+// If the current settings object's responsible document is NOT fully active,
+// return a promise rejected with a DOMException object whose name attribute
+// has the value "InvalidStateError".
+promise_test(async () => {
+ // `catch()` is used rather than static Promise methods because microtasks
+ // for `PromiseResolve()` do not run when Promises in inactive Documents are
+ // involved. Whether microtasks for `catch()` run depends on the realm of
+ // the handler rather than the realm of the Promise.
+ // See https://github.com/whatwg/html/issues/5319.
+ let promise_already_rejected = false;
+ let rejected_reason;
+ devices.getUserMedia({audio:true}).catch(reason => {
+ promise_already_rejected = true;
+ rejected_reason = reason;
+ });
+ // Race a settled promise to check that the returned promise is already
+ // rejected.
+ await Promise.reject().catch(() => {
+ assert_true(promise_already_rejected,
+ 'should have returned an already-rejected promise.');
+ assert_throws_dom('InvalidStateError', child_DOMException,
+ () => { throw rejected_reason });
+ });
+}, 'getUserMedia() in a discarded browsing context');
+
+// https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices
+// https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-for-spec-authors
+// Promise resolution occurs only in parallel steps, so, if there is any
+// manipulation of the Promise, it would occur through a queued task.
+promise_test(() => {
+ let promise_is_pending = true;
+ // Don't use `finally()`, because it uses `PromiseResolve()` and so
+ // microtasks don't run.
+ devices.enumerateDevices().then(() => promise_is_pending = false,
+ () => promise_is_pending = false);
+ return Promise.resolve().then(() => {
+ assert_true(promise_is_pending,
+ 'should have returned a pending promise.');
+ });
+}, 'enumerateDevices() in a discarded browsing context');
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices rotates deviceId across origins and after cookies get cleared</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+</head>
+<body>
+<iframe allow="camera 'src';microphone 'src'" id=same src="iframe-enumerate.html"></iframe>
+<iframe allow="camera 'src';microphone 'src'" id=cross src="https://www.w3c-test.org/mediacapture-streams/iframe-enumerate.html"></iframe>
+<script>
+
+ let deviceList;
+
+ promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({audio : true, video: true});
+ stream.getTracks().forEach(t => t.stop());
+ deviceList = await navigator.mediaDevices.enumerateDevices();
+ const msgWatcher = new EventWatcher(t, window, ['message']);
+ frames[0].postMessage('run', '*')
+ const e = await msgWatcher.wait_for('message');
+ const iframeDevices = e.data.devices;
+ assert_equals(deviceList.length, iframeDevices.length, "Same number of devices detected same-origin");
+ for (const device of deviceList) {
+ // Look for the same device in the iframe based on deviceId
+ // "default" can be used across several kinds, so it needs an additional check
+ // but we limit that check to "default" to detect re-use of deviceId across kinds
+ const sameDevice = iframeDevices.find(d => d.deviceId === device.deviceId && (device.deviceId !== "default" || d.kind === device.kind));
+ assert_true(!!sameDevice, "deviceIds stay the same when loaded in same origin");
+ assert_equals(sameDevice.label, device.label, "labels matches when deviceId matches");
+ assert_equals(sameDevice.kind, device.kind, "kind matches when deviceId matches");
+ // The group identifier MUST be uniquely generated for each document.
+ assert_not_equals(sameDevice.groupId, device.groupId, "groupId is specific to a document");
+ }
+ // setting a cookie as a way to detect if cookie clearing gets done
+ document.cookie = "test=true";
+ window.localStorage.touched = true;
+ }, "enumerateDevices has stable deviceIds across same-origin iframe");
+
+ promise_test(async t => {
+ const msgWatcher = new EventWatcher(t, window, ['message']);
+ frames[1].postMessage('run', '*')
+ const e = await msgWatcher.wait_for('message');
+ const iframeDevices = e.data.devices;
+ assert_equals(deviceList.length, iframeDevices.length, "Same number of devices detected cross-origin");
+ for (const device of deviceList) {
+ // An identifier can be reused across origins as long as
+ // it is not tied to the user and can be guessed by other means
+ // In practice, "default" is what is used today, so we hardcode it
+ // to be able to detect the general case of non-shared deviceIds
+ if (device.deviceId !== "default") {
+ const sameDevice = iframeDevices.find(d => d.deviceId === device.deviceId);
+ assert_false(!!sameDevice, "deviceIds are not shared across origin");
+ }
+ assert_false(!!iframeDevices.find(d => d.groupId === device.groupId), "groupId is specific to a document");
+ }
+ }, "enumerateDevices rotates deviceId across different-origin iframe");
+
+ promise_test(async t => {
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("allow", "camera 'src';microphone 'src'");
+ iframe.src = "iframe-enumerate-cleared.html";
+ document.body.appendChild(iframe);
+ const loadWatcher = new EventWatcher(t, iframe, ['load']);
+ await loadWatcher.wait_for('load');
+ assert_implements_optional(document.cookie === "", "Clear-Site-Data not enabled, can't test clearing deviceId");
+
+ const msgWatcher = new EventWatcher(t, window, ['message']);
+ frames[2].postMessage('run', '*')
+ const e = await msgWatcher.wait_for('message');
+ const iframeDevices = e.data.devices;
+ assert_equals(deviceList.length, iframeDevices.length, "Same number of devices detected after clearing cookies");
+ for (const device of deviceList) {
+ const sameDevice = iframeDevices.find(d => d.deviceId === device.deviceId);
+ assert_false(!!sameDevice, "deviceIds are not kept after clearing site data");
+ assert_false(!!iframeDevices.find(d => d.groupId === device.groupId), "groupId is specific to a document");
+ }
+
+ }, "enumerateDevices rotates deviceId after clearing site data");
+
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices depends only on capture state, not permission state</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+</head>
+<body>
+
+<script>
+ promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({audio : true, video: true});
+ stream.getTracks().forEach(t => t.stop());
+ // the page loaded below hasn't had capture enabled
+ // so enumerateDevices should not list detailed info yet
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("allow", "camera 'src';microphone 'src'");
+ iframe.src = "iframe-enumerate.html";
+ document.body.appendChild(iframe);
+ const loadWatcher = new EventWatcher(t, iframe, ['load']);
+ await loadWatcher.wait_for('load');
+ const msgWatcher = new EventWatcher(t, window, ['message']);
+ frames[0].postMessage('run', '*')
+ const e = await msgWatcher.wait_for('message');
+ const iframeDevices = e.data.devices;
+ const kinds = iframeDevices.map(({kind}) => kind);
+ assert_equals(kinds.length, new Set(kinds).size, "At most one of a kind prior to capture");
+ for (const device of iframeDevices) {
+ assert_equals(device.deviceId, "", "deviceId pre-capture is empty");
+ assert_equals(device.label, "", "label pre-capture is empty");
+ assert_equals(device.groupId, "", "groupId pre-capture is empty");
+ }
+ });
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices is returning new MediaDeviceInfo objects every time</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+</head>
+<body>
+<script>
+function doTest(callGetUserMedia, testName)
+{
+ promise_test(async () => {
+ if (callGetUserMedia) {
+ await setMediaPermission();
+ await navigator.mediaDevices.getUserMedia({audio : true, video: true});
+ }
+
+ const deviceList1 = await navigator.mediaDevices.enumerateDevices();
+ const deviceList2 = await navigator.mediaDevices.enumerateDevices();
+
+ assert_equals(deviceList1.length, deviceList2.length);
+ for (let i = 0; i < deviceList1.length; i++) {
+ const device1 = deviceList1[i];
+ const device2 = deviceList2[i];
+ assert_not_equals(device1, device2);
+ assert_equals(device1.deviceId, device2.deviceId, "deviceId");
+ assert_equals(device1.kind, device2.kind, "kind");
+ if (!callGetUserMedia) {
+ /* For camera and microphone devices,
+ if the browsing context did not capture (i.e. getUserMedia() was not called or never resolved successfully),
+ the MediaDeviceInfo object will contain a valid value for kind
+ but empty strings for deviceId, label, and groupId. */
+ assert_equals(device1.deviceId, "", "deviceId is empty before capture");
+ assert_equals(device1.groupId, "", "groupId is empty before capture");
+ assert_equals(device1.label, "", "label is empty before capture");
+ assert_in_array(device1.kind, ["audioinput", "audiooutput", "videoinput", "kind is set to a valid value before capture"]);
+ }
+ }
+ /* Additionally, at most one device of each kind
+ will be listed in enumerateDevices() result. */
+ // FIXME: ensure browsers are tested as if they had multiple devices of at least one kind -
+ // this probably needs https://w3c.github.io/mediacapture-automation/ support
+ if (!callGetUserMedia) {
+ const deviceKinds = deviceList1.map(d => d.kind);
+ for (let kind of deviceKinds) {
+ assert_equals(deviceKinds.filter(x => x===kind).length, 1, "At most 1 " + kind + " prior to capture");
+ }
+ }
+ }, testName);
+}
+
+//doTest(false, "enumerateDevices returns expected mostly empty objects in case device-info permission is not granted");
+doTest(true, "enumerateDevices returns expected objects in case device-info permission is granted");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices: test that enumerateDevices is present</title>
+<link rel="author" title="Dr Alex Gouaillard" href="mailto:agouaillard@gmail.com"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#enumerating-devices">
+<meta name='assert' content='Check that the enumerateDevices() method is present.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of the
+<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+"use strict";
+
+//NOTE ALEX: for completion, a test for ondevicechange event is missing.
+
+promise_test(async () => {
+ const deviceList = await navigator.mediaDevices.enumerateDevices();
+ for (const mediaInfo of deviceList) {
+ if (mediaInfo.kind == "audioinput" || mediaInfo.kind == "videoinput") {
+ assert_true(mediaInfo instanceof InputDeviceInfo);
+ } else if ( mediaInfo.kind == "audiooutput" ) {
+ assert_true(mediaInfo instanceof MediaDeviceInfo);
+ } else {
+ assert_unreached("mediaInfo.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
+ }
+ }
+}, "InputDeviceInfo is supported");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Test navigator.mediaDevices.getSupportedConstraints()</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#enumerating-devices">
+<meta name='assert' content='Test the getSupportedConstraints() method.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of the
+<code>navigator.mediaDevices.getSupportedConstraints()</code> method.</p>
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+"use strict";
+test(() => {
+ assert_inherits(navigator.mediaDevices, "getSupportedConstraints");
+ assert_equals(typeof navigator.mediaDevices.getSupportedConstraints, "function");
+}, "navigator.mediaDevices.getSupportedConstraints exists");
+
+{
+ const properties = [
+ "width",
+ "height",
+ "aspectRatio",
+ "frameRate",
+ "facingMode",
+ "resizeMode",
+ "sampleRate",
+ "sampleSize",
+ "echoCancellation",
+ "autoGainControl",
+ "noiseSuppression",
+ "latency",
+ "channelCount",
+ "deviceId",
+ "groupId"];
+ properties.forEach(property => {
+ test(()=>{
+ const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
+ assert_true(supportedConstraints[property]);
+ }, property + " is supported");
+ });
+}
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia: test that mediaDevices.getUserMedia is present</title>
+<link rel="author" title="Dr Alex Gouaillard" href="mailto:agouaillard@gmail.com"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#mediadevices-interface-extensions">
+<meta name='assert' content='Check that the mediaDevices.getUserMedia() method is present.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of the
+<code>navigator.mediaDevices.getUserMedia</code> method.</p>
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+test(function () {
+ assert_not_equals(navigator.mediaDevices.getUserMedia, undefined, "navigator.mediaDevices.getUserMedia exists.");
+ // TODO: do some stuff with it
+ assert_not_equals(navigator.mediaDevices.getSupportedConstraints, undefined, "navigator.mediaDevices.getSupportedConstraints exists.");
+ var list = navigator.mediaDevices.getSupportedConstraints();
+ // TODO: we are supposed to check that all values returned can be used in a constraint ....
+ // NOTE: the current list of attributes that may or may not be here
+ // ... FF for example has many no tin that list, should we fail if an attribute is present but not listed in the specs?
+ // list.width
+ // list.height
+ // list.aspectRatio
+ // list.frameRate
+ // list.facingMode
+ // list.volume
+ // list.sampleRate
+ // list.sampleSize
+ // list.echoCancellation
+ // list.latency
+ // list.channelCount
+ // list.deviceId
+ // list.groupId
+ }, "mediaDevices.getUserMedia() is present on navigator");
+
+promise_test(async t => {
+ // Both permissions are needed at some point, asking both at once
+ await setMediaPermission();
+ assert_true(navigator.mediaDevices.getSupportedConstraints()["groupId"],
+ "groupId should be supported");
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ for (const device of devices) {
+ await navigator.mediaDevices.getUserMedia(
+ {video: {groupId: {exact: device.groupId}}}).then(stream => {
+ const found_device = devices.find(({deviceId}) =>
+ deviceId == stream.getTracks()[0].getSettings().deviceId);
+ assert_not_equals(found_device, undefined);
+ assert_equals(found_device.kind, "videoinput");
+ assert_equals(found_device.groupId, device.groupId);
+ stream.getTracks().forEach(t => t.stop());
+ }, error => {
+ assert_equals(error.name, "OverconstrainedError");
+ assert_equals(error.constraint, "groupId");
+ const found_device = devices.find(element =>
+ element.kind == "videoinput" && element.groupId == device.groupId);
+ assert_equals(found_device, undefined);
+ });
+ }
+}, 'groupId is correctly supported by getUserMedia() for video devices');
+
+promise_test(async t => {
+ assert_true(navigator.mediaDevices.getSupportedConstraints()["groupId"],
+ "groupId should be supported");
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ for (const device of devices) {
+ await navigator.mediaDevices.getUserMedia(
+ {audio: {groupId: {exact: device.groupId}}}).then(stream => {
+ const found_device = devices.find(({deviceId}) =>
+ deviceId == stream.getTracks()[0].getSettings().deviceId);
+ assert_not_equals(found_device, undefined);
+ assert_equals(found_device.kind, "audioinput");
+ assert_equals(found_device.groupId, device.groupId);
+ stream.getTracks().forEach(t => t.stop());
+ }, error => {
+ assert_equals(error.name, "OverconstrainedError");
+ assert_equals(error.constraint, "groupId");
+ const found_device = devices.find(element =>
+ element.kind == "audioinput" && element.groupId == device.groupId);
+ assert_equals(found_device, undefined);
+ });
+ }
+}, 'groupId is correctly supported by getUserMedia() for audio devices');
+
+promise_test(async t => {
+ assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+ "resizeMode should be supported");
+ const stream = await navigator.mediaDevices.getUserMedia(
+ { video: {resizeMode: {exact: 'none'}}});
+ const [track] = stream.getVideoTracks();
+ t.add_cleanup(() => track.stop());
+ assert_equals(track.getSettings().resizeMode, 'none');
+}, 'getUserMedia() supports setting none as resizeMode.');
+
+promise_test(async t => {
+ assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+ "resizeMode should be supported");
+ const stream = await navigator.mediaDevices.getUserMedia(
+ { video: {resizeMode: {exact: 'crop-and-scale'}}});
+ const [track] = stream.getVideoTracks();
+ t.add_cleanup(() => track.stop());
+ assert_equals(track.getSettings().resizeMode, 'crop-and-scale');
+}, 'getUserMedia() supports setting crop-and-scale as resizeMode.');
+
+promise_test(async t => {
+ assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+ "resizeMode should be supported");
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia(
+ { video: {resizeMode: {exact: 'INVALID'}}});
+ t.add_cleanup(() => stream.getVideoTracks()[0].stop());
+ t.unreached_func('getUserMedia() should fail with invalid resizeMode')();
+ } catch (e) {
+ assert_equals(e.name, 'OverconstrainedError');
+ assert_equals(e.constraint, 'resizeMode');
+ }
+}, 'getUserMedia() fails with exact invalid resizeMode.');
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Assigning a MediaStream to a media element and not playing it results in rendering a first frame</title>
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that a HTMLMediaElement with an
+assigned MediaStream with a video track fires the appropriate events to reach
+the "canplay" event and readyState HAVE_ENOUGH_DATA even when not playing or
+autoplaying.</p>
+<video id="vid"></video>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+const vid = document.getElementById("vid");
+
+promise_test(async t => {
+ const wait = ms => new Promise(r => t.step_timeout(r, ms));
+ const timeout = (promise, time, msg) => Promise.race([
+ promise,
+ wait(time).then(() => Promise.reject(new Error(msg)))
+ ]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ vid.srcObject = stream;
+
+ await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+ assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+ "readyState is HAVE_ENOUGH_DATA after \"canplay\"");
+}, "Tests that loading a MediaStream in a media element eventually results in \"canplay\" even when not playing or autoplaying");
+
+promise_test(async t => {
+ const wait = ms => new Promise(r => t.step_timeout(r, ms));
+ const timeout = (promise, time, msg) => Promise.race([
+ promise,
+ wait(time).then(() => Promise.reject(new Error(msg)))
+ ]);
+ const unexpected = e => assert_unreached(`Got unexpected event ${e.type}`);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.ondurationchange = null;
+ stream.getTracks().forEach(track => track.stop())
+ });
+ vid.srcObject = stream;
+
+ vid.onloadstart = unexpected;
+ vid.ondurationchange = unexpected;
+ vid.onresize = unexpected;
+ vid.onloadedmetadata = unexpected;
+ vid.onloadeddata = unexpected;
+ vid.oncanplay = unexpected;
+ vid.oncanplaythrough = unexpected;
+
+ await timeout(new Promise(r => vid.onloadstart = r), 8000,
+ "loadstart timeout");
+ vid.onloadstart = unexpected;
+
+ await timeout(new Promise(r => vid.ondurationchange = r), 8000,
+ "durationchange timeout");
+ vid.ondurationchange = unexpected;
+ assert_equals(vid.duration, Infinity, "duration changes to Infinity");
+
+ await timeout(new Promise(r => vid.onresize = r), 8000,
+ "resize timeout");
+ vid.onresize = unexpected;
+ assert_not_equals(vid.videoWidth, 0,
+ "videoWidth is something after \"resize\"");
+ assert_not_equals(vid.videoHeight, 0,
+ "videoHeight is something after \"resize\"");
+
+ await timeout(new Promise(r => vid.onloadedmetadata = r), 8000,
+ "loadedmetadata timeout");
+ vid.onloadedmetadata = unexpected;
+ assert_greater_than_equal(vid.readyState, vid.HAVE_METADATA,
+ "readyState is at least HAVE_METADATA after \"loadedmetadata\"");
+
+ await timeout(new Promise(r => vid.onloadeddata = r), 8000,
+ "loadeddata timeout");
+ vid.onloadeddata = unexpected;
+ assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+ "readyState is HAVE_ENOUGH_DATA after \"loadeddata\" since there's no buffering");
+
+ await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+ vid.oncanplay = unexpected;
+ assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+ "readyState is HAVE_ENOUGH_DATA after \"canplay\" since there's no buffering");
+
+ await timeout(new Promise(r => vid.oncanplaythrough = r), 8000,
+ "canplaythrough timeout");
+ vid.oncanplaythrough = unexpected;
+ assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+ "readyState is HAVE_ENOUGH_DATA after \"canplaythrough\"");
+
+ // Crank the event loop to see whether any more events are fired.
+ await wait(100);
+}, "Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying");
+</script>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Test that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.</title>
+ <link rel="author" title="Matthew Wolenetz" href="mailto:wolenetz@chromium.org"/>
+ <script src="../../../resources/testharness.js"></script>
+ <script src="../../../resources/testharnessreport.js"></script>
+ <script src="../../../resources/testdriver.js"></script>
+ <script src="../../../resources/testdriver-vendor.js"></script>
+ <script src="permission-helper.js"></script>
+ </head>
+ <body>
+ <p class="instructions">When prompted, accept to share your audio and video streams.</p>
+ <p class="instructions">This test checks that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.</p>
+ <div id=log></div>
+
+ <audio preload="none"></audio>
+ <video preload="none"></video>
+
+ <script>
+ async function testPreloadNone(mediaElement, stream)
+ {
+ let rejectSuspendedPromise, rejectErrorPromise, resolveDataLoadedPromise;
+ const suspended = new Promise((r, rej) => {
+ rejectSuspendedPromise = rej;
+ });
+ const errored = new Promise((r, rej) => {
+ rejectErrorPromise = rej;
+ });
+ const loaded = new Promise(resolve => {
+ resolveDataLoadedPromise = resolve;
+ });
+
+ // The optional deferred load steps (for preload none) for MediaStream resources should be skipped.
+ mediaElement.addEventListener("suspend", () => {
+ rejectSuspendedPromise("'suspend' should not be fired.")
+ });
+ mediaElement.addEventListener("error", () => {
+ rejectErrorPromise("'error' should not be fired, code=" + mediaElement.error.code);
+ });
+
+ mediaElement.addEventListener("loadeddata", () => {
+ assert_equals(mediaElement.networkState, mediaElement.NETWORK_LOADING);
+ resolveDataLoadedPromise();
+ });
+
+ mediaElement.srcObject = stream;
+ assert_equals(mediaElement.networkState, mediaElement.NETWORK_NO_SOURCE); // Resource selection is active.
+ try {
+ await Promise.race([suspended, errored, loaded]);
+ } catch (msg) {
+ assert_unreached(msg);
+ }
+2 }
+
+ promise_test(async () =>
+ {
+ const aud = document.querySelector("audio");
+ // camera is needed for the next test, asking for both at once
+ await setMediaPermission();
+ let stream;
+ try {
+ stream = await navigator.mediaDevices.getUserMedia({audio:true});
+ } catch (e) {
+ assert_unreached("getUserMedia error callback was invoked.");
+ }
+ await testPreloadNone(aud, stream);
+ }, "Test that preload 'none' is ignored for MediaStream object URL used as srcObject for audio");
+
+ promise_test(async () =>
+ {
+ const vid = document.querySelector("video");
+ let stream;
+ try {
+ stream = await navigator.mediaDevices.getUserMedia({video:true});
+ } catch (e) {
+ assert_unreached("getUserMedia error callback was invoked.")
+ }
+ await testPreloadNone(vid, stream);
+
+ }, "Test that preload 'none' is ignored for MediaStream used as srcObject for video");
+ </script>
+ </body>
+</html>
+
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<meta name="timeout" content="long">
+<title>Assigning mediastream to a video element</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermedia">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the MediaStream object returned by
+the success callback in getUserMedia can be properly assigned to a video element
+via the <code>srcObject</code> attribute.</p>
+
+<audio id="aud"></audio>
+<video id="vid"></video>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+'use strict';
+const vid = document.getElementById("vid");
+
+function queueTask(f) {
+ window.onmessage = f;
+ window.postMessage("hi");
+}
+
+promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+}, "Tests that a MediaStream can be assigned to a video element with srcObject");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+
+ assert_true(!vid.seeking, "A MediaStream is not seekable");
+ assert_equals(vid.seekable.length, 0, "A MediaStream is not seekable");
+}, "Tests that a MediaStream assigned to a video element is not seekable");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+
+ assert_equals(vid.readyState, vid.HAVE_NOTHING,
+ "readyState is HAVE_NOTHING initially");
+ await new Promise(r => vid.onloadeddata = r);
+ assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+ "Upon having loaded a media stream, the UA sets readyState to HAVE_ENOUGH_DATA");
+}, "Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+
+ vid.preload = "metadata";
+ vid.srcObject = stream;
+
+ assert_equals(vid.buffered.length, 0,
+ "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+ assert_equals(vid.preload, "none", "preload must always be none");
+ vid.preload = "auto";
+ assert_equals(vid.preload, "none", "Setting preload must be ignored");
+
+ await new Promise(r => vid.onloadeddata = r);
+ assert_equals(vid.buffered.length, 0,
+ "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+
+ vid.srcObject = null;
+
+ assert_equals(vid.preload, "metadata",
+ "The preload attribute returns the value it had before using a MediaStream");
+}, "Tests that a video element with a MediaStream assigned is not preloaded");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+
+ vid.defaultPlaybackRate = 0.3;
+ vid.playbackRate = 0.3;
+ vid.onratechange = t.unreached_func("ratechange event must not be fired");
+ vid.srcObject = stream;
+
+ assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
+ vid.defaultPlaybackRate = 0.5;
+ assert_equals(vid.defaultPlaybackRate, 1,
+ "Setting defaultPlaybackRate must be ignored");
+
+ assert_equals(vid.playbackRate, 1, "playback rate is always 1");
+ vid.playbackRate = 0.5;
+ assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
+
+ vid.srcObject = null;
+ assert_equals(vid.defaultPlaybackRate, 0.3,
+ "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+ assert_equals(vid.playbackRate, 0.3,
+ "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject");
+
+ // Check that there's no ratechange event
+ await new Promise(r => t.step_timeout(r, 100));
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+
+ vid.defaultPlaybackRate = 0.3;
+ vid.playbackRate = 0.4;
+ vid.onratechange = t.unreached_func("ratechange event must not be fired");
+ vid.srcObject = stream;
+
+ assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
+ vid.defaultPlaybackRate = 0.5;
+ assert_equals(vid.defaultPlaybackRate, 1,
+ "Setting defaultPlaybackRate must be ignored");
+
+ assert_equals(vid.playbackRate, 1, "playback rate is always 1");
+ vid.playbackRate = 0.5;
+ assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
+
+ vid.srcObject = null;
+ assert_equals(vid.defaultPlaybackRate, 0.3,
+ "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+ assert_equals(vid.playbackRate, 0.3,
+ "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject (and fires ratechange)");
+ await new Promise(r => vid.onratechange = r);
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+ await new Promise(r => vid.oncanplay = r);
+ vid.play();
+ await new Promise(r => vid.ontimeupdate = r);
+ assert_greater_than(vid.currentTime, 0,
+ "currentTime is greater than 0 after first timeupdate");
+
+ assert_equals(vid.played.length, 1,
+ "A MediaStream's timeline always consists of a single range");
+ assert_equals(vid.played.start(0), 0,
+ "A MediaStream's timeline always starts at zero");
+ assert_equals(vid.played.end(0), vid.currentTime,
+ "A MediaStream's end MUST return the last known currentTime");
+
+ const time = vid.currentTime;
+ vid.currentTime = 0;
+ assert_equals(vid.currentTime, time,
+ "The UA MUST ignore attempts to set the currentTime attribute");
+}, "Tests that a media element with an assigned MediaStream reports the played attribute as expected");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+
+ assert_equals(vid.currentTime, 0, "The initial value is 0");
+ vid.currentTime = 42;
+ assert_equals(vid.currentTime, 0,
+ "The UA MUST ignore attempts to set the currentTime attribute (default playback start position)");
+
+ await new Promise(r => vid.onloadeddata = r);
+ assert_equals(vid.currentTime, 0, "The initial value is 0");
+ vid.currentTime = 42;
+ assert_equals(vid.currentTime, 0,
+ "The UA MUST ignore attempts to set the currentTime attribute (official playback position)");
+
+ vid.play();
+ await new Promise(r => vid.ontimeupdate = r);
+ assert_greater_than(vid.currentTime, 0,
+ "currentTime is greater than 0 after first timeupdate");
+
+ const lastTime = vid.currentTime;
+ vid.currentTime = 0;
+ assert_equals(vid.currentTime, lastTime,
+ "The UA MUST ignore attempts to set the currentTime attribute (restart)");
+
+ for(const t of stream.getTracks()) {
+ t.stop();
+ }
+ await new Promise(r => vid.onended = r);
+ assert_greater_than_equal(vid.currentTime, lastTime,
+ "currentTime advanced after stopping");
+}, "Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => {
+ vid.srcObject = null;
+ stream.getTracks().forEach(track => track.stop());
+ });
+ vid.srcObject = stream;
+
+ await new Promise(r => t.step_timeout(r, 500));
+
+ vid.play();
+ await new Promise(r => vid.ontimeupdate = r);
+ assert_between_exclusive(vid.currentTime, 0, 0.5,
+ "currentTime starts at 0 and has progressed at first timeupdate");
+}, "Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created");
+
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Adding a track to a MediaStream</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrackList-add-void-MediaStreamTrack-track">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#event-mediastream-addtrack">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio stream, then your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that adding a track to a MediaStream works as expected.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async t => {
+ await setMediaPermission();
+ const audio = await navigator.mediaDevices.getUserMedia({audio: true});
+ const video = await navigator.mediaDevices.getUserMedia({video: true});
+ assert_equals(video.getAudioTracks().length, 0, "video mediastream starts with no audio track");
+ video.addTrack(audio.getAudioTracks()[0]);
+ assert_equals(video.getAudioTracks().length, 1, "video mediastream has now one audio track");
+ video.addTrack(audio.getAudioTracks()[0]);
+ // If track is already in stream's track set, then abort these steps.
+ assert_equals(video.getAudioTracks().length, 1, "video mediastream still has one audio track");
+
+ audio.onaddtrack = t.step_func(function () {
+ assert_unreached("onaddtrack is not fired when the script directly modified the track of a mediastream");
+ });
+
+ assert_equals(audio.getVideoTracks().length, 0, "audio mediastream starts with no video track");
+ audio.addTrack(video.getVideoTracks()[0]);
+ assert_equals(audio.getVideoTracks().length, 1, "audio mediastream now has one video track");
+}, "Tests that adding a track to a MediaStream works as expected");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia({audio:true}) creates a stream with at least an audio track</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-kind">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the MediaStream object returned by
+the success callback in getUserMedia has exactly one audio track.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({audio:true});
+ assert_true(stream instanceof MediaStream, "getUserMedia success callback comes with a MediaStream object");
+ assert_equals(stream.getAudioTracks().length, 1, "the media stream has exactly one audio track");
+ assert_equals(stream.getAudioTracks()[0].kind, "audio", "getAudioTracks() returns a sequence of tracks whose kind is 'audio'");
+ assert_equals(stream.getVideoTracks().length, 0, "the media stream has zero video track");
+}, "Tests that a MediaStream with exactly one audio track is returned");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>MediaStream and MediaStreamTrack clone()</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediastream-clone">
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-clone">
+</head>
+<body>
+<p class="instructions">When prompted, accept to give permission to use your audio and video devices.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that cloning MediaStreams and MediaStreamTracks works as expected.</p>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+
+promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ assert_equals(stream.getAudioTracks().length, 1);
+ assert_equals(stream.getVideoTracks().length, 1);
+
+ const clone1 = stream.clone();
+ assert_equals(clone1.getAudioTracks().length, 1);
+ assert_equals(clone1.getVideoTracks().length, 1);
+ assert_not_equals(stream.getAudioTracks()[0].id, clone1.getAudioTracks()[0].id);
+ assert_not_equals(stream.getVideoTracks()[0].id, clone1.getVideoTracks()[0].id);
+
+ stream.getTracks().forEach(track => track.stop());
+ assert_false(stream.active);
+ assert_equals(stream.getAudioTracks()[0].readyState, "ended");
+ assert_equals(stream.getVideoTracks()[0].readyState, "ended");
+ assert_true(clone1.active);
+ assert_equals(clone1.getAudioTracks()[0].readyState, "live");
+ assert_equals(clone1.getVideoTracks()[0].readyState, "live");
+
+ clone1.getAudioTracks()[0].stop();
+ assert_true(clone1.active);
+ assert_equals(clone1.getAudioTracks()[0].readyState, "ended");
+ assert_equals(clone1.getVideoTracks()[0].readyState, "live");
+
+ const clone2 = clone1.clone();
+ assert_true(clone2.active);
+ assert_equals(clone2.getAudioTracks()[0].readyState, "ended");
+ assert_equals(clone2.getVideoTracks()[0].readyState, "live");
+
+ clone1.getVideoTracks()[0].stop();
+ clone2.getVideoTracks()[0].stop();
+
+ const clone3 = clone2.clone();
+ assert_false(clone3.active);
+ assert_equals(clone3.getAudioTracks()[0].readyState, "ended");
+ assert_equals(clone3.getVideoTracks()[0].readyState, "ended");
+ assert_not_equals(clone1.getAudioTracks()[0].id, clone2.getAudioTracks()[0].id);
+ assert_not_equals(clone1.getVideoTracks()[0].id, clone2.getVideoTracks()[0].id);
+ assert_not_equals(clone2.getAudioTracks()[0].id, clone3.getAudioTracks()[0].id);
+ assert_not_equals(clone2.getVideoTracks()[0].id, clone3.getVideoTracks()[0].id);
+ assert_not_equals(clone1.getAudioTracks()[0].id, clone3.getAudioTracks()[0].id);
+ assert_not_equals(clone1.getVideoTracks()[0].id, clone3.getVideoTracks()[0].id);
+}, "Tests that cloning MediaStream objects works as expected");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ assert_equals(stream.getAudioTracks().length, 1);
+ assert_equals(stream.getVideoTracks().length, 1);
+ assert_equals(stream.getAudioTracks()[0].readyState, "live");
+ assert_equals(stream.getVideoTracks()[0].readyState, "live");
+ assert_true(stream.active);
+
+ const audio_clone = stream.getAudioTracks()[0].clone();
+ const video_clone = stream.getVideoTracks()[0].clone();
+ assert_equals(audio_clone.readyState, "live");
+ assert_equals(video_clone.readyState, "live");
+ assert_not_equals(stream.getAudioTracks()[0].id, audio_clone.id);
+ assert_not_equals(stream.getVideoTracks()[0].id, video_clone.id);
+
+ stream.getTracks().forEach(track => track.stop());
+ assert_false(stream.active);
+ assert_equals(stream.getAudioTracks()[0].readyState, "ended");
+ assert_equals(stream.getVideoTracks()[0].readyState, "ended");
+ assert_equals(audio_clone.readyState, "live");
+ assert_equals(video_clone.readyState, "live");
+
+ stream.addTrack(audio_clone);
+ stream.addTrack(video_clone);
+ assert_true(stream.active);
+
+ stream.getTracks().forEach(track => track.stop());
+ assert_false(stream.active);
+ assert_equals(audio_clone.readyState, "ended");
+ assert_equals(video_clone.readyState, "ended");
+}, "Tests that cloning MediaStreamTrack objects works as expected");
+
+</script>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<body>
+ <script src="../../../resources/testharness.js"></script>
+ <script src="../../../resources/testharnessreport.js"></script>
+ <script src="../../../resources/testdriver.js"></script>
+ <script src="../../../resources/testdriver-vendor.js"></script>
+ <script src="permission-helper.js"></script>
+ <script src="../../../resources/get-host-info.sub.js"></script>
+ <script src="../../../resources/featurepolicy.js"></script>
+ <script>
+ 'use strict';
+
+ async function gUM({audio, video}) {
+ let stream;
+ if (!page_loaded_in_iframe()) {
+ await setMediaPermission();
+ }
+ try {
+ stream = await navigator.mediaDevices.getUserMedia({audio, video});
+ // getUserMedia must guarantee the number of tracks requested or fail.
+ if ((audio && stream.getAudioTracks().length == 0) ||
+ (video && stream.getVideoTracks().length == 0)) {
+ throw {name: `All requested devices must be present with ` +
+ `audio ${audio} and video ${video}, or fail`};
+ }
+ } finally {
+ if (stream) {
+ stream.getTracks().forEach(track => track.stop());
+ }
+ }
+ }
+
+ async function must_disallow_gUM({audio, video}) {
+ try {
+ await gUM({audio, video});
+ } catch (e) {
+ if (e.name == 'NotAllowedError') {
+ return;
+ }
+ throw e;
+ }
+ throw {name: `audio ${audio} and video ${video} constraints must not be ` +
+ `allowed.`};
+ }
+
+ const cross_domain = get_host_info().HTTP_REMOTE_ORIGIN;
+ run_all_fp_tests_allow_self(
+ cross_domain,
+ 'microphone',
+ 'NotAllowedError',
+ async () => {
+ await gUM({audio: true});
+ if (window.location.href.includes(cross_domain)) {
+ await must_disallow_gUM({video: true});
+ await must_disallow_gUM({audio: true, video: true});
+ }
+ }
+ );
+
+ run_all_fp_tests_allow_self(
+ cross_domain,
+ 'camera',
+ 'NotAllowedError',
+ async () => {
+ await gUM({video: true});
+ if (window.location.href.includes(cross_domain)) {
+ await must_disallow_gUM({audio: true});
+ await must_disallow_gUM({audio: true, video: true});
+ }
+ }
+ );
+
+ run_all_fp_tests_allow_self(
+ cross_domain,
+ 'camera;microphone',
+ 'NotAllowedError',
+ async () => {
+ await gUM({audio: true, video: true});
+ await gUM({audio: true});
+ await gUM({video: true});
+ }
+ );
+ </script>
+</body>
+
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Adding a track to an inactive MediaStream</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#widl-MediaStream-addTrack-void-MediaStreamTrack-track">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#widl-MediaStreamTrack-stop-void">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio stream, then
+your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that adding a track to an inactive
+MediaStream is allowed.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission();
+ const audio = await navigator.mediaDevices.getUserMedia({audio:true});
+ const video = await navigator.mediaDevices.getUserMedia({video:true});
+ audio.getAudioTracks()[0].stop();
+ assert_false(audio.active, "audio stream is inactive after stopping its only audio track");
+ assert_true(video.active, "video stream is active");
+ audio.addTrack(video.getVideoTracks()[0]);
+ audio.removeTrack(audio.getAudioTracks()[0]);
+}, "Tests that adding a track to an inactive MediaStream is allowed");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Retrieving a track from a MediaStream</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStream-getTrackById-MediaStreamTrack-DOMString-trackId">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that MediaStream.getTrackById behaves as expected</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ var track = stream.getVideoTracks()[0];
+ assert_equals(track, stream.getTrackById(track.id), "getTrackById returns track of given id");
+ assert_equals(stream.getTrackById(track.id + "foo"), null, "getTrackById of inexistant id returns null");
+}, "Tests that MediaStream.getTrackById works as expected");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia() creates a stream with a proper id</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStream-id">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the MediaStream object returned by
+the success callback in getUserMedia has a correct id.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+
+const allowedCharacters = /^[\u0021\u0023-\u0027\u002A-\u002B\u002D-\u002E\u0030-\u0039\u0041-\u005A\u005E-\u007E]*$/;
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video:true});
+ assert_equals(stream.id.length, 36, "the media stream id has 36 characters");
+ assert_regexp_match(stream.id, allowedCharacters, "the media stream id uses the set of allowed characters");
+}, "Tests that a MediaStream with a correct id is returned");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>MediaStream constructor algorithm</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStream">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#widl-MediaStream-id">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#mediastream">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#event-mediastreamtrack-ended">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#widl-MediaStreamTrack-stop-void">
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#widl-MediaStreamTrack-clone-MediaStreamTrack">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video and audio stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the MediaStream constructor
+follows the algorithm set in the spec.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+ promise_test(async () => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio:true})
+ let stream1 = new MediaStream();
+ assert_not_equals(stream.id, stream1.id, "Two different MediaStreams have different ids");
+ let stream2 = new MediaStream(stream);
+ assert_not_equals(stream.id, stream2.id, "A MediaStream constructed from another has a different id");
+ let audioTrack1 = stream.getAudioTracks()[0];
+ let videoTrack = stream.getVideoTracks()[0];
+ assert_equals(audioTrack1, stream2.getAudioTracks()[0], "A MediaStream constructed from another shares the same audio track");
+ assert_equals(videoTrack, stream2.getVideoTracks()[0], "A MediaStream constructed from another shares the same video track");
+ let stream4 = new MediaStream([audioTrack1]);
+ assert_equals(stream4.getTrackById(audioTrack1.id), audioTrack1, "a non-ended track gets added via the MediaStream constructor");
+
+ let audioTrack2 = audioTrack1.clone();
+ audioTrack2.addEventListener("ended", () => {
+ throw new Error("ended event should not be fired by MediaStreamTrack.stop().")
+ });
+ audioTrack2.stop();
+ assert_equals(audioTrack2.readyState, "ended", "a stopped track is marked ended synchronously");
+
+ let stream3 = new MediaStream([audioTrack2, videoTrack]);
+ assert_equals(stream3.getTrackById(audioTrack2.id), audioTrack2, "an ended track gets added via the MediaStream constructor");
+ assert_equals(stream3.getTrackById(videoTrack.id), videoTrack, "a non-ended track gets added via the MediaStream constructor even if the previous track was ended");
+
+ let stream5 = new MediaStream([audioTrack2]);
+ assert_equals(stream5.getTrackById(audioTrack2.id), audioTrack2, "an ended track gets added via the MediaStream constructor");
+ assert_false(stream5.active, "a MediaStream created using the MediaStream() constructor whose arguments are lists of MediaStreamTrack objects that are all ended, the MediaStream object MUST be created with its active attribute set to false");
+
+ audioTrack1.stop();
+ assert_equals(audioTrack1.readyState, "ended",
+ "Stopping audioTrack1 marks it ended synchronously");
+
+ videoTrack.stop();
+ assert_equals(videoTrack.readyState, "ended",
+ "Stopping videoTrack marks it ended synchronously");
+
+ assert_false(stream.active,
+ "The original MediaStream is marked inactive synchronously");
+ assert_false(stream1.active,
+ "MediaStream 1 is marked inactive synchronously");
+ assert_false(stream2.active,
+ "MediaStream 2 is marked inactive synchronously");
+ assert_false(stream3.active,
+ "MediaStream 3 is marked inactive synchronously");
+ assert_false(stream4.active,
+ "MediaStream 4 is marked inactive synchronously");
+
+}, "Tests that a MediaStream constructor follows the algorithm set in the spec");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Removing a track from a MediaStream</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrackList-remove-void-MediaStreamTrack-track">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#event-mediastream-removetrack">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio stream, then your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that removinging a track from a MediaStream works as expected.</p>
+<video id="video" height="120" width="160" autoplay muted></video>
+<audio id="audio" autoplay muted></audio>
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+
+promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ const tracks = stream.getTracks();
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
+ tracks.push(...stream2.getTracks());
+
+ stream.onremovetrack = stream2.onremovetrack = t.step_func(() =>
+ assert_unreached("onremovetrack is not triggered by script itself"));
+
+ assert_equals(stream.getTracks().length, 2, "mediastream starts with 2 tracks");
+ stream.removeTrack(stream.getVideoTracks()[0]);
+ assert_equals(stream.getTracks().length, 1, "mediastream has 1 track left");
+ stream.removeTrack(stream.getAudioTracks()[0]);
+ assert_equals(stream.getTracks().length, 0, "mediastream has no tracks left");
+ stream.removeTrack(stream2.getTracks()[0]); // should not throw
+
+ // Allow time to verify no events fire.
+ await new Promise(r => t.step_timeout(r, 1));
+
+}, "Tests that a removal from a MediaStream works as expected");
+
+async function doesEventFire(t, target, name, ms = 1) {
+ const cookie = {};
+ const value = await Promise.race([
+ new Promise(r => target.addEventListener(name, r, {once: true})),
+ new Promise(r => t.step_timeout(r, ms)).then(() => cookie)
+ ]);
+ return value !== cookie;
+}
+
+const doEventsFire = (t, target1, target2, name, ms = 1) => Promise.all([
+ doesEventFire(t, target1, "ended", ms),
+ doesEventFire(t, target2, "ended", ms)
+]);
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ const tracks = stream.getTracks();
+
+ audio.srcObject = video.srcObject = stream;
+
+ t.add_cleanup(() => {
+ for (const track of tracks) {
+ track.stop();
+ }
+ audio.srcObject = video.srcObject = null;
+ });
+
+ await Promise.all([
+ new Promise(r => audio.onloadedmetadata = r),
+ new Promise(r => video.onloadedmetadata = r)
+ ]);
+
+ assert_equals(audio.ended, false, "audio element starts out not ended");
+ assert_equals(video.ended, false, "video element starts out not ended");
+
+ stream.removeTrack(stream.getVideoTracks()[0]);
+ {
+ const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+ assert_equals(audio.ended, false, "audio element unaffected");
+ assert_equals(audioDidEnd, false, "no audio ended event should fire yet");
+ assert_equals(video.ended, false, "video element keeps going with audio track");
+ assert_equals(videoDidEnd, false, "no video ended event should fire yet");
+ }
+ stream.removeTrack(stream.getAudioTracks()[0]);
+ {
+ const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+ assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
+ assert_equals(audioDidEnd, true, "go audio ended event");
+ assert_equals(video.ended, true, "video element ended because no more tracks");
+ assert_equals(videoDidEnd, true, "got video ended event");
+ }
+}, "Test that removal from a MediaStream fires ended on media elements (video first)");
+
+promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ const tracks = stream.getTracks();
+
+ audio.srcObject = video.srcObject = stream;
+
+ t.add_cleanup(() => {
+ for (const track of tracks) {
+ track.stop();
+ }
+ audio.srcObject = video.srcObject = null;
+ });
+
+ await Promise.all([
+ new Promise(r => audio.onloadedmetadata = r),
+ new Promise(r => video.onloadedmetadata = r)
+ ]);
+
+ assert_equals(audio.ended, false, "audio element starts out not ended");
+ assert_equals(video.ended, false, "video element starts out not ended");
+
+ stream.removeTrack(stream.getAudioTracks()[0]);
+ {
+ const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+ assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
+ assert_equals(audioDidEnd, true, "got audio ended event");
+ assert_equals(video.ended, false, "video element keeps going with video track");
+ assert_equals(videoDidEnd, false, "no video ended event should fire yet");
+ }
+ stream.removeTrack(stream.getVideoTracks()[0]);
+ {
+ const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+ assert_equals(audio.ended, true, "audio element remains ended from before");
+ assert_equals(audioDidEnd, false, "no second audio ended event should fire");
+ assert_equals(video.ended, true, "video element ended because no more tracks");
+ assert_equals(videoDidEnd, true, "got video ended event");
+ }
+}, "Test that removal from a MediaStream fires ended on media elements (audio first)");
+
+</script>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<title>Test that camera and microphone are advertised in the feature list</title>
+<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features">
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#feature-policy-integration">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_in_array('camera', document.featurePolicy.features());
+}, 'document.featurePolicy.features should advertise camera.');
+
+test(() => {
+ assert_in_array('microphone', document.featurePolicy.features());
+}, 'document.featurePolicy.features should advertise microphone.');
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia({video:true}) creates a stream with one video track</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-NavigatorUserMedia-getUserMedia-void-MediaStreamConstraints-constraints-NavigatorUserMediaSuccessCallback-successCallback-NavigatorUserMediaErrorCallback-errorCallback">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-kind">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the MediaStream object returned by
+the success callback in getUserMedia has exactly one video track and no audio.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ assert_true(stream instanceof MediaStream, "getUserMedia success callback comes with a MediaStream object");
+ assert_equals(stream.getAudioTracks().length, 0, "the media stream has zero audio track");
+ assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+ assert_equals(stream.getVideoTracks()[0].kind, "video", "getAudioTracks() returns a sequence of tracks whose kind is 'video'");
+}, "Tests that a MediaStream with at least one video track is returned");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>A disabled audio track is rendered as silence</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#introduction">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreams-as-media-elements">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that a disabled audio track in a
+MediaStream is rendered as silence. It relies on the
+<a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">
+Web Audio API</a>.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+const aud = document.getElementById("aud");
+promise_test(async t => {
+ await setMediaPermission("granted", ["microphone"]);
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ var ctx = new AudioContext();
+ var streamSource = ctx.createMediaStreamSource(stream);
+ var silenceDetector = ctx.createScriptProcessor(1024);
+ var count = 10;
+ let resolveAudioProcessPromise;
+ const audioProcessed = new Promise(res => resolveAudioProcessPromise = res)
+
+ silenceDetector.onaudioprocess = function (e) {
+ var buffer1 = e.inputBuffer.getChannelData(0);
+ var buffer2 = e.inputBuffer.getChannelData(1);
+ var out = e.outputBuffer.getChannelData(0);
+ out = new Float32Array(buffer1);
+ for (var i = 0; i < buffer1.length; i++) {
+ assert_equals(buffer1[i], 0, "Audio buffer entry #" + i + " in channel 0 is silent");
+ }
+ for (var i = 0; i < buffer2.length; i++) {
+ assert_equals(buffer2[i], 0, "Audio buffer entry #" + i + " in channel 1 is silent");
+ }
+ count--;
+ if (count === 0) {
+ silenceDetector.onaudioprocess = null;
+ resolveAudioProcessPromise();
+ }
+ };
+ stream.getAudioTracks()[0].enabled = false;
+
+ streamSource.connect(silenceDetector);
+ silenceDetector.connect(ctx.destination);
+}, "Tests that a disabled audio track in a MediaStream is rendered as silence");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>A disabled video track is rendered as blackness</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#introduction">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreams-as-media-elements">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that a disabled video track in a
+MediaStream is rendered as blackness.</p>
+<video id="vid"></video>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+const vid = document.getElementById("vid");
+const cv = document.createElement("canvas");
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ if (stream.getVideoTracks()[0].enabled) {
+ stream.getVideoTracks()[0].enabled = false;
+ }
+
+ let resolveLoadedPromise;
+ const videoLoaded = new Promise(res => resolveLoadedPromise = res)
+ var testOnceLoadeddata = function() {
+ vid.removeEventListener("loadeddata", testOnceLoadeddata, false);
+ cv.width = vid.offsetWidth;
+ cv.height = vid.offsetHeight;
+ var ctx = cv.getContext("2d");
+ ctx.drawImage(vid,0,0);
+ var imageData = ctx.getImageData(0, 0, cv.width, cv.height);
+ for (var i = 0; i < imageData.data.length; i+=4) {
+ assert_equals(imageData.data[i], 0, "No red component in pixel #" + i);
+ assert_equals(imageData.data[i + 1], 0, "No green component in pixel #" + i);
+ assert_equals(imageData.data[i + 2], 0, "No blue component in pixel #" + i);
+ assert_equals(imageData.data[i + 3], 255, "No transparency in pixel #" + i);
+ }
+ resolveLoadedPromise();
+ };
+
+ vid.srcObject = stream;
+ vid.play();
+ vid.addEventListener("loadeddata", testOnceLoadeddata, false);
+}, "Tests that a disabled video track in a MediaStream is rendered as blackness");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack applyConstraints</title>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+ 'use strict'
+
+ // https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-applyconstraints
+
+ promise_test(async t => {
+ await setMediaPermission("granted", ["camera"]);
+ return navigator.mediaDevices.getUserMedia({ video: true })
+ .then(t.step_func(stream => {
+ return stream.getVideoTracks()[0].applyConstraints(
+ { groupId: { exact: "INVALID" } }).then(
+ t.unreached_func('Accepted invalid groupID'),
+ t.step_func(e => {
+ assert_equals(e.name, 'OverconstrainedError');
+ assert_equals(e.constraint, 'groupId');
+ }));
+ }));
+ }, 'applyConstraints rejects invalid groupID');
+
+ promise_test(t => {
+ return navigator.mediaDevices.getUserMedia({ video: true })
+ .then(t.step_func(stream => {
+ var track = stream.getVideoTracks()[0];
+ var groupId = track.getSettings().groupId;
+ return track.applyConstraints({ groupId: "INVALID" }).then(
+ t.step_func(() => {
+ assert_equals(track.getSettings().groupId, groupId);
+ }));
+ }));
+ }, 'applyConstraints accepts invalid ideal groupID, does not change setting');
+
+ promise_test(t => {
+ return navigator.mediaDevices.getUserMedia({ video: true })
+ .then(t.step_func(stream => {
+ var track = stream.getVideoTracks()[0];
+ var groupId = track.getSettings().groupId;
+ return navigator.mediaDevices.enumerateDevices().then(devices => {
+ var anotherDevice = devices.find(device => {
+ return device.kind == "videoinput" && device.groupId != groupId;
+ });
+ if (anotherDevice !== undefined) {
+ return track.applyConstraints(
+ { groupId: { exact: anotherDevice.groupId } }).then(
+ t.unreached_func(),
+ t.step_func(e => {
+ assert_equals(e.name, 'OverconstrainedError');
+ assert_equals(e.constraint, 'groupId');
+ }));
+ }
+ });
+ }));
+ }, 'applyConstraints rejects attempt to switch device using groupId');
+
+ promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({ video: true });
+ const [track] = stream.getVideoTracks();
+ t.add_cleanup(() => track.stop());
+ try {
+ await track.applyConstraints({ resizeMode: { exact: "INVALID" } });
+ t.unreached_func('applyConstraints() must fail with invalid resizeMode')();
+ } catch (e) {
+ assert_equals(e.name, 'OverconstrainedError');
+ assert_equals(e.constraint, 'resizeMode');
+ }
+ }, 'applyConstraints rejects invalid resizeMode');
+
+ promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({ video: true });
+ const [track] = stream.getVideoTracks();
+ t.add_cleanup(() => track.stop());
+ const resizeMode = track.getSettings().resizeMode;
+ await track.applyConstraints({ resizeMode: "INVALID" });
+ assert_equals(track.getSettings().resizeMode, resizeMode);
+ }, 'applyConstraints accepts invalid ideal resizeMode, does not change setting');
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Test that mediastreamtrack are properly ended</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#mediastreamtrack">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video and audio
+stream, and then revoke that permission.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the video and audio tracks of
+MediaStream object returned by the success callback in getUserMedia are
+correctly set into inactive state when permission is revoked.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+'use strict';
+promise_test(async t => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({
+ audio: true,
+ video: true,
+ });
+
+ const vidTrack = stream.getVideoTracks()[0];
+ assert_equals(vidTrack.readyState, "live",
+ "The video track object is in live state");
+ const vidEnded = new Promise(r => vidTrack.onended = r);
+ const audTrack = stream.getAudioTracks()[0];
+ assert_equals(audTrack.readyState, "live",
+ "The audio track object is in live state");
+ const audEnded = new Promise(r => audTrack.onended = r);
+
+ await Promise.race([vidEnded, audEnded]);
+ assert_equals(stream.getTracks().filter(t => t.readyState == "ended").length,
+ 1, "Only one track is ended after first track's ended event");
+ assert_equals(stream.getTracks().filter(t => t.readyState == "live").length,
+ 1, "One track is still live after first track's ended event");
+ assert_true(stream.active, "MediaStream is still active");
+
+ await Promise.all([vidEnded, audEnded]);
+ assert_equals(vidTrack.readyState, "ended", "Video track ended as expected");
+ assert_equals(audTrack.readyState, "ended", "Audio track ended as expected");
+ assert_false(stream.active, "MediaStream has become inactive as expected");
+}, "Tests that MediaStreamTracks end properly on permission revocation");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack and InputDeviceInfo GetCapabilities</title>
+<meta name="timeout" content="long">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+
+const audioProperties = [
+ {name: "sampleRate", type: "number"},
+ {name: "sampleSize", type: "number"},
+ {name: "echoCancellation", type: "boolean"},
+ {name: "autoGainControl", type: "boolean"},
+ {name: "noiseSuppression", type: "boolean"},
+ {name: "latency", type: "number"},
+ {name: "channelCount", type: "number"},
+ {name: "deviceId", type: "string"},
+ {name: "groupId", type: "string"}
+];
+
+const videoProperties = [
+ {name: "width", type: "number"},
+ {name: "height", type: "number"},
+ {name: "aspectRatio", type: "number"},
+ {name: "frameRate", type: "number"},
+ {name: "facingMode", type: "enum-any", validValues: ["user", "environment", "left", "right"]},
+ {name: "resizeMode", type: "enum-all", validValues: ["none", "crop-and-scale"]},
+ {name: "deviceId", type: "string"},
+ {name: "groupId", type: "string"},
+];
+
+function verifyBooleanCapability(capability) {
+ assert_less_than_equal(capability.length, 2);
+ capability.forEach(c => assert_equals(typeof c, "boolean"));
+}
+
+function verifyNumberCapability(capability) {
+ assert_equals(typeof capability, "object");
+ assert_equals(Object.keys(capability).length, 2);
+ assert_true(capability.hasOwnProperty('min'));
+ assert_true(capability.hasOwnProperty('max'));
+ assert_less_than_equal(capability.min, capability.max);
+}
+
+// Verify that any value provided by an enum capability is in the set of valid
+// values.
+function verifyEnumAnyCapability(capability, enumMembers) {
+ capability.forEach(c => {
+ assert_equals(typeof c, "string");
+ assert_in_array(c, enumMembers);
+ });
+}
+
+// Verify that all required values are supported by a capability.
+function verifyEnumAllCapability(capability, enumMembers, testNamePrefix) {
+ enumMembers.forEach(member => {
+ test(() => {
+ assert_in_array(member, capability);
+ }, testNamePrefix + " Value: " + member);
+ });
+}
+
+function testCapabilities(capabilities, property, testNamePrefix) {
+ let testName = testNamePrefix + " " + property.name;
+ test(() => {
+ assert_true(capabilities.hasOwnProperty(property.name));
+ }, testName + " property present.");
+
+ const capability = capabilities[property.name];
+ testName += " properly supported.";
+ if (property.type == "string") {
+ test(() => {
+ assert_equals(typeof capability, "string");
+ }, testName);
+ }
+
+ if (property.type == "boolean") {
+ test(() => {
+ verifyBooleanCapability(capability);
+ }, testName);
+ }
+
+ if (property.type == "number") {
+ test(() => {
+ verifyNumberCapability(capability);
+ }, testName);
+ }
+
+ if (property.type.startsWith("enum")) {
+ test(() => {
+ verifyEnumAnyCapability(capability, property.validValues);
+ }, testName);
+
+ if (property.type == "enum-all") {
+ verifyEnumAllCapability(capability, property.validValues, testName);
+ }
+ }
+}
+
+{
+ audioProperties.forEach((property, i) => {
+ promise_test(async t => {
+ if (i === 0) await setMediaPermission("granted", ["microphone"]);
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ t.add_cleanup(() => stream.getAudioTracks()[0].stop());
+ const audioCapabilities = stream.getAudioTracks()[0].getCapabilities();
+ testCapabilities(audioCapabilities, property, "Audio track getCapabilities()");
+ }, "Setup audio MediaStreamTrack getCapabilities() test for " + property.name);
+ });
+
+ videoProperties.forEach(property => {
+ promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => stream.getVideoTracks()[0].stop());
+ const audioCapabilities = stream.getVideoTracks()[0].getCapabilities();
+ testCapabilities(audioCapabilities, property, "Video track getCapabilities()");
+ }, "Setup video MediaStreamTrack getCapabilities() test for " + property.name);
+ });
+}
+
+{
+ audioProperties.forEach(property => {
+ promise_test(async t => {
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ for (const device of devices) {
+ // Test only one device.
+ if (device.kind == "audioinput") {
+ assert_inherits(device, "getCapabilities");
+ const capabilities = device.getCapabilities();
+ testCapabilities(capabilities, property, "Audio device getCapabilities()");
+ break;
+ }
+ }
+ }, "Setup audio InputDeviceInfo getCapabilities() test for " + property.name);
+ });
+
+ videoProperties.forEach(property => {
+ promise_test(async t => {
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ for (const device of devices) {
+ // Test only one device.
+ if (device.kind == "videoinput") {
+ assert_inherits(device, "getCapabilities");
+ const capabilities = device.getCapabilities();
+ testCapabilities(capabilities, property, "Video device getCapabilities()");
+ break;
+ }
+ }
+ }, "Setup video InputDeviceInfo getCapabilities() test for " + property.name);
+ });
+}
+</script>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack GetSettings</title>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<meta name=timeout content=long>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+ 'use strict'
+
+ // https://w3c.github.io/mediacapture-main/archives/20170605/getusermedia.html
+
+ async function createTrackAndGetSettings(t, kind) {
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ assert_equals(stream.getTracks().length, 1);
+ t.add_cleanup(() => stream.getTracks()[0].stop());
+ return stream.getTracks()[0].getSettings();
+ }
+
+ promise_test(async t => {
+ await setMediaPermission("granted", ["camera"]);
+ const mediaStream1 = await navigator.mediaDevices.getUserMedia({
+ video: true,
+ audio: false,
+ });
+ t.add_cleanup(() => mediaStream1.getVideoTracks()[0].stop());
+ const settings1 = mediaStream1.getVideoTracks()[0].getSettings();
+
+ const mediaStream2 = await navigator.mediaDevices.getUserMedia({
+ video: {
+ deviceId: {exact: settings1.deviceId},
+ },
+ audio: false
+ });
+ t.add_cleanup(() => mediaStream2.getVideoTracks()[0].stop());
+ const settings2 = mediaStream2.getVideoTracks()[0].getSettings();
+
+ assert_equals(settings1.deviceId, settings2.deviceId);
+ }, 'A device can be opened twice and have the same device ID');
+
+ promise_test(async t => {
+ const mediaStream1 = await navigator.mediaDevices.getUserMedia({
+ video: true,
+ audio: false,
+ });
+ t.add_cleanup(() => mediaStream1.getVideoTracks()[0].stop());
+ const settings1 = mediaStream1.getVideoTracks()[0].getSettings();
+
+ const mediaStream2 = await navigator.mediaDevices.getUserMedia({
+ video: {
+ deviceId: {exact: settings1.deviceId},
+ width: {
+ ideal: settings1.width / 2,
+ },
+ },
+ audio: false
+ });
+ t.add_cleanup(() => mediaStream2.getVideoTracks()[0].stop());
+ const settings2 = mediaStream2.getVideoTracks()[0].getSettings();
+
+ assert_equals(settings1.deviceId, settings2.deviceId);
+ assert_between_inclusive(settings2.width, settings1.width / 2, settings1.width);
+ }, 'A device can be opened twice with different resolutions requested');
+
+ promise_test(async t => {
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ const inputDevices = devices.filter(d => d.kind != "audiooutput");
+ assert_greater_than(inputDevices.length, 0);
+ for (const device of inputDevices) {
+ const device_id_constraint = {deviceId: {exact: device.deviceId}};
+ const constraints = device.kind == "audioinput"
+ ? {audio: device_id_constraint}
+ : {video: device_id_constraint};
+
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ assert_true(stream.getTracks()[0].getSettings().groupId === device.groupId, "device groupId");
+ assert_greater_than(device.groupId.length, 0);
+ }
+ }, 'groupId is correctly reported by getSettings() for all input devices');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.deviceId), "string",
+ "deviceId should exist and it should be a string.");
+ }, 'deviceId is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.groupId), "string",
+ "groupId should exist and it should be a string.");
+ }, 'groupId is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.sampleRate), "number",
+ "sampleRate should exist and it should be a number.");
+ assert_greater_than(settings.sampleRate, 0);
+ }, 'sampleRate is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.sampleSize), "number",
+ "sampleSize should exist and it should be a number.");
+ assert_greater_than(settings.sampleSize, 0);
+ }, 'sampleSize is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.echoCancellation), "boolean",
+ "echoCancellation should exist and it should be a boolean.");
+ }, 'echoCancellation is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.autoGainControl), "boolean",
+ "autoGainControl should exist and it should be a boolean.");
+ }, 'autoGainControl is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.noiseSuppression), "boolean",
+ "noiseSuppression should exist and it should be a boolean.");
+ }, 'noiseSuppression is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.latency), "number",
+ "latency should exist and it should be a number.");
+ assert_greater_than_equal(settings.latency,0);
+ }, 'latency is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "audio");
+ assert_equals(typeof(settings.channelCount), "number",
+ "channelCount should exist and it should be a number.");
+ assert_greater_than(settings.channelCount, 0);
+ }, 'channelCount is reported by getSettings() for getUserMedia() audio tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.deviceId), "string",
+ "deviceId should exist and it should be a string.");
+ }, 'deviceId is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.groupId), "string",
+ "groupId should exist and it should be a string.");
+ }, 'groupId is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.width), "number",
+ "width should exist and it should be a number.");
+ assert_true(Number.isInteger(settings.width), "width should be an integer.");
+ assert_greater_than_equal(settings.width, 0);;
+ }, 'width is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.height), "number",
+ "height should exist and it should be a number.");
+ assert_true(Number.isInteger(settings.height), "height should be an integer.");
+ assert_greater_than_equal(settings.height, 0);
+ }, 'height is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.aspectRatio), "number",
+ "aspectRatio should exist and it should be a number.");
+ assert_greater_than_equal(settings.aspectRatio, 0);
+ }, 'aspectRatio is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.frameRate), "number",
+ "frameRate should exist and it should be a number.");
+ assert_greater_than_equal(settings.frameRate, 0);
+ }, 'frameRate is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ // facingMode not treated as mandatory because not all platforms provide
+ // this information.
+ if (settings.facingMode) {
+ assert_equals(typeof(settings.facingMode), "string",
+ "If facingMode is provided it should be a string.");
+ assert_in_array(settings.facingMode,
+ ['user', 'environment', 'left', 'right']);
+ }
+ }, 'facingMode is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const settings = await createTrackAndGetSettings(t, "video");
+ assert_equals(typeof(settings.resizeMode), "string",
+ "resizeMode should exist and it should be a string.");
+ assert_in_array(settings.resizeMode, ['none', 'crop-and-scale']);
+ }, 'resizeMode is reported by getSettings() for getUserMedia() video tracks');
+
+ promise_test(async t => {
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video : true});
+ const audioTrack = stream.getAudioTracks()[0];
+ const videoTrack = stream.getVideoTracks()[0];
+
+ const audioDeviceId = audioTrack.getSettings().deviceId;
+ const videoDeviceId = videoTrack.getSettings().deviceId;
+ const audioGroupId = audioTrack.getSettings().groupId;
+ const videoGroupId = videoTrack.getSettings().groupId;
+
+ audioTrack.stop();
+ videoTrack.stop();
+
+ assert_equals(audioTrack.getSettings().deviceId, audioDeviceId, "audio track deviceId");
+ assert_equals(videoTrack.getSettings().deviceId, videoDeviceId, "video track deviceId");
+ assert_equals(audioTrack.getSettings().groupId, audioGroupId, "audio track groupId");
+ assert_equals(videoTrack.getSettings().groupId, videoGroupId, "video track groupId");
+ }, 'Stopped tracks should expose deviceId/groupId');
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>Distinct id for distinct mediastream tracks</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-id">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your audio and video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that distinct mediastream tracks have distinct ids.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true})
+ assert_not_equals(stream.getVideoTracks()[0], stream.getAudioTracks()[0].id, "audio and video tracks have distinct ids");
+}, "Tests that distinct mediastream tracks have distinct ids ");
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack transfer to iframe</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+promise_test(async () => {
+ const iframe = document.createElement("iframe");
+ const stream = await navigator.mediaDevices.getDisplayMedia({video: true});
+ const track = stream.getVideoTracks()[0];
+ const cloned_track = track.clone();
+ const iframeLoaded = new Promise((resolve) => {iframe.onload = resolve});
+
+ iframe.src = "support/iframe-MediaStreamTrack-transfer.html";
+ document.body.appendChild(iframe);
+
+ await iframeLoaded;
+
+ const nextMessage = new Promise((resolve) => {
+ window.onmessage = resolve
+ });
+
+ assert_not_equals(track.readyState, "ended");
+ iframe.contentWindow.postMessage(track);
+ assert_equals(track.readyState, "ended");
+ assert_equals(cloned_track.readyState, "live");
+
+ const message = await nextMessage;
+ assert_not_equals(message.data.result, 'Failure', 'Failed: ' + message.data.error);
+});
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+<title>getUserMedia({video:true}) creates a stream with a properly initialized video track</title>
+<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#idl-def-MediaStreamTrack">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#life-cycle-and-media-flow">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-kind">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-enabled">
+<link rel="help" href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html#widl-MediaStreamTrack-readyState">
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that the video track of MediaStream
+object returned by the success callback in getUserMedia is correctly initialized.</p>
+
+<div id='log'></div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script>
+promise_test(async () => {
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ const videoTracks = stream.getVideoTracks();
+ assert_equals(videoTracks.length, 1, "There is exactly one video track in the media stream");
+ track = videoTracks[0];
+ assert_equals(track.readyState, "live", "The track object is in live state");
+ assert_equals(track.kind, "video", "The track object is of video kind");
+ // Not clear that this is required by the spec,
+ // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=22212
+ assert_true(track.enabled, "The track object is enabed");
+});
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack transfer to iframe</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+promise_test(async () => {
+ const iframe = document.createElement("iframe");
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ const track = stream.getVideoTracks()[0];
+ const result = new Promise((resolve, reject) => {
+ window.onmessage = (e) => {
+ if (e.data.result === 'Failure') {
+ reject('Failed: ' + e.data.error);
+ } else {
+ resolve();
+ }
+ };
+ });
+ iframe.addEventListener("load", () => {
+ iframe.contentWindow.postMessage(track);
+ });
+ iframe.src = "support/iframe-MediaStreamTrack-transfer-video.html";
+ document.body.appendChild(iframe);
+ return result;
+});
+</script>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrack transfer to Worker</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<script id="workerCode" type="javascript/worker">
+self.onmessage = (e) => {
+ try {
+ if(e.data instanceof MediaStreamTrack) {
+ self.postMessage({result: 'Success'});
+ return;
+ } else {
+ self.postMessage({
+ result: 'Failure',
+ error: `${e.data} is not a MediaStreamTrack`
+ });
+ }
+ } catch (error) {
+ self.postMessage({
+ result: 'Failure',
+ error
+ });
+ }
+}
+</script>
+<script>
+promise_test(async () => {
+ const workerBlob = new Blob([document.querySelector('#workerCode').textContent],
+ {type: "text/javascript"});
+ const workerUrl = window.URL.createObjectURL(workerBlob);
+ const worker = new Worker(workerUrl);
+ window.URL.revokeObjectURL(workerUrl);
+ await setMediaPermission("granted", ["camera"]);
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ const track = stream.getVideoTracks()[0];
+ const result = new Promise((resolve, reject) => {
+ worker.onmessage = (e) => {
+ if (e.data.result === 'Failure') {
+ reject('Failed: ' + e.data.error);
+ } else {
+ resolve();
+ }
+ };
+ });
+ worker.postMessage(track, [track]);
+ return result;
+});
+</script>
--- /dev/null
+<!doctype html>
+<title>MediaStreamTrackEvent constructor</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#mediastreamtrackevent">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_equals(MediaStreamTrackEvent.length, 2);
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type");
+ });
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type", null);
+ });
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type", undefined);
+ });
+}, "The eventInitDict argument is required");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type", {});
+ });
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type", { track: null });
+ });
+ assert_throws_js(TypeError, function() {
+ new MediaStreamTrackEvent("type", { track: undefined });
+ });
+}, "The eventInitDict's track member is required.");
+
+test(function() {
+ // a MediaStreamTrack instance is needed to test, any instance will do.
+ var context = new AudioContext();
+ var dest = context.createMediaStreamDestination();
+ var track = dest.stream.getTracks()[0];
+ assert_true(track instanceof MediaStreamTrack);
+ var event = new MediaStreamTrackEvent("type", { track: track });
+ assert_equals(event.type, "type");
+ assert_equals(event.track, track);
+}, "The MediaStreamTrackEvent instance's track attribute is set.");
+</script>
--- /dev/null
+<html class="test-wait">
+<head>
+ <title>
+ Test enumerateDevices() calls either side of browsing context discard
+ </title>
+</head>
+<script>
+ const frame = document.createElement('frame');
+ document.documentElement.appendChild(frame);
+ const devices = frame.contentWindow.navigator.mediaDevices;
+ devices.enumerateDevices();
+ frame.remove();
+ devices.enumerateDevices();
+ // Wait long enough to expect the async enumerateDevices() code to complete.
+ navigator.mediaDevices.enumerateDevices().then(
+ () => document.documentElement.removeAttribute("class"));
+</script>
+</html>
--- /dev/null
+<!doctype html>
+<title>enumerateDevices() with navigation</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="permission-helper.js"></script>
+<body></body>
+<script>
+'use strict';
+const blank_url = 'blank.html';
+const search2 = '?2';
+
+function promise_new_task(t) {
+ return new Promise(resolve => t.step_timeout(resolve, 0));
+}
+function promise_event(target, name) {
+ return new Promise(resolve => target[`on${name}`] = resolve);
+}
+
+promise_test(async t => {
+ // Gecko persists only toplevel documents, so load documents in a toplevel.
+ await test_driver.bless('window.open()');
+ const proxy = window.open(blank_url);
+ t.add_cleanup(() => proxy.close());
+ await promise_event(proxy, 'pageshow');
+ const devices = proxy.navigator.mediaDevices;
+ // Use another task so that another load creates a new session history entry.
+ await promise_new_task(t);
+
+ proxy.location = blank_url + search2;
+ await promise_event(proxy, 'pagehide');
+ // Use another task to ensure the first subdocument is no longer fully
+ // active and proxy refers to the realm of the second document.
+ await promise_new_task(t);
+ assert_equals(proxy.location.search, search2, 'navigated search');
+ // Enumerate from the inactive first Window.
+ const promise_enumerate = devices.enumerateDevices();
+ // `then()` is used rather than static Promise methods because microtasks
+ // for `PromiseResolve()` do not run when Promises from inactive realms are
+ // involved. Whether microtasks for `then()` run depends on the realm of
+ // the handler rather than the realm of the Promise.
+ // Don't use `finally()`, because it uses `PromiseResolve()` and so
+ // microtasks don't run.
+ // See https://github.com/whatwg/html/issues/5319.
+ let promise_state = 'pending';
+ promise_enumerate.then(() => promise_state = 'resolved',
+ () => promise_state = 'rejected');
+ // Enumerate in the active second Window to provide enough time to check
+ // that the Promise from the inactive Window does not settle.
+ await proxy.navigator.mediaDevices.enumerateDevices();
+
+ proxy.history.back();
+ await promise_event(proxy, 'pagehide');
+ // enumerateDevices() Promise resolution is triggered only in parallel
+ // steps, so manipulation of the Promise (if the first document was
+ // persisted) would occur through a queued task, which would run after
+ // the pagehide event is dispatched and so after the associated
+ // microtask that runs the following assert.
+ // https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-for-spec-authors
+ assert_equals(promise_state, 'pending', 'Promise state while inactive');
+ // If the first document is restored, then that will occur immediately after
+ // pagehide (and associated microtasks), before the next global task is run.
+ // https://html.spec.whatwg.org/multipage/history.html#traverse-the-history-by-a-delta
+ await promise_new_task(t);
+ if (proxy.navigator.mediaDevices == devices) {
+ // The first document was persisted and restored.
+ assert_equals(proxy.location.search, '', 'history search');
+ await promise_enumerate;
+ } else {
+ // The first document was not restored, but gets re-fetched.
+ await t.step_wait(() => proxy.location.search == '', 'navigation');
+ assert_not_equals(proxy.navigator.mediaDevices, devices, 'new realm')
+ await proxy.navigator.mediaDevices.enumerateDevices();
+ assert_equals(promise_state, 'pending', 'Promise state after discard');
+ }
+}, 'enumerateDevices with navigation');
+</script>
--- /dev/null
+<!doctype html>
+<title>Historical Media Capture and Streams features</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_false("mozGetUserMedia" in navigator);
+}, "navigator.mozGetUserMedia should not exist");
+
+test(() => {
+ const mediaStream = new MediaStream();
+ assert_throws_js(TypeError, () => URL.createObjectURL(mediaStream));
+}, "Passing MediaStream to URL.createObjectURL() should throw");
+
+test(() => {
+ const mediaStream = new MediaStream();
+ assert_false("onactive" in mediaStream);
+}, "MediaStream.onactive should not exist");
+
+test(() => {
+ const mediaStream = new MediaStream();
+ assert_false("oninactive" in mediaStream);
+}, "MediaStream.oninactive should not exist");
+</script>
--- /dev/null
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+// https://w3c.github.io/mediacapture-main/
+
+idl_test(
+ ['mediacapture-streams'],
+ ['webidl', 'dom', 'html'],
+ async idl_array => {
+ const inputDevices = [];
+ const outputDevices = [];
+ try {
+ const list = await navigator.mediaDevices.enumerateDevices();
+ for (const device of list) {
+ if (device.kind in self) {
+ continue;
+ }
+ assert_in_array(device.kind, ['audioinput', 'videoinput', 'audiooutput']);
+ self[device.kind] = device;
+ if (device.kind.endsWith('input')) {
+ inputDevices.push(device.kind);
+ } else {
+ outputDevices.push(device.kind);
+ }
+ }
+ } catch (e) {}
+
+ try {
+ self.stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ self.track = stream.getTracks()[0];
+ self.trackEvent = new MediaStreamTrackEvent("type", {
+ track: track,
+ });
+ } catch (e) {}
+
+ idl_array.add_objects({
+ InputDeviceInfo: inputDevices,
+ MediaStream: ['stream', 'new MediaStream()'],
+ Navigator: ['navigator'],
+ MediaDevices: ['navigator.mediaDevices'],
+ MediaDeviceInfo: outputDevices,
+ MediaStreamTrack: ['track'],
+ MediaStreamTrackEvent: ['trackEvent'],
+ OverconstrainedError: ['new OverconstrainedError("constraint")'],
+ });
+ }
+);
--- /dev/null
+<!DOCTYPE html>
+<script src="message-enumerateddevices.js"></script>
--- /dev/null
+<!DOCTYPE html>
+<script src="message-enumerateddevices.js"></script>
--- /dev/null
+<!doctype html>
+<meta name="viewport" content="width=device-width">
+<title>Directory listing for /mediacapture-streams/</title>
+<h1>Directory listing for /mediacapture-streams/</h1>
+<ul>
+<li class="dir"><a href="/">..</a></li>
+<li class="file"><a href="GUM-api.https.html">GUM-api.https.html</a></li>
+<li class="file"><a href="GUM-deny.https.html">GUM-deny.https.html</a></li>
+<li class="file"><a href="GUM-empty-option-param.https.html">GUM-empty-option-param.https.html</a></li>
+<li class="file"><a href="GUM-impossible-constraint.https.html">GUM-impossible-constraint.https.html</a></li>
+<li class="file"><a href="GUM-invalid-facing-mode.https.html">GUM-invalid-facing-mode.https.html</a></li>
+<li class="file"><a href="GUM-non-applicable-constraint.https.html">GUM-non-applicable-constraint.https.html</a></li>
+<li class="file"><a href="GUM-optional-constraint.https.html">GUM-optional-constraint.https.html</a></li>
+<li class="file"><a href="GUM-required-constraint-with-ideal-value.https.html">GUM-required-constraint-with-ideal-value.https.html</a></li>
+<li class="file"><a href="GUM-trivial-constraint.https.html">GUM-trivial-constraint.https.html</a></li>
+<li class="file"><a href="GUM-unknownkey-option-param.https.html">GUM-unknownkey-option-param.https.html</a></li>
+<li class="file"><a href="META.yml">META.yml</a></li>
+<li class="file"><a href="MediaDevices-SecureContext.html">MediaDevices-SecureContext.html</a></li>
+<li class="file"><a href="MediaDevices-after-discard.https.html">MediaDevices-after-discard.https.html</a></li>
+<li class="file"><a href="MediaDevices-enumerateDevices-not-allowed-camera.https.html">MediaDevices-enumerateDevices-not-allowed-camera.https.html</a> (<a href="MediaDevices-enumerateDevices-not-allowed-camera.https.html.headers">.headers</a>)</li>
+<li class="file"><a href="MediaDevices-enumerateDevices-not-allowed-mic.https.html">MediaDevices-enumerateDevices-not-allowed-mic.https.html</a> (<a href="MediaDevices-enumerateDevices-not-allowed-mic.https.html.headers">.headers</a>)</li>
+<li class="file"><a href="MediaDevices-enumerateDevices-returned-objects.https.html">MediaDevices-enumerateDevices-returned-objects.https.html</a></li>
+<li class="file"><a href="MediaDevices-enumerateDevices.https.html">MediaDevices-enumerateDevices.https.html</a></li>
+<li class="file"><a href="MediaDevices-getSupportedConstraints.https.html">MediaDevices-getSupportedConstraints.https.html</a></li>
+<li class="file"><a href="MediaDevices-getUserMedia.https.html">MediaDevices-getUserMedia.https.html</a></li>
+<li class="file"><a href="MediaStream-MediaElement-firstframe.https.html">MediaStream-MediaElement-firstframe.https.html</a></li>
+<li class="file"><a href="MediaStream-MediaElement-preload-none-manual.https.html">MediaStream-MediaElement-preload-none-manual.https.html</a></li>
+<li class="file"><a href="MediaStream-MediaElement-srcObject.https.html">MediaStream-MediaElement-srcObject.https.html</a></li>
+<li class="file"><a href="MediaStream-add-audio-track.https.html">MediaStream-add-audio-track.https.html</a></li>
+<li class="file"><a href="MediaStream-audio-only.https.html">MediaStream-audio-only.https.html</a></li>
+<li class="file"><a href="MediaStream-clone.https.html">MediaStream-clone.https.html</a></li>
+<li class="file"><a href="MediaStream-default-feature-policy.https.html">MediaStream-default-feature-policy.https.html</a></li>
+<li class="file"><a href="MediaStream-finished-add.https.html">MediaStream-finished-add.https.html</a></li>
+<li class="file"><a href="MediaStream-gettrackid.https.html">MediaStream-gettrackid.https.html</a></li>
+<li class="file"><a href="MediaStream-id-manual.https.html">MediaStream-id-manual.https.html</a></li>
+<li class="file"><a href="MediaStream-idl.https.html">MediaStream-idl.https.html</a></li>
+<li class="file"><a href="MediaStream-removetrack.https.html">MediaStream-removetrack.https.html</a></li>
+<li class="file"><a href="MediaStream-supported-by-feature-policy.html">MediaStream-supported-by-feature-policy.html</a></li>
+<li class="file"><a href="MediaStream-video-only.https.html">MediaStream-video-only.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html">MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-MediaElement-disabled-video-is-black.https.html">MediaStreamTrack-MediaElement-disabled-video-is-black.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-applyConstraints.https.html">MediaStreamTrack-applyConstraints.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-end-manual.https.html">MediaStreamTrack-end-manual.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-getCapabilities.https.html">MediaStreamTrack-getCapabilities.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-getSettings.https.html">MediaStreamTrack-getSettings.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-id.https.html">MediaStreamTrack-id.https.html</a></li>
+<li class="file"><a href="MediaStreamTrack-init.https.html">MediaStreamTrack-init.https.html</a></li>
+<li class="file"><a href="MediaStreamTrackEvent-constructor.https.html">MediaStreamTrackEvent-constructor.https.html</a></li>
+<li class="file"><a href="historical.https.html">historical.https.html</a></li>
+<li class="file"><a href="idlharness.https.window.js">idlharness.https.window.js</a></li>
+</ul>
--- /dev/null
+onmessage = async e => {
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+ stream.getTracks().forEach(t => t.stop());
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ e.source.postMessage({
+ devices: devices.map(d => d.toJSON())
+ }, '*');
+}
--- /dev/null
+// Set permissions for camera and microphone using Web Driver
+// Status can be one of "granted" or "denied"
+// Scope take values from permission names
+async function setMediaPermission(status="granted", scope=["camera", "microphone"]) {
+ try {
+ for (let s of scope) {
+ await test_driver.set_permission({ name: s }, status, true);
+ }
+ } catch (e) {
+ const noSetPermissionSupport = typeof e === "string" && e.match(/set_permission not implemented/);
+ if (!(noSetPermissionSupport ||
+ (e instanceof Error && e.message.match("unimplemented")) )) {
+ throw e;
+ }
+ // Web Driver not implemented action
+ // FF: https://bugzilla.mozilla.org/show_bug.cgi?id=1524074
+
+ // with current WPT runners, will default to granted state for FF and Safari
+ // throw if status!="granted" to invalidate test results
+ if (status === "denied") {
+ assert_implements_optional(!noSetPermissionSupport, "Unable to set permission to denied for this test");
+ }
+ }
+}
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>iframe</title>
+ <script>
+ function onMsg(e) {
+ if(e.data instanceof MediaStreamTrack) {
+ const track = e.data;
+ video = document.getElementById("myvideo");
+ video.srcObject = new MediaStream ([track]);
+ video.play();
+
+ parent.postMessage({result: 'Success'});
+ } else {
+ parent.postMessage({
+ result: 'Failure',
+ error: `${e.data} is not a MediaStreamTrack`
+ });
+ }
+ }
+ window.addEventListener("message", onMsg);
+ </script>
+ </head>
+ <body>
+ <video id="myvideo"></video>
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>iframe</title>
+ <script>
+ function onMsg(e) {
+ alert("0000000000000");
+ if(e.data instanceof MediaStreamTrack) {
+ parent.postMessage({result: 'Success'});
+ } else {
+ parent.postMessage({
+ result: 'Failure',
+ error: `${e.data} is not a MediaStreamTrack`
+ });
+ }
+ }
+ window.addEventListener("message", onMsg);
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
--- /dev/null
+// Feature test to avoid timeouts
+function assert_feature_policy_supported() {
+ assert_not_equals(document.featurePolicy, undefined,
+ 'Feature Policy is supported');
+}
+// Tests whether a feature that is enabled/disabled by feature policy works
+// as expected.
+// Arguments:
+// feature_description: a short string describing what feature is being
+// tested. Examples: "usb.GetDevices()", "PaymentRequest()".
+// test: test created by testharness. Examples: async_test, promise_test.
+// src: URL where a feature's availability is checked. Examples:
+// "/feature-policy/resources/feature-policy-payment.html",
+// "/feature-policy/resources/feature-policy-usb.html".
+// expect_feature_available: a callback(data, feature_description) to
+// verify if a feature is available or unavailable as expected.
+// The file under the path "src" defines what "data" is sent back as a
+// postMessage. Inside the callback, some tests (e.g., EXPECT_EQ,
+// EXPECT_TRUE, etc) are run accordingly to test a feature's
+// availability.
+// Example: expect_feature_available_default(data, feature_description).
+// feature_name: Optional argument, only provided when testing iframe allow
+// attribute. "feature_name" is the feature name of a policy controlled
+// feature (https://wicg.github.io/feature-policy/#features).
+// See examples at:
+// https://github.com/WICG/feature-policy/blob/master/features.md
+// allow_attribute: Optional argument, only used for testing fullscreen:
+// "allowfullscreen"
+function test_feature_availability(
+ feature_description, test, src, expect_feature_available, feature_name,
+ allow_attribute) {
+ let frame = document.createElement('iframe');
+ frame.src = src;
+
+ if (typeof feature_name !== 'undefined') {
+ frame.allow = frame.allow.concat(";" + feature_name);
+ }
+
+ if (typeof allow_attribute !== 'undefined') {
+ frame.setAttribute(allow_attribute, true);
+ }
+
+ window.addEventListener('message', test.step_func(function handler(evt) {
+ if (evt.source === frame.contentWindow) {
+ expect_feature_available(evt.data, feature_description);
+ document.body.removeChild(frame);
+ window.removeEventListener('message', handler);
+ test.done();
+ }
+ }));
+
+ document.body.appendChild(frame);
+}
+
+// Default helper functions to test a feature's availability:
+function expect_feature_available_default(data, feature_description) {
+ assert_true(data.enabled, feature_description);
+}
+
+function expect_feature_unavailable_default(data, feature_description) {
+ assert_false(data.enabled, feature_description);
+}
+
+// This is the same as test_feature_availability() but instead of passing in a
+// function to check the result of the message sent back from an iframe, instead
+// just compares the result to an expected result passed in.
+// Arguments:
+// test: test created by testharness. Examples: async_test, promise_test.
+// src: the URL to load in an iframe in which to test the feature.
+// expected_result: the expected value to compare to the data passed back
+// from the src page by postMessage.
+// allow_attribute: Optional argument, only provided when an allow
+// attribute should be specified on the iframe.
+function test_feature_availability_with_post_message_result(
+ test, src, expected_result, allow_attribute) {
+ var test_result = function(data, feature_description) {
+ assert_equals(data, expected_result);
+ };
+ test_feature_availability(null, test, src, test_result, allow_attribute);
+}
+
+// If this page is intended to test the named feature (according to the URL),
+// tests the feature availability and posts the result back to the parent.
+// Otherwise, does nothing.
+function test_feature_in_iframe(feature_name, feature_promise_factory) {
+ if (location.hash.endsWith(`#${feature_name}`)) {
+ feature_promise_factory().then(
+ () => window.parent.postMessage('#OK', '*'),
+ (e) => window.parent.postMessage('#' + e.name, '*'));
+ }
+}
+
+// Returns true if the URL for this page indicates that it is embedded in an
+// iframe.
+function page_loaded_in_iframe() {
+ return location.hash.startsWith('#iframe');
+}
+
+// Returns a same-origin (relative) URL suitable for embedding in an iframe for
+// testing the availability of the feature.
+function same_origin_url(feature_name) {
+ // Append #iframe to the URL so we can detect the iframe'd version of the
+ // page.
+ return location.pathname + '#iframe#' + feature_name;
+}
+
+// Returns a cross-origin (absolute) URL suitable for embedding in an iframe for
+// testing the availability of the feature.
+function cross_origin_url(base_url, feature_name) {
+ return base_url + same_origin_url(feature_name);
+}
+
+// This function runs all feature policy tests for a particular feature that
+// has a default policy of "self". This includes testing:
+// 1. Feature usage succeeds by default in the top level frame.
+// 2. Feature usage succeeds by default in a same-origin iframe.
+// 3. Feature usage fails by default in a cross-origin iframe.
+// 4. Feature usage suceeds when an allow attribute is specified on a
+// cross-origin iframe.
+//
+// The same page which called this function will be loaded in the iframe in
+// order to test feature usage there. When this function is called in that
+// context it will simply run the feature and return a result back via
+// postMessage.
+//
+// Arguments:
+// cross_origin: A cross-origin URL base to be used to load the page which
+// called into this function.
+// feature_name: The name of the feature as it should be specified in an
+// allow attribute.
+// error_name: If feature usage does not succeed, this is the string
+// representation of the error that will be passed in the rejected
+// promise.
+// feature_promise_factory: A function which returns a promise which tests
+// feature usage. If usage succeeds, the promise should resolve. If it
+// fails, the promise should reject with an error that can be
+// represented as a string.
+function run_all_fp_tests_allow_self(
+ cross_origin, feature_name, error_name, feature_promise_factory) {
+ // This may be the version of the page loaded up in an iframe. If so, just
+ // post the result of running the feature promise back to the parent.
+ if (page_loaded_in_iframe()) {
+ test_feature_in_iframe(feature_name, feature_promise_factory);
+ return;
+ }
+
+ // Run the various tests.
+ // 1. Allowed in top-level frame.
+ promise_test(
+ () => feature_promise_factory(),
+ 'Default "' + feature_name +
+ '" feature policy ["self"] allows the top-level document.');
+
+ // 2. Allowed in same-origin iframe.
+ const same_origin_frame_pathname = same_origin_url(feature_name);
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, same_origin_frame_pathname, '#OK');
+ },
+ 'Default "' + feature_name +
+ '" feature policy ["self"] allows same-origin iframes.');
+
+ // 3. Blocked in cross-origin iframe.
+ const cross_origin_frame_url = cross_origin_url(cross_origin, feature_name);
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, cross_origin_frame_url, '#' + error_name);
+ },
+ 'Default "' + feature_name +
+ '" feature policy ["self"] disallows cross-origin iframes.');
+
+ // 4. Allowed in cross-origin iframe with "allow" attribute.
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, cross_origin_frame_url, '#OK', feature_name);
+ },
+ 'Feature policy "' + feature_name +
+ '" can be enabled in cross-origin iframes using "allow" attribute.');
+}
+
+// This function runs all feature policy tests for a particular feature that
+// has a default policy of "*". This includes testing:
+// 1. Feature usage succeeds by default in the top level frame.
+// 2. Feature usage succeeds by default in a same-origin iframe.
+// 3. Feature usage succeeds by default in a cross-origin iframe.
+// 4. Feature usage fails when an allow attribute is specified on a
+// cross-origin iframe with a value of "feature-name 'none'".
+//
+// The same page which called this function will be loaded in the iframe in
+// order to test feature usage there. When this function is called in that
+// context it will simply run the feature and return a result back via
+// postMessage.
+//
+// Arguments:
+// cross_origin: A cross-origin URL base to be used to load the page which
+// called into this function.
+// feature_name: The name of the feature as it should be specified in an
+// allow attribute.
+// error_name: If feature usage does not succeed, this is the string
+// representation of the error that will be passed in the rejected
+// promise.
+// feature_promise_factory: A function which returns a promise which tests
+// feature usage. If usage succeeds, the promise should resolve. If it
+// fails, the promise should reject with an error that can be
+// represented as a string.
+function run_all_fp_tests_allow_all(
+ cross_origin, feature_name, error_name, feature_promise_factory) {
+ // This may be the version of the page loaded up in an iframe. If so, just
+ // post the result of running the feature promise back to the parent.
+ if (page_loaded_in_iframe()) {
+ test_feature_in_iframe(feature_name, feature_promise_factory);
+ return;
+ }
+
+ // Run the various tests.
+ // 1. Allowed in top-level frame.
+ promise_test(
+ () => feature_promise_factory(),
+ 'Default "' + feature_name +
+ '" feature policy ["*"] allows the top-level document.');
+
+ // 2. Allowed in same-origin iframe.
+ const same_origin_frame_pathname = same_origin_url(feature_name);
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, same_origin_frame_pathname, '#OK');
+ },
+ 'Default "' + feature_name +
+ '" feature policy ["*"] allows same-origin iframes.');
+
+ // 3. Allowed in cross-origin iframe.
+ const cross_origin_frame_url = cross_origin_url(cross_origin, feature_name);
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, cross_origin_frame_url, '#OK');
+ },
+ 'Default "' + feature_name +
+ '" feature policy ["*"] allows cross-origin iframes.');
+
+ // 4. Blocked in cross-origin iframe with "allow" attribute set to 'none'.
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, cross_origin_frame_url, '#' + error_name,
+ feature_name + " 'none'");
+ },
+ 'Feature policy "' + feature_name +
+ '" can be disabled in cross-origin iframes using "allow" attribute.');
+
+ // 5. Blocked in same-origin iframe with "allow" attribute set to 'none'.
+ async_test(
+ t => {
+ test_feature_availability_with_post_message_result(
+ t, same_origin_frame_pathname, '#' + error_name,
+ feature_name + " 'none'");
+ },
+ 'Feature policy "' + feature_name +
+ '" can be disabled in same-origin iframes using "allow" attribute.');
+}
+
+// This function tests that a given policy allows each feature for the correct
+// list of origins specified by the |expected_policy|.
+// Arguments:
+// expected_policy: A list of {feature, allowlist} pairs where the feature is
+// enabled for every origin in the allowlist, in the |policy|.
+// policy: Either a document.featurePolicy or an iframe.featurePolicy to be
+// tested.
+// message: A short description of what policy is being tested.
+function test_allowlists(expected_policy, policy, message) {
+ for (var allowlist of allowlists) {
+ test(function() {
+ assert_array_equals(
+ policy.getAllowlistForFeature(allowlist.feature),
+ allowlist.allowlist);
+ }, message + ' for feature ' + allowlist.feature);
+ }
+}
+
+// This function tests that a subframe's document policy allows a given feature.
+// A feature is allowed in a frame either through inherited policy or specified
+// by iframe allow attribute.
+// Arguments:
+// test: test created by testharness. Examples: async_test, promise_test.
+// feature: feature name that should be allowed in the frame.
+// src: the URL to load in the frame.
+// allow: the allow attribute (container policy) of the iframe
+function test_allowed_feature_for_subframe(message, feature, src, allow) {
+ let frame = document.createElement('iframe');
+ if (typeof allow !== 'undefined') {
+ frame.allow = allow;
+ }
+ promise_test(function() {
+ assert_feature_policy_supported();
+ frame.src = src;
+ return new Promise(function(resolve, reject) {
+ window.addEventListener('message', function handler(evt) {
+ resolve(evt.data);
+ }, { once: true });
+ document.body.appendChild(frame);
+ }).then(function(data) {
+ assert_true(data.includes(feature), feature);
+ });
+ }, message);
+}
+
+// This function tests that a subframe's document policy disallows a given
+// feature. A feature is allowed in a frame either through inherited policy or
+// specified by iframe allow attribute.
+// Arguments:
+// test: test created by testharness. Examples: async_test, promise_test.
+// feature: feature name that should not be allowed in the frame.
+// src: the URL to load in the frame.
+// allow: the allow attribute (container policy) of the iframe
+function test_disallowed_feature_for_subframe(message, feature, src, allow) {
+ let frame = document.createElement('iframe');
+ if (typeof allow !== 'undefined') {
+ frame.allow = allow;
+ }
+ promise_test(function() {
+ assert_feature_policy_supported();
+ frame.src = src;
+ return new Promise(function(resolve, reject) {
+ window.addEventListener('message', function handler(evt) {
+ resolve(evt.data);
+ }, { once: true });
+ document.body.appendChild(frame);
+ }).then(function(data) {
+ assert_false(data.includes(feature), feature);
+ });
+ }, message);
+}
+
+// This function tests that a subframe with header policy defined on a given
+// feature allows and disallows the feature as expected.
+// Arguments:
+// feature: feature name.
+// frame_header_policy: either *, 'self' or 'none', defines the frame
+// document's header policy on |feature|.
+// src: the URL to load in the frame.
+// test_expects: contains 6 expected results of either |feature| is allowed
+// or not inside of a local or remote iframe nested inside
+// the subframe given the header policy to be either *,
+// 'slef', or 'none'.
+// test_name: name of the test.
+function test_subframe_header_policy(
+ feature, frame_header_policy, src, test_expects, test_name) {
+ let frame = document.createElement('iframe');
+ promise_test(function() {
+ assert_feature_policy_supported()
+ frame.src = src + '?pipe=sub|header(Feature-Policy,' + feature + ' '
+ + frame_header_policy + ';)';
+ return new Promise(function(resolve) {
+ window.addEventListener('message', function handler(evt) {
+ resolve(evt.data);
+ });
+ document.body.appendChild(frame);
+ }).then(function(results) {
+ for (var j = 0; j < results.length; j++) {
+ var data = results[j];
+
+ function test_result(message, test_expect) {
+ if (test_expect) {
+ assert_true(data.allowedfeatures.includes(feature), message);
+ } else {
+ assert_false(data.allowedfeatures.includes(feature), message);
+ }
+ }
+
+ if (data.frame === 'local') {
+ if (data.policy === '*') {
+ test_result('local_all:', test_expects.local_all);
+ }
+ if (data.policy === '\'self\'') {
+ test_result('local_self:', test_expects.local_self);
+ }
+ if (data.policy === '\'none\'') {
+ test_result('local_none:', test_expects.local_none);
+ }
+ }
+
+ if (data.frame === 'remote') {
+ if (data.policy === '*') {
+ test_result('remote_all:', test_expects.remote_all);
+ }
+ if (data.policy === '\'self\'') {
+ test_result('remote_self:', test_expects.remote_self);
+ }
+ if (data.policy === '\'none\'') {
+ test_result('remote_none:', test_expects.remote_none);
+ }
+ }
+ }
+ });
+ }, test_name);
+}
+
+// This function tests that frame policy allows a given feature correctly. A
+// feature is allowed in a frame either through inherited policy or specified
+// by iframe allow attribute.
+// Arguments:
+// feature: feature name.
+// src: the URL to load in the frame. If undefined, the iframe will have a
+// srcdoc="" attribute
+// test_expect: boolean value of whether the feature should be allowed.
+// allow: optional, the allow attribute (container policy) of the iframe.
+// allowfullscreen: optional, boolean value of allowfullscreen attribute.
+// sandbox: optional boolean. If true, the frame will be sandboxed (with
+// allow-scripts, so that tests can run in it.)
+function test_frame_policy(
+ feature, src, srcdoc, test_expect, allow, allowfullscreen, sandbox) {
+ let frame = document.createElement('iframe');
+ document.body.appendChild(frame);
+ // frame_policy should be dynamically updated as allow and allowfullscreen is
+ // updated.
+ var frame_policy = frame.featurePolicy;
+ if (typeof allow !== 'undefined') {
+ frame.setAttribute('allow', allow);
+ }
+ if (!!allowfullscreen) {
+ frame.setAttribute('allowfullscreen', true);
+ }
+ if (!!sandbox) {
+ frame.setAttribute('sandbox', 'allow-scripts');
+ }
+ if (!!src) {
+ frame.src = src;
+ }
+ if (!!srcdoc) {
+ frame.srcdoc = "<h1>Hello world!</h1>";
+ }
+ if (test_expect) {
+ assert_true(frame_policy.allowedFeatures().includes(feature));
+ } else {
+ assert_false(frame_policy.allowedFeatures().includes(feature));
+ }
+}
+
+function expect_reports(report_count, policy_name, description) {
+ async_test(t => {
+ var num_received_reports = 0;
+ new ReportingObserver(t.step_func((reports, observer) => {
+ const relevant_reports = reports.filter(r => (r.body.featureId === policy_name));
+ num_received_reports += relevant_reports.length;
+ if (num_received_reports >= report_count) {
+ t.done();
+ }
+ }), {types: ['permissions-policy-violation'], buffered: true}).observe();
+ }, description);
+}
--- /dev/null
+/**
+ * Host information for cross-origin tests.
+ * @returns {Object} with properties for different host information.
+ */
+function get_host_info() {
+
+ var HTTP_PORT = '80';
+ var HTTP_PORT2 = '81';
+ var HTTPS_PORT = '443';
+ var HTTPS_PORT2 = '444';
+ var PROTOCOL = self.location.protocol;
+ var IS_HTTPS = (PROTOCOL == "https:");
+ var PORT = IS_HTTPS ? HTTPS_PORT : HTTP_PORT;
+ var PORT2 = IS_HTTPS ? HTTPS_PORT2 : HTTP_PORT2;
+ var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT);
+ var HTTP_PORT2_ELIDED = HTTP_PORT2 == "80" ? "" : (":" + HTTP_PORT2);
+ var HTTPS_PORT_ELIDED = HTTPS_PORT == "443" ? "" : (":" + HTTPS_PORT);
+ var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED;
+ var ORIGINAL_HOST = 'w3c-test.org';
+ var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www.' + ORIGINAL_HOST);
+ var OTHER_HOST = 'www2.w3c-test.org';
+ var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('not-web-platform.test');
+
+ return {
+ HTTP_PORT: HTTP_PORT,
+ HTTP_PORT2: HTTP_PORT2,
+ HTTPS_PORT: HTTPS_PORT,
+ HTTPS_PORT2: HTTPS_PORT2,
+ PORT: PORT,
+ PORT2: PORT2,
+ ORIGINAL_HOST: ORIGINAL_HOST,
+ REMOTE_HOST: REMOTE_HOST,
+
+ ORIGIN: PROTOCOL + "//" + ORIGINAL_HOST + PORT_ELIDED,
+ HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + HTTP_PORT_ELIDED,
+ HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_ORIGIN_WITH_CREDS: 'https://foo:bar@' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
+ HTTP_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + ORIGINAL_HOST + HTTP_PORT2_ELIDED,
+ REMOTE_ORIGIN: PROTOCOL + "//" + REMOTE_HOST + PORT_ELIDED,
+ OTHER_ORIGIN: PROTOCOL + "//" + OTHER_HOST + PORT_ELIDED,
+ HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + HTTP_PORT_ELIDED,
+ HTTP_NOTSAMESITE_ORIGIN: 'http://' + NOTSAMESITE_HOST + HTTP_PORT_ELIDED,
+ HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + REMOTE_HOST + HTTP_PORT2_ELIDED,
+ HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
+ UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
+ AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
+ };
+}
+
+/**
+ * When a default port is used, location.port returns the empty string.
+ * This function attempts to provide an exact port, assuming we are running under wptserve.
+ * @param {*} loc - can be Location/<a>/<area>/URL, but assumes http/https only.
+ * @returns {string} The port number.
+ */
+function get_port(loc) {
+ if (loc.port) {
+ return loc.port;
+ }
+ return loc.protocol === 'https:' ? '443' : '80';
+}
--- /dev/null
+(function() {
+ "use strict";
+ var idCounter = 0;
+ let testharness_context = null;
+
+ function getInViewCenterPoint(rect) {
+ var left = Math.max(0, rect.left);
+ var right = Math.min(window.innerWidth, rect.right);
+ var top = Math.max(0, rect.top);
+ var bottom = Math.min(window.innerHeight, rect.bottom);
+
+ var x = 0.5 * (left + right);
+ var y = 0.5 * (top + bottom);
+
+ return [x, y];
+ }
+
+ function getPointerInteractablePaintTree(element) {
+ let elementDocument = element.ownerDocument;
+ if (!elementDocument.contains(element)) {
+ return [];
+ }
+
+ var rectangles = element.getClientRects();
+
+ if (rectangles.length === 0) {
+ return [];
+ }
+
+ var centerPoint = getInViewCenterPoint(rectangles[0]);
+
+ if ("elementsFromPoint" in elementDocument) {
+ return elementDocument.elementsFromPoint(centerPoint[0], centerPoint[1]);
+ } else if ("msElementsFromPoint" in elementDocument) {
+ var rv = elementDocument.msElementsFromPoint(centerPoint[0], centerPoint[1]);
+ return Array.prototype.slice.call(rv ? rv : []);
+ } else {
+ throw new Error("document.elementsFromPoint unsupported");
+ }
+ }
+
+ function inView(element) {
+ var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
+ return pointerInteractablePaintTree.indexOf(element) !== -1;
+ }
+
+
+ /**
+ * @namespace {test_driver}
+ */
+ window.test_driver = {
+ /**
+ * Set the context in which testharness.js is loaded
+ *
+ * @param {WindowProxy} context - the window containing testharness.js
+ **/
+ set_test_context: function(context) {
+ if (window.test_driver_internal.set_test_context) {
+ window.test_driver_internal.set_test_context(context);
+ }
+ testharness_context = context;
+ },
+
+ /**
+ * postMessage to the context containing testharness.js
+ *
+ * @param {Object} msg - the data to POST
+ **/
+ message_test: function(msg) {
+ let target = testharness_context;
+ if (testharness_context === null) {
+ target = window;
+ }
+ target.postMessage(msg, "*");
+ },
+
+ /**
+ * Trigger user interaction in order to grant additional privileges to
+ * a provided function.
+ *
+ * See `triggered by user activation
+ * <https://html.spec.whatwg.org/#triggered-by-user-activation>`_.
+ *
+ * @example
+ * var mediaElement = document.createElement('video');
+ *
+ * test_driver.bless('initiate media playback', function () {
+ * mediaElement.play();
+ * });
+ *
+ * @param {String} intent - a description of the action which must be
+ * triggered by user interaction
+ * @param {Function} action - code requiring escalated privileges
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled following user interaction and
+ * execution of the provided `action` function;
+ * rejected if interaction fails or the provided
+ * function throws an error
+ */
+ bless: function(intent, action, context=null) {
+ let contextDocument = context ? context.document : document;
+ var button = contextDocument.createElement("button");
+ button.innerHTML = "This test requires user interaction.<br />" +
+ "Please click here to allow " + intent + ".";
+ button.id = "wpt-test-driver-bless-" + (idCounter += 1);
+ const elem = contextDocument.body || contextDocument.documentElement;
+ elem.appendChild(button);
+
+ let wait_click = new Promise(resolve => button.addEventListener("click", resolve));
+
+ return test_driver.click(button)
+ .then(wait_click)
+ .then(function() {
+ button.remove();
+
+ if (typeof action === "function") {
+ return action();
+ }
+ return null;
+ });
+ },
+
+ /**
+ * Triggers a user-initiated click
+ *
+ * If ``element`` isn't inside the
+ * viewport, it will be scrolled into view before the click
+ * occurs.
+ *
+ * If ``element`` is from a different browsing context, the
+ * command will be run in that context.
+ *
+ * Matches the behaviour of the `Element Click
+ * <https://w3c.github.io/webdriver/#element-click>`_
+ * WebDriver command.
+ *
+ * **Note:** If the element to be clicked does not have a
+ * unique ID, the document must not have any DOM mutations
+ * made between the function being called and the promise
+ * settling.
+ *
+ * @param {Element} element - element to be clicked
+ * @returns {Promise} fulfilled after click occurs, or rejected in
+ * the cases the WebDriver command errors
+ */
+ click: function(element) {
+ if (!inView(element)) {
+ element.scrollIntoView({behavior: "instant",
+ block: "end",
+ inline: "nearest"});
+ }
+
+ var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
+ if (pointerInteractablePaintTree.length === 0 ||
+ !element.contains(pointerInteractablePaintTree[0])) {
+ return Promise.reject(new Error("element click intercepted error"));
+ }
+
+ var rect = element.getClientRects()[0];
+ var centerPoint = getInViewCenterPoint(rect);
+ return window.test_driver_internal.click(element,
+ {x: centerPoint[0],
+ y: centerPoint[1]});
+ },
+
+ /**
+ * Deletes all cookies.
+ *
+ * Matches the behaviour of the `Delete All Cookies
+ * <https://w3c.github.io/webdriver/#delete-all-cookies>`_
+ * WebDriver command.
+ *
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after cookies are deleted, or rejected in
+ * the cases the WebDriver command errors
+ */
+ delete_all_cookies: function(context=null) {
+ return window.test_driver_internal.delete_all_cookies(context);
+ },
+
+ /**
+ * Send keys to an element.
+ *
+ * If ``element`` isn't inside the
+ * viewport, it will be scrolled into view before the click
+ * occurs.
+ *
+ * If ``element`` is from a different browsing context, the
+ * command will be run in that context.
+ *
+ * To send special keys, send the respective key's codepoint,
+ * as defined by `WebDriver
+ * <https://w3c.github.io/webdriver/#keyboard-actions>`_. For
+ * example, the "tab" key is represented as "``\uE004``".
+ *
+ * **Note:** these special-key codepoints are not necessarily
+ * what you would expect. For example, <kbd>Esc</kbd> is the
+ * invalid Unicode character ``\uE00C``, not the ``\u001B`` Escape
+ * character from ASCII.
+ *
+ * This matches the behaviour of the
+ * `Send Keys
+ * <https://w3c.github.io/webdriver/#element-send-keys>`_
+ * WebDriver command.
+ *
+ * **Note:** If the element to be clicked does not have a
+ * unique ID, the document must not have any DOM mutations
+ * made between the function being called and the promise
+ * settling.
+ *
+ * @param {Element} element - element to send keys to
+ * @param {String} keys - keys to send to the element
+ * @returns {Promise} fulfilled after keys are sent, or rejected in
+ * the cases the WebDriver command errors
+ */
+ send_keys: function(element, keys) {
+ if (!inView(element)) {
+ element.scrollIntoView({behavior: "instant",
+ block: "end",
+ inline: "nearest"});
+ }
+
+ var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
+ if (pointerInteractablePaintTree.length === 0 ||
+ !element.contains(pointerInteractablePaintTree[0])) {
+ return Promise.reject(new Error("element send_keys intercepted error"));
+ }
+
+ return window.test_driver_internal.send_keys(element, keys);
+ },
+
+ /**
+ * Freeze the current page
+ *
+ * The freeze function transitions the page from the HIDDEN state to
+ * the FROZEN state as described in `Lifecycle API for Web Pages
+ * <https://github.com/WICG/page-lifecycle/blob/master/README.md>`_.
+ *
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the freeze request is sent, or rejected
+ * in case the WebDriver command errors
+ */
+ freeze: function(context=null) {
+ return window.test_driver_internal.freeze();
+ },
+
+ /**
+ * Minimizes the browser window.
+ *
+ * Matches the the behaviour of the `Minimize
+ * <https://www.w3.org/TR/webdriver/#minimize-window>`_
+ * WebDriver command
+ *
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled with the previous {@link
+ * https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect}
+ * value, after the window is minimized.
+ */
+ minimize_window: function(context=null) {
+ return window.test_driver_internal.minimize_window(context);
+ },
+
+ /**
+ * Restore the window from minimized/maximized state to a given rect.
+ *
+ * Matches the behaviour of the `Set Window Rect
+ * <https://www.w3.org/TR/webdriver/#set-window-rect>`_
+ * WebDriver command
+ *
+ * @param {Object} rect - A {@link
+ * https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect}
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the window is restored to the given rect.
+ */
+ set_window_rect: function(rect, context=null) {
+ return window.test_driver_internal.set_window_rect(rect, context);
+ },
+
+ /**
+ * Send a sequence of actions
+ *
+ * This function sends a sequence of actions to perform.
+ *
+ * Matches the behaviour of the `Actions
+ * <https://w3c.github.io/webdriver/#actions>`_ feature in
+ * WebDriver.
+ *
+ * Authors are encouraged to use the
+ * :js:class:`test_driver.Actions` builder rather than
+ * invoking this API directly.
+ *
+ * @param {Array} actions - an array of actions. The format is
+ * the same as the actions property
+ * of the `Perform Actions
+ * <https://w3c.github.io/webdriver/#perform-actions>`_
+ * WebDriver command. Each element is
+ * an object representing an input
+ * source and each input source
+ * itself has an actions property
+ * detailing the behaviour of that
+ * source at each timestep (or
+ * tick). Authors are not expected to
+ * construct the actions sequence by
+ * hand, but to use the builder api
+ * provided in testdriver-actions.js
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the actions are performed, or rejected in
+ * the cases the WebDriver command errors
+ */
+ action_sequence: function(actions, context=null) {
+ return window.test_driver_internal.action_sequence(actions, context);
+ },
+
+ /**
+ * Generates a test report on the current page
+ *
+ * The generate_test_report function generates a report (to be
+ * observed by ReportingObserver) for testing purposes.
+ *
+ * Matches the `Generate Test Report
+ * <https://w3c.github.io/reporting/#generate-test-report-command>`_
+ * WebDriver command.
+ *
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the report is generated, or
+ * rejected if the report generation fails
+ */
+ generate_test_report: function(message, context=null) {
+ return window.test_driver_internal.generate_test_report(message, context);
+ },
+
+ /**
+ * Sets the state of a permission
+ *
+ * This function simulates a user setting a permission into a
+ * particular state.
+ *
+ * Matches the `Set Permission
+ * <https://w3c.github.io/permissions/#set-permission-command>`_
+ * WebDriver command.
+ *
+ * @example
+ * await test_driver.set_permission({ name: "background-fetch" }, "denied");
+ * await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted", true);
+ *
+ * @param {Object} descriptor - a `PermissionDescriptor
+ * <https://w3c.github.io/permissions/#dictdef-permissiondescriptor>`_
+ * object
+ * @param {String} state - the state of the permission
+ * @param {boolean} one_realm - Optional. Whether the permission applies to only one realm
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ * @returns {Promise} fulfilled after the permission is set, or rejected if setting the
+ * permission fails
+ */
+ set_permission: function(descriptor, state, one_realm=false, context=null) {
+ let permission_params = {
+ descriptor,
+ state,
+ oneRealm: one_realm,
+ };
+ return window.test_driver_internal.set_permission(permission_params, context);
+
+ },
+
+ /**
+ * Creates a virtual authenticator
+ *
+ * This function creates a virtual authenticator for use with
+ * the U2F and WebAuthn APIs.
+ *
+ * Matches the `Add Virtual Authenticator
+ * <https://w3c.github.io/webauthn/#sctn-automation-add-virtual-authenticator>`_
+ * WebDriver command.
+ *
+ * @param {Object} config - an `Authenticator Configuration
+ * <https://w3c.github.io/webauthn/#authenticator-configuration>`_
+ * object
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the authenticator is added, or
+ * rejected in the cases the WebDriver command
+ * errors. Returns the ID of the authenticator
+ */
+ add_virtual_authenticator: function(config, context=null) {
+ return window.test_driver_internal.add_virtual_authenticator(config, context);
+ },
+
+ /**
+ * Removes a virtual authenticator
+ *
+ * This function removes a virtual authenticator that has been
+ * created by :js:func:`add_virtual_authenticator`.
+ *
+ * Matches the `Remove Virtual Authenticator
+ * <https://w3c.github.io/webauthn/#sctn-automation-remove-virtual-authenticator>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator to be
+ * removed.
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the authenticator is removed, or
+ * rejected in the cases the WebDriver command
+ * errors
+ */
+ remove_virtual_authenticator: function(authenticator_id, context=null) {
+ return window.test_driver_internal.remove_virtual_authenticator(authenticator_id, context);
+ },
+
+ /**
+ * Adds a credential to a virtual authenticator
+ *
+ * Matches the `Add Credential
+ * <https://w3c.github.io/webauthn/#sctn-automation-add-credential>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator
+ * @param {Object} credential - A `Credential Parameters
+ * <https://w3c.github.io/webauthn/#credential-parameters>`_
+ * object
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the credential is added, or
+ * rejected in the cases the WebDriver command
+ * errors
+ */
+ add_credential: function(authenticator_id, credential, context=null) {
+ return window.test_driver_internal.add_credential(authenticator_id, credential, context);
+ },
+
+ /**
+ * Gets all the credentials stored in an authenticator
+ *
+ * This function retrieves all the credentials (added via the U2F API,
+ * WebAuthn, or the add_credential function) stored in a virtual
+ * authenticator
+ *
+ * Matches the `Get Credentials
+ * <https://w3c.github.io/webauthn/#sctn-automation-get-credentials>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the credentials are
+ * returned, or rejected in the cases the
+ * WebDriver command errors. Returns an
+ * array of `Credential Parameters
+ * <https://w3c.github.io/webauthn/#credential-parameters>`_
+ */
+ get_credentials: function(authenticator_id, context=null) {
+ return window.test_driver_internal.get_credentials(authenticator_id, context=null);
+ },
+
+ /**
+ * Remove a credential stored in an authenticator
+ *
+ * Matches the `Remove Credential
+ * <https://w3c.github.io/webauthn/#sctn-automation-remove-credential>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator
+ * @param {String} credential_id - the ID of the credential
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the credential is removed, or
+ * rejected in the cases the WebDriver command
+ * errors.
+ */
+ remove_credential: function(authenticator_id, credential_id, context=null) {
+ return window.test_driver_internal.remove_credential(authenticator_id, credential_id, context);
+ },
+
+ /**
+ * Removes all the credentials stored in a virtual authenticator
+ *
+ * Matches the `Remove All Credentials
+ * <https://w3c.github.io/webauthn/#sctn-automation-remove-all-credentials>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} fulfilled after the credentials are removed, or
+ * rejected in the cases the WebDriver command
+ * errors.
+ */
+ remove_all_credentials: function(authenticator_id, context=null) {
+ return window.test_driver_internal.remove_all_credentials(authenticator_id, context);
+ },
+
+ /**
+ * Sets the User Verified flag on an authenticator
+ *
+ * Sets whether requests requiring user verification will succeed or
+ * fail on a given virtual authenticator
+ *
+ * Matches the `Set User Verified
+ * <https://w3c.github.io/webauthn/#sctn-automation-set-user-verified>`_
+ * WebDriver command.
+ *
+ * @param {String} authenticator_id - the ID of the authenticator
+ * @param {boolean} uv - the User Verified flag
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ */
+ set_user_verified: function(authenticator_id, uv, context=null) {
+ return window.test_driver_internal.set_user_verified(authenticator_id, uv, context);
+ },
+
+ /**
+ * Sets the storage access rule for an origin when embedded
+ * in a third-party context.
+ *
+ * Matches the `Set Storage Access
+ * <https://privacycg.github.io/storage-access/#set-storage-access-command>`_
+ * WebDriver command.
+ *
+ * @param {String} origin - A third-party origin to block or allow.
+ * May be "*" to indicate all origins.
+ * @param {String} embedding_origin - an embedding (first-party) origin
+ * on which {origin}'s access should
+ * be blocked or allowed.
+ * May be "*" to indicate all origins.
+ * @param {String} state - The storage access setting.
+ * Must be either "allowed" or "blocked".
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} Fulfilled after the storage access rule has been
+ * set, or rejected if setting the rule fails.
+ */
+ set_storage_access: function(origin, embedding_origin, state, context=null) {
+ if (state !== "allowed" && state !== "blocked") {
+ throw new Error("storage access status must be 'allowed' or 'blocked'");
+ }
+ const blocked = state === "blocked";
+ return window.test_driver_internal.set_storage_access(origin, embedding_origin, blocked, context);
+ },
+
+ /**
+ * Sets the current transaction automation mode for Secure Payment
+ * Confirmation.
+ *
+ * This function places `Secure Payment
+ * Confirmation <https://w3c.github.io/secure-payment-confirmation>`_ into
+ * an automated 'autoaccept' or 'autoreject' mode, to allow testing
+ * without user interaction with the transaction UX prompt.
+ *
+ * Matches the `Set SPC Transaction Mode
+ * <https://w3c.github.io/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode>`_
+ * WebDriver command.
+ *
+ * @example
+ * await test_driver.set_spc_transaction_mode("autoaccept");
+ * test.add_cleanup(() => {
+ * return test_driver.set_spc_transaction_mode("none");
+ * });
+ *
+ * // Assumption: `request` is a PaymentRequest with a secure-payment-confirmation
+ * // payment method.
+ * const response = await request.show();
+ *
+ * @param {String} mode - The `transaction mode
+ * <https://w3c.github.io/secure-payment-confirmation/#enumdef-transactionautomationmode>`_
+ * to set. Must be one of "``none``",
+ * "``autoaccept``", or
+ * "``autoreject``".
+ * @param {WindowProxy} context - Browsing context in which
+ * to run the call, or null for the current
+ * browsing context.
+ *
+ * @returns {Promise} Fulfilled after the transaction mode has been set,
+ * or rejected if setting the mode fails.
+ */
+ set_spc_transaction_mode: function(mode, context=null) {
+ return window.test_driver_internal.set_spc_transaction_mode(mode, context);
+ },
+ };
+
+ window.test_driver_internal = {
+ /**
+ * This flag should be set to `true` by any code which implements the
+ * internal methods defined below for automation purposes. Doing so
+ * allows the library to signal failure immediately when an automated
+ * implementation of one of the methods is not available.
+ */
+ in_automation: false,
+
+ click: function(element, coords) {
+ if (this.in_automation) {
+ return Promise.reject(new Error('Not implemented'));
+ }
+
+ return new Promise(function(resolve, reject) {
+ element.addEventListener("click", resolve);
+ });
+ },
+
+ delete_all_cookies: function(context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ send_keys: function(element, keys) {
+ if (this.in_automation) {
+ return Promise.reject(new Error('Not implemented'));
+ }
+
+ return new Promise(function(resolve, reject) {
+ var seen = "";
+
+ function remove() {
+ element.removeEventListener("keydown", onKeyDown);
+ }
+
+ function onKeyDown(event) {
+ if (event.key.length > 1) {
+ return;
+ }
+
+ seen += event.key;
+
+ if (keys.indexOf(seen) !== 0) {
+ reject(new Error("Unexpected key sequence: " + seen));
+ remove();
+ } else if (seen === keys) {
+ resolve();
+ remove();
+ }
+ }
+
+ element.addEventListener("keydown", onKeyDown);
+ });
+ },
+
+ freeze: function(context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ minimize_window: function(context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ set_window_rect: function(rect, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ action_sequence: function(actions, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ generate_test_report: function(message, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ set_permission: function(permission_params, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ add_virtual_authenticator: function(config, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ remove_virtual_authenticator: function(authenticator_id, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ add_credential: function(authenticator_id, credential, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ get_credentials: function(authenticator_id, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ remove_credential: function(authenticator_id, credential_id, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ remove_all_credentials: function(authenticator_id, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ set_user_verified: function(authenticator_id, uv, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ set_storage_access: function(origin, embedding_origin, blocked, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ set_spc_transaction_mode: function(mode, context=null) {
+ return Promise.reject(new Error("unimplemented"));
+ },
+
+ };
+})();
/*global self*/
/*jshint latedef: nofunc*/
-/*
-Distributed under both the W3C Test Suite License [1] and the W3C
-3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
-policies and contribution forms [3].
-[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
-[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
-[3] http://www.w3.org/2004/10/27-testcases
-*/
+/* Documentation: https://web-platform-tests.org/writing-tests/testharness-api.html
+ * (../docs/_writing-tests/testharness-api.md) */
-/* Documentation is in docs/api.md */
-
-(function ()
+(function (global_scope)
{
- var debug = false;
// default timeout is 10 seconds, test can override if needed
var settings = {
output:true,
"normal":10000,
"long":60000
},
- test_timeout:null
+ test_timeout:null,
+ message_events: ["start", "test_state", "result", "completion"],
+ debug: false,
};
var xhtml_ns = "http://www.w3.org/1999/xhtml";
*
* // Should return the test harness timeout duration in milliseconds.
* float test_timeout();
- *
- * // Should return the global scope object.
- * object global_scope();
* };
*/
this.output_handler = null;
this.all_loaded = false;
var this_obj = this;
+ this.message_events = [];
+ this.dispatched_messages = [];
+
+ this.message_functions = {
+ start: [add_start_callback, remove_start_callback,
+ function (properties) {
+ this_obj._dispatch("start_callback", [properties],
+ {type: "start", properties: properties});
+ }],
+
+ test_state: [add_test_state_callback, remove_test_state_callback,
+ function(test) {
+ this_obj._dispatch("test_state_callback", [test],
+ {type: "test_state",
+ test: test.structured_clone()});
+ }],
+ result: [add_result_callback, remove_result_callback,
+ function (test) {
+ this_obj.output_handler.show_status();
+ this_obj._dispatch("result_callback", [test],
+ {type: "result",
+ test: test.structured_clone()});
+ }],
+ completion: [add_completion_callback, remove_completion_callback,
+ function (tests, harness_status, asserts) {
+ var cloned_tests = map(tests, function(test) {
+ return test.structured_clone();
+ });
+ this_obj._dispatch("completion_callback", [tests, harness_status],
+ {type: "complete",
+ tests: cloned_tests,
+ status: harness_status.structured_clone(),
+ asserts: asserts.map(assert => assert.structured_clone())});
+ }]
+ }
+
on_event(window, 'load', function() {
this_obj.all_loaded = true;
});
+
+ on_event(window, 'message', function(event) {
+ if (event.data && event.data.type === "getmessages" && event.source) {
+ // A window can post "getmessages" to receive a duplicate of every
+ // message posted by this environment so far. This allows subscribers
+ // from fetch_tests_from_window to 'catch up' to the current state of
+ // this environment.
+ for (var i = 0; i < this_obj.dispatched_messages.length; ++i)
+ {
+ event.source.postMessage(this_obj.dispatched_messages[i], "*");
+ }
+ }
+ });
}
WindowTestEnvironment.prototype._dispatch = function(selector, callback_args, message_arg) {
+ this.dispatched_messages.push(message_arg);
this._forEach_windows(
- function(w, is_same_origin) {
- if (is_same_origin && selector in w) {
+ function(w, same_origin) {
+ if (same_origin) {
try {
- w[selector].apply(undefined, callback_args);
- } catch (e) {
- if (debug) {
- throw e;
- }
+ var has_selector = selector in w;
+ } catch(e) {
+ // If document.domain was set at some point same_origin can be
+ // wrong and the above will fail.
+ has_selector = false;
+ }
+ if (has_selector) {
+ try {
+ w[selector].apply(undefined, callback_args);
+ } catch (e) {}
}
}
if (supports_post_message(w) && w !== self) {
};
WindowTestEnvironment.prototype._forEach_windows = function(callback) {
- // Iterate of the the windows [self ... top, opener]. The callback is passed
- // two objects, the first one is the windows object itself, the second one
- // is a boolean indicating whether or not its on the same origin as the
+ // Iterate over the windows [self ... top, opener]. The callback is passed
+ // two objects, the first one is the window object itself, the second one
+ // is a boolean indicating whether or not it's on the same origin as the
// current window.
var cache = this.window_cache;
if (!cache) {
var w = self;
var i = 0;
var so;
- var origins = location.ancestorOrigins;
while (w != w.parent) {
w = w.parent;
- // In WebKit, calls to parent windows' properties that aren't on the same
- // origin cause an error message to be displayed in the error console but
- // don't throw an exception. This is a deviation from the current HTML5
- // spec. See: https://bugs.webkit.org/show_bug.cgi?id=43504
- // The problem with WebKit's behavior is that it pollutes the error console
- // with error messages that can't be caught.
- //
- // This issue can be mitigated by relying on the (for now) proprietary
- // `location.ancestorOrigins` property which returns an ordered list of
- // the origins of enclosing windows. See:
- // http://trac.webkit.org/changeset/113945.
- if (origins) {
- so = (location.origin == origins[i]);
- } else {
- so = is_same_origin(w);
- }
+ so = is_same_origin(w);
cache.push([w, so]);
i++;
}
w = window.opener;
if (w) {
- // window.opener isn't included in the `location.ancestorOrigins` prop.
- // We'll just have to deal with a simple check and an error msg on WebKit
- // browsers in this case.
cache.push([w, is_same_origin(w)]);
}
this.window_cache = cache;
this.output_handler = output;
var this_obj = this;
+
add_start_callback(function (properties) {
this_obj.output_handler.init(properties);
- this_obj._dispatch("start_callback", [properties],
- { type: "start", properties: properties });
});
+
add_test_state_callback(function(test) {
this_obj.output_handler.show_status();
- this_obj._dispatch("test_state_callback", [test],
- { type: "test_state", test: test.structured_clone() });
});
+
add_result_callback(function (test) {
this_obj.output_handler.show_status();
- this_obj._dispatch("result_callback", [test],
- { type: "result", test: test.structured_clone() });
});
- add_completion_callback(function (tests, harness_status) {
- this_obj.output_handler.show_results(tests, harness_status);
- var cloned_tests = map(tests, function(test) { return test.structured_clone(); });
- this_obj._dispatch("completion_callback", [tests, harness_status],
- { type: "complete", tests: cloned_tests,
- status: harness_status.structured_clone() });
+
+ add_completion_callback(function (tests, harness_status, asserts_run) {
+ this_obj.output_handler.show_results(tests, harness_status, asserts_run);
});
+ this.setup_messages(settings.message_events);
};
+ WindowTestEnvironment.prototype.setup_messages = function(new_events) {
+ var this_obj = this;
+ forEach(settings.message_events, function(x) {
+ var current_dispatch = this_obj.message_events.indexOf(x) !== -1;
+ var new_dispatch = new_events.indexOf(x) !== -1;
+ if (!current_dispatch && new_dispatch) {
+ this_obj.message_functions[x][0](this_obj.message_functions[x][2]);
+ } else if (current_dispatch && !new_dispatch) {
+ this_obj.message_functions[x][1](this_obj.message_functions[x][2]);
+ }
+ });
+ this.message_events = new_events;
+ }
+
WindowTestEnvironment.prototype.next_default_test_name = function() {
- //Don't use document.title to work around an Opera bug in XHTML documents
- var title = document.getElementsByTagName("title")[0];
- var prefix = (title && title.firstChild && title.firstChild.data) || "Untitled";
var suffix = this.name_counter > 0 ? " " + this.name_counter : "";
this.name_counter++;
- return prefix + suffix;
+ return get_title() + suffix;
};
WindowTestEnvironment.prototype.on_new_harness_properties = function(properties) {
this.output_handler.setup(properties);
+ if (properties.hasOwnProperty("message_events")) {
+ this.setup_messages(properties.message_events);
+ }
};
WindowTestEnvironment.prototype.add_on_loaded_callback = function(callback) {
return settings.harness_timeout.normal;
};
- WindowTestEnvironment.prototype.global_scope = function() {
- return window;
- };
-
/*
* Base TestEnvironment implementation for a generic web worker.
*
WorkerTestEnvironment.prototype.next_default_test_name = function() {
var suffix = this.name_counter > 0 ? " " + this.name_counter : "";
this.name_counter++;
- return "Untitled" + suffix;
+ return get_title() + suffix;
};
WorkerTestEnvironment.prototype.on_new_harness_properties = function() {};
});
});
add_completion_callback(
- function(tests, harness_status) {
+ function(tests, harness_status, asserts) {
this_obj._dispatch({
type: "complete",
tests: map(tests,
function(test) {
return test.structured_clone();
}),
- status: harness_status.structured_clone()
+ status: harness_status.structured_clone(),
+ asserts: asserts.map(assert => assert.structured_clone()),
});
});
};
return null;
};
- WorkerTestEnvironment.prototype.global_scope = function() {
- return self;
- };
-
/*
* Dedicated web workers.
* https://html.spec.whatwg.org/multipage/workers.html#dedicatedworkerglobalscope
self.addEventListener("connect",
function(message_event) {
this_obj._add_message_port(message_event.source);
- });
+ }, false);
}
SharedWorkerTestEnvironment.prototype = Object.create(WorkerTestEnvironment.prototype);
var this_obj = this;
self.addEventListener("message",
function(event) {
- if (event.data.type && event.data.type === "connect") {
- this_obj._add_message_port(event.ports[0]);
- event.ports[0].start();
+ if (event.data && event.data.type && event.data.type === "connect") {
+ this_obj._add_message_port(event.source);
}
- });
+ }, false);
// The oninstall event is received after the service worker script and
// all imported scripts have been fetched and executed. It's the
// equivalent of an onload event for a document. All tests should have
// been added by the time this event is received, thus it's not
- // necessary to wait until the onactivate event.
- on_event(self, "install",
- function(event) {
- this_obj.all_loaded = true;
- if (this_obj.on_loaded_callback) {
- this_obj.on_loaded_callback();
- }
- });
+ // necessary to wait until the onactivate event. However, tests for
+ // installed service workers need another event which is equivalent to
+ // the onload event because oninstall is fired only on installation. The
+ // onmessage event is used for that purpose since tests using
+ // testharness.js should ask the result to its service worker by
+ // PostMessage. If the onmessage event is triggered on the service
+ // worker's context, that means the worker's script has been evaluated.
+ on_event(self, "install", on_all_loaded);
+ on_event(self, "message", on_all_loaded);
+ function on_all_loaded() {
+ if (this_obj.all_loaded)
+ return;
+ this_obj.all_loaded = true;
+ if (this_obj.on_loaded_callback) {
+ this_obj.on_loaded_callback();
+ }
+ }
}
+
ServiceWorkerTestEnvironment.prototype = Object.create(WorkerTestEnvironment.prototype);
ServiceWorkerTestEnvironment.prototype.add_on_loaded_callback = function(callback) {
}
};
+ /*
+ * JavaScript shells.
+ *
+ * This class is used as the test_environment when testharness is running
+ * inside a JavaScript shell.
+ */
+ function ShellTestEnvironment() {
+ this.name_counter = 0;
+ this.all_loaded = false;
+ this.on_loaded_callback = null;
+ Promise.resolve().then(function() {
+ this.all_loaded = true
+ if (this.on_loaded_callback) {
+ this.on_loaded_callback();
+ }
+ }.bind(this));
+ this.message_list = [];
+ this.message_ports = [];
+ }
+
+ ShellTestEnvironment.prototype.next_default_test_name = function() {
+ var suffix = this.name_counter > 0 ? " " + this.name_counter : "";
+ this.name_counter++;
+ return "Untitled" + suffix;
+ };
+
+ ShellTestEnvironment.prototype.on_new_harness_properties = function() {};
+
+ ShellTestEnvironment.prototype.on_tests_ready = function() {};
+
+ ShellTestEnvironment.prototype.add_on_loaded_callback = function(callback) {
+ if (this.all_loaded) {
+ callback();
+ } else {
+ this.on_loaded_callback = callback;
+ }
+ };
+
+ ShellTestEnvironment.prototype.test_timeout = function() {
+ // Tests running in a shell don't have a default timeout, so behave as
+ // if settings.explicit_timeout is true.
+ return null;
+ };
+
function create_test_environment() {
- if ('document' in self) {
+ if ('document' in global_scope) {
return new WindowTestEnvironment();
}
- if ('DedicatedWorkerGlobalScope' in self &&
- self instanceof DedicatedWorkerGlobalScope) {
+ if ('DedicatedWorkerGlobalScope' in global_scope &&
+ global_scope instanceof DedicatedWorkerGlobalScope) {
return new DedicatedWorkerTestEnvironment();
}
- if ('SharedWorkerGlobalScope' in self &&
- self instanceof SharedWorkerGlobalScope) {
+ if ('SharedWorkerGlobalScope' in global_scope &&
+ global_scope instanceof SharedWorkerGlobalScope) {
return new SharedWorkerTestEnvironment();
}
- if ('ServiceWorkerGlobalScope' in self &&
- self instanceof ServiceWorkerGlobalScope) {
+ if ('ServiceWorkerGlobalScope' in global_scope &&
+ global_scope instanceof ServiceWorkerGlobalScope) {
return new ServiceWorkerTestEnvironment();
}
- throw new Error("Unsupported test environment");
+ if ('WorkerGlobalScope' in global_scope &&
+ global_scope instanceof WorkerGlobalScope) {
+ return new DedicatedWorkerTestEnvironment();
+ }
+
+ return new ShellTestEnvironment();
}
var test_environment = create_test_environment();
function is_shared_worker(worker) {
- return 'SharedWorker' in self && worker instanceof SharedWorker;
+ return 'SharedWorker' in global_scope && worker instanceof SharedWorker;
}
function is_service_worker(worker) {
- return 'ServiceWorker' in self && worker instanceof ServiceWorker;
+ // The worker object may be from another execution context,
+ // so do not use instanceof here.
+ return 'ServiceWorker' in global_scope &&
+ Object.prototype.toString.call(worker) == '[object ServiceWorker]';
+ }
+
+ var seen_func_name = Object.create(null);
+
+ function get_test_name(func, name)
+ {
+ if (name) {
+ return name;
+ }
+
+ if (func) {
+ var func_code = func.toString();
+
+ // Try and match with brackets, but fallback to matching without
+ var arrow = func_code.match(/^\(\)\s*=>\s*(?:{(.*)}\s*|(.*))$/);
+
+ // Check for JS line separators
+ if (arrow !== null && !/[\u000A\u000D\u2028\u2029]/.test(func_code)) {
+ var trimmed = (arrow[1] !== undefined ? arrow[1] : arrow[2]).trim();
+ // drop trailing ; if there's no earlier ones
+ trimmed = trimmed.replace(/^([^;]*)(;\s*)+$/, "$1");
+
+ if (trimmed) {
+ let name = trimmed;
+ if (seen_func_name[trimmed]) {
+ // This subtest name already exists, so add a suffix.
+ name += " " + seen_func_name[trimmed];
+ } else {
+ seen_func_name[trimmed] = 0;
+ }
+ seen_func_name[trimmed] += 1;
+ return name;
+ }
+ }
+ }
+
+ return test_environment.next_default_test_name();
}
/*
* API functions
*/
-
function test(func, name, properties)
{
- var test_name = name ? name : test_environment.next_default_test_name();
- properties = properties ? properties : {};
+ if (tests.promise_setup_called) {
+ tests.status.status = tests.status.ERROR;
+ tests.status.message = '`test` invoked after `promise_setup`';
+ tests.complete();
+ }
+ var test_name = get_test_name(func, name);
var test_obj = new Test(test_name, properties);
- test_obj.step(func, test_obj, test_obj);
+ var value = test_obj.step(func, test_obj, test_obj);
+
+ if (value !== undefined) {
+ var msg = 'Test named "' + test_name +
+ '" passed a function to `test` that returned a value.';
+
+ try {
+ if (value && typeof value.then === 'function') {
+ msg += ' Consider using `promise_test` instead when ' +
+ 'using Promises or async/await.';
+ }
+ } catch (err) {}
+
+ tests.status.status = tests.status.ERROR;
+ tests.status.message = msg;
+ }
+
if (test_obj.phase === test_obj.phases.STARTED) {
test_obj.done();
}
function async_test(func, name, properties)
{
+ if (tests.promise_setup_called) {
+ tests.status.status = tests.status.ERROR;
+ tests.status.message = '`async_test` invoked after `promise_setup`';
+ tests.complete();
+ }
if (typeof func !== "function") {
properties = name;
name = func;
func = null;
}
- var test_name = name ? name : test_environment.next_default_test_name();
- properties = properties ? properties : {};
+ var test_name = get_test_name(func, name);
var test_obj = new Test(test_name, properties);
if (func) {
- test_obj.step(func, test_obj, test_obj);
+ var value = test_obj.step(func, test_obj, test_obj);
+
+ // Test authors sometimes return values to async_test, expecting us
+ // to handle the value somehow. Make doing so a harness error to be
+ // clear this is invalid, and point authors to promise_test if it
+ // may be appropriate.
+ //
+ // Note that we only perform this check on the initial function
+ // passed to async_test, not on any later steps - we haven't seen a
+ // consistent problem with those (and it's harder to check).
+ if (value !== undefined) {
+ var msg = 'Test named "' + test_name +
+ '" passed a function to `async_test` that returned a value.';
+
+ try {
+ if (value && typeof value.then === 'function') {
+ msg += ' Consider using `promise_test` instead when ' +
+ 'using Promises or async/await.';
+ }
+ } catch (err) {}
+
+ tests.set_status(tests.status.ERROR, msg);
+ tests.complete();
+ }
}
return test_obj;
}
function promise_test(func, name, properties) {
- var test = async_test(name, properties);
- Promise.resolve(test.step(func, test, test))
- .then(
- function() {
- test.done();
- })
- .catch(test.step_func(
- function(value) {
- if (value instanceof AssertionError) {
- throw value;
- }
- assert(false, "promise_test", null,
- "Unhandled rejection with value: ${value}", {value:value});
- }));
+ if (typeof func !== "function") {
+ properties = name;
+ name = func;
+ func = null;
+ }
+ var test_name = get_test_name(func, name);
+ var test = new Test(test_name, properties);
+ test._is_promise_test = true;
+
+ // If there is no promise tests queue make one.
+ if (!tests.promise_tests) {
+ tests.promise_tests = Promise.resolve();
+ }
+ tests.promise_tests = tests.promise_tests.then(function() {
+ return new Promise(function(resolve) {
+ var promise = test.step(func, test, test);
+
+ test.step(function() {
+ assert(!!promise, "promise_test", null,
+ "test body must return a 'thenable' object (received ${value})",
+ {value:promise});
+ assert(typeof promise.then === "function", "promise_test", null,
+ "test body must return a 'thenable' object (received an object with no `then` method)",
+ null);
+ });
+
+ // Test authors may use the `step` method within a
+ // `promise_test` even though this reflects a mixture of
+ // asynchronous control flow paradigms. The "done" callback
+ // should be registered prior to the resolution of the
+ // user-provided Promise to avoid timeouts in cases where the
+ // Promise does not settle but a `step` function has thrown an
+ // error.
+ add_test_done_callback(test, resolve);
+
+ Promise.resolve(promise)
+ .catch(test.step_func(
+ function(value) {
+ if (value instanceof AssertionError) {
+ throw value;
+ }
+ assert(false, "promise_test", null,
+ "Unhandled rejection with value: ${value}", {value:value});
+ }))
+ .then(function() {
+ test.done();
+ });
+ });
+ });
}
+ /**
+ * Make a copy of a Promise in the current realm.
+ *
+ * @param {Promise} promise the given promise that may be from a different
+ * realm
+ * @returns {Promise}
+ *
+ * An arbitrary promise provided by the caller may have originated in
+ * another frame that have since navigated away, rendering the frame's
+ * document inactive. Such a promise cannot be used with `await` or
+ * Promise.resolve(), as microtasks associated with it may be prevented
+ * from being run. See https://github.com/whatwg/html/issues/5319 for a
+ * particular case.
+ *
+ * In functions we define here, there is an expectation from the caller
+ * that the promise is from the current realm, that can always be used with
+ * `await`, etc. We therefore create a new promise in this realm that
+ * inherit the value and status from the given promise.
+ */
+
+ function bring_promise_to_current_realm(promise) {
+ return new Promise(promise.then.bind(promise));
+ }
+
+ function promise_rejects_js(test, constructor, promise, description) {
+ return bring_promise_to_current_realm(promise)
+ .then(test.unreached_func("Should have rejected: " + description))
+ .catch(function(e) {
+ assert_throws_js_impl(constructor, function() { throw e },
+ description, "promise_rejects_js");
+ });
+ }
+
+ /**
+ * Assert that a Promise is rejected with the right DOMException.
+ *
+ * @param test the test argument passed to promise_test
+ * @param {number|string} type. See documentation for assert_throws_dom.
+ *
+ * For the remaining arguments, there are two ways of calling
+ * promise_rejects_dom:
+ *
+ * 1) If the DOMException is expected to come from the current global, the
+ * third argument should be the promise expected to reject, and a fourth,
+ * optional, argument is the assertion description.
+ *
+ * 2) If the DOMException is expected to come from some other global, the
+ * third argument should be the DOMException constructor from that global,
+ * the fourth argument the promise expected to reject, and the fifth,
+ * optional, argument the assertion description.
+ */
+
+ function promise_rejects_dom(test, type, promiseOrConstructor, descriptionOrPromise, maybeDescription) {
+ let constructor, promise, description;
+ if (typeof promiseOrConstructor === "function" &&
+ promiseOrConstructor.name === "DOMException") {
+ constructor = promiseOrConstructor;
+ promise = descriptionOrPromise;
+ description = maybeDescription;
+ } else {
+ constructor = self.DOMException;
+ promise = promiseOrConstructor;
+ description = descriptionOrPromise;
+ assert(maybeDescription === undefined,
+ "Too many args pased to no-constructor version of promise_rejects_dom");
+ }
+ return bring_promise_to_current_realm(promise)
+ .then(test.unreached_func("Should have rejected: " + description))
+ .catch(function(e) {
+ assert_throws_dom_impl(type, function() { throw e }, description,
+ "promise_rejects_dom", constructor);
+ });
+ }
+
+ function promise_rejects_exactly(test, exception, promise, description) {
+ return bring_promise_to_current_realm(promise)
+ .then(test.unreached_func("Should have rejected: " + description))
+ .catch(function(e) {
+ assert_throws_exactly_impl(exception, function() { throw e },
+ description, "promise_rejects_exactly");
+ });
+ }
+
+ /**
+ * This constructor helper allows DOM events to be handled using Promises,
+ * which can make it a lot easier to test a very specific series of events,
+ * including ensuring that unexpected events are not fired at any point.
+ */
+ function EventWatcher(test, watchedNode, eventTypes, timeoutPromise)
+ {
+ if (typeof eventTypes == 'string') {
+ eventTypes = [eventTypes];
+ }
+
+ var waitingFor = null;
+
+ // This is null unless we are recording all events, in which case it
+ // will be an Array object.
+ var recordedEvents = null;
+
+ var eventHandler = test.step_func(function(evt) {
+ assert_true(!!waitingFor,
+ 'Not expecting event, but got ' + evt.type + ' event');
+ assert_equals(evt.type, waitingFor.types[0],
+ 'Expected ' + waitingFor.types[0] + ' event, but got ' +
+ evt.type + ' event instead');
+
+ if (Array.isArray(recordedEvents)) {
+ recordedEvents.push(evt);
+ }
+
+ if (waitingFor.types.length > 1) {
+ // Pop first event from array
+ waitingFor.types.shift();
+ return;
+ }
+ // We need to null out waitingFor before calling the resolve function
+ // since the Promise's resolve handlers may call wait_for() which will
+ // need to set waitingFor.
+ var resolveFunc = waitingFor.resolve;
+ waitingFor = null;
+ // Likewise, we should reset the state of recordedEvents.
+ var result = recordedEvents || evt;
+ recordedEvents = null;
+ resolveFunc(result);
+ });
+
+ for (var i = 0; i < eventTypes.length; i++) {
+ watchedNode.addEventListener(eventTypes[i], eventHandler, false);
+ }
+
+ /**
+ * Returns a Promise that will resolve after the specified event or
+ * series of events has occurred.
+ *
+ * @param options An optional options object. If the 'record' property
+ * on this object has the value 'all', when the Promise
+ * returned by this function is resolved, *all* Event
+ * objects that were waited for will be returned as an
+ * array.
+ *
+ * For example,
+ *
+ * ```js
+ * const watcher = new EventWatcher(t, div, [ 'animationstart',
+ * 'animationiteration',
+ * 'animationend' ]);
+ * return watcher.wait_for([ 'animationstart', 'animationend' ],
+ * { record: 'all' }).then(evts => {
+ * assert_equals(evts[0].elapsedTime, 0.0);
+ * assert_equals(evts[1].elapsedTime, 2.0);
+ * });
+ * ```
+ */
+ this.wait_for = function(types, options) {
+ if (waitingFor) {
+ return Promise.reject('Already waiting for an event or events');
+ }
+ if (typeof types == 'string') {
+ types = [types];
+ }
+ if (options && options.record && options.record === 'all') {
+ recordedEvents = [];
+ }
+ return new Promise(function(resolve, reject) {
+ var timeout = test.step_func(function() {
+ // If the timeout fires after the events have been received
+ // or during a subsequent call to wait_for, ignore it.
+ if (!waitingFor || waitingFor.resolve !== resolve)
+ return;
+
+ // This should always fail, otherwise we should have
+ // resolved the promise.
+ assert_true(waitingFor.types.length == 0,
+ 'Timed out waiting for ' + waitingFor.types.join(', '));
+ var result = recordedEvents;
+ recordedEvents = null;
+ var resolveFunc = waitingFor.resolve;
+ waitingFor = null;
+ resolveFunc(result);
+ });
+
+ if (timeoutPromise) {
+ timeoutPromise().then(timeout);
+ }
+
+ waitingFor = {
+ types: types,
+ resolve: resolve,
+ reject: reject
+ };
+ });
+ };
+
+ function stop_watching() {
+ for (var i = 0; i < eventTypes.length; i++) {
+ watchedNode.removeEventListener(eventTypes[i], eventHandler, false);
+ }
+ };
+
+ test._add_cleanup(stop_watching);
+
+ return this;
+ }
+ expose(EventWatcher, 'EventWatcher');
+
function setup(func_or_properties, maybe_properties)
{
var func = null;
test_environment.on_new_harness_properties(properties);
}
+ function promise_setup(func, maybe_properties)
+ {
+ if (typeof func !== "function") {
+ tests.set_status(tests.status.ERROR,
+ "promise_test invoked without a function");
+ tests.complete();
+ return;
+ }
+ tests.promise_setup_called = true;
+
+ if (!tests.promise_tests) {
+ tests.promise_tests = Promise.resolve();
+ }
+
+ tests.promise_tests = tests.promise_tests
+ .then(function()
+ {
+ var properties = maybe_properties || {};
+ var result;
+
+ tests.setup(null, properties);
+ result = func();
+ test_environment.on_new_harness_properties(properties);
+
+ if (!result || typeof result.then !== "function") {
+ throw "Non-thenable returned by function passed to `promise_setup`";
+ }
+ return result;
+ })
+ .catch(function(e)
+ {
+ tests.set_status(tests.status.ERROR,
+ String(e),
+ e && e.stack);
+ tests.complete();
+ });
+ }
+
function done() {
if (tests.tests.length === 0) {
- tests.set_file_is_test();
+ // `done` is invoked after handling uncaught exceptions, so if the
+ // harness status is already set, the corresponding message is more
+ // descriptive than the generic message defined here.
+ if (tests.status.status === null) {
+ tests.status.status = tests.status.ERROR;
+ tests.status.message = "done() was called without first defining any tests";
+ }
+
+ tests.complete();
+ return;
}
if (tests.file_is_test) {
+ // file is test files never have asynchronous cleanup logic,
+ // meaning the fully-synchronous `done` function can be used here.
tests.tests[0].done();
}
tests.end_wait();
});
}
+ /*
+ * Register a function as a DOM event listener to the given object for the
+ * event bubbling phase.
+ *
+ * This function was deprecated in November of 2019.
+ */
function on_event(object, event, callback)
{
object.addEventListener(event, callback, false);
}
+ function step_timeout(f, t) {
+ var outer_this = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ return setTimeout(function() {
+ f.apply(outer_this, args);
+ }, t * tests.timeout_multiplier);
+ }
+
expose(test, 'test');
expose(async_test, 'async_test');
expose(promise_test, 'promise_test');
+ expose(promise_rejects_js, 'promise_rejects_js');
+ expose(promise_rejects_dom, 'promise_rejects_dom');
+ expose(promise_rejects_exactly, 'promise_rejects_exactly');
expose(generate_tests, 'generate_tests');
expose(setup, 'setup');
+ expose(promise_setup, 'promise_setup');
expose(done, 'done');
expose(on_event, 'on_event');
+ expose(step_timeout, 'step_timeout');
/*
* Return a string truncated to the given length, with ... added at the end
// instanceof doesn't work if the node is from another window (like an
// iframe's contentWindow):
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=12295
- if ("nodeType" in object &&
- "nodeName" in object &&
- "nodeValue" in object &&
- "childNodes" in object) {
+ try {
+ var has_node_properties = ("nodeType" in object &&
+ "nodeName" in object &&
+ "nodeValue" in object &&
+ "childNodes" in object);
+ } catch (e) {
+ // We're probably cross-origin, which means we aren't a node
+ return false;
+ }
+
+ if (has_node_properties) {
try {
object.nodeType;
} catch (e) {
return false;
}
+ var replacements = {
+ "0": "0",
+ "1": "x01",
+ "2": "x02",
+ "3": "x03",
+ "4": "x04",
+ "5": "x05",
+ "6": "x06",
+ "7": "x07",
+ "8": "b",
+ "9": "t",
+ "10": "n",
+ "11": "v",
+ "12": "f",
+ "13": "r",
+ "14": "x0e",
+ "15": "x0f",
+ "16": "x10",
+ "17": "x11",
+ "18": "x12",
+ "19": "x13",
+ "20": "x14",
+ "21": "x15",
+ "22": "x16",
+ "23": "x17",
+ "24": "x18",
+ "25": "x19",
+ "26": "x1a",
+ "27": "x1b",
+ "28": "x1c",
+ "29": "x1d",
+ "30": "x1e",
+ "31": "x1f",
+ "0xfffd": "ufffd",
+ "0xfffe": "ufffe",
+ "0xffff": "uffff",
+ };
+
/*
* Convert a value to a nice, human-readable string
*/
seen.push(val);
}
if (Array.isArray(val)) {
- return "[" + val.map(function(x) {return format_value(x, seen);}).join(", ") + "]";
+ let output = "[";
+ if (val.beginEllipsis !== undefined) {
+ output += "…, ";
+ }
+ output += val.map(function(x) {return format_value(x, seen);}).join(", ");
+ if (val.endEllipsis !== undefined) {
+ output += ", …";
+ }
+ return output + "]";
}
switch (typeof val) {
case "string":
- val = val.replace("\\", "\\\\");
- for (var i = 0; i < 32; i++) {
- var replace = "\\";
- switch (i) {
- case 0: replace += "0"; break;
- case 1: replace += "x01"; break;
- case 2: replace += "x02"; break;
- case 3: replace += "x03"; break;
- case 4: replace += "x04"; break;
- case 5: replace += "x05"; break;
- case 6: replace += "x06"; break;
- case 7: replace += "x07"; break;
- case 8: replace += "b"; break;
- case 9: replace += "t"; break;
- case 10: replace += "n"; break;
- case 11: replace += "v"; break;
- case 12: replace += "f"; break;
- case 13: replace += "r"; break;
- case 14: replace += "x0e"; break;
- case 15: replace += "x0f"; break;
- case 16: replace += "x10"; break;
- case 17: replace += "x11"; break;
- case 18: replace += "x12"; break;
- case 19: replace += "x13"; break;
- case 20: replace += "x14"; break;
- case 21: replace += "x15"; break;
- case 22: replace += "x16"; break;
- case 23: replace += "x17"; break;
- case 24: replace += "x18"; break;
- case 25: replace += "x19"; break;
- case 26: replace += "x1a"; break;
- case 27: replace += "x1b"; break;
- case 28: replace += "x1c"; break;
- case 29: replace += "x1d"; break;
- case 30: replace += "x1e"; break;
- case 31: replace += "x1f"; break;
- }
- val = val.replace(RegExp(String.fromCharCode(i), "g"), replace);
+ val = val.replace(/\\/g, "\\\\");
+ for (var p in replacements) {
+ var replace = "\\" + replacements[p];
+ val = val.replace(RegExp(String.fromCharCode(p), "g"), replace);
}
return '"' + val.replace(/"/g, '\\"') + '"';
case "boolean":
/* falls through */
default:
- return typeof val + ' "' + truncate(String(val), 60) + '"';
+ try {
+ return typeof val + ' "' + truncate(String(val), 1000) + '"';
+ } catch(e) {
+ return ("[stringifying object threw " + String(e) +
+ " with type " + String(typeof e) + "]");
+ }
}
}
expose(format_value, "format_value");
* Assertions
*/
+ function expose_assert(f, name) {
+ function assert_wrapper(...args) {
+ let status = Test.statuses.TIMEOUT;
+ let stack = null;
+ try {
+ if (settings.debug) {
+ console.debug("ASSERT", name, tests.current_test && tests.current_test.name, args);
+ }
+ if (tests.output) {
+ tests.set_assert(name, args);
+ }
+ const rv = f.apply(undefined, args);
+ status = Test.statuses.PASS;
+ return rv;
+ } catch(e) {
+ if (e instanceof AssertionError) {
+ status = Test.statuses.FAIL;
+ stack = e.stack;
+ } else {
+ status = Test.statuses.ERROR;
+ }
+ throw e;
+ } finally {
+ if (tests.output && !stack) {
+ stack = get_stack();
+ }
+ if (tests.output) {
+ tests.set_assert_status(status, stack);
+ }
+ }
+ }
+ expose(assert_wrapper, name);
+ }
+
function assert_true(actual, description)
{
assert(actual === true, "assert_true", description,
"expected true got ${actual}", {actual:actual});
}
- expose(assert_true, "assert_true");
+ expose_assert(assert_true, "assert_true");
function assert_false(actual, description)
{
assert(actual === false, "assert_false", description,
"expected false got ${actual}", {actual:actual});
}
- expose(assert_false, "assert_false");
+ expose_assert(assert_false, "assert_false");
function same_value(x, y) {
if (y !== y) {
"expected ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_equals, "assert_equals");
+ expose_assert(assert_equals, "assert_equals");
function assert_not_equals(actual, expected, description)
{
"got disallowed value ${actual}",
{actual:actual});
}
- expose(assert_not_equals, "assert_not_equals");
+ expose_assert(assert_not_equals, "assert_not_equals");
function assert_in_array(actual, expected, description)
{
"value ${actual} not in array ${expected}",
{actual:actual, expected:expected});
}
- expose(assert_in_array, "assert_in_array");
+ expose_assert(assert_in_array, "assert_in_array");
+ // This function was deprecated in July of 2015.
+ // See https://github.com/web-platform-tests/wpt/issues/2033
function assert_object_equals(actual, expected, description)
{
+ assert(typeof actual === "object" && actual !== null, "assert_object_equals", description,
+ "value is ${actual}, expected object",
+ {actual: actual});
//This needs to be improved a great deal
function check_equal(actual, expected, stack)
{
} else {
assert(same_value(actual[p], expected[p]), "assert_object_equals", description,
"property ${p} expected ${expected} got ${actual}",
- {p:p, expected:expected, actual:actual});
+ {p:p, expected:expected[p], actual:actual[p]});
}
}
for (p in expected) {
}
check_equal(actual, expected, []);
}
- expose(assert_object_equals, "assert_object_equals");
+ expose_assert(assert_object_equals, "assert_object_equals");
function assert_array_equals(actual, expected, description)
{
+ const max_array_length = 20;
+ function shorten_array(arr, offset = 0) {
+ // Make ", …" only show up when it would likely reduce the length, not accounting for
+ // fonts.
+ if (arr.length < max_array_length + 2) {
+ return arr;
+ }
+ // By default we want half the elements after the offset and half before
+ // But if that takes us past the end of the array, we have more before, and
+ // if it takes us before the start we have more after.
+ const length_after_offset = Math.floor(max_array_length / 2);
+ let upper_bound = Math.min(length_after_offset + offset, arr.length);
+ const lower_bound = Math.max(upper_bound - max_array_length, 0);
+
+ if (lower_bound === 0) {
+ upper_bound = max_array_length;
+ }
+
+ const output = arr.slice(lower_bound, upper_bound);
+ if (lower_bound > 0) {
+ output.beginEllipsis = true;
+ }
+ if (upper_bound < arr.length) {
+ output.endEllipsis = true;
+ }
+ return output;
+ }
+
+ assert(typeof actual === "object" && actual !== null && "length" in actual,
+ "assert_array_equals", description,
+ "value is ${actual}, expected array",
+ {actual:actual});
assert(actual.length === expected.length,
"assert_array_equals", description,
- "lengths differ, expected ${expected} got ${actual}",
- {expected:expected.length, actual:actual.length});
+ "lengths differ, expected array ${expected} length ${expectedLength}, got ${actual} length ${actualLength}",
+ {expected:shorten_array(expected, expected.length - 1), expectedLength:expected.length,
+ actual:shorten_array(actual, actual.length - 1), actualLength:actual.length
+ });
for (var i = 0; i < actual.length; i++) {
assert(actual.hasOwnProperty(i) === expected.hasOwnProperty(i),
"assert_array_equals", description,
- "property ${i}, property expected to be ${expected} but was ${actual}",
+ "expected property ${i} to be ${expected} but was ${actual} (expected array ${arrayExpected} got ${arrayActual})",
{i:i, expected:expected.hasOwnProperty(i) ? "present" : "missing",
- actual:actual.hasOwnProperty(i) ? "present" : "missing"});
+ actual:actual.hasOwnProperty(i) ? "present" : "missing",
+ arrayExpected:shorten_array(expected, i), arrayActual:shorten_array(actual, i)});
assert(same_value(expected[i], actual[i]),
"assert_array_equals", description,
- "property ${i}, expected ${expected} but got ${actual}",
- {i:i, expected:expected[i], actual:actual[i]});
+ "expected property ${i} to be ${expected} but got ${actual} (expected array ${arrayExpected} got ${arrayActual})",
+ {i:i, expected:expected[i], actual:actual[i],
+ arrayExpected:shorten_array(expected, i), arrayActual:shorten_array(actual, i)});
}
}
- expose(assert_array_equals, "assert_array_equals");
+ expose_assert(assert_array_equals, "assert_array_equals");
+
+ function assert_array_approx_equals(actual, expected, epsilon, description)
+ {
+ /*
+ * Test if two primitive arrays are equal within +/- epsilon
+ */
+ assert(actual.length === expected.length,
+ "assert_array_approx_equals", description,
+ "lengths differ, expected ${expected} got ${actual}",
+ {expected:expected.length, actual:actual.length});
+
+ for (var i = 0; i < actual.length; i++) {
+ assert(actual.hasOwnProperty(i) === expected.hasOwnProperty(i),
+ "assert_array_approx_equals", description,
+ "property ${i}, property expected to be ${expected} but was ${actual}",
+ {i:i, expected:expected.hasOwnProperty(i) ? "present" : "missing",
+ actual:actual.hasOwnProperty(i) ? "present" : "missing"});
+ assert(typeof actual[i] === "number",
+ "assert_array_approx_equals", description,
+ "property ${i}, expected a number but got a ${type_actual}",
+ {i:i, type_actual:typeof actual[i]});
+ assert(Math.abs(actual[i] - expected[i]) <= epsilon,
+ "assert_array_approx_equals", description,
+ "property ${i}, expected ${expected} +/- ${epsilon}, expected ${expected} but got ${actual}",
+ {i:i, expected:expected[i], actual:actual[i], epsilon:epsilon});
+ }
+ }
+ expose_assert(assert_array_approx_equals, "assert_array_approx_equals");
function assert_approx_equals(actual, expected, epsilon, description)
{
/*
- * Test if two primitive numbers are equal withing +/- epsilon
+ * Test if two primitive numbers are equal within +/- epsilon
*/
assert(typeof actual === "number",
"assert_approx_equals", description,
"expected a number but got a ${type_actual}",
{type_actual:typeof actual});
- assert(Math.abs(actual - expected) <= epsilon,
- "assert_approx_equals", description,
- "expected ${expected} +/- ${epsilon} but got ${actual}",
- {expected:expected, actual:actual, epsilon:epsilon});
+ // The epsilon math below does not place nice with NaN and Infinity
+ // But in this case Infinity = Infinity and NaN = NaN
+ if (isFinite(actual) || isFinite(expected)) {
+ assert(Math.abs(actual - expected) <= epsilon,
+ "assert_approx_equals", description,
+ "expected ${expected} +/- ${epsilon} but got ${actual}",
+ {expected:expected, actual:actual, epsilon:epsilon});
+ } else {
+ assert_equals(actual, expected);
+ }
}
- expose(assert_approx_equals, "assert_approx_equals");
+ expose_assert(assert_approx_equals, "assert_approx_equals");
function assert_less_than(actual, expected, description)
{
"expected a number less than ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_less_than, "assert_less_than");
+ expose_assert(assert_less_than, "assert_less_than");
function assert_greater_than(actual, expected, description)
{
"expected a number greater than ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_greater_than, "assert_greater_than");
+ expose_assert(assert_greater_than, "assert_greater_than");
+
+ function assert_between_exclusive(actual, lower, upper, description)
+ {
+ /*
+ * Test if a primitive number is between two others
+ */
+ assert(typeof actual === "number",
+ "assert_between_exclusive", description,
+ "expected a number but got a ${type_actual}",
+ {type_actual:typeof actual});
+
+ assert(actual > lower && actual < upper,
+ "assert_between_exclusive", description,
+ "expected a number greater than ${lower} " +
+ "and less than ${upper} but got ${actual}",
+ {lower:lower, upper:upper, actual:actual});
+ }
+ expose_assert(assert_between_exclusive, "assert_between_exclusive");
function assert_less_than_equal(actual, expected, description)
{
{type_actual:typeof actual});
assert(actual <= expected,
- "assert_less_than", description,
+ "assert_less_than_equal", description,
"expected a number less than or equal to ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_less_than_equal, "assert_less_than_equal");
+ expose_assert(assert_less_than_equal, "assert_less_than_equal");
function assert_greater_than_equal(actual, expected, description)
{
"expected a number greater than or equal to ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_greater_than_equal, "assert_greater_than_equal");
+ expose_assert(assert_greater_than_equal, "assert_greater_than_equal");
+
+ function assert_between_inclusive(actual, lower, upper, description)
+ {
+ /*
+ * Test if a primitive number is between to two others or equal to either of them
+ */
+ assert(typeof actual === "number",
+ "assert_between_inclusive", description,
+ "expected a number but got a ${type_actual}",
+ {type_actual:typeof actual});
+
+ assert(actual >= lower && actual <= upper,
+ "assert_between_inclusive", description,
+ "expected a number greater than or equal to ${lower} " +
+ "and less than or equal to ${upper} but got ${actual}",
+ {lower:lower, upper:upper, actual:actual});
+ }
+ expose_assert(assert_between_inclusive, "assert_between_inclusive");
function assert_regexp_match(actual, expected, description) {
/*
"expected ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
- expose(assert_regexp_match, "assert_regexp_match");
+ expose_assert(assert_regexp_match, "assert_regexp_match");
function assert_class_string(object, class_string, description) {
- assert_equals({}.toString.call(object), "[object " + class_string + "]",
- description);
+ var actual = {}.toString.call(object);
+ var expected = "[object " + class_string + "]";
+ assert(same_value(actual, expected), "assert_class_string", description,
+ "expected ${expected} but got ${actual}",
+ {expected:expected, actual:actual});
}
- expose(assert_class_string, "assert_class_string");
+ expose_assert(assert_class_string, "assert_class_string");
-
- function _assert_own_property(name) {
- return function(object, property_name, description)
- {
- assert(property_name in object,
- name, description,
- "expected property ${p} missing", {p:property_name});
- };
+ function assert_own_property(object, property_name, description) {
+ assert(object.hasOwnProperty(property_name),
+ "assert_own_property", description,
+ "expected property ${p} missing", {p:property_name});
}
- expose(_assert_own_property("assert_exists"), "assert_exists");
- expose(_assert_own_property("assert_own_property"), "assert_own_property");
+ expose_assert(assert_own_property, "assert_own_property");
- function assert_not_exists(object, property_name, description)
- {
+ function assert_not_own_property(object, property_name, description) {
assert(!object.hasOwnProperty(property_name),
- "assert_not_exists", description,
- "unexpected property ${p} found", {p:property_name});
+ "assert_not_own_property", description,
+ "unexpected property ${p} is found on object", {p:property_name});
}
- expose(assert_not_exists, "assert_not_exists");
+ expose_assert(assert_not_own_property, "assert_not_own_property");
function _assert_inherits(name) {
return function (object, property_name, description)
{
- assert(typeof object === "object",
+ assert((typeof object === "object" && object !== null) ||
+ typeof object === "function" ||
+ // Or has [[IsHTMLDDA]] slot
+ String(object) === "[object HTMLAllCollection]",
name, description,
"provided value is not an object");
{p:property_name});
};
}
- expose(_assert_inherits("assert_inherits"), "assert_inherits");
- expose(_assert_inherits("assert_idl_attribute"), "assert_idl_attribute");
+ expose_assert(_assert_inherits("assert_inherits"), "assert_inherits");
+ expose_assert(_assert_inherits("assert_idl_attribute"), "assert_idl_attribute");
function assert_readonly(object, property_name, description)
{
object[property_name] = initial_value;
}
}
- expose(assert_readonly, "assert_readonly");
+ expose_assert(assert_readonly, "assert_readonly");
+
+ /**
+ * Assert a JS Error with the expected constructor is thrown.
+ *
+ * @param {object} constructor The expected exception constructor.
+ * @param {Function} func Function which should throw.
+ * @param {string} description Error description for the case that the error is not thrown.
+ */
+ function assert_throws_js(constructor, func, description)
+ {
+ assert_throws_js_impl(constructor, func, description,
+ "assert_throws_js");
+ }
+ expose_assert(assert_throws_js, "assert_throws_js");
- function assert_throws(code, func, description)
+ /**
+ * Like assert_throws_js but allows specifying the assertion type
+ * (assert_throws_js or promise_rejects_js, in practice).
+ */
+ function assert_throws_js_impl(constructor, func, description,
+ assertion_type)
{
try {
func.call(this);
- assert(false, "assert_throws", description,
+ assert(false, assertion_type, description,
"${func} did not throw", {func:func});
} catch (e) {
if (e instanceof AssertionError) {
throw e;
}
- if (code === null) {
- return;
+
+ // Basic sanity-checks on the thrown exception.
+ assert(typeof e === "object",
+ assertion_type, description,
+ "${func} threw ${e} with type ${type}, not an object",
+ {func:func, e:e, type:typeof e});
+
+ assert(e !== null,
+ assertion_type, description,
+ "${func} threw null, not an object",
+ {func:func});
+
+ // Basic sanity-check on the passed-in constructor
+ assert(typeof constructor == "function",
+ assertion_type, description,
+ "${constructor} is not a constructor",
+ {constructor:constructor});
+ var obj = constructor;
+ while (obj) {
+ if (typeof obj === "function" &&
+ obj.name === "Error") {
+ break;
+ }
+ obj = Object.getPrototypeOf(obj);
}
- if (typeof code === "object") {
- assert(typeof e == "object" && "name" in e && e.name == code.name,
- "assert_throws", description,
- "${func} threw ${actual} (${actual_name}) expected ${expected} (${expected_name})",
- {func:func, actual:e, actual_name:e.name,
- expected:code,
- expected_name:code.name});
- return;
+ assert(obj != null,
+ assertion_type, description,
+ "${constructor} is not an Error subtype",
+ {constructor:constructor});
+
+ // And checking that our exception is reasonable
+ assert(e.constructor === constructor &&
+ e.name === constructor.name,
+ assertion_type, description,
+ "${func} threw ${actual} (${actual_name}) expected instance of ${expected} (${expected_name})",
+ {func:func, actual:e, actual_name:e.name,
+ expected:constructor,
+ expected_name:constructor.name});
+ }
+ }
+
+ /**
+ * Assert a DOMException with the expected type is thrown.
+ *
+ * @param {number|string} type The expected exception name or code. See the
+ * table of names and codes at
+ * https://heycam.github.io/webidl/#dfn-error-names-table
+ * If a number is passed it should be one of the numeric code values
+ * in that table (e.g. 3, 4, etc). If a string is passed it can
+ * either be an exception name (e.g. "HierarchyRequestError",
+ * "WrongDocumentError") or the name of the corresponding error code
+ * (e.g. "HIERARCHY_REQUEST_ERR", "WRONG_DOCUMENT_ERR").
+ *
+ * For the remaining arguments, there are two ways of calling
+ * promise_rejects_dom:
+ *
+ * 1) If the DOMException is expected to come from the current global, the
+ * second argument should be the function expected to throw and a third,
+ * optional, argument is the assertion description.
+ *
+ * 2) If the DOMException is expected to come from some other global, the
+ * second argument should be the DOMException constructor from that global,
+ * the third argument the function expected to throw, and the fourth, optional,
+ * argument the assertion description.
+ */
+ function assert_throws_dom(type, funcOrConstructor, descriptionOrFunc, maybeDescription)
+ {
+ let constructor, func, description;
+ if (funcOrConstructor.name === "DOMException") {
+ constructor = funcOrConstructor;
+ func = descriptionOrFunc;
+ description = maybeDescription;
+ } else {
+ constructor = self.DOMException;
+ func = funcOrConstructor;
+ description = descriptionOrFunc;
+ assert(maybeDescription === undefined,
+ "Too many args pased to no-constructor version of assert_throws_dom");
+ }
+ assert_throws_dom_impl(type, func, description, "assert_throws_dom", constructor)
+ }
+ expose_assert(assert_throws_dom, "assert_throws_dom");
+
+ /**
+ * Similar to assert_throws_dom but allows specifying the assertion type
+ * (assert_throws_dom or promise_rejects_dom, in practice). The
+ * "constructor" argument must be the DOMException constructor from the
+ * global we expect the exception to come from.
+ */
+ function assert_throws_dom_impl(type, func, description, assertion_type, constructor)
+ {
+ try {
+ func.call(this);
+ assert(false, assertion_type, description,
+ "${func} did not throw", {func:func});
+ } catch (e) {
+ if (e instanceof AssertionError) {
+ throw e;
}
- var code_name_map = {
+ // Basic sanity-checks on the thrown exception.
+ assert(typeof e === "object",
+ assertion_type, description,
+ "${func} threw ${e} with type ${type}, not an object",
+ {func:func, e:e, type:typeof e});
+
+ assert(e !== null,
+ assertion_type, description,
+ "${func} threw null, not an object",
+ {func:func});
+
+ // Sanity-check our type
+ assert(typeof type == "number" ||
+ typeof type == "string",
+ assertion_type, description,
+ "${type} is not a number or string",
+ {type:type});
+
+ var codename_name_map = {
INDEX_SIZE_ERR: 'IndexSizeError',
HIERARCHY_REQUEST_ERR: 'HierarchyRequestError',
WRONG_DOCUMENT_ERR: 'WrongDocumentError',
NO_MODIFICATION_ALLOWED_ERR: 'NoModificationAllowedError',
NOT_FOUND_ERR: 'NotFoundError',
NOT_SUPPORTED_ERR: 'NotSupportedError',
+ INUSE_ATTRIBUTE_ERR: 'InUseAttributeError',
INVALID_STATE_ERR: 'InvalidStateError',
SYNTAX_ERR: 'SyntaxError',
INVALID_MODIFICATION_ERR: 'InvalidModificationError',
DATA_CLONE_ERR: 'DataCloneError'
};
- var name = code in code_name_map ? code_name_map[code] : code;
-
var name_code_map = {
IndexSizeError: 1,
HierarchyRequestError: 3,
NoModificationAllowedError: 7,
NotFoundError: 8,
NotSupportedError: 9,
+ InUseAttributeError: 10,
InvalidStateError: 11,
SyntaxError: 12,
InvalidModificationError: 13,
InvalidNodeTypeError: 24,
DataCloneError: 25,
+ EncodingError: 0,
+ NotReadableError: 0,
UnknownError: 0,
ConstraintError: 0,
DataError: 0,
TransactionInactiveError: 0,
ReadOnlyError: 0,
- VersionError: 0
+ VersionError: 0,
+ OperationError: 0,
+ NotAllowedError: 0
};
- if (!(name in name_code_map)) {
- throw new AssertionError('Test bug: unrecognized DOMException code "' + code + '" passed to assert_throws()');
+ var code_name_map = {};
+ for (var key in name_code_map) {
+ if (name_code_map[key] > 0) {
+ code_name_map[name_code_map[key]] = key;
+ }
}
- var required_props = { code: name_code_map[name] };
+ var required_props = {};
+ var name;
+
+ if (typeof type === "number") {
+ if (type === 0) {
+ throw new AssertionError('Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()');
+ } else if (!(type in code_name_map)) {
+ throw new AssertionError('Test bug: unrecognized DOMException code "' + type + '" passed to assert_throws_dom()');
+ }
+ name = code_name_map[type];
+ required_props.code = type;
+ } else if (typeof type === "string") {
+ name = type in codename_name_map ? codename_name_map[type] : type;
+ if (!(name in name_code_map)) {
+ throw new AssertionError('Test bug: unrecognized DOMException code name or name "' + type + '" passed to assert_throws_dom()');
+ }
+
+ required_props.code = name_code_map[name];
+ }
if (required_props.code === 0 ||
- ("name" in e && e.name !== e.name.toUpperCase() && e.name !== "DOMException")) {
+ ("name" in e &&
+ e.name !== e.name.toUpperCase() &&
+ e.name !== "DOMException")) {
// New style exception: also test the name property.
required_props.name = name;
}
- //We'd like to test that e instanceof the appropriate interface,
- //but we can't, because we don't know what window it was created
- //in. It might be an instanceof the appropriate interface on some
- //unknown other window. TODO: Work around this somehow?
-
- assert(typeof e == "object",
- "assert_throws", description,
- "${func} threw ${e} with type ${type}, not an object",
- {func:func, e:e, type:typeof e});
-
for (var prop in required_props) {
- assert(typeof e == "object" && prop in e && e[prop] == required_props[prop],
- "assert_throws", description,
- "${func} threw ${e} that is not a DOMException " + code + ": property ${prop} is equal to ${actual}, expected ${expected}",
+ assert(prop in e && e[prop] == required_props[prop],
+ assertion_type, description,
+ "${func} threw ${e} that is not a DOMException " + type + ": property ${prop} is equal to ${actual}, expected ${expected}",
{func:func, e:e, prop:prop, actual:e[prop], expected:required_props[prop]});
}
+
+ // Check that the exception is from the right global. This check is last
+ // so more specific, and more informative, checks on the properties can
+ // happen in case a totally incorrect exception is thrown.
+ assert(e.constructor === constructor,
+ assertion_type, description,
+ "${func} threw an exception from the wrong global",
+ {func});
+
+ }
+ }
+
+ /**
+ * Assert the provided value is thrown.
+ *
+ * @param {value} exception The expected exception.
+ * @param {Function} func Function which should throw.
+ * @param {string} description Error description for the case that the error is not thrown.
+ */
+ function assert_throws_exactly(exception, func, description)
+ {
+ assert_throws_exactly_impl(exception, func, description,
+ "assert_throws_exactly");
+ }
+ expose_assert(assert_throws_exactly, "assert_throws_exactly");
+
+ /**
+ * Like assert_throws_exactly but allows specifying the assertion type
+ * (assert_throws_exactly or promise_rejects_exactly, in practice).
+ */
+ function assert_throws_exactly_impl(exception, func, description,
+ assertion_type)
+ {
+ try {
+ func.call(this);
+ assert(false, assertion_type, description,
+ "${func} did not throw", {func:func});
+ } catch (e) {
+ if (e instanceof AssertionError) {
+ throw e;
+ }
+
+ assert(same_value(e, exception), assertion_type, description,
+ "${func} threw ${e} but we expected it to throw ${exception}",
+ {func:func, e:e, exception:exception});
}
}
- expose(assert_throws, "assert_throws");
function assert_unreached(description) {
assert(false, "assert_unreached", description,
"Reached unreachable code");
}
- expose(assert_unreached, "assert_unreached");
+ expose_assert(assert_unreached, "assert_unreached");
function assert_any(assert_func, actual, expected_array)
{
throw new AssertionError(errors.join("\n\n"));
}
}
+ // FIXME: assert_any cannot use expose_assert, because assert_wrapper does
+ // not support nested assert calls (e.g. to assert_func). We need to
+ // support bypassing assert_wrapper for the inner asserts here.
expose(assert_any, "assert_any");
+ /**
+ * Assert that a feature is implemented, based on a 'truthy' condition.
+ *
+ * This function should be used to early-exit from tests in which there is
+ * no point continuing without support for a non-optional spec or spec
+ * feature. For example:
+ *
+ * assert_implements(window.Foo, 'Foo is not supported');
+ *
+ * @param {object} condition The truthy value to test
+ * @param {string} description Error description for the case that the condition is not truthy.
+ */
+ function assert_implements(condition, description) {
+ assert(!!condition, "assert_implements", description);
+ }
+ expose_assert(assert_implements, "assert_implements")
+
+ /**
+ * Assert that an optional feature is implemented, based on a 'truthy' condition.
+ *
+ * This function should be used to early-exit from tests in which there is
+ * no point continuing without support for an explicitly optional spec or
+ * spec feature. For example:
+ *
+ * assert_implements_optional(video.canPlayType("video/webm"),
+ * "webm video playback not supported");
+ *
+ * @param {object} condition The truthy value to test
+ * @param {string} description Error description for the case that the condition is not truthy.
+ */
+ function assert_implements_optional(condition, description) {
+ if (!condition) {
+ throw new OptionalFeatureUnsupportedError(description);
+ }
+ }
+ expose_assert(assert_implements_optional, "assert_implements_optional")
+
function Test(name, properties)
{
if (tests.file_is_test && tests.tests.length) {
}
this.name = name;
- this.phase = this.phases.INITIAL;
+ this.phase = (tests.is_aborted || tests.phase === tests.phases.COMPLETE) ?
+ this.phases.COMPLETE : this.phases.INITIAL;
this.status = this.NOTRUN;
this.timeout_id = null;
this.index = null;
- this.properties = properties;
- var timeout = properties.timeout ? properties.timeout : settings.test_timeout;
- if (timeout !== null) {
- this.timeout_length = timeout * tests.timeout_multiplier;
- } else {
- this.timeout_length = null;
+ this.properties = properties || {};
+ this.timeout_length = settings.test_timeout;
+ if (this.timeout_length !== null) {
+ this.timeout_length *= tests.timeout_multiplier;
}
this.message = null;
+ this.stack = null;
this.steps = [];
+ this._is_promise_test = false;
this.cleanup_callbacks = [];
+ this._user_defined_cleanup_count = 0;
+ this._done_callbacks = [];
+
+ // Tests declared following harness completion are likely an indication
+ // of a programming error, but they cannot be reported
+ // deterministically.
+ if (tests.phase === tests.phases.COMPLETE) {
+ return;
+ }
tests.push(this);
}
PASS:0,
FAIL:1,
TIMEOUT:2,
- NOTRUN:3
+ NOTRUN:3,
+ PRECONDITION_FAILED:4
};
Test.prototype = merge({}, Test.statuses);
INITIAL:0,
STARTED:1,
HAS_RESULT:2,
- COMPLETE:3
+ CLEANING:3,
+ COMPLETE:4
};
+ Test.prototype.status_formats = {
+ 0: "Pass",
+ 1: "Fail",
+ 2: "Timeout",
+ 3: "Not Run",
+ 4: "Optional Feature Unsupported",
+ }
+
+ Test.prototype.format_status = function() {
+ return this.status_formats[this.status];
+ }
+
Test.prototype.structured_clone = function()
{
if (!this._structured_clone) {
this._structured_clone = merge({
name:String(this.name),
properties:merge({}, this.properties),
+ phases:merge({}, this.phases)
}, Test.statuses);
}
this._structured_clone.status = this.status;
this._structured_clone.message = this.message;
+ this._structured_clone.stack = this.stack;
this._structured_clone.index = this.index;
+ this._structured_clone.phase = this.phase;
return this._structured_clone;
};
if (this.phase > this.phases.STARTED) {
return;
}
+
+ if (settings.debug && this.phase !== this.phases.STARTED) {
+ console.log("TEST START", this.name);
+ }
this.phase = this.phases.STARTED;
- //If we don't get a result before the harness times out that will be a test timout
+ //If we don't get a result before the harness times out that will be a test timeout
this.set_status(this.TIMEOUT, "Test timed out");
tests.started = true;
+ tests.current_test = this;
tests.notify_test_state(this);
if (this.timeout_id === null) {
this_obj = this;
}
+ if (settings.debug) {
+ console.debug("TEST STEP", this.name);
+ }
+
try {
return func.apply(this_obj, Array.prototype.slice.call(arguments, 2));
} catch (e) {
if (this.phase >= this.phases.HAS_RESULT) {
return;
}
- var message = (typeof e === "object" && e !== null) ? e.message : e;
- if (typeof e.stack != "undefined" && typeof e.message == "string") {
- //Try to make it more informative for some exceptions, at least
- //in Gecko and WebKit. This results in a stack dump instead of
- //just errors like "Cannot read property 'parentNode' of null"
- //or "root is null". Makes it a lot longer, of course.
- message += "(stack: " + e.stack + ")";
- }
- this.set_status(this.FAIL, message);
+ var status = e instanceof OptionalFeatureUnsupportedError ? this.PRECONDITION_FAILED : this.FAIL;
+ var message = String((typeof e === "object" && e !== null) ? e.message : e);
+ var stack = e.stack ? e.stack : null;
+
+ this.set_status(status, message, stack);
this.phase = this.phases.HAS_RESULT;
this.done();
+ } finally {
+ this.current_test = null;
}
};
});
};
- Test.prototype.add_cleanup = function(callback) {
+ Test.prototype.step_timeout = function(f, timeout) {
+ var test_this = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ return setTimeout(this.step_func(function() {
+ return f.apply(test_this, args);
+ }), timeout * tests.timeout_multiplier);
+ };
+
+ Test.prototype.step_wait_func = function(cond, func, description,
+ timeout=3000, interval=100) {
+ /**
+ * Poll for a function to return true, and call a callback
+ * function once it does, or assert if a timeout is
+ * reached. This is preferred over a simple step_timeout
+ * whenever possible since it allows the timeout to be longer
+ * to reduce intermittents without compromising test execution
+ * speed when the condition is quickly met.
+ *
+ * @param {Function} cond A function taking no arguments and
+ * returning a boolean. The callback is called
+ * when this function returns true.
+ * @param {Function} func A function taking no arguments to call once
+ * the condition is met.
+ * @param {string} description Error message to add to assert in case of
+ * failure.
+ * @param {number} timeout Timeout in ms. This is multiplied by the global
+ * timeout_multiplier
+ * @param {number} interval Polling interval in ms
+ *
+ **/
+
+ var timeout_full = timeout * tests.timeout_multiplier;
+ var remaining = Math.ceil(timeout_full / interval);
+ var test_this = this;
+
+ var wait_for_inner = test_this.step_func(() => {
+ if (cond()) {
+ func();
+ } else {
+ if(remaining === 0) {
+ assert(false, "step_wait_func", description,
+ "Timed out waiting on condition");
+ }
+ remaining--;
+ setTimeout(wait_for_inner, interval);
+ }
+ });
+
+ wait_for_inner();
+ };
+
+ Test.prototype.step_wait_func_done = function(cond, func, description,
+ timeout=3000, interval=100) {
+ /**
+ * Poll for a function to return true, and invoke a callback
+ * followed by this.done() once it does, or assert if a timeout
+ * is reached. This is preferred over a simple step_timeout
+ * whenever possible since it allows the timeout to be longer
+ * to reduce intermittents without compromising test execution speed
+ * when the condition is quickly met.
+ *
+ * @param {Function} cond A function taking no arguments and
+ * returning a boolean. The callback is called
+ * when this function returns true.
+ * @param {Function} func A function taking no arguments to call once
+ * the condition is met.
+ * @param {string} description Error message to add to assert in case of
+ * failure.
+ * @param {number} timeout Timeout in ms. This is multiplied by the global
+ * timeout_multiplier
+ * @param {number} interval Polling interval in ms
+ *
+ **/
+
+ this.step_wait_func(cond, () => {
+ if (func) {
+ func();
+ }
+ this.done();
+ }, description, timeout, interval);
+ }
+
+ Test.prototype.step_wait = function(cond, description, timeout=3000, interval=100) {
+ /**
+ * Poll for a function to return true, and resolve a promise
+ * once it does, or assert if a timeout is reached. This is
+ * preferred over a simple step_timeout whenever possible
+ * since it allows the timeout to be longer to reduce
+ * intermittents without compromising test execution speed
+ * when the condition is quickly met.
+ *
+ * @param {Function} cond A function taking no arguments and
+ * returning a boolean.
+ * @param {string} description Error message to add to assert in case of
+ * failure.
+ * @param {number} timeout Timeout in ms. This is multiplied by the global
+ * timeout_multiplier
+ * @param {number} interval Polling interval in ms
+ * @returns {Promise} Promise resolved once cond is met.
+ *
+ **/
+
+ return new Promise(resolve => {
+ this.step_wait_func(cond, resolve, description, timeout, interval);
+ });
+ }
+
+ /*
+ * Private method for registering cleanup functions. `testharness.js`
+ * internals should use this method instead of the public `add_cleanup`
+ * method in order to hide implementation details from the harness status
+ * message in the case errors.
+ */
+ Test.prototype._add_cleanup = function(callback) {
this.cleanup_callbacks.push(callback);
};
- Test.prototype.force_timeout = function() {
- this.set_status(this.TIMEOUT);
- this.phase = this.phases.HAS_RESULT;
+ /*
+ * Schedule a function to be run after the test result is known, regardless
+ * of passing or failing state. The behavior of this function will not
+ * influence the result of the test, but if an exception is thrown, the
+ * test harness will report an error.
+ */
+ Test.prototype.add_cleanup = function(callback) {
+ this._user_defined_cleanup_count += 1;
+ this._add_cleanup(callback);
};
Test.prototype.set_timeout = function()
}
};
- Test.prototype.set_status = function(status, message)
+ Test.prototype.set_status = function(status, message, stack)
{
this.status = status;
this.message = message;
+ this.stack = stack ? stack : null;
};
Test.prototype.timeout = function()
this.done();
};
+ Test.prototype.force_timeout = Test.prototype.timeout;
+
+ /**
+ * Update the test status, initiate "cleanup" functions, and signal test
+ * completion.
+ */
Test.prototype.done = function()
{
- if (this.phase == this.phases.COMPLETE) {
+ if (this.phase >= this.phases.CLEANING) {
return;
}
this.set_status(this.PASS, null);
}
- this.phase = this.phases.COMPLETE;
+ if (global_scope.clearTimeout) {
+ clearTimeout(this.timeout_id);
+ }
+
+ if (settings.debug) {
+ console.log("TEST DONE",
+ this.status,
+ this.name,)
+ }
- clearTimeout(this.timeout_id);
- tests.result(this);
this.cleanup();
};
+ function add_test_done_callback(test, callback)
+ {
+ if (test.phase === test.phases.COMPLETE) {
+ callback();
+ return;
+ }
+
+ test._done_callbacks.push(callback);
+ }
+
+ /*
+ * Invoke all specified cleanup functions. If one or more produce an error,
+ * the context is in an unpredictable state, so all further testing should
+ * be cancelled.
+ */
Test.prototype.cleanup = function() {
+ var error_count = 0;
+ var bad_value_count = 0;
+ function on_error() {
+ error_count += 1;
+ // Abort tests immediately so that tests declared within subsequent
+ // cleanup functions are not run.
+ tests.abort();
+ }
+ var this_obj = this;
+ var results = [];
+
+ this.phase = this.phases.CLEANING;
+
forEach(this.cleanup_callbacks,
function(cleanup_callback) {
- cleanup_callback();
+ var result;
+
+ try {
+ result = cleanup_callback();
+ } catch (e) {
+ on_error();
+ return;
+ }
+
+ if (!is_valid_cleanup_result(this_obj, result)) {
+ bad_value_count += 1;
+ // Abort tests immediately so that tests declared
+ // within subsequent cleanup functions are not run.
+ tests.abort();
+ }
+
+ results.push(result);
});
+
+ if (!this._is_promise_test) {
+ cleanup_done(this_obj, error_count, bad_value_count);
+ } else {
+ all_async(results,
+ function(result, done) {
+ if (result && typeof result.then === "function") {
+ result
+ .then(null, on_error)
+ .then(done);
+ } else {
+ done();
+ }
+ },
+ function() {
+ cleanup_done(this_obj, error_count, bad_value_count);
+ });
+ }
};
+ /**
+ * Determine if the return value of a cleanup function is valid for a given
+ * test. Any test may return the value `undefined`. Tests created with
+ * `promise_test` may alternatively return "thenable" object values.
+ */
+ function is_valid_cleanup_result(test, result) {
+ if (result === undefined) {
+ return true;
+ }
+
+ if (test._is_promise_test) {
+ return result && typeof result.then === "function";
+ }
+
+ return false;
+ }
+
+ function cleanup_done(test, error_count, bad_value_count) {
+ if (error_count || bad_value_count) {
+ var total = test._user_defined_cleanup_count;
+
+ tests.status.status = tests.status.ERROR;
+ tests.status.message = "Test named '" + test.name +
+ "' specified " + total +
+ " 'cleanup' function" + (total > 1 ? "s" : "");
+
+ if (error_count) {
+ tests.status.message += ", and " + error_count + " failed";
+ }
+
+ if (bad_value_count) {
+ var type = test._is_promise_test ?
+ "non-thenable" : "non-undefined";
+ tests.status.message += ", and " + bad_value_count +
+ " returned a " + type + " value";
+ }
+
+ tests.status.message += ".";
+
+ tests.status.stack = null;
+ }
+
+ test.phase = test.phases.COMPLETE;
+ tests.result(test);
+ forEach(test._done_callbacks,
+ function(callback) {
+ callback();
+ });
+ test._done_callbacks.length = 0;
+ }
+
/*
* A RemoteTest object mirrors a Test object on a remote worker. The
* associated RemoteWorker updates the RemoteTest object in response to
this.index = null;
this.phase = this.phases.INITIAL;
this.update_state_from(clone);
+ this._done_callbacks = [];
tests.push(this);
}
RemoteTest.prototype.structured_clone = function() {
var clone = {};
Object.keys(this).forEach(
- function(key) {
- if (typeof(this[key]) === "object") {
- clone[key] = merge({}, this[key]);
+ (function(key) {
+ var value = this[key];
+ // `RemoteTest` instances are responsible for managing
+ // their own "done" callback functions, so those functions
+ // are not relevant in other execution contexts. Because of
+ // this (and because Function values cannot be serialized
+ // for cross-realm transmittance), the property should not
+ // be considered when cloning instances.
+ if (key === '_done_callbacks' ) {
+ return;
+ }
+
+ if (typeof value === "object" && value !== null) {
+ clone[key] = merge({}, value);
} else {
- clone[key] = this[key];
+ clone[key] = value;
}
- });
+ }).bind(this));
clone.phases = merge({}, this.phases);
return clone;
};
- RemoteTest.prototype.cleanup = function() {};
+ /**
+ * `RemoteTest` instances are objects which represent tests running in
+ * another realm. They do not define "cleanup" functions (if necessary,
+ * such functions are defined on the associated `Test` instance within the
+ * external realm). However, `RemoteTests` may have "done" callbacks (e.g.
+ * as attached by the `Tests` instance responsible for tracking the overall
+ * test status in the parent realm). The `cleanup` method delegates to
+ * `done` in order to ensure that such callbacks are invoked following the
+ * completion of the `RemoteTest`.
+ */
+ RemoteTest.prototype.cleanup = function() {
+ this.done();
+ };
RemoteTest.prototype.phases = Test.prototype.phases;
RemoteTest.prototype.update_state_from = function(clone) {
this.status = clone.status;
this.message = clone.message;
+ this.stack = clone.stack;
if (this.phase === this.phases.INITIAL) {
this.phase = this.phases.STARTED;
}
};
RemoteTest.prototype.done = function() {
this.phase = this.phases.COMPLETE;
+
+ forEach(this._done_callbacks,
+ function(callback) {
+ callback();
+ });
+ }
+
+ RemoteTest.prototype.format_status = function() {
+ return Test.prototype.status_formats[this.status];
}
/*
- * A RemoteWorker listens for test events from a worker. These events are
- * then used to construct and maintain RemoteTest objects that mirror the
- * tests running on the remote worker.
+ * A RemoteContext listens for test events from a remote test context, such
+ * as another window or a worker. These events are then used to construct
+ * and maintain RemoteTest objects that mirror the tests running in the
+ * remote context.
+ *
+ * An optional third parameter can be used as a predicate to filter incoming
+ * MessageEvents.
*/
- function RemoteWorker(worker) {
+ function RemoteContext(remote, message_target, message_filter) {
this.running = true;
+ this.started = false;
this.tests = new Array();
+ this.early_exception = null;
var this_obj = this;
- worker.onerror = function(error) { this_obj.worker_error(error); };
+ // If remote context is cross origin assigning to onerror is not
+ // possible, so silently catch those errors.
+ try {
+ remote.onerror = function(error) { this_obj.remote_error(error); };
+ } catch (e) {
+ // Ignore.
+ }
- var message_port;
+ // Keeping a reference to the remote object and the message handler until
+ // remote_done() is seen prevents the remote object and its message channel
+ // from going away before all the messages are dispatched.
+ this.remote = remote;
+ this.message_target = message_target;
+ this.message_handler = function(message) {
+ var passesFilter = !message_filter || message_filter(message);
+ // The reference to the `running` property in the following
+ // condition is unnecessary because that value is only set to
+ // `false` after the `message_handler` function has been
+ // unsubscribed.
+ // TODO: Simplify the condition by removing the reference.
+ if (this_obj.running && message.data && passesFilter &&
+ (message.data.type in this_obj.message_handlers)) {
+ this_obj.message_handlers[message.data.type].call(this_obj, message.data);
+ }
+ };
- if (is_service_worker(worker)) {
- // The ServiceWorker's implicit MessagePort is currently not
- // reliably accessible from the ServiceWorkerGlobalScope due to
- // Blink setting MessageEvent.source to null for messages sent via
- // ServiceWorker.postMessage(). Until that's resolved, create an
- // explicit MessageChannel and pass one end to the worker.
- var message_channel = new MessageChannel();
- message_port = message_channel.port1;
- message_port.start();
- worker.postMessage({type: "connect"}, [message_channel.port2]);
- } else if (is_shared_worker(worker)) {
- message_port = worker.port;
- } else {
- message_port = worker;
+ if (self.Promise) {
+ this.done = new Promise(function(resolve) {
+ this_obj.doneResolve = resolve;
+ });
}
- // Keeping a reference to the worker until worker_done() is seen
- // prevents the Worker object and its MessageChannel from going away
- // before all the messages are dispatched.
- this.worker = worker;
-
- message_port.onmessage =
- function(message) {
- if (this_obj.running && (message.data.type in this_obj.message_handlers)) {
- this_obj.message_handlers[message.data.type].call(this_obj, message.data);
- }
- };
+ this.message_target.addEventListener("message", this.message_handler);
}
- RemoteWorker.prototype.worker_error = function(error) {
+ RemoteContext.prototype.remote_error = function(error) {
+ if (error.preventDefault) {
+ error.preventDefault();
+ }
+
+ // Defer interpretation of errors until the testing protocol has
+ // started and the remote test's `allow_uncaught_exception` property
+ // is available.
+ if (!this.started) {
+ this.early_exception = error;
+ } else if (!this.allow_uncaught_exception) {
+ this.report_uncaught(error);
+ }
+ };
+
+ RemoteContext.prototype.report_uncaught = function(error) {
var message = error.message || String(error);
var filename = (error.filename ? " " + error.filename: "");
- // FIXME: Display worker error states separately from main document
- // error state.
- this.worker_done({
- status: {
- status: tests.status.ERROR,
- message: "Error in worker" + filename + ": " + message
- }
- });
- error.preventDefault();
+ // FIXME: Display remote error states separately from main document
+ // error state.
+ tests.set_status(tests.status.ERROR,
+ "Error in remote" + filename + ": " + message,
+ error.stack);
+ };
+
+ RemoteContext.prototype.start = function(data) {
+ this.started = true;
+ this.allow_uncaught_exception = data.properties.allow_uncaught_exception;
+
+ if (this.early_exception && !this.allow_uncaught_exception) {
+ this.report_uncaught(this.early_exception);
+ }
};
- RemoteWorker.prototype.test_state = function(data) {
+ RemoteContext.prototype.test_state = function(data) {
var remote_test = this.tests[data.test.index];
if (!remote_test) {
remote_test = new RemoteTest(data.test);
tests.notify_test_state(remote_test);
};
- RemoteWorker.prototype.test_done = function(data) {
+ RemoteContext.prototype.test_done = function(data) {
var remote_test = this.tests[data.test.index];
remote_test.update_state_from(data.test);
remote_test.done();
tests.result(remote_test);
};
- RemoteWorker.prototype.worker_done = function(data) {
+ RemoteContext.prototype.remote_done = function(data) {
if (tests.status.status === null &&
data.status.status !== data.status.OK) {
- tests.status.status = data.status.status;
- tests.status.message = data.status.message;
+ tests.set_status(data.status.status, data.status.message, data.status.stack);
+ }
+
+ for (let assert of data.asserts) {
+ var record = new AssertRecord();
+ record.assert_name = assert.assert_name;
+ record.args = assert.args;
+ record.test = assert.test != null ? this.tests[assert.test.index] : null;
+ record.status = assert.status;
+ record.stack = assert.stack;
+ tests.asserts_run.push(record);
}
+
+ this.message_target.removeEventListener("message", this.message_handler);
this.running = false;
- this.worker = null;
+
+ // If remote context is cross origin assigning to onerror is not
+ // possible, so silently catch those errors.
+ try {
+ this.remote.onerror = null;
+ } catch (e) {
+ // Ignore.
+ }
+
+ this.remote = null;
+ this.message_target = null;
+ if (this.doneResolve) {
+ this.doneResolve();
+ }
+
if (tests.all_done()) {
tests.complete();
}
};
- RemoteWorker.prototype.message_handlers = {
- test_state: RemoteWorker.prototype.test_state,
- result: RemoteWorker.prototype.test_done,
- complete: RemoteWorker.prototype.worker_done
+ RemoteContext.prototype.message_handlers = {
+ start: RemoteContext.prototype.start,
+ test_state: RemoteContext.prototype.test_state,
+ result: RemoteContext.prototype.test_done,
+ complete: RemoteContext.prototype.remote_done
};
/*
{
this.status = null;
this.message = null;
+ this.stack = null;
}
TestsStatus.statuses = {
OK:0,
ERROR:1,
- TIMEOUT:2
+ TIMEOUT:2,
+ PRECONDITION_FAILED:3
};
TestsStatus.prototype = merge({}, TestsStatus.statuses);
+ TestsStatus.prototype.formats = {
+ 0: "OK",
+ 1: "Error",
+ 2: "Timeout",
+ 3: "Optional Feature Unsupported"
+ }
+
+
TestsStatus.prototype.structured_clone = function()
{
if (!this._structured_clone) {
msg = msg ? String(msg) : msg;
this._structured_clone = merge({
status:this.status,
- message:msg
+ message:msg,
+ stack:this.stack
}, TestsStatus.statuses);
}
return this._structured_clone;
};
+ TestsStatus.prototype.format_status = function() {
+ return this.formats[this.status];
+ }
+
+ function AssertRecord(test, assert_name, args = []) {
+ this.assert_name = assert_name;
+ this.test = test;
+ // Avoid keeping complex objects alive
+ this.args = args.map(x => format_value(x).replace(/\n/g, " "));
+ this.status = null;
+ }
+
+ AssertRecord.prototype.structured_clone = function() {
+ return {
+ assert_name: this.assert_name,
+ test: this.test ? this.test.structured_clone() : null,
+ args: this.args,
+ status: this.status,
+ }
+ }
+
function Tests()
{
this.tests = [];
this.allow_uncaught_exception = false;
this.file_is_test = false;
+ // This value is lazily initialized in order to avoid introducing a
+ // dependency on ECMAScript 2015 Promises to all tests.
+ this.promise_tests = null;
+ this.promise_setup_called = false;
this.timeout_multiplier = 1;
this.timeout_length = test_environment.test_timeout();
this.test_done_callbacks = [];
this.all_done_callbacks = [];
- this.pending_workers = [];
+ this.hide_test_state = false;
+ this.pending_remotes = [];
+
+ this.current_test = null;
+ this.asserts_run = [];
+
+ // Track whether output is enabled, and thus whether or not we should
+ // track asserts.
+ //
+ // On workers we don't get properties set from testharnessreport.js, so
+ // we don't know whether or not to track asserts. To avoid the
+ // resulting performance hit, we assume we are not meant to. This means
+ // that assert tracking does not function on workers.
+ this.output = settings.output && 'document' in global_scope;
this.status = new TestsStatus();
{
clearTimeout(this.timeout_id);
}
+ } else if (p == "single_test" && value) {
+ this.set_file_is_test();
} else if (p == "timeout_multiplier") {
this.timeout_multiplier = value;
+ if (this.timeout_length) {
+ this.timeout_length *= this.timeout_multiplier;
+ }
+ } else if (p == "hide_test_state") {
+ this.hide_test_state = value;
+ } else if (p == "output") {
+ this.output = value;
+ } else if (p === "debug") {
+ settings.debug = value;
}
}
}
try {
func();
} catch (e) {
- this.status.status = this.status.ERROR;
+ this.status.status = e instanceof OptionalFeatureUnsupportedError ? this.status.PRECONDITION_FAILED : this.status.ERROR;
this.status.message = String(e);
+ this.status.stack = e.stack ? e.stack : null;
+ this.complete();
}
}
this.set_timeout();
this.wait_for_finish = true;
this.file_is_test = true;
// Create the test, which will add it to the list of tests
- async_test();
+ tests.current_test = async_test();
+ };
+
+ Tests.prototype.set_status = function(status, message, stack)
+ {
+ this.status.status = status;
+ this.status.message = message;
+ this.status.stack = stack ? stack : null;
};
Tests.prototype.set_timeout = function() {
- var this_obj = this;
- clearTimeout(this.timeout_id);
- if (this.timeout_length !== null) {
- this.timeout_id = setTimeout(function() {
- this_obj.timeout();
- }, this.timeout_length);
+ if (global_scope.clearTimeout) {
+ var this_obj = this;
+ clearTimeout(this.timeout_id);
+ if (this.timeout_length !== null) {
+ this.timeout_id = setTimeout(function() {
+ this_obj.timeout();
+ }, this.timeout_length);
+ }
}
};
Tests.prototype.timeout = function() {
+ var test_in_cleanup = null;
+
if (this.status.status === null) {
- this.status.status = this.status.TIMEOUT;
+ forEach(this.tests,
+ function(test) {
+ // No more than one test is expected to be in the
+ // "CLEANUP" phase at any time
+ if (test.phase === test.phases.CLEANING) {
+ test_in_cleanup = test;
+ }
+
+ test.phase = test.phases.COMPLETE;
+ });
+
+ // Timeouts that occur while a test is in the "cleanup" phase
+ // indicate that some global state was not properly reverted. This
+ // invalidates the overall test execution, so the timeout should be
+ // reported as an error and cancel the execution of any remaining
+ // tests.
+ if (test_in_cleanup) {
+ this.status.status = this.status.ERROR;
+ this.status.message = "Timeout while running cleanup for " +
+ "test named \"" + test_in_cleanup.name + "\".";
+ tests.status.stack = null;
+ } else {
+ this.status.status = this.status.TIMEOUT;
+ }
}
+
this.complete();
};
};
Tests.prototype.all_done = function() {
- return (this.tests.length > 0 && test_environment.all_loaded &&
- this.num_pending === 0 && !this.wait_for_finish &&
+ return this.tests.length > 0 && test_environment.all_loaded &&
+ (this.num_pending === 0 || this.is_aborted) && !this.wait_for_finish &&
!this.processing_callbacks &&
- !this.pending_workers.some(function(w) { return w.running; }));
+ !this.pending_remotes.some(function(w) { return w.running; });
};
Tests.prototype.start = function() {
Tests.prototype.result = function(test)
{
- if (this.phase > this.phases.HAVE_RESULTS) {
- return;
+ // If the harness has already transitioned beyond the `HAVE_RESULTS`
+ // phase, subsequent tests should not cause it to revert.
+ if (this.phase <= this.phases.HAVE_RESULTS) {
+ this.phase = this.phases.HAVE_RESULTS;
}
- this.phase = this.phases.HAVE_RESULTS;
this.num_pending--;
this.notify_result(test);
};
if (this.phase === this.phases.COMPLETE) {
return;
}
- this.phase = this.phases.COMPLETE;
var this_obj = this;
- this.tests.forEach(
- function(x)
- {
- if (x.phase < x.phases.COMPLETE) {
- this_obj.notify_result(x);
- x.cleanup();
- x.phase = x.phases.COMPLETE;
- }
- }
- );
- this.notify_complete();
+ var all_complete = function() {
+ this_obj.phase = this_obj.phases.COMPLETE;
+ this_obj.notify_complete();
+ };
+ var incomplete = filter(this.tests,
+ function(test) {
+ return test.phase < test.phases.COMPLETE;
+ });
+
+ /**
+ * To preserve legacy behavior, overall test completion must be
+ * signaled synchronously.
+ */
+ if (incomplete.length === 0) {
+ all_complete();
+ return;
+ }
+
+ all_async(incomplete,
+ function(test, testDone)
+ {
+ if (test.phase === test.phases.INITIAL) {
+ test.phase = test.phases.COMPLETE;
+ testDone();
+ } else {
+ add_test_done_callback(test, testDone);
+ test.cleanup();
+ }
+ },
+ all_complete);
+ };
+
+ Tests.prototype.set_assert = function(assert_name, args) {
+ this.asserts_run.push(new AssertRecord(this.current_test, assert_name, args))
+ }
+
+ Tests.prototype.set_assert_status = function(status, stack) {
+ let assert_record = this.asserts_run[this.asserts_run.length - 1];
+ assert_record.status = status;
+ assert_record.stack = stack;
+ }
+
+ /**
+ * Update the harness status to reflect an unrecoverable harness error that
+ * should cancel all further testing. Update all previously-defined tests
+ * which have not yet started to indicate that they will not be executed.
+ */
+ Tests.prototype.abort = function() {
+ this.status.status = this.status.ERROR;
+ this.is_aborted = true;
+
+ forEach(this.tests,
+ function(test) {
+ if (test.phase === test.phases.INITIAL) {
+ test.phase = test.phases.COMPLETE;
+ }
+ });
+ };
+
+ /*
+ * Determine if any tests share the same `name` property. Return an array
+ * containing the names of any such duplicates.
+ */
+ Tests.prototype.find_duplicates = function() {
+ var names = Object.create(null);
+ var duplicates = [];
+
+ forEach (this.tests,
+ function(test)
+ {
+ if (test.name in names && duplicates.indexOf(test.name) === -1) {
+ duplicates.push(test.name);
+ }
+ names[test.name] = true;
+ });
+
+ return duplicates;
};
+ function code_unit_str(char) {
+ return 'U+' + char.charCodeAt(0).toString(16);
+ }
+
+ function sanitize_unpaired_surrogates(str) {
+ return str.replace(
+ /([\ud800-\udbff]+)(?![\udc00-\udfff])|(^|[^\ud800-\udbff])([\udc00-\udfff]+)/g,
+ function(_, low, prefix, high) {
+ var output = prefix || ""; // prefix may be undefined
+ var string = low || high; // only one of these alternates can match
+ for (var i = 0; i < string.length; i++) {
+ output += code_unit_str(string[i]);
+ }
+ return output;
+ });
+ }
+
+ function sanitize_all_unpaired_surrogates(tests) {
+ forEach (tests,
+ function (test)
+ {
+ var sanitized = sanitize_unpaired_surrogates(test.name);
+
+ if (test.name !== sanitized) {
+ test.name = sanitized;
+ delete test._structured_clone;
+ }
+ });
+ }
+
Tests.prototype.notify_complete = function() {
var this_obj = this;
+ var duplicates;
+
if (this.status.status === null) {
- this.status.status = this.status.OK;
+ duplicates = this.find_duplicates();
+
+ // Some transports adhere to UTF-8's restriction on unpaired
+ // surrogates. Sanitize the titles so that the results can be
+ // consistently sent via all transports.
+ sanitize_all_unpaired_surrogates(this.tests);
+
+ // Test names are presumed to be unique within test files--this
+ // allows consumers to use them for identification purposes.
+ // Duplicated names violate this expectation and should therefore
+ // be reported as an error.
+ if (duplicates.length) {
+ this.status.status = this.status.ERROR;
+ this.status.message =
+ duplicates.length + ' duplicate test name' +
+ (duplicates.length > 1 ? 's' : '') + ': "' +
+ duplicates.join('", "') + '"';
+ } else {
+ this.status.status = this.status.OK;
+ }
}
forEach (this.all_done_callbacks,
function(callback)
{
- callback(this_obj.tests, this_obj.status);
+ callback(this_obj.tests, this_obj.status, this_obj.asserts_run);
});
};
+ /*
+ * Constructs a RemoteContext that tracks tests from a specific worker.
+ */
+ Tests.prototype.create_remote_worker = function(worker) {
+ var message_port;
+
+ if (is_service_worker(worker)) {
+ message_port = navigator.serviceWorker;
+ worker.postMessage({type: "connect"});
+ } else if (is_shared_worker(worker)) {
+ message_port = worker.port;
+ message_port.start();
+ } else {
+ message_port = worker;
+ }
+
+ return new RemoteContext(worker, message_port);
+ };
+
+ /*
+ * Constructs a RemoteContext that tracks tests from a specific window.
+ */
+ Tests.prototype.create_remote_window = function(remote) {
+ remote.postMessage({type: "getmessages"}, "*");
+ return new RemoteContext(
+ remote,
+ window,
+ function(msg) {
+ return msg.source === remote;
+ }
+ );
+ };
+
Tests.prototype.fetch_tests_from_worker = function(worker) {
if (this.phase >= this.phases.COMPLETE) {
return;
}
- this.pending_workers.push(new RemoteWorker(worker));
+ var remoteContext = this.create_remote_worker(worker);
+ this.pending_remotes.push(remoteContext);
+ return remoteContext.done;
};
function fetch_tests_from_worker(port) {
- tests.fetch_tests_from_worker(port);
+ return tests.fetch_tests_from_worker(port);
}
expose(fetch_tests_from_worker, 'fetch_tests_from_worker');
+ Tests.prototype.fetch_tests_from_window = function(remote) {
+ if (this.phase >= this.phases.COMPLETE) {
+ return;
+ }
+
+ this.pending_remotes.push(this.create_remote_window(remote));
+ };
+
+ function fetch_tests_from_window(window) {
+ tests.fetch_tests_from_window(window);
+ }
+ expose(fetch_tests_from_window, 'fetch_tests_from_window');
+
function timeout() {
if (tests.timeout_length === null) {
tests.timeout();
tests.test_state_callbacks.push(callback);
}
- function add_result_callback(callback)
- {
+ function add_result_callback(callback) {
tests.test_done_callbacks.push(callback);
}
- function add_completion_callback(callback)
- {
- tests.all_done_callbacks.push(callback);
+ function add_completion_callback(callback) {
+ tests.all_done_callbacks.push(callback);
}
expose(add_start_callback, 'add_start_callback');
expose(add_result_callback, 'add_result_callback');
expose(add_completion_callback, 'add_completion_callback');
+ function remove(array, item) {
+ var index = array.indexOf(item);
+ if (index > -1) {
+ array.splice(index, 1);
+ }
+ }
+
+ function remove_start_callback(callback) {
+ remove(tests.start_callbacks, callback);
+ }
+
+ function remove_test_state_callback(callback) {
+ remove(tests.test_state_callbacks, callback);
+ }
+
+ function remove_result_callback(callback) {
+ remove(tests.test_done_callbacks, callback);
+ }
+
+ function remove_completion_callback(callback) {
+ remove(tests.all_done_callbacks, callback);
+ }
+
/*
* Output listener
*/
Output.prototype.resolve_log = function() {
var output_document;
+ if (this.output_node) {
+ return;
+ }
if (typeof this.output_document === "function") {
output_document = this.output_document.apply(undefined);
} else {
}
var node = output_document.getElementById("log");
if (!node) {
- if (!document.body || document.readyState == "loading") {
+ if (output_document.readyState === "loading") {
return;
}
- node = output_document.createElement("div");
+ node = output_document.createElementNS("http://www.w3.org/1999/xhtml", "div");
node.id = "log";
- output_document.body.appendChild(node);
+ if (output_document.body) {
+ output_document.body.appendChild(node);
+ } else {
+ var root = output_document.documentElement;
+ var is_html = (root &&
+ root.namespaceURI == "http://www.w3.org/1999/xhtml" &&
+ root.localName == "html");
+ var is_svg = (output_document.defaultView &&
+ "SVGSVGElement" in output_document.defaultView &&
+ root instanceof output_document.defaultView.SVGSVGElement);
+ if (is_svg) {
+ var foreignObject = output_document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
+ foreignObject.setAttribute("width", "100%");
+ foreignObject.setAttribute("height", "100%");
+ root.appendChild(foreignObject);
+ foreignObject.appendChild(node);
+ } else if (is_html) {
+ root.appendChild(output_document.createElementNS("http://www.w3.org/1999/xhtml", "body"))
+ .appendChild(node);
+ } else {
+ root.appendChild(node);
+ }
+ }
}
this.output_document = output_document;
this.output_node = node;
if (this.phase < this.STARTED) {
this.init();
}
- if (!this.enabled) {
+ if (!this.enabled || this.phase === this.COMPLETE) {
return;
}
+ this.resolve_log();
if (this.phase < this.HAVE_RESULTS) {
- this.resolve_log();
this.phase = this.HAVE_RESULTS;
}
var done_count = tests.tests.length - tests.num_pending;
- if (this.output_node) {
+ if (this.output_node && !tests.hide_test_state) {
if (done_count < 100 ||
(done_count < 1000 && done_count % 100 === 0) ||
done_count % 1000 === 0) {
}
};
- Output.prototype.show_results = function (tests, harness_status) {
+ Output.prototype.show_results = function (tests, harness_status, asserts_run) {
if (this.phase >= this.COMPLETE) {
return;
}
log.removeChild(log.lastChild);
}
- var script_prefix = null;
- var scripts = document.getElementsByTagName("script");
- for (var i = 0; i < scripts.length; i++) {
- var src;
- if (scripts[i].src) {
- src = scripts[i].src;
- } else if (scripts[i].href) {
- //SVG case
- src = scripts[i].href.baseVal;
- }
-
- var matches = src && src.match(/^(.*\/|)testharness\.js$/);
- if (matches) {
- script_prefix = matches[1];
- break;
- }
- }
-
- if (script_prefix !== null) {
- var stylesheet = output_document.createElementNS(xhtml_ns, "link");
- stylesheet.setAttribute("rel", "stylesheet");
- stylesheet.setAttribute("href", script_prefix + "testharness.css");
- var heads = output_document.getElementsByTagName("head");
- if (heads.length) {
- heads[0].appendChild(stylesheet);
- }
+ var stylesheet = output_document.createElementNS(xhtml_ns, "style");
+ stylesheet.textContent = stylesheetContent;
+ var heads = output_document.getElementsByTagName("head");
+ if (heads.length) {
+ heads[0].appendChild(stylesheet);
}
- var status_text_harness = {};
- status_text_harness[harness_status.OK] = "OK";
- status_text_harness[harness_status.ERROR] = "Error";
- status_text_harness[harness_status.TIMEOUT] = "Timeout";
-
- var status_text = {};
- status_text[Test.prototype.PASS] = "Pass";
- status_text[Test.prototype.FAIL] = "Fail";
- status_text[Test.prototype.TIMEOUT] = "Timeout";
- status_text[Test.prototype.NOTRUN] = "Not Run";
-
var status_number = {};
forEach(tests,
function(test) {
- var status = status_text[test.status];
+ var status = test.format_status();
if (status_number.hasOwnProperty(status)) {
status_number[status] += 1;
} else {
["h2", {}, "Summary"],
function()
{
-
- var status = status_text_harness[harness_status.status];
+ var status = harness_status.format_status();
var rv = [["section", {},
["p", {},
"Harness status: ",
if (harness_status.status === harness_status.ERROR) {
rv[0].push(["pre", {}, harness_status.message]);
+ if (harness_status.stack) {
+ rv[0].push(["pre", {}, harness_status.stack]);
+ }
}
return rv;
},
function() {
var rv = [["div", {}]];
var i = 0;
- while (status_text.hasOwnProperty(i)) {
- if (status_number.hasOwnProperty(status_text[i])) {
- var status = status_text[i];
- rv[0].push(["div", {"class":status_class(status)},
+ while (Test.prototype.status_formats.hasOwnProperty(i)) {
+ if (status_number.hasOwnProperty(Test.prototype.status_formats[i])) {
+ var status = Test.prototype.status_formats[i];
+ rv[0].push(["div", {},
["label", {},
["input", {type:"checkbox", checked:"checked"}],
- status_number[status] + " " + status]]);
+ status_number[status] + " ",
+ ["span", {"class":status_class(status)}, status]]]);
}
i++;
}
e.preventDefault();
return;
}
- var result_class = element.parentNode.getAttribute("class");
+ var result_class = element.querySelector("span[class]").getAttribute("class");
var style_element = output_document.querySelector("style#hide-" + result_class);
var input_element = element.querySelector("input");
if (!style_element && !input_element.checked) {
style_element = output_document.createElementNS(xhtml_ns, "style");
style_element.id = "hide-" + result_class;
- style_element.textContent = "table#results > tbody > tr."+result_class+"{display:none}";
+ style_element.textContent = "table#results > tbody > tr.overall-"+result_class+"{display:none}";
output_document.body.appendChild(style_element);
} else if (style_element && input_element.checked) {
style_element.parentNode.removeChild(style_element);
return '';
}
+ var asserts_run_by_test = new Map();
+ asserts_run.forEach(assert => {
+ if (!asserts_run_by_test.has(assert.test)) {
+ asserts_run_by_test.set(assert.test, []);
+ }
+ asserts_run_by_test.get(assert.test).push(assert);
+ });
+
+ function get_asserts_output(test) {
+ var asserts = asserts_run_by_test.get(test);
+ if (!asserts) {
+ return "No asserts ran";
+ }
+ rv = "<table>";
+ rv += asserts.map(assert => {
+ var output_fn = "<strong>" + escape_html(assert.assert_name) + "</strong>(";
+ var prefix_len = output_fn.length;
+ var output_args = assert.args;
+ var output_len = output_args.reduce((prev, current) => prev+current, prefix_len);
+ if (output_len[output_len.length - 1] > 50) {
+ output_args = output_args.map((x, i) =>
+ (i > 0 ? " ".repeat(prefix_len) : "" )+ x + (i < output_args.length - 1 ? ",\n" : ""));
+ } else {
+ output_args = output_args.map((x, i) => x + (i < output_args.length - 1 ? ", " : ""));
+ }
+ output_fn += escape_html(output_args.join(""));
+ output_fn += ')';
+ var output_location;
+ if (assert.stack) {
+ output_location = assert.stack.split("\n", 1)[0].replace(/@?\w+:\/\/[^ "\/]+(?::\d+)?/g, " ");
+ }
+ return "<tr class='overall-" +
+ status_class(Test.prototype.status_formats[assert.status]) + "'>" +
+ "<td class='" +
+ status_class(Test.prototype.status_formats[assert.status]) + "'>" +
+ Test.prototype.status_formats[assert.status] + "</td>" +
+ "<td><pre>" +
+ output_fn +
+ (output_location ? "\n" + escape_html(output_location) : "") +
+ "</pre></td></tr>";
+ }
+ ).join("\n");
+ rv += "</table>";
+ return rv;
+ }
+
log.appendChild(document.createElementNS(xhtml_ns, "section"));
var assertions = has_assertions();
var html = "<h2>Details</h2><table id='results' " + (assertions ? "class='assertions'" : "" ) + ">" +
"<th>Message</th></tr></thead>" +
"<tbody>";
for (var i = 0; i < tests.length; i++) {
- html += '<tr class="' +
- escape_html(status_class(status_text[tests[i].status])) +
- '"><td>' +
- escape_html(status_text[tests[i].status]) +
+ var test = tests[i];
+ html += '<tr class="overall-' +
+ status_class(test.format_status()) +
+ '">' +
+ '<td class="' +
+ status_class(test.format_status()) +
+ '">' +
+ test.format_status() +
"</td><td>" +
- escape_html(tests[i].name) +
+ escape_html(test.name) +
"</td><td>" +
- (assertions ? escape_html(get_assertion(tests[i])) + "</td><td>" : "") +
- escape_html(tests[i].message ? tests[i].message : " ") +
- "</td></tr>";
+ (assertions ? escape_html(get_assertion(test)) + "</td><td>" : "") +
+ escape_html(test.message ? tests[i].message : " ") +
+ (tests[i].stack ? "<pre>" +
+ escape_html(tests[i].stack) +
+ "</pre>": "");
+ if (!(test instanceof RemoteTest)) {
+ html += "<details><summary>Asserts run</summary>" + get_asserts_output(test) + "</details>"
+ }
+ html += "</td></tr>";
}
html += "</tbody></table>";
try {
/*
* Template code
*
- * A template is just a javascript structure. An element is represented as:
+ * A template is just a JavaScript structure. An element is represented as:
*
* [tag_name, {attr_name:attr_value}, child1, child2]
*
}
/*
- * Utility funcions
+ * Utility functions
*/
function assert(expected_true, function_name, description, error, substitutions)
{
- if (tests.tests.length === 0) {
- tests.set_file_is_test();
- }
if (expected_true !== true) {
var msg = make_message(function_name, description,
error, substitutions);
function AssertionError(message)
{
+ if (typeof message == "string") {
+ message = sanitize_unpaired_surrogates(message);
+ }
this.message = message;
+ this.stack = get_stack();
}
+ expose(AssertionError, "AssertionError");
- AssertionError.prototype.toString = function() {
- return this.message;
- };
+ AssertionError.prototype = Object.create(Error.prototype);
+
+ const get_stack = function() {
+ var stack = new Error().stack;
+ // IE11 does not initialize 'Error.stack' until the object is thrown.
+ if (!stack) {
+ try {
+ throw new Error();
+ } catch (e) {
+ stack = e.stack;
+ }
+ }
+
+ // 'Error.stack' is not supported in all browsers/versions
+ if (!stack) {
+ return "(Stack trace unavailable)";
+ }
+
+ var lines = stack.split("\n");
+
+ // Create a pattern to match stack frames originating within testharness.js. These include the
+ // script URL, followed by the line/col (e.g., '/resources/testharness.js:120:21').
+ // Escape the URL per http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+ // in case it contains RegExp characters.
+ var script_url = get_script_url();
+ var re_text = script_url ? script_url.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') : "\\btestharness.js";
+ var re = new RegExp(re_text + ":\\d+:\\d+");
+
+ // Some browsers include a preamble that specifies the type of the error object. Skip this by
+ // advancing until we find the first stack frame originating from testharness.js.
+ var i = 0;
+ while (!re.test(lines[i]) && i < lines.length) {
+ i++;
+ }
+
+ // Then skip the top frames originating from testharness.js to begin the stack at the test code.
+ while (re.test(lines[i]) && i < lines.length) {
+ i++;
+ }
+
+ // Paranoid check that we didn't skip all frames. If so, return the original stack unmodified.
+ if (i >= lines.length) {
+ return stack;
+ }
+
+ return lines.slice(i).join("\n");
+ }
+
+ function OptionalFeatureUnsupportedError(message)
+ {
+ AssertionError.call(this, message);
+ }
+ OptionalFeatureUnsupportedError.prototype = Object.create(AssertionError.prototype);
+ expose(OptionalFeatureUnsupportedError, "OptionalFeatureUnsupportedError");
function make_message(function_name, description, error, substitutions)
{
Array.prototype.push.apply(array, items);
}
- function forEach (array, callback, thisObj)
+ function forEach(array, callback, thisObj)
{
for (var i = 0; i < array.length; i++) {
if (array.hasOwnProperty(i)) {
}
}
+ /**
+ * Immediately invoke a "iteratee" function with a series of values in
+ * parallel and invoke a final "done" function when all of the "iteratee"
+ * invocations have signaled completion.
+ *
+ * If all callbacks complete synchronously (or if no callbacks are
+ * specified), the `done_callback` will be invoked synchronously. It is the
+ * responsibility of the caller to ensure asynchronicity in cases where
+ * that is desired.
+ *
+ * @param {array} value Zero or more values to use in the invocation of
+ * `iter_callback`
+ * @param {function} iter_callback A function that will be invoked once for
+ * each of the provided `values`. Two
+ * arguments will be available in each
+ * invocation: the value from `values` and
+ * a function that must be invoked to
+ * signal completion
+ * @param {function} done_callback A function that will be invoked after
+ * all operations initiated by the
+ * `iter_callback` function have signaled
+ * completion
+ */
+ function all_async(values, iter_callback, done_callback)
+ {
+ var remaining = values.length;
+
+ if (remaining === 0) {
+ done_callback();
+ }
+
+ forEach(values,
+ function(element) {
+ var invoked = false;
+ var elDone = function() {
+ if (invoked) {
+ return;
+ }
+
+ invoked = true;
+ remaining -= 1;
+
+ if (remaining === 0) {
+ done_callback();
+ }
+ };
+
+ iter_callback(element, elDone);
+ });
+ }
+
function merge(a,b)
{
var rv = {};
function expose(object, name)
{
var components = name.split(".");
- var target = test_environment.global_scope();
+ var target = global_scope;
for (var i = 0; i < components.length - 1; i++) {
if (!(components[i] in target)) {
target[components[i]] = {};
}
}
+ /** Returns the 'src' URL of the first <script> tag in the page to include the file 'testharness.js'. */
+ function get_script_url()
+ {
+ if (!('document' in global_scope)) {
+ return undefined;
+ }
+
+ var scripts = document.getElementsByTagName("script");
+ for (var i = 0; i < scripts.length; i++) {
+ var src;
+ if (scripts[i].src) {
+ src = scripts[i].src;
+ } else if (scripts[i].href) {
+ //SVG case
+ src = scripts[i].href.baseVal;
+ }
+
+ var matches = src && src.match(/^(.*\/|)testharness\.js$/);
+ if (matches) {
+ return src;
+ }
+ }
+ return undefined;
+ }
+
+ /** Returns the <title> or filename or "Untitled" */
+ function get_title()
+ {
+ if ('document' in global_scope) {
+ //Don't use document.title to work around an Opera/Presto bug in XHTML documents
+ var title = document.getElementsByTagName("title")[0];
+ if (title && title.firstChild && title.firstChild.data) {
+ return title.firstChild.data;
+ }
+ }
+ if ('META_TITLE' in global_scope && META_TITLE) {
+ return META_TITLE;
+ }
+ if ('location' in global_scope) {
+ return location.pathname.substring(location.pathname.lastIndexOf('/') + 1, location.pathname.indexOf('.'));
+ }
+ return "Untitled";
+ }
+
function supports_post_message(w)
{
var supports;
var type;
- // Given IE implements postMessage across nested iframes but not across
+ // Given IE implements postMessage across nested iframes but not across
// windows or tabs, you can't infer cross-origin communication from the presence
// of postMessage on the current window object only.
//
// Touching the postMessage prop on a window can throw if the window is
// not from the same origin AND post message is not supported in that
// browser. So just doing an existence test here won't do, you also need
- // to wrap it in a try..cacth block.
+ // to wrap it in a try..catch block.
try {
type = typeof w.postMessage;
if (type === "function") {
var tests = new Tests();
- addEventListener("error", function(e) {
- if (tests.file_is_test) {
- var test = tests.tests[0];
- if (test.phase >= test.phases.HAS_RESULT) {
- return;
+ if (global_scope.addEventListener) {
+ var error_handler = function(error, message, stack) {
+ var optional_unsupported = error instanceof OptionalFeatureUnsupportedError;
+ if (tests.file_is_test) {
+ var test = tests.tests[0];
+ if (test.phase >= test.phases.HAS_RESULT) {
+ return;
+ }
+ var status = optional_unsupported ? test.PRECONDITION_FAILED : test.FAIL;
+ test.set_status(status, message, stack);
+ test.phase = test.phases.HAS_RESULT;
+ } else if (!tests.allow_uncaught_exception) {
+ var status = optional_unsupported ? tests.status.PRECONDITION_FAILED : tests.status.ERROR;
+ tests.status.status = status;
+ tests.status.message = message;
+ tests.status.stack = stack;
}
+
+ // Do not transition to the "complete" phase if the test has been
+ // configured to allow uncaught exceptions. This gives the test an
+ // opportunity to define subtests based on the exception reporting
+ // behavior.
+ if (!tests.allow_uncaught_exception) {
+ done();
+ }
+ };
+
+ addEventListener("error", function(e) {
var message = e.message;
- test.set_status(test.FAIL, message);
- test.phase = test.phases.HAS_RESULT;
- test.done();
- done();
- } else if (!tests.allow_uncaught_exception) {
- tests.status.status = tests.status.ERROR;
- tests.status.message = e.message;
- }
- });
+ var stack;
+ if (e.error && e.error.stack) {
+ stack = e.error.stack;
+ } else {
+ stack = e.filename + ":" + e.lineno + ":" + e.colno;
+ }
+ error_handler(e.error, message, stack);
+ }, false);
+
+ addEventListener("unhandledrejection", function(e) {
+ var message;
+ if (e.reason && e.reason.message) {
+ message = "Unhandled rejection: " + e.reason.message;
+ } else {
+ message = "Unhandled rejection";
+ }
+ var stack;
+ if (e.reason && e.reason.stack) {
+ stack = e.reason.stack;
+ }
+ error_handler(e.reason, message, stack);
+ }, false);
+ }
test_environment.on_tests_ready();
-})();
+ /**
+ * Stylesheet
+ */
+ var stylesheetContent = "\
+html {\
+ font-family:DejaVu Sans, Bitstream Vera Sans, Arial, Sans;\
+}\
+\
+#log .warning,\
+#log .warning a {\
+ color: black;\
+ background: yellow;\
+}\
+\
+#log .error,\
+#log .error a {\
+ color: white;\
+ background: red;\
+}\
+\
+section#summary {\
+ margin-bottom:1em;\
+}\
+\
+table#results {\
+ border-collapse:collapse;\
+ table-layout:fixed;\
+ width:100%;\
+}\
+\
+table#results > thead > tr > th:first-child,\
+table#results > tbody > tr > td:first-child {\
+ width:8em;\
+}\
+\
+table#results > thead > tr > th:last-child,\
+table#results > thead > tr > td:last-child {\
+ width:50%;\
+}\
+\
+table#results.assertions > thead > tr > th:last-child,\
+table#results.assertions > tbody > tr > td:last-child {\
+ width:35%;\
+}\
+\
+table#results > thead > > tr > th {\
+ padding:0;\
+ padding-bottom:0.5em;\
+ border-bottom:medium solid black;\
+}\
+\
+table#results > tbody > tr> td {\
+ padding:1em;\
+ padding-bottom:0.5em;\
+ border-bottom:thin solid black;\
+}\
+\
+.pass {\
+ color:green;\
+}\
+\
+.fail {\
+ color:red;\
+}\
+\
+tr.timeout {\
+ color:red;\
+}\
+\
+tr.notrun {\
+ color:blue;\
+}\
+\
+tr.optionalunsupported {\
+ color:blue;\
+}\
+\
+.ok {\
+ color:green;\
+}\
+\
+.error {\
+ color:red;\
+}\
+\
+.pass, .fail, .timeout, .notrun, .optionalunsupported .ok, .timeout, .error {\
+ font-variant:small-caps;\
+}\
+\
+table#results span {\
+ display:block;\
+}\
+\
+table#results span.expected {\
+ font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;\
+ white-space:pre;\
+}\
+\
+table#results span.actual {\
+ font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace;\
+ white-space:pre;\
+}\
+";
+
+})(self);
// vim: set expandtab shiftwidth=4 tabstop=4:
-/*global add_completion_callback, setup */
+/* global add_completion_callback */
+/* global setup */
+
/*
- * This file is intended for vendors to implement
- * code needed to integrate testharness.js tests with their own test systems.
- *
- * The default implementation extracts metadata from the tests and validates
- * it against the cached version that should be present in the test source
- * file. If the cache is not found or is out of sync, source code suitable for
- * caching the metadata is optionally generated.
- *
- * The cached metadata is present for extraction by test processing tools that
- * are unable to execute javascript.
- *
- * Metadata is attached to tests via the properties parameter in the test
- * constructor. See testharness.js for details.
+ * This file is intended for vendors to implement code needed to integrate
+ * testharness.js tests with their own test systems.
*
* Typically test system integration will attach callbacks when each test has
* run, using add_result_callback(callback(test)), or when the whole test file
* parameters they are called with see testharness.js
*/
+function dump_test_results(tests, status) {
+ var results_element = document.createElement("script");
+ results_element.type = "text/json";
+ results_element.id = "__testharness__results__";
+ var test_results = tests.map(function(x) {
+ return {name:x.name, status:x.status, message:x.message, stack:x.stack}
+ });
+ var data = {test:window.location.href,
+ tests:test_results,
+ status: status.status,
+ message: status.message,
+ stack: status.stack};
+ results_element.textContent = JSON.stringify(data);
+
+ // To avoid a HierarchyRequestError with XML documents, ensure that 'results_element'
+ // is inserted at a location that results in a valid document.
+ var parent = document.body
+ ? document.body // <body> is required in XHTML documents
+ : document.documentElement; // fallback for optional <body> in HTML5, SVG, etc.
+
+ parent.appendChild(results_element);
+}
-
-var metadata_generator = {
-
- currentMetadata: {},
- cachedMetadata: false,
- metadataProperties: ['help', 'assert', 'author'],
-
- error: function(message) {
- var messageElement = document.createElement('p');
- messageElement.setAttribute('class', 'error');
- this.appendText(messageElement, message);
-
- var summary = document.getElementById('summary');
- if (summary) {
- summary.parentNode.insertBefore(messageElement, summary);
- }
- else {
- document.body.appendChild(messageElement);
- }
- },
-
- /**
- * Ensure property value has contact information
- */
- validateContact: function(test, propertyName) {
- var result = true;
- var value = test.properties[propertyName];
- var values = Array.isArray(value) ? value : [value];
- for (var index = 0; index < values.length; index++) {
- value = values[index];
- var re = /(\S+)(\s*)<(.*)>(.*)/;
- if (! re.test(value)) {
- re = /(\S+)(\s+)(http[s]?:\/\/)(.*)/;
- if (! re.test(value)) {
- this.error('Metadata property "' + propertyName +
- '" for test: "' + test.name +
- '" must have name and contact information ' +
- '("name <email>" or "name http(s)://")');
- result = false;
- }
- }
- }
- return result;
- },
-
- /**
- * Extract metadata from test object
- */
- extractFromTest: function(test) {
- var testMetadata = {};
- // filter out metadata from other properties in test
- for (var metaIndex = 0; metaIndex < this.metadataProperties.length;
- metaIndex++) {
- var meta = this.metadataProperties[metaIndex];
- if (test.properties.hasOwnProperty(meta)) {
- if ('author' == meta) {
- this.validateContact(test, meta);
- }
- testMetadata[meta] = test.properties[meta];
- }
- }
- return testMetadata;
- },
-
- /**
- * Compare cached metadata to extracted metadata
- */
- validateCache: function() {
- for (var testName in this.currentMetadata) {
- if (! this.cachedMetadata.hasOwnProperty(testName)) {
- return false;
- }
- var testMetadata = this.currentMetadata[testName];
- var cachedTestMetadata = this.cachedMetadata[testName];
- delete this.cachedMetadata[testName];
-
- for (var metaIndex = 0; metaIndex < this.metadataProperties.length;
- metaIndex++) {
- var meta = this.metadataProperties[metaIndex];
- if (cachedTestMetadata.hasOwnProperty(meta) &&
- testMetadata.hasOwnProperty(meta)) {
- if (Array.isArray(cachedTestMetadata[meta])) {
- if (! Array.isArray(testMetadata[meta])) {
- return false;
- }
- if (cachedTestMetadata[meta].length ==
- testMetadata[meta].length) {
- for (var index = 0;
- index < cachedTestMetadata[meta].length;
- index++) {
- if (cachedTestMetadata[meta][index] !=
- testMetadata[meta][index]) {
- return false;
- }
- }
- }
- else {
- return false;
- }
- }
- else {
- if (Array.isArray(testMetadata[meta])) {
- return false;
- }
- if (cachedTestMetadata[meta] != testMetadata[meta]) {
- return false;
- }
- }
- }
- else if (cachedTestMetadata.hasOwnProperty(meta) ||
- testMetadata.hasOwnProperty(meta)) {
- return false;
- }
- }
- }
- for (var testName in this.cachedMetadata) {
- return false;
- }
- return true;
- },
-
- appendText: function(elemement, text) {
- elemement.appendChild(document.createTextNode(text));
- },
-
- jsonifyArray: function(arrayValue, indent) {
- var output = '[';
-
- if (1 == arrayValue.length) {
- output += JSON.stringify(arrayValue[0]);
- }
- else {
- for (var index = 0; index < arrayValue.length; index++) {
- if (0 < index) {
- output += ',\n ' + indent;
- }
- output += JSON.stringify(arrayValue[index]);
- }
- }
- output += ']';
- return output;
- },
-
- jsonifyObject: function(objectValue, indent) {
- var output = '{';
- var value;
-
- var count = 0;
- for (var property in objectValue) {
- ++count;
- if (Array.isArray(objectValue[property]) ||
- ('object' == typeof(value))) {
- ++count;
- }
- }
- if (1 == count) {
- for (var property in objectValue) {
- output += ' "' + property + '": ' +
- JSON.stringify(objectValue[property]) +
- ' ';
- }
- }
- else {
- var first = true;
- for (var property in objectValue) {
- if (! first) {
- output += ',';
- }
- first = false;
- output += '\n ' + indent + '"' + property + '": ';
- value = objectValue[property];
- if (Array.isArray(value)) {
- output += this.jsonifyArray(value, indent +
- ' '.substr(0, 5 + property.length));
- }
- else if ('object' == typeof(value)) {
- output += this.jsonifyObject(value, indent + ' ');
- }
- else {
- output += JSON.stringify(value);
- }
- }
- if (1 < output.length) {
- output += '\n' + indent;
- }
- }
- output += '}';
- return output;
- },
-
- /**
- * Generate javascript source code for captured metadata
- * Metadata is in pretty-printed JSON format
- */
- generateSource: function() {
- var source =
- '<script id="metadata_cache">/*\n' +
- this.jsonifyObject(this.currentMetadata, '') + '\n' +
- '*/</script>\n';
- return source;
- },
-
- /**
- * Add element containing metadata source code
- */
- addSourceElement: function(event) {
- var sourceWrapper = document.createElement('div');
- sourceWrapper.setAttribute('id', 'metadata_source');
-
- var instructions = document.createElement('p');
- if (this.cachedMetadata) {
- this.appendText(instructions,
- 'Replace the existing <script id="metadata_cache"> element ' +
- 'in the test\'s <head> with the following:');
- }
- else {
- this.appendText(instructions,
- 'Copy the following into the <head> element of the test ' +
- 'or the test\'s metadata sidecar file:');
- }
- sourceWrapper.appendChild(instructions);
-
- var sourceElement = document.createElement('pre');
- this.appendText(sourceElement, this.generateSource());
-
- sourceWrapper.appendChild(sourceElement);
-
- var messageElement = document.getElementById('metadata_issue');
- messageElement.parentNode.insertBefore(sourceWrapper,
- messageElement.nextSibling);
- messageElement.parentNode.removeChild(messageElement);
-
- (event.preventDefault) ? event.preventDefault() :
- event.returnValue = false;
- },
-
- /**
- * Extract the metadata cache from the cache element if present
- */
- getCachedMetadata: function() {
- var cacheElement = document.getElementById('metadata_cache');
-
- if (cacheElement) {
- var cacheText = cacheElement.firstChild.nodeValue;
- var openBrace = cacheText.indexOf('{');
- var closeBrace = cacheText.lastIndexOf('}');
- if ((-1 < openBrace) && (-1 < closeBrace)) {
- cacheText = cacheText.slice(openBrace, closeBrace + 1);
- try {
- this.cachedMetadata = JSON.parse(cacheText);
- }
- catch (exc) {
- this.cachedMetadata = 'Invalid JSON in Cached metadata. ';
- }
- }
- else {
- this.cachedMetadata = 'Metadata not found in cache element. ';
- }
- }
- },
-
- /**
- * Main entry point, extract metadata from tests, compare to cached version
- * if present.
- * If cache not present or differs from extrated metadata, generate an error
- */
- process: function(tests) {
- for (var index = 0; index < tests.length; index++) {
- var test = tests[index];
- if (this.currentMetadata.hasOwnProperty(test.name)) {
- this.error('Duplicate test name: ' + test.name);
- }
- else {
- this.currentMetadata[test.name] = this.extractFromTest(test);
- }
- }
-
- this.getCachedMetadata();
-
- var message = null;
- var messageClass = 'warning';
- var showSource = false;
-
- if (0 === tests.length) {
- if (this.cachedMetadata) {
- message = 'Cached metadata present but no tests. ';
- }
- }
- else if (1 === tests.length) {
- if (this.cachedMetadata) {
- message = 'Single test files should not have cached metadata. ';
- }
- else {
- var testMetadata = this.currentMetadata[tests[0].name];
- for (var meta in testMetadata) {
- if (testMetadata.hasOwnProperty(meta)) {
- message = 'Single tests should not have metadata. ' +
- 'Move metadata to <head>. ';
- break;
- }
- }
- }
- }
- else {
- if (this.cachedMetadata) {
- messageClass = 'error';
- if ('string' == typeof(this.cachedMetadata)) {
- message = this.cachedMetadata;
- showSource = true;
- }
- else if (! this.validateCache()) {
- message = 'Cached metadata out of sync. ';
- showSource = true;
- }
- }
- }
-
- if (message) {
- var messageElement = document.createElement('p');
- messageElement.setAttribute('id', 'metadata_issue');
- messageElement.setAttribute('class', messageClass);
- this.appendText(messageElement, message);
-
- if (showSource) {
- var link = document.createElement('a');
- this.appendText(link, 'Click for source code.');
- link.setAttribute('href', '#');
- link.setAttribute('onclick',
- 'metadata_generator.addSourceElement(event)');
- messageElement.appendChild(link);
- }
-
- var summary = document.getElementById('summary');
- if (summary) {
- summary.parentNode.insertBefore(messageElement, summary);
- }
- else {
- var log = document.getElementById('log');
- if (log) {
- log.appendChild(messageElement);
- }
- }
- }
- },
-
- setup: function() {
- add_completion_callback(
- function (tests, harness_status) {
- metadata_generator.process(tests, harness_status);
- });
- }
-};
-
-metadata_generator.setup();
+add_completion_callback(dump_test_results);
/* If the parent window has a testharness_properties object,
* we use this to provide the test settings. This is used by the
</specs>
</testcase>
</set>
+ <set name="MediaCapture_streams_IOT" type="js">
+ <capabilities>
+ <capability name="http://tizen.org/feature/profile"><value>COMMON</value></capability>
+ </capabilities>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-api.https" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-api.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-empty-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an empty options parameter" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-empty-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-impossible-constraint.https" purpose="Tests that setting an impossible constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-impossible-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-invalid-facing-mode.https" purpose="Tests that setting an invalid facingMode constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-invalid-facing-mode.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_1" purpose="Test that setting video-only valid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_2" purpose="Test that setting video-only invalid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_3" purpose="Test that setting audio-only valid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_4" purpose="Test that setting audio-only invalid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-optional-constraint.https" purpose="Tests that setting an optional constraint in getUserMedia is handled as optional" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-optional-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-required-constraint-with-ideal-value" purpose="Tests that setting a required constraint with an ideal value in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-required-constraint-with-ideal-value.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-trivial-constraint.https" purpose="Tests that setting a trivial mandatory constraint in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-trivial-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-unknownkey-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an unknown constraint" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-unknownkey-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices-returned-objects.https" purpose="enumerateDevices returns expected objects in case device-info permission is granted" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices.https" purpose="InputDeviceInfo is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_1" purpose="navigator.mediaDevices.getSupportedConstraints exists" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_2" purpose="width is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_3" purpose="height is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_4" purpose="aspectRatio is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_5" purpose="frameRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_6" purpose="facingMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_7" purpose="resizeMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_8" purpose="sampleRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_9" purpose="sampleSize is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_10" purpose="echoCancellation is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_11" purpose="autoGainControl is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_12" purpose="noiseSuppression is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_13" purpose="latency is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_14" purpose="channelCount is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_15" purpose="deviceId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_16" purpose="groupId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_1" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_2" purpose="groupId is correctly supported by getUserMedia() for video devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_3" purpose="groupId is correctly supported by getUserMedia() for audio devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_4" purpose="getUserMedia() supports setting none as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_5" purpose="getUserMedia() supports setting crop-and-scale as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_6" purpose="getUserMedia() fails with exact invalid resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_2" purpose="Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_2" purpose="Test that preload 'none' is ignored for MediaStream used as srcObject for video" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_1" purpose="Tests that a MediaStream can be assigned to a video element with srcObject" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_2" purpose="Tests that a MediaStream assigned to a video element is not seekable" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_3" purpose="Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_4" purpose="Tests that a video element with a MediaStream assigned is not preloaded" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_5" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_6" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_7" purpose="Tests that a media element with an assigned MediaStream reports the played attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_8" purpose="Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_9" purpose="Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-add-audio-track.https" purpose="Camera is not exposed in mediaDevices.enumerateDevices()" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-add-audio-track.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-audio-only.https" purpose="Tests that a MediaStream with exactly one audio track is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-audio-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_1" purpose="Tests that cloning MediaStream objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_2" purpose="Tests that cloning MediaStreamTrack objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-finished-add.https" purpose="Tests that adding a track to an inactive MediaStream is allowed" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-finished-add.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-gettrackid.https" purpose="Tests that MediaStream.getTrackById works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-gettrackid.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-id.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-idl.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-idl.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_1" purpose="Tests that a removal from a MediaStream works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_2" purpose="Test that removal from a MediaStream fires ended on media elements (video first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_3" purpose="Test that removal from a MediaStream fires ended on media elements (audio first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_1" purpose="document.featurePolicy.features should advertise camera." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_2" purpose="document.featurePolicy.features should advertise microphone." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-video-only.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-video-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-audio-is-silence.https" purpose="Tests that a disabled audio track in a MediaStream is rendered as silence" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-video-is-black.https" purpose="Tests that a disabled video track in a MediaStream is rendered as blackness" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_1" purpose="applyConstraints rejects invalid groupID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_2" purpose="applyConstraints accepts invalid ideal groupID, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_3" purpose="applyConstraints rejects attempt to switch device using groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_4" purpose="applyConstraints rejects invalid resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_5" purpose="applyConstraints accepts invalid ideal resizeMode, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-end-manual.https" purpose="Tests that MediaStreamTracks end properly on permission revocation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-end-manual.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_1" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_2" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_3" purpose="Setup audio MediaStreamTrack getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_4" purpose="Setup audio MediaStreamTrack getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_5" purpose="Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_6" purpose="Setup audio MediaStreamTrack getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_7" purpose="Setup audio MediaStreamTrack getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_8" purpose="Setup audio MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_9" purpose="Setup audio MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_10" purpose="Setup video MediaStreamTrack getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_11" purpose="Setup video MediaStreamTrack getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_12" purpose="Setup video MediaStreamTrack getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_13" purpose="Setup video MediaStreamTrack getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_14" purpose="Setup video MediaStreamTrack getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_15" purpose="Setup video MediaStreamTrack getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_16" purpose="Setup video MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_17" purpose="Setup video MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_18" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_19" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_20" purpose="Setup audio InputDeviceInfo getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_21" purpose="Setup audio InputDeviceInfo getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_22" purpose="Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=22</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_23" purpose="Setup audio InputDeviceInfo getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=23</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_24" purpose="Setup audio InputDeviceInfo getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=24</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_25" purpose="Setup audio InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=25</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_26" purpose="Setup audio InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=26</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_27" purpose="Setup video InputDeviceInfo getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=27</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_28" purpose="Setup video InputDeviceInfo getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=28</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_29" purpose="Setup video InputDeviceInfo getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=29</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_30" purpose="Setup video InputDeviceInfo getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=30</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_31" purpose="Setup video InputDeviceInfo getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=31</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_32" purpose="Setup video InputDeviceInfo getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=32</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_33" purpose="Setup video InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=33</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_34" purpose="Setup video InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=34</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_1" purpose="A device can be opened twice and have the same device ID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_2" purpose="A device can be opened twice with different resolutions requested" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_3" purpose="groupId is correctly reported by getSettings() for all input devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_4" purpose="deviceId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_5" purpose="groupId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_6" purpose="sampleRate is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_7" purpose="sampleSize is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_8" purpose="echoCancellation is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_9" purpose="autoGainControl is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_10" purpose="noiseSuppression is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_11" purpose="latency is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_12" purpose="channelCount is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_13" purpose="deviceId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_14" purpose="groupId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_15" purpose="width is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_16" purpose="height is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_17" purpose="aspectRatio is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_18" purpose="frameRate is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_19" purpose="facingMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_20" purpose="resizeMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_21" purpose="Stopped tracks should expose deviceId/groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-id.https" purpose="Tests that distinct mediastream tracks have distinct ids" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-init.https" purpose="getUserMedia({video:true}) creates a stream with a properly initialized video track" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-init.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_1" purpose="The eventInitDict argument is required" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_2" purpose="The eventInitDict's track member is required." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_3" purpose="The MediaStreamTrackEvent instance's track attribute is set." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_1" purpose="navigator.mozGetUserMedia should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_2" purpose="Passing MediaStream to URL.createObjectURL() should throw" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_3" purpose="MediaStream.onactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_4" purpose="MediaStream.oninactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ </set>
+ <set name="MediaCapture_streams_VD_TV" type="js">
+ <capabilities>
+ <capability name="http://tizen.org/feature/profile"><value>TV</value></capability>
+ <capability name="http://tizen.org/feature/microphone"></capability>
+ </capabilities>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-api.https" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-api.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-empty-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an empty options parameter" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-empty-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-impossible-constraint.https" purpose="Tests that setting an impossible constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-impossible-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-invalid-facing-mode.https" purpose="Tests that setting an invalid facingMode constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-invalid-facing-mode.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_1" purpose="Test that setting video-only valid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_2" purpose="Test that setting video-only invalid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_3" purpose="Test that setting audio-only valid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_4" purpose="Test that setting audio-only invalid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-optional-constraint.https" purpose="Tests that setting an optional constraint in getUserMedia is handled as optional" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-optional-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-required-constraint-with-ideal-value" purpose="Tests that setting a required constraint with an ideal value in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-required-constraint-with-ideal-value.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-trivial-constraint.https" purpose="Tests that setting a trivial mandatory constraint in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-trivial-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-unknownkey-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an unknown constraint" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-unknownkey-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices-returned-objects.https" purpose="enumerateDevices returns expected objects in case device-info permission is granted" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices.https" purpose="InputDeviceInfo is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_1" purpose="navigator.mediaDevices.getSupportedConstraints exists" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_2" purpose="width is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_3" purpose="height is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_4" purpose="aspectRatio is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_5" purpose="frameRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_6" purpose="facingMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_7" purpose="resizeMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_8" purpose="sampleRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_9" purpose="sampleSize is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_10" purpose="echoCancellation is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_11" purpose="autoGainControl is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_12" purpose="noiseSuppression is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_13" purpose="latency is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_14" purpose="channelCount is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_15" purpose="deviceId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_16" purpose="groupId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_1" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_2" purpose="groupId is correctly supported by getUserMedia() for video devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_3" purpose="groupId is correctly supported by getUserMedia() for audio devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_4" purpose="getUserMedia() supports setting none as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_5" purpose="getUserMedia() supports setting crop-and-scale as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_6" purpose="getUserMedia() fails with exact invalid resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_2" purpose="Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_2" purpose="Test that preload 'none' is ignored for MediaStream used as srcObject for video" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_1" purpose="Tests that a MediaStream can be assigned to a video element with srcObject" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_2" purpose="Tests that a MediaStream assigned to a video element is not seekable" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_3" purpose="Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_4" purpose="Tests that a video element with a MediaStream assigned is not preloaded" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_5" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_6" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_7" purpose="Tests that a media element with an assigned MediaStream reports the played attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_8" purpose="Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_9" purpose="Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-add-audio-track.https" purpose="Camera is not exposed in mediaDevices.enumerateDevices()" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-add-audio-track.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-audio-only.https" purpose="Tests that a MediaStream with exactly one audio track is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-audio-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_1" purpose="Tests that cloning MediaStream objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_2" purpose="Tests that cloning MediaStreamTrack objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-finished-add.https" purpose="Tests that adding a track to an inactive MediaStream is allowed" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-finished-add.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-gettrackid.https" purpose="Tests that MediaStream.getTrackById works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-gettrackid.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-id.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-idl.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-idl.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_1" purpose="Tests that a removal from a MediaStream works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_2" purpose="Test that removal from a MediaStream fires ended on media elements (video first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_3" purpose="Test that removal from a MediaStream fires ended on media elements (audio first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_1" purpose="document.featurePolicy.features should advertise camera." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_2" purpose="document.featurePolicy.features should advertise microphone." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-video-only.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-video-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-audio-is-silence.https" purpose="Tests that a disabled audio track in a MediaStream is rendered as silence" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-video-is-black.https" purpose="Tests that a disabled video track in a MediaStream is rendered as blackness" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_1" purpose="applyConstraints rejects invalid groupID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_2" purpose="applyConstraints accepts invalid ideal groupID, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_3" purpose="applyConstraints rejects attempt to switch device using groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_4" purpose="applyConstraints rejects invalid resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_5" purpose="applyConstraints accepts invalid ideal resizeMode, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-end-manual.https" purpose="Tests that MediaStreamTracks end properly on permission revocation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-end-manual.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_1" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_2" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_3" purpose="Setup audio MediaStreamTrack getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_4" purpose="Setup audio MediaStreamTrack getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_5" purpose="Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_6" purpose="Setup audio MediaStreamTrack getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_7" purpose="Setup audio MediaStreamTrack getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_8" purpose="Setup audio MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_9" purpose="Setup audio MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_10" purpose="Setup video MediaStreamTrack getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_11" purpose="Setup video MediaStreamTrack getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_12" purpose="Setup video MediaStreamTrack getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_13" purpose="Setup video MediaStreamTrack getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_14" purpose="Setup video MediaStreamTrack getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_15" purpose="Setup video MediaStreamTrack getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_16" purpose="Setup video MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_17" purpose="Setup video MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_18" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_19" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_20" purpose="Setup audio InputDeviceInfo getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_21" purpose="Setup audio InputDeviceInfo getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_22" purpose="Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=22</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_23" purpose="Setup audio InputDeviceInfo getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=23</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_24" purpose="Setup audio InputDeviceInfo getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=24</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_25" purpose="Setup audio InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=25</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_26" purpose="Setup audio InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=26</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_27" purpose="Setup video InputDeviceInfo getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=27</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_28" purpose="Setup video InputDeviceInfo getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=28</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_29" purpose="Setup video InputDeviceInfo getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=29</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_30" purpose="Setup video InputDeviceInfo getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=30</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_31" purpose="Setup video InputDeviceInfo getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=31</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_32" purpose="Setup video InputDeviceInfo getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=32</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_33" purpose="Setup video InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=33</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_34" purpose="Setup video InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=34</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_1" purpose="A device can be opened twice and have the same device ID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_2" purpose="A device can be opened twice with different resolutions requested" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_3" purpose="groupId is correctly reported by getSettings() for all input devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_4" purpose="deviceId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_5" purpose="groupId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_6" purpose="sampleRate is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_7" purpose="sampleSize is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_8" purpose="echoCancellation is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_9" purpose="autoGainControl is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_10" purpose="noiseSuppression is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_11" purpose="latency is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_12" purpose="channelCount is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_13" purpose="deviceId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_14" purpose="groupId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_15" purpose="width is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_16" purpose="height is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_17" purpose="aspectRatio is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_18" purpose="frameRate is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_19" purpose="facingMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_20" purpose="resizeMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_21" purpose="Stopped tracks should expose deviceId/groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-id.https" purpose="Tests that distinct mediastream tracks have distinct ids" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-init.https" purpose="getUserMedia({video:true}) creates a stream with a properly initialized video track" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-init.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_1" purpose="The eventInitDict argument is required" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_2" purpose="The eventInitDict's track member is required." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_3" purpose="The MediaStreamTrackEvent instance's track attribute is set." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_1" purpose="navigator.mozGetUserMedia should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_2" purpose="Passing MediaStream to URL.createObjectURL() should throw" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_3" purpose="MediaStream.onactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_4" purpose="MediaStream.oninactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ </set>
</suite>
</test_definition>
<set name="MediaCapture" type="js">
<capabilities>
<capability name="http://tizen.org/feature/camera"/>
- </capabilities>
- <capabilities>
<capability name="http://tizen.org/feature/microphone"/>
</capabilities>
<testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="HTMLInputElement_exist" purpose="Check if the interface HTMLInputElement exists">
<description>
<test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/capture_reflect.html?total_num=2&amp;locator_key=id&amp;value=2</test_script_entry>
</description>
- </testcase>
- <!-- <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="manual" id="capture_video" purpose="Check if the input will accept an video when capture set to acmcorder">
+ </testcase>
+ </set>
+ <set name="MediaCapture_streams_IOT" type="js">
+ <capabilities>
+ <capability name="http://tizen.org/feature/profile"><value>COMMON</value></capability>
+ </capabilities>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-api.https" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
<description>
- <steps>
- <pre_condition/>
- <step order="1">
- <step_desc>Click the button, allow microphone and camera access, and start to capture a video</step_desc>
- <expected>There appears a video capture screen, there is a way to disable the audio record, and there is a way to stop the video capture.</expected>
- </step>
- </steps>
- <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/capture_video.html</test_script_entry>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-api.https.html</test_script_entry>
</description>
- </testcase>
- <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="manual" id="capture_fallback_file_upload" purpose="Check if the input will can accept an file as expected when accept is set to a MIME type">
- <description>
- <steps>
- <pre_condition/>
- <step order="1">
- <step_desc>Download upload.doc to local, then Select the local upload.doc file.</step_desc>
- <expected>Pass</expected>
- </step>
- </steps>
- <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/capture_fallback_file_upload.html</test_script_entry>
- </description>
- </testcase> -->
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-empty-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an empty options parameter" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-empty-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-impossible-constraint.https" purpose="Tests that setting an impossible constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-impossible-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-invalid-facing-mode.https" purpose="Tests that setting an invalid facingMode constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-invalid-facing-mode.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_1" purpose="Test that setting video-only valid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_2" purpose="Test that setting video-only invalid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_3" purpose="Test that setting audio-only valid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_4" purpose="Test that setting audio-only invalid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-optional-constraint.https" purpose="Tests that setting an optional constraint in getUserMedia is handled as optional" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-optional-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-required-constraint-with-ideal-value" purpose="Tests that setting a required constraint with an ideal value in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-required-constraint-with-ideal-value.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-trivial-constraint.https" purpose="Tests that setting a trivial mandatory constraint in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-trivial-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-unknownkey-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an unknown constraint" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-unknownkey-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices-returned-objects.https" purpose="enumerateDevices returns expected objects in case device-info permission is granted" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices.https" purpose="InputDeviceInfo is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_1" purpose="navigator.mediaDevices.getSupportedConstraints exists" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_2" purpose="width is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_3" purpose="height is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_4" purpose="aspectRatio is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_5" purpose="frameRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_6" purpose="facingMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_7" purpose="resizeMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_8" purpose="sampleRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_9" purpose="sampleSize is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_10" purpose="echoCancellation is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_11" purpose="autoGainControl is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_12" purpose="noiseSuppression is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_13" purpose="latency is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_14" purpose="channelCount is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_15" purpose="deviceId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_16" purpose="groupId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_1" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_2" purpose="groupId is correctly supported by getUserMedia() for video devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_3" purpose="groupId is correctly supported by getUserMedia() for audio devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_4" purpose="getUserMedia() supports setting none as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_5" purpose="getUserMedia() supports setting crop-and-scale as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_6" purpose="getUserMedia() fails with exact invalid resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_2" purpose="Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_2" purpose="Test that preload 'none' is ignored for MediaStream used as srcObject for video" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_1" purpose="Tests that a MediaStream can be assigned to a video element with srcObject" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_2" purpose="Tests that a MediaStream assigned to a video element is not seekable" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_3" purpose="Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_4" purpose="Tests that a video element with a MediaStream assigned is not preloaded" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_5" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_6" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_7" purpose="Tests that a media element with an assigned MediaStream reports the played attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_8" purpose="Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_9" purpose="Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-add-audio-track.https" purpose="Camera is not exposed in mediaDevices.enumerateDevices()" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-add-audio-track.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-audio-only.https" purpose="Tests that a MediaStream with exactly one audio track is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-audio-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_1" purpose="Tests that cloning MediaStream objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_2" purpose="Tests that cloning MediaStreamTrack objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-finished-add.https" purpose="Tests that adding a track to an inactive MediaStream is allowed" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-finished-add.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-gettrackid.https" purpose="Tests that MediaStream.getTrackById works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-gettrackid.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-id.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-idl.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-idl.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_1" purpose="Tests that a removal from a MediaStream works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_2" purpose="Test that removal from a MediaStream fires ended on media elements (video first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_3" purpose="Test that removal from a MediaStream fires ended on media elements (audio first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_1" purpose="document.featurePolicy.features should advertise camera." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_2" purpose="document.featurePolicy.features should advertise microphone." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-video-only.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-video-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-audio-is-silence.https" purpose="Tests that a disabled audio track in a MediaStream is rendered as silence" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-video-is-black.https" purpose="Tests that a disabled video track in a MediaStream is rendered as blackness" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_1" purpose="applyConstraints rejects invalid groupID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_2" purpose="applyConstraints accepts invalid ideal groupID, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_3" purpose="applyConstraints rejects attempt to switch device using groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_4" purpose="applyConstraints rejects invalid resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_5" purpose="applyConstraints accepts invalid ideal resizeMode, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-end-manual.https" purpose="Tests that MediaStreamTracks end properly on permission revocation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-end-manual.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_1" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_2" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_3" purpose="Setup audio MediaStreamTrack getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_4" purpose="Setup audio MediaStreamTrack getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_5" purpose="Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_6" purpose="Setup audio MediaStreamTrack getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_7" purpose="Setup audio MediaStreamTrack getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_8" purpose="Setup audio MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_9" purpose="Setup audio MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_10" purpose="Setup video MediaStreamTrack getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_11" purpose="Setup video MediaStreamTrack getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_12" purpose="Setup video MediaStreamTrack getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_13" purpose="Setup video MediaStreamTrack getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_14" purpose="Setup video MediaStreamTrack getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_15" purpose="Setup video MediaStreamTrack getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_16" purpose="Setup video MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_17" purpose="Setup video MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_18" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_19" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_20" purpose="Setup audio InputDeviceInfo getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_21" purpose="Setup audio InputDeviceInfo getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_22" purpose="Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=22</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_23" purpose="Setup audio InputDeviceInfo getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=23</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_24" purpose="Setup audio InputDeviceInfo getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=24</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_25" purpose="Setup audio InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=25</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_26" purpose="Setup audio InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=26</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_27" purpose="Setup video InputDeviceInfo getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=27</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_28" purpose="Setup video InputDeviceInfo getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=28</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_29" purpose="Setup video InputDeviceInfo getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=29</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_30" purpose="Setup video InputDeviceInfo getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=30</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_31" purpose="Setup video InputDeviceInfo getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=31</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_32" purpose="Setup video InputDeviceInfo getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=32</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_33" purpose="Setup video InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=33</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_34" purpose="Setup video InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=34</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_1" purpose="A device can be opened twice and have the same device ID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_2" purpose="A device can be opened twice with different resolutions requested" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_3" purpose="groupId is correctly reported by getSettings() for all input devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_4" purpose="deviceId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_5" purpose="groupId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_6" purpose="sampleRate is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_7" purpose="sampleSize is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_8" purpose="echoCancellation is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_9" purpose="autoGainControl is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_10" purpose="noiseSuppression is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_11" purpose="latency is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_12" purpose="channelCount is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_13" purpose="deviceId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_14" purpose="groupId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_15" purpose="width is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_16" purpose="height is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_17" purpose="aspectRatio is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_18" purpose="frameRate is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_19" purpose="facingMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_20" purpose="resizeMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_21" purpose="Stopped tracks should expose deviceId/groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-id.https" purpose="Tests that distinct mediastream tracks have distinct ids" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-init.https" purpose="getUserMedia({video:true}) creates a stream with a properly initialized video track" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-init.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_1" purpose="The eventInitDict argument is required" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_2" purpose="The eventInitDict's track member is required." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_3" purpose="The MediaStreamTrackEvent instance's track attribute is set." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_1" purpose="navigator.mozGetUserMedia should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_2" purpose="Passing MediaStream to URL.createObjectURL() should throw" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_3" purpose="MediaStream.onactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_4" purpose="MediaStream.oninactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ </set>
+ <set name="MediaCapture_streams_VD_TV" type="js">
+ <capabilities>
+ <capability name="http://tizen.org/feature/profile"><value>TV</value></capability>
+ <capability name="http://tizen.org/feature/microphone"></capability>
+ </capabilities>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-api.https" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-api.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-empty-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an empty options parameter" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-empty-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-impossible-constraint.https" purpose="Tests that setting an impossible constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-impossible-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-invalid-facing-mode.https" purpose="Tests that setting an invalid facingMode constraint in getUserMedia fails" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-invalid-facing-mode.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_1" purpose="Test that setting video-only valid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_2" purpose="Test that setting video-only invalid constraints inside of audio is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_3" purpose="Test that setting audio-only valid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-non-applicable-constraint.https_4" purpose="Test that setting audio-only invalid constraints inside of video is simply ignored" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-non-applicable-constraint.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-optional-constraint.https" purpose="Tests that setting an optional constraint in getUserMedia is handled as optional" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-optional-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-required-constraint-with-ideal-value" purpose="Tests that setting a required constraint with an ideal value in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-required-constraint-with-ideal-value.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-trivial-constraint.https" purpose="Tests that setting a trivial mandatory constraint in getUserMedia works" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-trivial-constraint.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="GUM-unknownkey-option-param.https" purpose="Tests that getUserMedia is rejected with a TypeError when used with an unknown constraint" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/GUM-unknownkey-option-param.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices-returned-objects.https" purpose="enumerateDevices returns expected objects in case device-info permission is granted" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-enumerateDevices.https" purpose="InputDeviceInfo is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-enumerateDevices.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_1" purpose="navigator.mediaDevices.getSupportedConstraints exists" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_2" purpose="width is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_3" purpose="height is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_4" purpose="aspectRatio is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_5" purpose="frameRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_6" purpose="facingMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_7" purpose="resizeMode is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_8" purpose="sampleRate is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_9" purpose="sampleSize is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_10" purpose="echoCancellation is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_11" purpose="autoGainControl is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_12" purpose="noiseSuppression is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_13" purpose="latency is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_14" purpose="channelCount is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_15" purpose="deviceId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getSupportedConstraints.https_16" purpose="groupId is supported" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_1" purpose="mediaDevices.getUserMedia() is present on navigator" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_2" purpose="groupId is correctly supported by getUserMedia() for video devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_3" purpose="groupId is correctly supported by getUserMedia() for audio devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_4" purpose="getUserMedia() supports setting none as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_5" purpose="getUserMedia() supports setting crop-and-scale as resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaDevices-getUserMedia.https_6" purpose="getUserMedia() fails with exact invalid resizeMode." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaDevices-getUserMedia.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-firstframe.https_2" purpose="Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_1" purpose="Tests that loading a MediaStream in a media element eventually results in canplay even when not playing or autoplaying" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-preload-none.https_2" purpose="Test that preload 'none' is ignored for MediaStream used as srcObject for video" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_1" purpose="Tests that a MediaStream can be assigned to a video element with srcObject" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_2" purpose="Tests that a MediaStream assigned to a video element is not seekable" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_3" purpose="Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_4" purpose="Tests that a video element with a MediaStream assigned is not preloaded" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_5" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_6" purpose="Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_7" purpose="Tests that a media element with an assigned MediaStream reports the played attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_8" purpose="Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-MediaElement-srcObject.https_9" purpose="Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-add-audio-track.https" purpose="Camera is not exposed in mediaDevices.enumerateDevices()" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-add-audio-track.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-audio-only.https" purpose="Tests that a MediaStream with exactly one audio track is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-audio-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_1" purpose="Tests that cloning MediaStream objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-clone.https_2" purpose="Tests that cloning MediaStreamTrack objects works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-clone.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-finished-add.https" purpose="Tests that adding a track to an inactive MediaStream is allowed" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-finished-add.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-gettrackid.https" purpose="Tests that MediaStream.getTrackById works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-gettrackid.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-id.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-idl.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-idl.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_1" purpose="Tests that a removal from a MediaStream works as expected" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_2" purpose="Test that removal from a MediaStream fires ended on media elements (video first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-removetrack.https_3" purpose="Test that removal from a MediaStream fires ended on media elements (audio first)" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-removetrack.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_1" purpose="document.featurePolicy.features should advertise camera." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-supported-by-feature-policy_2" purpose="document.featurePolicy.features should advertise microphone." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-supported-by-feature-policy.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStream-video-only.https" purpose="Tests that a MediaStream with a correct id is returned" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStream-video-only.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-audio-is-silence.https" purpose="Tests that a disabled audio track in a MediaStream is rendered as silence" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-MediaElement-disabled-video-is-black.https" purpose="Tests that a disabled video track in a MediaStream is rendered as blackness" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_1" purpose="applyConstraints rejects invalid groupID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_2" purpose="applyConstraints accepts invalid ideal groupID, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_3" purpose="applyConstraints rejects attempt to switch device using groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_4" purpose="applyConstraints rejects invalid resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-applyConstraints.https_5" purpose="applyConstraints accepts invalid ideal resizeMode, does not change setting" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-end-manual.https" purpose="Tests that MediaStreamTracks end properly on permission revocation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-end-manual.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_1" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_2" purpose="Setup audio MediaStreamTrack getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_3" purpose="Setup audio MediaStreamTrack getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_4" purpose="Setup audio MediaStreamTrack getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_5" purpose="Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_6" purpose="Setup audio MediaStreamTrack getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_7" purpose="Setup audio MediaStreamTrack getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_8" purpose="Setup audio MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_9" purpose="Setup audio MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_10" purpose="Setup video MediaStreamTrack getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_11" purpose="Setup video MediaStreamTrack getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_12" purpose="Setup video MediaStreamTrack getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_13" purpose="Setup video MediaStreamTrack getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_14" purpose="Setup video MediaStreamTrack getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_15" purpose="Setup video MediaStreamTrack getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_16" purpose="Setup video MediaStreamTrack getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_17" purpose="Setup video MediaStreamTrack getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_18" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_19" purpose="Setup audio InputDeviceInfo getCapabilities() test for sampleSize" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_20" purpose="Setup audio InputDeviceInfo getCapabilities() test for echoCancellation" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_21" purpose="Setup audio InputDeviceInfo getCapabilities() test for autoGainControl" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_22" purpose="Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=22</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_23" purpose="Setup audio InputDeviceInfo getCapabilities() test for latency" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=23</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_24" purpose="Setup audio InputDeviceInfo getCapabilities() test for channelCount" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=24</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_25" purpose="Setup audio InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=25</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_26" purpose="Setup audio InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=26</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_27" purpose="Setup video InputDeviceInfo getCapabilities() test for width" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=27</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_28" purpose="Setup video InputDeviceInfo getCapabilities() test for height" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=28</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_29" purpose="Setup video InputDeviceInfo getCapabilities() test for aspectRatio" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=29</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_30" purpose="Setup video InputDeviceInfo getCapabilities() test for frameRate" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=30</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_31" purpose="Setup video InputDeviceInfo getCapabilities() test for facingMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=31</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_32" purpose="Setup video InputDeviceInfo getCapabilities() test for resizeMode" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=32</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_33" purpose="Setup video InputDeviceInfo getCapabilities() test for deviceId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=33</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getCapabilities.https_34" purpose="Setup video InputDeviceInfo getCapabilities() test for groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html?total_num=34&locator_key=id&value=34</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_1" purpose="A device can be opened twice and have the same device ID" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_2" purpose="A device can be opened twice with different resolutions requested" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_3" purpose="groupId is correctly reported by getSettings() for all input devices" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_4" purpose="deviceId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_5" purpose="groupId is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_6" purpose="sampleRate is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_7" purpose="sampleSize is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_8" purpose="echoCancellation is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_9" purpose="autoGainControl is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_10" purpose="noiseSuppression is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_11" purpose="latency is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_12" purpose="channelCount is reported by getSettings() for getUserMedia() audio tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_13" purpose="deviceId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_14" purpose="groupId is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_15" purpose="width is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_16" purpose="height is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_17" purpose="aspectRatio is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_18" purpose="frameRate is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_19" purpose="facingMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_20" purpose="resizeMode is reported by getSettings() for getUserMedia() video tracks" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-getSettings.https_21" purpose="Stopped tracks should expose deviceId/groupId" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-getSettings.https.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-id.https" purpose="Tests that distinct mediastream tracks have distinct ids" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-id.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrack-init.https" purpose="getUserMedia({video:true}) creates a stream with a properly initialized video track" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrack-init.https.html</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_1" purpose="The eventInitDict argument is required" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_2" purpose="The eventInitDict's track member is required." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="MediaStreamTrackEvent-constructor.https_3" purpose="The MediaStreamTrackEvent instance's track attribute is set." onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_1" purpose="navigator.mozGetUserMedia should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_2" purpose="Passing MediaStream to URL.createObjectURL() should throw" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_3" purpose="MediaStream.onactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ </description>
+ </testcase>
+ <testcase component="W3C_HTML5 APIs/Media/HTML Media Capture" execution_type="auto" id="historical.https_4" purpose="MediaStream.oninactive should not exist" onload_delay="90">
+ <description>
+ <test_script_entry>/opt/tct-mediacapture-w3c-tests/mediacapture/w3c/mediacapture-streams/historical.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ </description>
+ </testcase>
</set>
</suite>
</test_definition>