// META: script=/resources/testdriver.js // META: script=/resources/testdriver-vendor.js // META: timeout=long 'use strict'; const validFocusBehaviors = ['focus-captured-surface', 'no-focus-change']; const validDisplaySurfaces = ['window', 'browser']; test(() => { assert_own_property(window, 'CaptureController'); }, 'CaptureController in window'); const stopTracks = stream => stream.getTracks().forEach(track => track.stop()); validFocusBehaviors.forEach( (focusBehavior) => test( (t) => { const controller = new CaptureController(); controller.setFocusBehavior(focusBehavior); }, `setFocusBehavior("${ focusBehavior}") must succeed before capture starts`)); ['invalid', null, undefined, {}, true].forEach( (focusBehavior) => test( () => { const controller = new CaptureController(); assert_throws_js( TypeError, () => controller.setFocusBehavior(focusBehavior)); }, `setFocusBehavior("${ focusBehavior}") must throw TypeError if focusBehavior is invalid`)); promise_test(async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia({controller}); t.add_cleanup(() => stopTracks(stream)); assert_equals(stream.getTracks().length, 1); assert_equals(stream.getVideoTracks().length, 1); assert_equals(stream.getAudioTracks().length, 0); }, 'getDisplayMedia({controller}) must succeed'); ['invalid', null, {}, true].forEach( (controller) => promise_test( async (t) => { await test_driver.bless('getDisplayMedia()'); await promise_rejects_js( t, TypeError, navigator.mediaDevices.getDisplayMedia({controller})); }, `getDisplayMedia({controller: ${ controller}}) must fail with TypeError`)); promise_test(async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia({controller}); t.add_cleanup(() => stopTracks(stream)); await test_driver.bless('getDisplayMedia()'); const p = navigator.mediaDevices.getDisplayMedia({controller}); t.add_cleanup(async () => { try { stopTracks(await p); } catch { } }); await promise_rejects_dom( t, 'InvalidStateError', Promise.race([p, Promise.resolve()]), 'getDisplayMedia should have returned an already-rejected promise.'); }, 'getDisplayMedia({controller}) must fail with InvalidStateError if controller is bound'); validDisplaySurfaces.forEach((displaySurface) => { validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface}}); t.add_cleanup(() => stopTracks(stream)); controller.setFocusBehavior(focusBehavior); }, `setFocusBehavior("${ focusBehavior}") must succeed when window of opportunity is opened if capturing a ${ displaySurface}`)); }); validDisplaySurfaces.forEach((displaySurface) => { validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const p = navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface}}); controller.setFocusBehavior(focusBehavior); const stream = await p; t.add_cleanup(() => stopTracks(stream)); }, `setFocusBehavior("${ focusBehavior}") must succeed when getDisplayMedia promise is pending if capturing a ${ displaySurface}`)); }); validDisplaySurfaces.forEach((displaySurface) => { validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface}}); stopTracks(stream); assert_throws_dom( 'InvalidStateError', () => controller.setFocusBehavior(focusBehavior)); }, `setFocusBehavior("${ focusBehavior}") must throw InvalidStateError when track is stopped if capturing a ${ displaySurface}`)); }); validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface: 'monitor'}}); t.add_cleanup(() => stopTracks(stream)); assert_throws_dom( 'InvalidStateError', () => controller.setFocusBehavior(focusBehavior)); }, `setFocusBehavior("${ focusBehavior}") must throw InvalidStateError if capturing a monitor`)); validDisplaySurfaces.forEach((displaySurface) => { validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface}}); t.add_cleanup(() => stopTracks(stream)); await new Promise((resolve) => step_timeout(resolve, 0)); assert_throws_dom( 'InvalidStateError', () => controller.setFocusBehavior(focusBehavior)); }, `setFocusBehavior("${ focusBehavior}") must throw InvalidStateError when window of opportunity is closed if capturing a ${ displaySurface}`)); }); validDisplaySurfaces.forEach((displaySurface) => { validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); await test_driver.bless('getDisplayMedia()'); const stream = await navigator.mediaDevices.getDisplayMedia( {controller, video: {displaySurface}}); t.add_cleanup(() => stopTracks(stream)); controller.setFocusBehavior(focusBehavior) assert_throws_dom( 'InvalidStateError', () => controller.setFocusBehavior(focusBehavior)); }, `setFocusBehavior("${ focusBehavior}") must throw InvalidStateError the second time if capturing a ${ displaySurface}`)); }); validFocusBehaviors.forEach( (focusBehavior) => promise_test( async (t) => { const controller = new CaptureController(); const options = { controller: controller, video: {width: {max: 0}}, } try { await test_driver.bless('getDisplayMedia()'); stopTracks(await navigator.mediaDevices.getDisplayMedia(options)); } catch (err) { assert_equals(err.name, 'OverconstrainedError', err.message); assert_throws_dom( 'InvalidStateError', () => controller.setFocusBehavior(focusBehavior)); return; } assert_unreached('getDisplayMedia should have failed'); }, `setFocusBehavior("${ focusBehavior}") must throw InvalidStateError if getDisplayMedia fails`));