Bug 1322856 - Expose ContextualIdentities (aka containers) to WebExtensions - part 1, r=kmaglione
This commit is contained in:
@@ -16,6 +16,8 @@ module.exports = { // eslint-disable-line no-undef
|
|||||||
"Extension": true,
|
"Extension": true,
|
||||||
"ExtensionManagement": true,
|
"ExtensionManagement": true,
|
||||||
"extensions": true,
|
"extensions": true,
|
||||||
|
"getContainerForCookieStoreId": true,
|
||||||
|
"getCookieStoreIdForContainer": true,
|
||||||
"global": true,
|
"global": true,
|
||||||
"NetUtil": true,
|
"NetUtil": true,
|
||||||
"openOptionsPage": true,
|
"openOptionsPage": true,
|
||||||
|
|||||||
@@ -429,10 +429,21 @@ this.ExtensionData = class {
|
|||||||
// Errors are handled by the type checks above.
|
// Errors are handled by the type checks above.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let containersEnabled = true;
|
||||||
|
try {
|
||||||
|
containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||||
|
} catch (e) {
|
||||||
|
// If we fail here, we are in some xpcshell test.
|
||||||
|
}
|
||||||
|
|
||||||
let permissions = this.manifest.permissions || [];
|
let permissions = this.manifest.permissions || [];
|
||||||
|
|
||||||
let whitelist = [];
|
let whitelist = [];
|
||||||
for (let perm of permissions) {
|
for (let perm of permissions) {
|
||||||
|
if (perm == "contextualIdentities" && !containersEnabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
this.permissions.add(perm);
|
this.permissions.add(perm);
|
||||||
|
|
||||||
let match = /^(\w+)(?:\.(\w+)(?:\.\w+)*)?$/.exec(perm);
|
let match = /^(\w+)(?:\.(\w+)(?:\.\w+)*)?$/.exec(perm);
|
||||||
|
|||||||
109
toolkit/components/extensions/ext-contextualIdentities.js
Normal file
109
toolkit/components/extensions/ext-contextualIdentities.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {interfaces: Ci, utils: Cu} = Components;
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
|
||||||
|
"resource://gre/modules/ContextualIdentityService.jsm");
|
||||||
|
|
||||||
|
function convert(identity) {
|
||||||
|
let result = {
|
||||||
|
name: ContextualIdentityService.getUserContextLabel(identity.userContextId),
|
||||||
|
icon: identity.icon,
|
||||||
|
color: identity.color,
|
||||||
|
cookieStoreId: getCookieStoreIdForContainer(identity.userContextId),
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.registerSchemaAPI("contextualIdentities", "addon_parent", context => {
|
||||||
|
let self = {
|
||||||
|
contextualIdentities: {
|
||||||
|
get(cookieStoreId) {
|
||||||
|
let containerId = getContainerForCookieStoreId(cookieStoreId);
|
||||||
|
if (!containerId) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
let identity = ContextualIdentityService.getIdentityFromId(containerId);
|
||||||
|
return Promise.resolve(convert(identity));
|
||||||
|
},
|
||||||
|
|
||||||
|
query(details) {
|
||||||
|
let identities = [];
|
||||||
|
ContextualIdentityService.getIdentities().forEach(identity => {
|
||||||
|
if (details.name &&
|
||||||
|
ContextualIdentityService.getUserContextLabel(identity.userContextId) != details.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
identities.push(convert(identity));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(identities);
|
||||||
|
},
|
||||||
|
|
||||||
|
create(details) {
|
||||||
|
let identity = ContextualIdentityService.create(details.name,
|
||||||
|
details.icon,
|
||||||
|
details.color);
|
||||||
|
return Promise.resolve(convert(identity));
|
||||||
|
},
|
||||||
|
|
||||||
|
update(cookieStoreId, details) {
|
||||||
|
let containerId = getContainerForCookieStoreId(cookieStoreId);
|
||||||
|
if (!containerId) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
let identity = ContextualIdentityService.getIdentityFromId(containerId);
|
||||||
|
if (!identity) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (details.name !== null) {
|
||||||
|
identity.name = details.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (details.color !== null) {
|
||||||
|
identity.color = details.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (details.icon !== null) {
|
||||||
|
identity.icon = details.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ContextualIdentityService.update(identity.userContextId,
|
||||||
|
identity.name, identity.icon,
|
||||||
|
identity.color)) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(convert(identity));
|
||||||
|
},
|
||||||
|
|
||||||
|
remove(cookieStoreId) {
|
||||||
|
let containerId = getContainerForCookieStoreId(cookieStoreId);
|
||||||
|
if (!containerId) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
let identity = ContextualIdentityService.getIdentityFromId(containerId);
|
||||||
|
if (!identity) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to create the identity object before removing it.
|
||||||
|
let convertedIdentity = convert(identity);
|
||||||
|
|
||||||
|
if (!ContextualIdentityService.remove(identity.userContextId)) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(convertedIdentity);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
});
|
||||||
@@ -22,7 +22,7 @@ global.getCookieStoreIdForTab = function(data, tab) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tab.userContextId) {
|
if (tab.userContextId) {
|
||||||
return CONTAINER_STORE + tab.userContextId;
|
return getCookieStoreIdForContainer(tab.userContextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DEFAULT_STORE;
|
return DEFAULT_STORE;
|
||||||
@@ -40,6 +40,10 @@ global.isContainerCookieStoreId = function(storeId) {
|
|||||||
return storeId !== null && storeId.startsWith(CONTAINER_STORE);
|
return storeId !== null && storeId.startsWith(CONTAINER_STORE);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
global.getCookieStoreIdForContainer = function(containerId) {
|
||||||
|
return CONTAINER_STORE + containerId;
|
||||||
|
};
|
||||||
|
|
||||||
global.getContainerForCookieStoreId = function(storeId) {
|
global.getContainerForCookieStoreId = function(storeId) {
|
||||||
if (!global.isContainerCookieStoreId(storeId)) {
|
if (!global.isContainerCookieStoreId(storeId)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -76,7 +80,7 @@ function convert({cookie, isPrivate}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.originAttributes.userContextId) {
|
if (cookie.originAttributes.userContextId) {
|
||||||
result.storeId = CONTAINER_STORE + cookie.originAttributes.userContextId;
|
result.storeId = getCookieStoreIdForContainer(cookie.originAttributes.userContextId);
|
||||||
} else if (cookie.originAttributes.privateBrowsingId || isPrivate) {
|
} else if (cookie.originAttributes.privateBrowsingId || isPrivate) {
|
||||||
result.storeId = PRIVATE_STORE;
|
result.storeId = PRIVATE_STORE;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# scripts
|
# scripts
|
||||||
category webextension-scripts alarms chrome://extensions/content/ext-alarms.js
|
category webextension-scripts alarms chrome://extensions/content/ext-alarms.js
|
||||||
category webextension-scripts backgroundPage chrome://extensions/content/ext-backgroundPage.js
|
category webextension-scripts backgroundPage chrome://extensions/content/ext-backgroundPage.js
|
||||||
|
category webextension-scripts contextualIdentities chrome://extensions/content/ext-contextualIdentities.js
|
||||||
category webextension-scripts cookies chrome://extensions/content/ext-cookies.js
|
category webextension-scripts cookies chrome://extensions/content/ext-cookies.js
|
||||||
category webextension-scripts downloads chrome://extensions/content/ext-downloads.js
|
category webextension-scripts downloads chrome://extensions/content/ext-downloads.js
|
||||||
category webextension-scripts management chrome://extensions/content/ext-management.js
|
category webextension-scripts management chrome://extensions/content/ext-management.js
|
||||||
@@ -41,6 +42,7 @@ category webextension-scripts-addon storage chrome://extensions/content/ext-c-st
|
|||||||
|
|
||||||
# schemas
|
# schemas
|
||||||
category webextension-schemas alarms chrome://extensions/content/schemas/alarms.json
|
category webextension-schemas alarms chrome://extensions/content/schemas/alarms.json
|
||||||
|
category webextension-schemas contextualIdentities chrome://extensions/content/schemas/contextual_identities.json
|
||||||
category webextension-schemas cookies chrome://extensions/content/schemas/cookies.json
|
category webextension-schemas cookies chrome://extensions/content/schemas/cookies.json
|
||||||
category webextension-schemas downloads chrome://extensions/content/schemas/downloads.json
|
category webextension-schemas downloads chrome://extensions/content/schemas/downloads.json
|
||||||
category webextension-schemas events chrome://extensions/content/schemas/events.json
|
category webextension-schemas events chrome://extensions/content/schemas/events.json
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ toolkit.jar:
|
|||||||
content/extensions/ext-alarms.js
|
content/extensions/ext-alarms.js
|
||||||
content/extensions/ext-backgroundPage.js
|
content/extensions/ext-backgroundPage.js
|
||||||
content/extensions/ext-browser-content.js
|
content/extensions/ext-browser-content.js
|
||||||
|
content/extensions/ext-contextualIdentities.js
|
||||||
content/extensions/ext-cookies.js
|
content/extensions/ext-cookies.js
|
||||||
content/extensions/ext-downloads.js
|
content/extensions/ext-downloads.js
|
||||||
content/extensions/ext-management.js
|
content/extensions/ext-management.js
|
||||||
|
|||||||
123
toolkit/components/extensions/schemas/contextual_identities.json
Normal file
123
toolkit/components/extensions/schemas/contextual_identities.json
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"namespace": "manifest",
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"$extend": "Permission",
|
||||||
|
"choices": [{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"contextualIdentities"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"namespace": "contextualIdentities",
|
||||||
|
"description": "Use the <code>browser.contextualIdentities</code> API to query and modify contextual identity, also called as containers.",
|
||||||
|
"permissions": ["contextualIdentities"],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"id": "ContextualIdentity",
|
||||||
|
"type": "object",
|
||||||
|
"description": "Represents information about a contextual identity.",
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "description": "The name of the contextual identity."},
|
||||||
|
"icon": {"type": "string", "description": "The icon of the contextual identity."},
|
||||||
|
"color": {"type": "string", "description": "The color of the contextual identity."},
|
||||||
|
"cookieStoreId": {"type": "string", "description": "The cookie store ID of the contextual identity."}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"functions": [
|
||||||
|
{
|
||||||
|
"name": "get",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Retrieves information about a single contextual identity.",
|
||||||
|
"async": true,
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "cookieStoreId",
|
||||||
|
"description": "The ID of the contextual identity cookie store. "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "query",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Retrieves all contextual identities",
|
||||||
|
"async": true,
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"name": "details",
|
||||||
|
"description": "Information to filter the contextual identities being retrieved.",
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "optional": true, "description": "Filters the contextual identity by name."}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "create",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Creates a contextual identity with the given data.",
|
||||||
|
"async": true,
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"name": "details",
|
||||||
|
"description": "Details about the contextual identity being created.",
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "optional": false, "description": "The name of the contextual identity." },
|
||||||
|
"color": {"type": "string", "optional": false, "description": "The color of the contextual identity." },
|
||||||
|
"icon": {"type": "string", "optional": false, "description": "The icon of the contextual identity." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "update",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Updates a contextual identity with the given data.",
|
||||||
|
"async": true,
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "cookieStoreId",
|
||||||
|
"description": "The ID of the contextual identity cookie store. "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"name": "details",
|
||||||
|
"description": "Details about the contextual identity being created.",
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "optional": true, "description": "The name of the contextual identity." },
|
||||||
|
"color": {"type": "string", "optional": true, "description": "The color of the contextual identity." },
|
||||||
|
"icon": {"type": "string", "optional": true, "description": "The icon of the contextual identity." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "remove",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Deletes a contetual identity by its cookie Store ID.",
|
||||||
|
"async": true,
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "cookieStoreId",
|
||||||
|
"description": "The ID of the contextual identity cookie store. "
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
toolkit.jar:
|
toolkit.jar:
|
||||||
% content extensions %content/extensions/
|
% content extensions %content/extensions/
|
||||||
content/extensions/schemas/alarms.json
|
content/extensions/schemas/alarms.json
|
||||||
|
content/extensions/schemas/contextual_identities.json
|
||||||
content/extensions/schemas/cookies.json
|
content/extensions/schemas/cookies.json
|
||||||
content/extensions/schemas/downloads.json
|
content/extensions/schemas/downloads.json
|
||||||
content/extensions/schemas/events.json
|
content/extensions/schemas/events.json
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
do_get_profile();
|
||||||
|
|
||||||
|
add_task(function* test_contextualIdentities_without_permissions() {
|
||||||
|
function backgroundScript() {
|
||||||
|
browser.test.assertTrue(!browser.contextualIdentities,
|
||||||
|
"contextualIdentities API is not available when the contextualIdentities permission is not required");
|
||||||
|
browser.test.notifyPass("contextualIdentities_permission");
|
||||||
|
}
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: `(${backgroundScript})()`,
|
||||||
|
manifest: {
|
||||||
|
permissions: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
yield extension.startup();
|
||||||
|
yield extension.awaitFinish("contextualIdentities_permission");
|
||||||
|
yield extension.unload();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
add_task(function* test_contextualIdentity_no_containers() {
|
||||||
|
function backgroundScript() {
|
||||||
|
browser.test.assertTrue(!browser.contextualIdentities,
|
||||||
|
"contextualIdentities API is not available when the containers are disabled");
|
||||||
|
browser.test.notifyPass("contextualIdentities_pref");
|
||||||
|
}
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: `(${backgroundScript})()`,
|
||||||
|
manifest: {
|
||||||
|
permissions: ["contextualIdentities"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||||
|
|
||||||
|
yield extension.startup();
|
||||||
|
yield extension.awaitFinish("contextualIdentities_pref");
|
||||||
|
yield extension.unload();
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("privacy.userContext.enabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* test_contextualIdentity_with_permissions() {
|
||||||
|
async function backgroundScript() {
|
||||||
|
let ci = await browser.contextualIdentities.get("foobar");
|
||||||
|
browser.test.assertEq(null, ci, "No identity should be returned here");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.get("firefox-container-1");
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertTrue("name" in ci, "We have an identity.name");
|
||||||
|
browser.test.assertTrue("color" in ci, "We have an identity.color");
|
||||||
|
browser.test.assertTrue("icon" in ci, "We have an identity.icon");
|
||||||
|
browser.test.assertEq("Personal", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("firefox-container-1", ci.cookieStoreId, "identity.cookieStoreId is correct");
|
||||||
|
|
||||||
|
let cis = await browser.contextualIdentities.query({});
|
||||||
|
browser.test.assertEq(4, cis.length, "by default we should have 4 containers");
|
||||||
|
|
||||||
|
cis = await browser.contextualIdentities.query({name: "Personal"});
|
||||||
|
browser.test.assertEq(1, cis.length, "by default we should have 1 container called Personal");
|
||||||
|
|
||||||
|
cis = await browser.contextualIdentities.query({name: "foobar"});
|
||||||
|
browser.test.assertEq(0, cis.length, "by default we should have 0 container called foobar");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.create({name: "foobar", color: "red", icon: "icon"});
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertEq("foobar", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("red", ci.color, "identity.color is correct");
|
||||||
|
browser.test.assertEq("icon", ci.icon, "identity.icon is correct");
|
||||||
|
browser.test.assertTrue(!!ci.cookieStoreId, "identity.cookieStoreId is correct");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.get(ci.cookieStoreId);
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertEq("foobar", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("red", ci.color, "identity.color is correct");
|
||||||
|
browser.test.assertEq("icon", ci.icon, "identity.icon is correct");
|
||||||
|
|
||||||
|
cis = await browser.contextualIdentities.query({});
|
||||||
|
browser.test.assertEq(5, cis.length, "now we have 5 identities");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.update(ci.cookieStoreId, {name: "barfoo", color: "blue", icon: "icon icon"});
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertEq("barfoo", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("blue", ci.color, "identity.color is correct");
|
||||||
|
browser.test.assertEq("icon icon", ci.icon, "identity.icon is correct");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.get(ci.cookieStoreId);
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertEq("barfoo", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("blue", ci.color, "identity.color is correct");
|
||||||
|
browser.test.assertEq("icon icon", ci.icon, "identity.icon is correct");
|
||||||
|
|
||||||
|
ci = await browser.contextualIdentities.remove(ci.cookieStoreId);
|
||||||
|
browser.test.assertTrue(!!ci, "We have an identity");
|
||||||
|
browser.test.assertEq("barfoo", ci.name, "identity.name is correct");
|
||||||
|
browser.test.assertEq("blue", ci.color, "identity.color is correct");
|
||||||
|
browser.test.assertEq("icon icon", ci.icon, "identity.icon is correct");
|
||||||
|
|
||||||
|
cis = await browser.contextualIdentities.query({});
|
||||||
|
browser.test.assertEq(4, cis.length, "we are back to 4 identities");
|
||||||
|
|
||||||
|
browser.test.notifyPass("contextualIdentities");
|
||||||
|
}
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: `(${backgroundScript})()`,
|
||||||
|
manifest: {
|
||||||
|
permissions: ["contextualIdentities"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref("privacy.userContext.enabled", true);
|
||||||
|
|
||||||
|
yield extension.startup();
|
||||||
|
yield extension.awaitFinish("contextualIdentities");
|
||||||
|
yield extension.unload();
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("privacy.userContext.enabled");
|
||||||
|
});
|
||||||
@@ -25,6 +25,8 @@ skip-if = os == "android" # Android does not use Places for history.
|
|||||||
[test_ext_background_window_properties.js]
|
[test_ext_background_window_properties.js]
|
||||||
skip-if = os == "android"
|
skip-if = os == "android"
|
||||||
[test_ext_contexts.js]
|
[test_ext_contexts.js]
|
||||||
|
[test_ext_contextual_identities.js]
|
||||||
|
skip-if = os == "android" # Containers are not exposed to android.
|
||||||
[test_ext_downloads.js]
|
[test_ext_downloads.js]
|
||||||
[test_ext_downloads_download.js]
|
[test_ext_downloads_download.js]
|
||||||
skip-if = os == "android"
|
skip-if = os == "android"
|
||||||
|
|||||||
Reference in New Issue
Block a user