summaryrefslogtreecommitdiffstats
path: root/dom/permission/tests
diff options
context:
space:
mode:
Diffstat (limited to 'dom/permission/tests')
-rw-r--r--dom/permission/tests/file_empty.html2
-rw-r--r--dom/permission/tests/mochitest.ini11
-rw-r--r--dom/permission/tests/test_cross_origin_iframe.html251
-rw-r--r--dom/permission/tests/test_permissions_api.html298
4 files changed, 562 insertions, 0 deletions
diff --git a/dom/permission/tests/file_empty.html b/dom/permission/tests/file_empty.html
new file mode 100644
index 0000000000..15648ec5aa
--- /dev/null
+++ b/dom/permission/tests/file_empty.html
@@ -0,0 +1,2 @@
+<h1>I'm just a support file</h1>
+<p>I get loaded to do permission testing.</p>
diff --git a/dom/permission/tests/mochitest.ini b/dom/permission/tests/mochitest.ini
new file mode 100644
index 0000000000..fb631736f6
--- /dev/null
+++ b/dom/permission/tests/mochitest.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+support-files =
+ file_empty.html
+prefs =
+ dom.security.featurePolicy.header.enabled=true
+ dom.security.featurePolicy.webidl.enabled=true
+
+[test_cross_origin_iframe.html]
+fail-if = xorigin
+[test_permissions_api.html]
+skip-if = xorigin # Hangs
diff --git a/dom/permission/tests/test_cross_origin_iframe.html b/dom/permission/tests/test_cross_origin_iframe.html
new file mode 100644
index 0000000000..b024592e75
--- /dev/null
+++ b/dom/permission/tests/test_cross_origin_iframe.html
@@ -0,0 +1,251 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title>Test for Permissions API</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+
+<body>
+ <pre id="test"></pre>
+ <script type="application/javascript">
+ /*globals SpecialPowers, SimpleTest, is, ok, */
+ 'use strict';
+
+ function setPermission(type, allow) {
+ return new Promise(resolve => {
+ SpecialPowers.popPermissions(() => {
+ SpecialPowers.pushPermissions(
+ [{ type, allow, context: document }],
+ resolve
+ );
+ });
+ });
+ }
+
+ function checkPermission(aIFrame, aExpectedState, aName) {
+ return SpecialPowers.spawn(
+ aIFrame,
+ [{name: aName, expectedState: aExpectedState}],
+ async aInput => {
+ try {
+ let result = await content.navigator
+ .permissions
+ .query({ name: aInput.name });
+ is(
+ SpecialPowers.wrap(result).state,
+ aInput.expectedState,
+ `correct state for '${aInput.name}'`
+ );
+ } catch (e) {
+ ok(false, `query should not have rejected for '${aInput.name}'`)
+ }
+ }
+ );
+ }
+
+ function createIframe(aId, aAllow) {
+ return new Promise((resolve) => {
+ const iframe = document.createElement('iframe');
+ iframe.id = aId;
+ iframe.src = 'https://example.org/tests/dom/permission/tests/file_empty.html';
+ if (aAllow) {
+ iframe.allow = aAllow;
+ }
+ iframe.onload = () => resolve(iframe);
+ document.body.appendChild(iframe);
+ });
+ }
+
+ function removeIframe(aId) {
+ return new Promise((resolve) => {
+ document.body.removeChild(document.getElementById(aId));
+ resolve();
+ });
+ }
+
+ const {
+ UNKNOWN_ACTION,
+ PROMPT_ACTION,
+ ALLOW_ACTION,
+ DENY_ACTION
+ } = SpecialPowers.Ci.nsIPermissionManager;
+
+ const tests = [
+ {
+ id: 'query navigation top unknown',
+ top: UNKNOWN_ACTION,
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'denied',
+ },
+ {
+ id: 'query notifications top unknown',
+ top: UNKNOWN_ACTION,
+ name: 'notifications',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query push top unknown',
+ top: UNKNOWN_ACTION,
+ name: 'push',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query persistent-storage unknown',
+ top: UNKNOWN_ACTION,
+ name: 'persistent-storage',
+ type: 'persistent-storage',
+ expected: 'denied',
+ },
+ {
+ id: 'query navigation top prompt',
+ top: PROMPT_ACTION,
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'denied',
+ },
+ {
+ id: 'query notifications top prompt',
+ top: PROMPT_ACTION,
+ name: 'notifications',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query push top prompt',
+ top: PROMPT_ACTION,
+ name: 'push',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query persistent-storage top prompt',
+ top: PROMPT_ACTION,
+ name: 'persistent-storage',
+ type: 'persistent-storage',
+ expected: 'denied',
+ },
+ {
+ id: 'query navigation top denied',
+ top: DENY_ACTION,
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'denied',
+ },
+ {
+ id: 'query notifications top denied',
+ top: DENY_ACTION,
+ name: 'notifications',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query push top denied',
+ top: DENY_ACTION,
+ name: 'push',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query persistent-storage top denied',
+ top: DENY_ACTION,
+ name: 'persistent-storage',
+ type: 'persistent-storage',
+ expected: 'denied',
+ },
+ {
+ id: 'query navigation top granted',
+ top: ALLOW_ACTION,
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'denied',
+ },
+ {
+ id: 'query notifications top granted',
+ top: ALLOW_ACTION,
+ name: 'notifications',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query push top granted',
+ top: ALLOW_ACTION,
+ name: 'push',
+ type: 'desktop-notification',
+ expected: 'denied',
+ },
+ {
+ id: 'query persistent-storage top granted',
+ top: ALLOW_ACTION,
+ name: 'persistent-storage',
+ type: 'persistent-storage',
+ expected: 'denied',
+ },
+ {
+ id: 'query navigation top denied, iframe has allow attribute',
+ top: DENY_ACTION,
+ allow: 'geolocation',
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'denied',
+ },
+ {
+ id: 'query navigation top granted, iframe has allow attribute',
+ top: ALLOW_ACTION,
+ allow: 'geolocation',
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'granted',
+ },
+ {
+ id: 'query navigation top prompt, iframe has allow attribute',
+ top: PROMPT_ACTION,
+ allow: 'geolocation',
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'prompt',
+ },
+ {
+ id: 'query navigation top unknown, iframe has allow attribute',
+ top: UNKNOWN_ACTION,
+ allow: 'geolocation',
+ name: 'geolocation',
+ type: 'geo',
+ expected: 'prompt',
+ },
+
+ ];
+
+ SimpleTest.waitForExplicitFinish();
+
+ async function nextTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ let test = tests.shift();
+ await setPermission(test.type, test.top)
+ .then(() => createIframe(test.id, test.allow))
+ .then(iframe => checkPermission(iframe, test.expected, test.name))
+ .then(() => removeIframe(test.id));
+
+ SimpleTest.executeSoon(nextTest);
+ }
+
+ SpecialPowers.pushPrefEnv({"set": [
+ ["permissions.delegation.enabled", true],
+ ]}).then(nextTest);
+ </script>
+</body>
+
+</html>
diff --git a/dom/permission/tests/test_permissions_api.html b/dom/permission/tests/test_permissions_api.html
new file mode 100644
index 0000000000..bef0b56a03
--- /dev/null
+++ b/dom/permission/tests/test_permissions_api.html
@@ -0,0 +1,298 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title>Test for Permissions API</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+
+<body>
+ <pre id="test"></pre>
+ <script type="application/javascript">
+ /*globals SpecialPowers, SimpleTest, is, ok, */
+ 'use strict';
+
+ const {
+ UNKNOWN_ACTION,
+ PROMPT_ACTION,
+ ALLOW_ACTION,
+ DENY_ACTION
+ } = SpecialPowers.Ci.nsIPermissionManager;
+
+ SimpleTest.waitForExplicitFinish();
+
+ const PERMISSIONS = [{
+ name: 'geolocation',
+ type: 'geo'
+ }, {
+ name: 'notifications',
+ type: 'desktop-notification'
+ }, {
+ name: 'push',
+ type: 'desktop-notification'
+ }, {
+ name: 'persistent-storage',
+ type: 'persistent-storage'
+ }, {
+ name: 'midi',
+ type: 'midi'
+ }, ];
+
+ const UNSUPPORTED_PERMISSIONS = [
+ 'foobarbaz', // Not in spec, for testing only.
+ ];
+
+ // Create a closure, so that tests are run on the correct window object.
+ function createPermissionTester(iframe) {
+ const iframeWindow = iframe.contentWindow;
+ return {
+ async setPermissions(allow, context = iframeWindow.document) {
+ const permissions = PERMISSIONS.map(({ type }) => {
+ return {
+ type,
+ allow,
+ context,
+ };
+ });
+ await SpecialPowers.popPermissions();
+ return SpecialPowers.pushPermissions(permissions);
+ },
+ revokePermissions() {
+ const promisesToRevoke = PERMISSIONS.map(({ name }) => {
+ return iframeWindow.navigator.permissions
+ .revoke({ name })
+ .then(
+ ({ state }) => is(state, 'prompt', `correct state for '${name}'`),
+ () => ok(false, `revoke should not have rejected for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToRevoke);
+ },
+ revokeUnsupportedPermissions() {
+ const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
+ return iframeWindow.navigator.permissions
+ .revoke({ name })
+ .then(
+ () => ok(false, `revoke should not have resolved for '${name}'`),
+ error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToRevoke);
+ },
+ checkPermissions(expectedState) {
+ const promisesToQuery = PERMISSIONS.map(({ name: expectedName }) => {
+ return iframeWindow.navigator.permissions
+ .query({ name: expectedName })
+ .then(
+ ({ state, name }) => {
+ is(state, expectedState, `correct state for '${expectedName}'`)
+ is(name, expectedName, `correct name for '${expectedName}'`)
+ },
+ () => ok(false, `query should not have rejected for '${name}'`)
+ );
+ });
+ return Promise.all(promisesToQuery);
+ },
+ checkUnsupportedPermissions() {
+ const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
+ return iframeWindow.navigator.permissions
+ .query({ name })
+ .then(
+ () => ok(false, `query should not have resolved for '${name}'`),
+ error => {
+ is(error.name, 'TypeError',
+ `query should have thrown TypeError for '${name}'`);
+ }
+ );
+ });
+ return Promise.all(promisesToQuery);
+ },
+ promiseStateChanged(name, state) {
+ return iframeWindow.navigator.permissions
+ .query({ name })
+ .then(status => {
+ return new Promise( resolve => {
+ status.onchange = () => {
+ status.onchange = null;
+ is(status.state, state, `state changed for '${name}'`);
+ resolve();
+ };
+ });
+ },
+ () => ok(false, `query should not have rejected for '${name}'`));
+ },
+ testStatusOnChange() {
+ return new Promise((resolve) => {
+ SpecialPowers.popPermissions(() => {
+ const permission = 'geolocation';
+ const promiseGranted = this.promiseStateChanged(permission, 'granted');
+ this.setPermissions(ALLOW_ACTION);
+ promiseGranted.then(async () => {
+ const promisePrompt = this.promiseStateChanged(permission, 'prompt');
+ await SpecialPowers.popPermissions();
+ return promisePrompt;
+ }).then(resolve);
+ });
+ });
+ },
+ testInvalidQuery() {
+ return iframeWindow.navigator.permissions
+ .query({ name: 'invalid' })
+ .then(
+ () => ok(false, 'invalid query should not have resolved'),
+ () => ok(true, 'invalid query should have rejected')
+ );
+ },
+ testInvalidRevoke() {
+ return iframeWindow.navigator.permissions
+ .revoke({ name: 'invalid' })
+ .then(
+ () => ok(false, 'invalid revoke should not have resolved'),
+ () => ok(true, 'invalid revoke should have rejected')
+ );
+ },
+ async testNotFullyActiveDoc() {
+ const iframe1 = await createIframe();
+ const expectedErrorClass = iframe1.contentWindow.DOMException;
+ const permAPI = iframe1.contentWindow.navigator.permissions;
+ // Document no longer fully active
+ iframe1.remove();
+ await new Promise((res) => {
+ permAPI.query({ name: "geolocation" }).catch((error) => {
+ ok(
+ error instanceof expectedErrorClass,
+ "DOMException from other realm"
+ );
+ is(
+ error.name,
+ "InvalidStateError",
+ "Must reject with a InvalidStateError"
+ );
+ iframe1.remove();
+ res();
+ });
+ });
+ },
+ async testNotFullyActiveChange() {
+ await SpecialPowers.popPermissions();
+ const iframe2 = await createIframe();
+ const initialStatus = await iframe2.contentWindow.navigator.permissions.query(
+ { name: "geolocation" }
+ );
+ await SpecialPowers.pushPermissions([
+ {
+ type: "geo",
+ allow: PROMPT_ACTION,
+ context: iframe2.contentWindow.document,
+ },
+ ]);
+ is(
+ initialStatus.state,
+ "prompt",
+ "Initially the iframe's permission is prompt"
+ );
+
+ // Document no longer fully active
+ const stolenDoc = iframe2.contentWindow.document;
+ iframe2.remove();
+ initialStatus.onchange = () => {
+ ok(false, "onchange must not fire when document is not fully active.");
+ };
+ // We set it to grant for this origin, but the PermissionStatus doesn't change.
+ await SpecialPowers.pushPermissions([
+ {
+ type: "geo",
+ allow: ALLOW_ACTION,
+ context: stolenDoc,
+ },
+ ]);
+ is(
+ initialStatus.state,
+ "prompt",
+ "Inactive document's permission must not change"
+ );
+
+ // Re-attach the iframe
+ document.body.appendChild(iframe2);
+ await new Promise((res) => (iframe2.onload = res));
+ // Fully active again
+ const newStatus = await iframe2.contentWindow.navigator.permissions.query({
+ name: "geolocation",
+ });
+ is(newStatus.state, "granted", "Reflect that we are granted");
+
+ const newEventPromise = new Promise((res) => (newStatus.onchange = res));
+ await SpecialPowers.pushPermissions([
+ {
+ type: "geo",
+ allow: DENY_ACTION,
+ context: iframe2.contentWindow.document,
+ },
+ ]);
+ // Event fires...
+ await newEventPromise;
+ is(initialStatus.state, "prompt", "Remains prompt, as it's actually dead.");
+ is(newStatus.state, "denied", "New status must be 'denied'.");
+ iframe2.remove();
+ },
+ };
+ }
+
+ function enablePrefs() {
+ const ops = {
+ 'set': [
+ ['dom.permissions.revoke.enable', true],
+ ],
+ };
+ return SpecialPowers.pushPrefEnv(ops);
+ }
+
+ function createIframe() {
+ return new Promise((resolve) => {
+ const iframe = document.createElement('iframe');
+ iframe.src = 'file_empty.html';
+ iframe.onload = () => resolve(iframe);
+ document.body.appendChild(iframe);
+ });
+ }
+
+ window.onload = () => {
+ enablePrefs()
+ .then(createIframe)
+ .then(createPermissionTester)
+ .then((tester) => {
+ return tester
+ .checkUnsupportedPermissions()
+ .then(() => tester.setPermissions(UNKNOWN_ACTION))
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.setPermissions(PROMPT_ACTION))
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.setPermissions(ALLOW_ACTION))
+ .then(() => tester.checkPermissions('granted'))
+ .then(() => tester.setPermissions(DENY_ACTION))
+ .then(() => tester.checkPermissions('denied'))
+ .then(() => tester.testStatusOnChange())
+ .then(() => tester.testInvalidQuery())
+ .then(() => tester.revokeUnsupportedPermissions())
+ .then(() => tester.revokePermissions())
+ .then(() => tester.checkPermissions('prompt'))
+ .then(() => tester.testInvalidRevoke())
+ .then(() => tester.testNotFullyActiveDoc())
+ .then(() => tester.testNotFullyActiveChange());
+ })
+ .then(SimpleTest.finish)
+ .catch((e) => {
+ ok(false, `Unexpected error ${e}`);
+ SimpleTest.finish();
+ });
+ };
+ </script>
+</body>
+
+</html>