blob: cd8e9c87453dc1e3ccee88f49cff1a0c873c6289 [file] [edit]
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ConstrainablePattern getCapabilities/getConstraints/getSettings return the internal slots</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
// MediaCapture-Main §"ConstrainablePattern":
// https://w3c.github.io/mediacapture-main/#constrainable-interface
//
// MediaStreamTrack implements ConstrainablePattern, which exposes three
// getter-style methods:
//
// getCapabilities() — returns the [[Capabilities]] internal slot
// (the device's full range of values for each
// constrainable property)
// getConstraints() — returns the [[Constraints]] internal slot (the
// most recently applied constraints, or {} if none
// have been applied)
// getSettings() — returns the [[Settings]] internal slot (the
// current actual settings the track is operating
// under)
//
// All three return plain dictionaries (per IDL, the IDL records are
// stringified to JS objects). Across multiple calls without an
// intervening mutation, each must return equivalent data.
if (window.testRunner) {
testRunner.setMicrophonePermission(true);
testRunner.setCameraPermission(true);
}
promise_test(async test => {
// getCapabilities returns the [[Capabilities]] internal slot.
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
test.add_cleanup(() => stream.getTracks().forEach(t => t.stop()));
const track = stream.getVideoTracks()[0];
const caps = track.getCapabilities();
assert_equals(typeof caps, "object", "getCapabilities returns an object");
assert_not_equals(caps, null, "getCapabilities returns non-null");
// Idempotent: a second call yields the same content (no per-call
// mutation of [[Capabilities]]).
const caps2 = track.getCapabilities();
assert_object_equals(caps, caps2,
"two getCapabilities calls return equivalent content");
// Per spec, capability values for constrainable properties of the
// device should include at least the kind-applicable members. For a
// video track this includes width/height or facingMode.
const hasAtLeastOneCap = "width" in caps || "height" in caps
|| "facingMode" in caps || "deviceId" in caps;
assert_true(hasAtLeastOneCap,
"video track getCapabilities exposes at least one constrainable property");
}, "getCapabilities returns the [[Capabilities]] internal slot as a plain object");
promise_test(async test => {
// getConstraints returns the [[Constraints]] internal slot —
// the most recently *successfully applied* constraints.
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
test.add_cleanup(() => stream.getTracks().forEach(t => t.stop()));
const track = stream.getVideoTracks()[0];
// Before any explicit applyConstraints, [[Constraints]] reflects
// whatever getUserMedia was called with — for our setup, no constraints.
let c = track.getConstraints();
assert_equals(typeof c, "object", "getConstraints returns an object");
// After applyConstraints with a successful constraint, getConstraints
// returns the applied set verbatim.
await track.applyConstraints({ frameRate: { ideal: 24 } });
c = track.getConstraints();
assert_object_equals(c, { frameRate: { ideal: 24 } },
"getConstraints returns the most recently applied constraints");
// A second applyConstraints replaces (not merges) [[Constraints]].
await track.applyConstraints({ width: { ideal: 320 } });
c = track.getConstraints();
assert_object_equals(c, { width: { ideal: 320 } },
"getConstraints reflects only the most recent applyConstraints input " +
"(replaces prior constraints, not merges)");
assert_false("frameRate" in c,
"prior frameRate constraint cleared by second applyConstraints");
}, "getConstraints returns the [[Constraints]] internal slot (most recent successfully applied)");
promise_test(async test => {
// getSettings returns the [[Settings]] internal slot —
// the actual current operating values for each constrainable property.
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
test.add_cleanup(() => stream.getTracks().forEach(t => t.stop()));
const track = stream.getVideoTracks()[0];
const settings = track.getSettings();
assert_equals(typeof settings, "object", "getSettings returns an object");
// Settings must include a deviceId (the spec marks it as inherent
// constrainable property for every track).
assert_true("deviceId" in settings, "getSettings includes deviceId");
assert_equals(typeof settings.deviceId, "string", "deviceId is a string");
// Idempotent: two calls without mutation return equivalent content.
const settings2 = track.getSettings();
assert_object_equals(settings, settings2,
"two getSettings calls return equivalent content");
}, "getSettings returns the [[Settings]] internal slot as a plain object");
</script>
</head>
<body></body>
</html>