diff options
Diffstat (limited to 'testing/web-platform/mozilla/tests/mediacapture-streams')
4 files changed, 259 insertions, 0 deletions
diff --git a/testing/web-platform/mozilla/tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html b/testing/web-platform/mozilla/tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html new file mode 100644 index 0000000000..e7dcd4e531 --- /dev/null +++ b/testing/web-platform/mozilla/tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html @@ -0,0 +1,110 @@ +<!doctype html> +<html> +<head> +<title>enumerateDevices: test that enumerateDevices is present (legacy Firefox)</title> +<meta name='assert' content='Check that the enumerateDevices() method is present (legacy Firefox).'/> +</head> +<body> +<h1 class="instructions">Description</h1> +<p class="instructions">This is a modified copy of +testing/web-platform/tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html +testing legacy Firefox version 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"; + +promise_test(async () => { + assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists"); + const devices = await navigator.mediaDevices.enumerateDevices(); + for (const {kind, deviceId, label, groupId} of devices) { + assert_in_array(kind, ["videoinput", "audioinput", "audiooutput"]); + assert_greater_than(deviceId.length, 0, "deviceId should be present even if getUserMedia was never called successfully (legacy)."); + assert_equals(label, "", "label should be empty string if getUserMedia was never called successfully."); + assert_greater_than(groupId.length, 0, "groupId should be present even if getUserMedia was never called successfully (legacy)."); + } + assert_less_than_equal(devices.filter(({kind}) => kind == "audioinput").length, + 1, "there should be zero or one audio input device."); + assert_less_than_equal(devices.filter(({kind}) => kind == "videoinput").length, + 1, "there should be zero or one video input device."); + assert_equals(devices.filter(({kind}) => kind == "audiooutput").length, + 0, "there should be no audio output devices."); + assert_less_than_equal(devices.length, 2, + "there should be no more than two devices."); + if (devices.length > 1) { + assert_equals(devices[0].kind, "audioinput", "audioinput is first"); + assert_equals(devices[1].kind, "videoinput", "videoinput is second"); + } +}, "mediaDevices.enumerateDevices() is present and working - before capture"); + +promise_test(async t => { + await setMediaPermission("granted"); + const stream = await navigator.mediaDevices.getUserMedia({ video: true }); + stream.getTracks()[0].stop(); + + const devices = await navigator.mediaDevices.enumerateDevices(); + const kinds = ["audioinput", "videoinput"]; + for (const {kind, deviceId} of devices) { + assert_in_array(kind, kinds, "camera doesn't expose audiooutput"); + assert_equals(typeof deviceId, "string", "deviceId is a string."); + switch (kind) { + case "videoinput": + assert_greater_than(deviceId.length, 0, "video deviceId should not be empty."); + break; + case "audioinput": + assert_greater_than(deviceId.length, 0, "audio deviceId should not be empty (legacy)."); + break; + } + } +}, "mediaDevices.enumerateDevices() is working - after video capture"); + +// This test is designed to come after its video counterpart directly above +promise_test(async t => { + const devices1 = await navigator.mediaDevices.enumerateDevices(); + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + stream.getTracks()[0].stop(); + const devices = await navigator.mediaDevices.enumerateDevices(); + assert_equals(devices.filter(({kind}) => kind == "videoinput").length, + devices1.filter(({kind}) => kind == "videoinput").length, + "same number of (previously exposed) videoinput devices"); + assert_greater_than_equal(devices.filter(d => d.kind == "audioinput").length, + devices1.filter(d => d.kind == "audioinput").length, + "same number or more audioinput devices"); + const order = ["audioinput", "videoinput", "audiooutput"]; + for (const {kind, deviceId} of devices) { + assert_in_array(kind, order, "expected kind"); + assert_equals(typeof deviceId, "string", "deviceId is a string."); + switch (kind) { + case "videoinput": + assert_greater_than(deviceId.length, 0, "video deviceId should not be empty."); + break; + case "audioinput": + assert_greater_than(deviceId.length, 0, "audio deviceId should not be empty."); + break; + } + } + const kinds = devices.map(({kind}) => kind); + const correct = [...kinds].sort((a, b) => order.indexOf(a) - order.indexOf(b)); + assert_equals(JSON.stringify(kinds), JSON.stringify(correct), "correct order"); +}, "mediaDevices.enumerateDevices() is working - after video then audio capture"); + +promise_test(async () => { + const devices = await navigator.mediaDevices.enumerateDevices(); + for (const mediaInfo of devices) { + if (mediaInfo.kind == "audioinput" || mediaInfo.kind == "videoinput") { + assert_true("InputDeviceInfo" in window, "InputDeviceInfo exists"); + 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> diff --git a/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-in-background.https.html b/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-in-background.https.html new file mode 100644 index 0000000000..55d1d24dce --- /dev/null +++ b/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-in-background.https.html @@ -0,0 +1,67 @@ +<!doctype html> +<title>enumerateDevices() in background tab with focus in chrome</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> +<body></body> +<script> +'use strict'; +// This test is not in cross-browser wpt because it uses Gecko-specific API +// for focusing browser chrome and it assumes a specific tab browser design. +// It assumes that +// * browser chrome widget focus is associated with a single current document +// presentation (tab), +// https://github.com/w3c/mediacapture-main/issues/752#issuecomment-742036800 +// * window.open() focuses the new tab and makes the current tab hidden, and +// * the opener tab becomes the current and visible tab again when the new tab +// is closed. +const blank_url = '/common/blank.html'; + +function promise_event(target, name) { + return new Promise(resolve => target[`on${name}`] = resolve); +} + +promise_test(async t => { + // Open a new tab, which is expected to receive focus and hide the first tab. + await test_driver.bless('window.open()'); + assert_true(document.hasFocus(), 'This test needs focus on the browser.'); + const promise_hidden = promise_event(document, 'visibilitychange'); + const proxy = window.open(blank_url); + t.add_cleanup(() => proxy.close()); + await Promise.all([ + promise_hidden, + promise_event(proxy, 'focus'), + promise_event(proxy, 'load'), + ]); + assert_true(proxy.document.hasFocus(), 'proxy.document.hasFocus()'); + + await Promise.all([ + promise_event(proxy, 'blur'), + SpecialPowers.spawnChrome([], function focus_url_bar() { + this.browsingContext.topChromeWindow.gURLBar.focus(); + }), + ]); + assert_false(proxy.document.hasFocus(), 'proxy.document.hasFocus()'); + assert_false(document.hasFocus(), 'document.hasFocus()'); + assert_equals(document.visibilityState, 'hidden', 'visibilityState'); + + // Enumeration should remain pending while the first tab is background. + const promise_enumerate = navigator.mediaDevices.enumerateDevices(); + // Enumerate in the foreground tab to confirm that URL bar focus is + // sufficient, and to provide enough time to check that the Promise from the + // background tab does not settle. + await proxy.navigator.mediaDevices.enumerateDevices(); + // Race a settled Promise to check that the enumeration in the background tab + // has not settled. + const result = await Promise.race([promise_enumerate, 'pending']); + assert_equals(result, 'pending', 'pending Promise while background.'); + + // The enumeration Promise should resolve after the first tab returns to the + // foreground. + proxy.close(); + await promise_event(document, 'visibilitychange'); + assert_equals(document.visibilityState, 'visible', 'visibilityState'); + await promise_enumerate; +}, 'enumerateDevices in background'); +</script> diff --git a/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-without-focus.https.html b/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-without-focus.https.html new file mode 100644 index 0000000000..6516a514c5 --- /dev/null +++ b/testing/web-platform/mozilla/tests/mediacapture-streams/enumerateDevices-without-focus.https.html @@ -0,0 +1,58 @@ +<!doctype html> +<title>enumerateDevices() without focus</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> +<body></body> +<script> +'use strict'; +const blank_url = '/common/blank.html'; + +function promise_event(target, name) { + return new Promise(resolve => target[`on${name}`] = resolve); +} +// When testdriver.js supports switch-to-window, it can replace this function +// and this test can be upstreamed. +// https://github.com/web-platform-tests/wpt/issues/10666 +function switch_toplevel_focus_for_window(win) { + return win.SpecialPowers.spawnChrome([], function activate_browser_window() { + this.browsingContext.topChromeWindow.focus(); + }); +} + +promise_test(async t => { + await test_driver.bless('window.open()'); + assert_true(document.hasFocus(), 'This test needs focus on the document.'); + const promise_blur = promise_event(window, 'blur'); + // 'resizable' is requested for a separate OS window on relevant platforms + // so that this test tests OS focus changes rather than document visibility. + const proxy = window.open(blank_url, '', 'resizable'); + t.add_cleanup(() => proxy.close()); + await Promise.all([ + promise_blur, + switch_toplevel_focus_for_window(proxy), + promise_event(proxy, 'load'), + ]); + assert_false(document.hasFocus(), 'document.hasFocus() after blur'); + + // Enumeration should remain pending without focus. + const promise_enumerate = navigator.mediaDevices.enumerateDevices(); + // Enumerate in the focused window to provide enough time to check that + // the Promise from the unfocused window does not settle. + await proxy.navigator.mediaDevices.enumerateDevices(); + // Race a settled Promise to check that the enumeration in the first window + // has not settled. + const result = await Promise.race([promise_enumerate, 'pending']); + assert_equals(result, 'pending', 'pending Promise without focus.'); + + // The enumeration Promise should resolve after focus returns to the window. + proxy.close(); + await Promise.all([ + promise_event(window, 'focus'), + switch_toplevel_focus_for_window(window), + ]); + assert_true(document.hasFocus(), 'document.hasFocus() after focus'); + await promise_enumerate; +}, 'enumerateDevices without focus'); +</script> diff --git a/testing/web-platform/mozilla/tests/mediacapture-streams/permission-helper.js b/testing/web-platform/mozilla/tests/mediacapture-streams/permission-helper.js new file mode 100644 index 0000000000..0a237f7d43 --- /dev/null +++ b/testing/web-platform/mozilla/tests/mediacapture-streams/permission-helper.js @@ -0,0 +1,24 @@ +// 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); + } + } 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"); + } + } +} |