suspend-after-construct.html (2811B)
1 <!doctype html> 2 <title>Test AudioContext state updates with suspend() shortly after 3 construction</title> 4 <script src=/resources/testharness.js></script> 5 <script src=/resources/testharnessreport.js></script> 6 <script> 7 // A separate async_test is used for tracking state change counts so that it 8 // can report excess changes after the promise_test for the iteration has 9 // completed. 10 const changeCountingTest = async_test('State change counting'); 11 12 const doTest = async (testCount) => { 13 const ctx = new AudioContext(); 14 // Explicitly resume to get a promise to indicate whether the context 15 // successfully started running. 16 const resume = ctx.resume(); 17 const suspend = ctx.suspend(); 18 let stateChangesDone = new Promise((resolve) => { 19 ctx.onstatechange = () => { 20 ++ctx.stateChangeCount; 21 changeCountingTest.step(() => { 22 assert_less_than_equal(ctx.stateChangeCount, 23 ctx.expectedStateChangeCount, 24 `ctx ${testCount} state change count.`); 25 assert_equals(ctx.state, ctx.expectedState, `ctx ${testCount} state`); 26 }); 27 if (ctx.stateChangeCount == ctx.totalStateChangeCount) { 28 resolve(); 29 } 30 }; 31 }); 32 ctx.stateChangeCount = 0; 33 ctx.expectedStateChangeCount = 1; 34 ctx.expectedState = 'running'; 35 ctx.totalStateChangeCount = 2; 36 let resumeState = 'pending'; 37 resume.then(() => { 38 resumeState = 'fulfilled'; 39 assert_equals(ctx.state, 'running', 'state on resume fulfilled.'); 40 }).catch(() => { 41 // The resume() promise may be rejected if "Attempt to acquire system 42 // resources" fails. The spec does not discuss the possibility of a 43 // subsequent suspend causing such a failure, but accept this as a 44 // reasonable behavior. 45 resumeState = 'rejected'; 46 assert_equals(ctx.state, 'suspended', 'state on resume rejected.'); 47 assert_equals(ctx.stateChangeCount, 0); 48 ctx.expectedStateChangeCount = 0; 49 stateChangesDone = Promise.resolve(); 50 }); 51 suspend.then(() => { 52 assert_not_equals(resumeState, 'pending', 53 'resume promise should settle before suspend promise.') 54 if (resumeState == 'fulfilled') { 55 ++ctx.expectedStateChangeCount; 56 } 57 ctx.expectedState = 'suspended'; 58 assert_equals(ctx.state, 'suspended', 'state on suspend fulfilled.'); 59 }); 60 await resume; 61 await suspend; 62 await stateChangesDone; 63 }; 64 65 // Repeat the test because Gecko uses different code when there is more than 66 // one AudioContext. The third run provides time to check that no further 67 // state changes from the second run are pending. 68 for (const testCount of [1, 2, 3]) { 69 promise_test(() => { return doTest(testCount); }, `Iteration ${testCount}`); 70 } 71 promise_test(async () => changeCountingTest.done(), 'Stop waiting'); 72 </script>