new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_getUserMedia_constrainVideo.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="mediaStreamPlayback.js"></script>
+</head>
+<body>
+<div id="content" style="display: none">
+ <video id="video" width="120" autoplay></video><br>
+ <video id="video2" width="120" autoplay></video><br>
+</div>
+<pre id="test">
+<script type="application/javascript">
+createHTML({ title: "Test getUserMedia constraint video", bug: "1088621" });
+
+let videoPropMap = { width: "videoWidth", height: "videoHeight" };
+
+let gum = c => navigator.mediaDevices.getUserMedia({ fake: true, video: c });
+
+let testGum = (constraints, expected) => {
+ let msg = "Testing " + JSON.stringify(constraints) + " - ";
+ let expectedError = (typeof expected == "string")? expected : null;
+
+ return gum(constraints).then(stream => {
+ if (expectedError) {
+ throw ({ name: "success" });
+ }
+ let settings = stream.getTracks()[0].getSettings();
+ for (let prop in expected) {
+ is(settings[prop], expected[prop], msg + "Get expected " + prop);
+ }
+ video.srcObject = stream;
+ return new Promise(resolve => video.onloadedmetadata = resolve);
+ })
+ .then(() => {
+ for (let prop in expected) {
+ if (prop in videoPropMap) {
+ is(video[videoPropMap[prop]], expected[prop],
+ msg + "Get expected video." + videoPropMap[prop]);
+ }
+ }
+ video.srcObject.stop();
+ video.srcObject = null;
+ })
+ .then(() => wait(200)) // TODO: Remove this workaround for Bug 1289665.
+ .catch(e => {
+ is(e.name, expectedError,
+ msg + (e.name == "success" ? "Get expected success" :
+ "Get expected error (" + e.message +")"));
+ });
+};
+
+let tests = [
+ [false, "NotSupportedError"],
+ [true, { width: 640, height: 480, frameRate: 30 }],
+ [{}, { width: 640, height: 480, frameRate: 30 }],
+ [{ width: 1280, height: 720 }, { width: 1280, height: 720, frameRate: 30 }],
+ [{ width: 710, height: 800 }, { width: 640, height: 480, frameRate: 30 }],
+ [{ width: 720, height: 800 }, { width: 1408, height: 792, frameRate: 30 }],
+ [{ width: 640, height: 480, frameRate: 17 }, { width: 640, height: 480, frameRate: 30 }],
+ [{ width: 640, height: 480, frameRate: 16 }, { width: 896, height: 504, frameRate: 15 }],
+ [{ width: { ideal: 480 } }, { width: 480, height: 360, frameRate: 30 }],
+ [{ height: { min: 2048 } }, "OverconstrainedError"],
+ [{ height: { min: 576 } }, { width: 1024, height: 576, frameRate: 30 }],
+ [{ height: { max: 35 } }, "OverconstrainedError"],
+ [{ height: { max: 180 } }, { width: 240, height: 180, frameRate: 30 }],
+ [{ frameRate: { exact: 12 } }, "OverconstrainedError"],
+ [{ frameRate: { exact: 10 } }, { width: 896, height: 504, frameRate: 10 }],
+ [{ frameRate: { min: 15, max: 10 } }, "OverconstrainedError"],
+ [{ width: { max: 240 }, height: { min: 720 } }, "OverconstrainedError"],
+ [{ width: { min: 320, ideal: 160, max: 640 },
+ height: { min: 200, ideal: 120, max: 480 } },
+ { width: 320, height: 240, frameRate: 30 }],
+];
+
+let concurrentConstraints = { width: { ideal: 1024, min: 320 },
+ height: { ideal: 576, max: 720 } };
+let concurrentTests = [
+ [true, { width: 1024, height: 576, frameRate: 30 }],
+ [{ width: 160, height: 120 }, { width: 1024, height: 576, frameRate: 30 }],
+ [{ width: 640, height: 480, frameRate: 10 }, { width: 1024, height: 576, frameRate: 30 }],
+ [{ width: 1280, height: 720, frameRate: 15 }, { width: 1280, height: 720, frameRate: 30 }],
+ [{ width: { max: 160 } }, "OverconstrainedError"],
+ [{ height: { min: 792 } }, "OverconstrainedError"],
+];
+
+runTest(() => tests.reduce((p, test) => p.then(() => testGum(...test)),
+ Promise.resolve())
+ // Test concurrent gUM requests.
+ .then(() => gum(concurrentConstraints))
+ .then(stream => {
+ video2.srcObject = stream;
+ return concurrentTests.reduce((p, test) => p.then(() => testGum(...test)),
+ Promise.resolve());
+ })
+ .then(() => {
+ video2.srcObject.getTracks().forEach(track => track.stop());
+ video2.srcObject = null;
+ })
+ .catch(e => ok(false, "Unexpected " + e)));
+
+</script>
+</pre>
+</body>
+</html>