| <!-- webkit-test-runner [ MediaSessionCoordinatorEnabled=true ] --> |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>mock-mediasession-coordinator</title> |
| <script src="../video-test.js"></script> |
| <script> |
| |
| let waiting = false; |
| async function waitForDebugger() |
| { |
| let counter = 0; |
| while (waiting) { |
| await sleepFor(100); |
| counter++; |
| } |
| } |
| |
| function changeHandler(change) |
| { |
| window.latestChange = change; |
| } |
| |
| window.addEventListener('load', async event => { |
| |
| window.latestAction = ''; |
| window.latestChange = ''; |
| |
| if (!window.internals) { |
| failTest('This test requires Internals'); |
| return; |
| } |
| |
| let changePromise = () => { |
| return new Promise(resolve => { |
| navigator.mediaSession.coordinator.addEventListener('coordinatorstatechange', (event) => { |
| consoleWrite(`EVENT(${event.type} STATE(${navigator.mediaSession.coordinator.state})`); |
| resolve(); |
| }, { once: true }); |
| }); |
| } |
| |
| await waitForDebugger(); |
| |
| consoleWrite(''); |
| consoleWrite('** There mediaSession.coordinator.state should be closed initially.'); |
| |
| testExpected('navigator.mediaSession.coordinator.state', "closed"); |
| |
| consoleWrite(''); |
| consoleWrite('** Test that mediaSession.coordinator.coordinatorstatechange event is fired when it changes.'); |
| |
| run('internals.registerMockMediaSessionCoordinator(changeHandler)'); |
| |
| await changePromise(); |
| |
| ['play', 'pause', 'seekto'].forEach(action => { |
| navigator.mediaSession.setActionHandler(action, actionDetails => { |
| consoleWrite(`ACTION(${actionDetails.action})`); |
| latestAction = actionDetails.action; |
| }); |
| }); |
| |
| let testAction = async (action, func, expectFailure) => { |
| latestAction = ''; |
| |
| run(`promise = ${func.toString()}`); |
| try { |
| if (expectFailure) |
| await shouldReject(promise); |
| else |
| await shouldResolve(promise); |
| } catch(ex) {} |
| |
| consoleWrite(''); |
| }; |
| |
| let testReadyStates = async (testCallback) => { |
| let previousState = 'havenothing'; |
| navigator.mediaSession.readyState = 'havenothing'; |
| for (let state of ['havemetadata', 'havecurrentdata', 'havefuturedata', 'haveenoughdata', 'havenothing']) { |
| testExpected('navigator.mediaSession.readyState', previousState); |
| |
| latestChange = ''; |
| run(`navigator.mediaSession.readyState = '${state}'`); |
| |
| await testCallback() |
| |
| testExpected('navigator.mediaSession.readyState', state); |
| previousState = state; |
| consoleWrite(''); |
| }; |
| } |
| |
| let testPlaybackStates = async (testCallback) => { |
| let previousState = 'none'; |
| navigator.mediaSession.playbackState = 'none'; |
| for (let state of ['paused', 'playing', 'none']) { |
| |
| testExpected('navigator.mediaSession.playbackState', previousState); |
| |
| latestChange = ''; |
| run(`navigator.mediaSession.playbackState = '${state}'`); |
| |
| await testCallback() |
| |
| testExpected('navigator.mediaSession.playbackState', state); |
| previousState = state; |
| consoleWrite(''); |
| }; |
| } |
| |
| let actions = [ |
| { action: 'play', func : 'navigator.mediaSession.coordinator.play()' }, |
| { action: 'pause', func : 'navigator.mediaSession.coordinator.pause()' }, |
| { action: 'seekto', func : 'navigator.mediaSession.coordinator.seekTo(10)' }, |
| ]; |
| |
| // Before joining |
| consoleWrite(''); |
| consoleWrite('** navigator.mediaSession.coordinator.state should be "waiting" initially') |
| testExpected('navigator.mediaSession.coordinator.state', 'waiting'); |
| |
| consoleWrite(''); |
| consoleWrite('** Test that when coordinator methods fail and promises reject before mediaSession.join() is called.') |
| for (let action of actions) |
| await testAction(action.action, action.func, true); |
| |
| consoleWrite(`** Test that mediaSession does not notify coordinator when states change before mediaSession.join() is called.`) |
| consoleWrite('* PositionState'); |
| latestChange = ''; |
| run('navigator.mediaSession.setPositionState({ duration: 1, playbackRate: 1, position: 0 })'); |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| |
| consoleWrite(''); |
| consoleWrite('* ReadyState'); |
| await testReadyStates(async () => { |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| }); |
| |
| consoleWrite('* PlaybackState'); |
| await testPlaybackStates(async () => { |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| }); |
| |
| consoleWrite('<br>'); |
| consoleWrite('** session.join() should reject on failure'); |
| run('internals.setMockMediaSessionCoordinatorCommandsShouldFail(true)'); |
| run('promise = navigator.mediaSession.coordinator.join()'); |
| await shouldReject(promise).then(() => { }).catch(() => { }); |
| testExpected('navigator.mediaSession.coordinator.state', 'waiting'); |
| testExpected('latestChange', ''); |
| |
| consoleWrite(''); |
| run('internals.setMockMediaSessionCoordinatorCommandsShouldFail(false)'); |
| run('promise = navigator.mediaSession.coordinator.join()'); |
| await changePromise(); |
| await shouldResolve(promise).then(() => { }).catch(() => { }); |
| testExpected('navigator.mediaSession.coordinator.state', 'joined'); |
| |
| consoleWrite(''); |
| consoleWrite('** Test that when coordinator methods succeed, promises resolve and mediaSession action handlers are called.') |
| internals.setMockMediaSessionCoordinatorCommandsShouldFail(false); |
| for (let action of actions) |
| await testAction(action.action, action.func, false); |
| |
| consoleWrite('** Test that when coordinator methods fail, promises reject and mediaSession action handlers are not called.') |
| internals.setMockMediaSessionCoordinatorCommandsShouldFail(true); |
| for (let action of actions) |
| await testAction(action.action, action.func, true); |
| |
| consoleWrite(`** Test that mediaSession notifies coordinator when positionState changes.`) |
| run('navigator.mediaSession.setPositionState({ duration: 1, playbackRate: 1, position: 0 })'); |
| await testExpectedEventually('latestChange', 'positionStateChanged', '==', 100); |
| |
| consoleWrite(''); |
| consoleWrite('** Test that mediaSession notifies coordinator when readyState changes.'); |
| await testReadyStates(async () => { await testExpectedEventually('latestChange', 'readyStateChanged', '==', 100); }) |
| |
| consoleWrite('** Test that mediaSession notifies coordinator when playbackState changes.') |
| await testPlaybackStates(async () => { testExpectedEventually('latestChange', 'playbackStateChanged', '==', 100); }); |
| |
| // After leaving |
| consoleWrite('<br>'); |
| consoleWrite('** Leave the session') |
| run('navigator.mediaSession.coordinator.leave()'); |
| await changePromise(); |
| testExpected('navigator.mediaSession.coordinator.state', 'closed'); |
| |
| latestChange = ''; |
| |
| consoleWrite(''); |
| consoleWrite('** Test that when coordinator methods fail and promises reject after mediaSession.leave() has been called.') |
| for (let action of actions) |
| await testAction(action.action, action.func, true); |
| |
| consoleWrite(`** Test that mediaSession does not notify coordinator when states change after mediaSession.leave() has been called.`) |
| consoleWrite('* PositionState'); |
| latestChange = ''; |
| run('navigator.mediaSession.setPositionState({ duration: 1, playbackRate: 1, position: 0 })'); |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| |
| consoleWrite(''); |
| consoleWrite('* ReadyState'); |
| await testReadyStates(async () => { |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| }); |
| |
| consoleWrite('* PlaybackState'); |
| await testPlaybackStates(async () => { |
| await sleepFor(20); |
| testExpected('latestChange', ''); |
| }); |
| |
| consoleWrite('<br>'); |
| consoleWrite('** It should not be possible to join or leave a closed session'); |
| run('promise = navigator.mediaSession.coordinator.join()'); |
| await shouldReject(promise).then(() => { }).catch(() => { }); |
| |
| let exception; |
| try { |
| navigator.mediaSession.coordinator.leave(); |
| } catch (ex) { |
| exception = ex; |
| } |
| let expected = 'InvalidStateError: Unable to leave when state is closed'; |
| logResult(exception.toString() == expected, `TEST(navigator.mediaSession.coordinator.leave()) THROWS(${expected})`); |
| |
| consoleWrite(''); |
| endTest(); |
| }, {once: true}); |
| |
| </script> |
| </head> |
| <body> |
| |
| </body> |
| </html> |