summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html')
-rw-r--r--testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html197
1 files changed, 197 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html b/testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html
new file mode 100644
index 0000000000..d6ce370772
--- /dev/null
+++ b/testing/web-platform/tests/mediacapture-record/MediaRecorder-stop.html
@@ -0,0 +1,197 @@
+<!doctype html>
+<html>
+<head>
+ <title>MediaRecorder Stop</title>
+ <meta name=variant content="?mimeType=''">
+ <meta name=variant content="?mimeType=video/webm;codecs=vp8,opus">
+ <meta name=variant content="?mimeType=video/webm;codecs=vp9,opus">
+ <meta name=variant content="?mimeType=video/webm;codecs=av1,opus">
+ <meta name=variant content="?mimeType=video/mp4;codecs=avc1,mp4a.40.2">
+ <link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#mediarecorder">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="utils/sources.js"></script>
+</head>
+<body>
+<script>
+ function recordEvents(target, events) {
+ let arr = [];
+ for (let ev of events) {
+ target.addEventListener(ev, _ => arr.push(ev));
+ }
+ return arr;
+ }
+
+ // This function is used to check that elements of |actual| is a sub
+ // sequence in the |expected| sequence.
+ function assertSequenceIn(actual, expected) {
+ let i = 0;
+ for (event of actual) {
+ const j = expected.slice(i).indexOf(event);
+ assert_greater_than_equal(
+ j, 0, "Sequence element " + event + " is not included in " +
+ expected.slice(i));
+ // Ensure duplicates in actual aren't silently accepted by skipping
+ // past the matched element.
+ i = j + 1;
+ }
+ return true;
+ }
+
+ function doneWithUnsupportedType(mimeType) {
+ if (mimeType) {
+ assert_implements_optional(MediaRecorder.isTypeSupported(mimeType),
+ `"${mimeType}" for MediaRecorder is not supported`);
+ }
+ }
+
+ const params = new URLSearchParams(window.location.search);
+ const mimeType = params.get('mimeType');
+ const tag = `mimeType "${mimeType}"`;
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream: video} = createVideoStream(t);
+ const recorder = new MediaRecorder(video, {mimeType});
+ const events = recordEvents(recorder,
+ ["start", "stop", "dataavailable", "pause", "resume", "error"]);
+ assert_equals(video.getVideoTracks().length, 1, "video mediastream starts with one track");
+ recorder.start();
+ assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
+ video.getVideoTracks()[0].stop();
+ assert_equals(recorder.state, "recording", "MediaRecorder state should be recording immediately following last track ending");
+ const event = await new Promise(r => recorder.onstop = r);
+
+ assert_equals(event.type, "stop", "the event type should be stop");
+ assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
+ assert_equals(recorder.state, "inactive", "MediaRecorder is inactive after stop event");
+
+ // As the test is written, it's not guaranteed that
+ // onstart/ondataavailable is invoked, but it's fine if they are.
+ // The stop element is guaranteed to be in events when we get here.
+ assertSequenceIn(events, ["start", "dataavailable", "stop"]);
+ }, "MediaRecorder will stop recording and fire a stop event when all tracks are ended");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream: video} = createVideoStream(t);
+ const recorder = new MediaRecorder(video, {mimeType});
+ const events = recordEvents(recorder,
+ ["start", "stop", "dataavailable", "pause", "resume", "error"]);
+ recorder.start();
+ assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
+ recorder.stop();
+ assert_equals(recorder.state, "inactive", "MediaRecorder state should be inactive immediately following stop() call");
+
+ const event = await new Promise (r => recorder.onstop = r);
+ assert_equals(event.type, "stop", "the event type should be stop");
+ assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
+ assert_equals(recorder.state, "inactive", "MediaRecorder is inactive after stop event");
+
+ // As the test is written, it's not guaranteed that
+ // onstart/ondataavailable is invoked, but it's fine if they are.
+ // The stop element is guaranteed to be in events when we get here.
+ assertSequenceIn(events, ["start", "dataavailable", "stop"]);
+ }, "MediaRecorder will stop recording and fire a stop event when stop() is called");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const recorder = new MediaRecorder(createVideoStream(t).stream, {mimeType});
+ recorder.stop();
+ await Promise.race([
+ new Promise((_, reject) => recorder.onstop =
+ _ => reject(new Error("onstop should never have been called"))),
+ new Promise(r => t.step_timeout(r, 0))]);
+ }, "MediaRecorder will not fire an exception when stopped after creation");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const recorder = new MediaRecorder(createVideoStream(t).stream, {mimeType});
+ recorder.start();
+ recorder.stop();
+ const event = await new Promise(r => recorder.onstop = r);
+ recorder.stop();
+ await Promise.race([
+ new Promise((_, reject) => recorder.onstop =
+ _ => reject(new Error("onstop should never have been called"))),
+ new Promise(r => t.step_timeout(r, 0))]);
+ }, "MediaRecorder will not fire an exception when stopped after having just been stopped");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream} = createVideoStream(t);
+ const recorder = new MediaRecorder(stream, {mimeType});
+ recorder.start();
+ stream.getVideoTracks()[0].stop();
+ const event = await new Promise(r => recorder.onstop = r);
+ recorder.stop();
+ await Promise.race([
+ new Promise((_, reject) => recorder.onstop =
+ _ => reject(new Error("onstop should never have been called"))),
+ new Promise(r => t.step_timeout(r, 0))]);
+ }, "MediaRecorder will not fire an exception when stopped after having just been spontaneously stopped");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream} = createAudioVideoStream(t);
+ const recorder = new MediaRecorder(stream, {mimeType});
+ const events = [];
+ const startPromise = new Promise(resolve => recorder.onstart = resolve);
+ const stopPromise = new Promise(resolve => recorder.onstop = resolve);
+
+ startPromise.then(() => events.push("start"));
+ stopPromise.then(() => events.push("stop"));
+
+ recorder.start();
+ recorder.stop();
+
+ await stopPromise;
+ assert_array_equals(events, ["start", "stop"]);
+ }, "MediaRecorder will fire start event even if stopped synchronously");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream} = createAudioVideoStream(t);
+ const recorder = new MediaRecorder(stream, {mimeType});
+ const events = [];
+ const startPromise = new Promise(resolve => recorder.onstart = resolve);
+ const stopPromise = new Promise(resolve => recorder.onstop = resolve);
+ const errorPromise = new Promise(resolve => recorder.onerror = resolve);
+ const dataPromise = new Promise(resolve => recorder.ondataavailable = resolve);
+
+ startPromise.then(() => events.push("start"));
+ stopPromise.then(() => events.push("stop"));
+ errorPromise.then(() => events.push("error"));
+ dataPromise.then(() => events.push("data"));
+
+ recorder.start();
+ stream.removeTrack(stream.getAudioTracks()[0]);
+
+ await stopPromise;
+ assert_array_equals(events, ["start", "error", "data", "stop"]);
+ }, "MediaRecorder will fire start event even if a track is removed synchronously");
+
+ promise_test(async t => {
+ doneWithUnsupportedType(mimeType);
+
+ const {stream} = createFlowingAudioVideoStream(t);
+ const recorder = new MediaRecorder(stream, {mimeType});
+ const events = recordEvents(recorder,
+ ["start", "stop", "dataavailable", "pause", "resume", "error"]);
+ const dataPromise = new Promise(r => recorder.ondataavailable = r);
+ recorder.start(0);
+ await dataPromise;
+ recorder.stop();
+ await new Promise (r => recorder.onstop = r);
+ assertSequenceIn(events, ["start", "dataavailable", "stop"]);
+ }, "MediaRecorder will fire only start and stop events in a basic recording flow.");
+
+</script>
+</body>
+</html>