forked from mirrors/gecko-dev
MozReview-Commit-ID: HbqFgaBWCP8 --HG-- rename : toolkit/modules/tests/browser/.eslintrc.js => toolkit/components/remotepagemanager/tests/browser/.eslintrc.js rename : toolkit/modules/tests/browser/browser_RemotePageManager.js => toolkit/components/remotepagemanager/tests/browser/browser_RemotePageManager.js rename : toolkit/modules/tests/browser/testremotepagemanager.html => toolkit/components/remotepagemanager/tests/browser/testremotepagemanager.html rename : toolkit/modules/tests/browser/testremotepagemanager2.html => toolkit/components/remotepagemanager/tests/browser/testremotepagemanager2.html extra : rebase_source : 193874a39cf4fd383bd6e28a9536b0602905d4ac
504 lines
18 KiB
JavaScript
504 lines
18 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
const TEST_URL = "http://www.example.com/browser/toolkit/components/remotepagemanager/tests/browser/testremotepagemanager.html";
|
|
|
|
var { RemotePages, RemotePageManager } =
|
|
ChromeUtils.import("resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm", {});
|
|
|
|
function failOnMessage(message) {
|
|
ok(false, "Should not have seen message " + message.name);
|
|
}
|
|
|
|
function waitForMessage(port, message, expectedPort = port) {
|
|
return new Promise((resolve) => {
|
|
function listener(message) {
|
|
is(message.target, expectedPort, "Message should be from the right port.");
|
|
|
|
port.removeMessageListener(listener);
|
|
resolve(message);
|
|
}
|
|
|
|
port.addMessageListener(message, listener);
|
|
});
|
|
}
|
|
|
|
function waitForPort(url, createTab = true) {
|
|
return new Promise((resolve) => {
|
|
RemotePageManager.addRemotePageListener(url, (port) => {
|
|
RemotePageManager.removeRemotePageListener(url);
|
|
|
|
waitForMessage(port, "RemotePage:Load").then(() => resolve(port));
|
|
});
|
|
|
|
if (createTab)
|
|
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, url);
|
|
});
|
|
}
|
|
|
|
function waitForPage(pages, url = TEST_URL) {
|
|
return new Promise((resolve) => {
|
|
function listener({ target }) {
|
|
pages.removeMessageListener("RemotePage:Init", listener);
|
|
|
|
waitForMessage(target, "RemotePage:Load").then(() => resolve(target));
|
|
}
|
|
|
|
pages.addMessageListener("RemotePage:Init", listener);
|
|
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, url);
|
|
});
|
|
}
|
|
|
|
function swapDocShells(browser1, browser2) {
|
|
// Swap frameLoaders.
|
|
browser1.swapDocShells(browser2);
|
|
|
|
// Swap permanentKeys.
|
|
let tmp = browser1.permanentKey;
|
|
browser1.permanentKey = browser2.permanentKey;
|
|
browser2.permanentKey = tmp;
|
|
}
|
|
|
|
add_task(async function sharedData_aka_initialProcessData() {
|
|
const includesTest = () => Services.cpmm.
|
|
sharedData.get("RemotePageManager:urls").has(TEST_URL);
|
|
is(includesTest(), false, "Shouldn't have test url in initial process data yet");
|
|
|
|
const loadedPort = waitForPort(TEST_URL);
|
|
is(includesTest(), true, "Should have test url when waiting for it to load");
|
|
|
|
await loadedPort;
|
|
is(includesTest(), false, "Should have test url removed when done listening");
|
|
|
|
gBrowser.removeCurrentTab();
|
|
});
|
|
|
|
// Test that opening a page creates a port, sends the load event and then
|
|
// navigating to a new page sends the unload event. Going back should create a
|
|
// new port
|
|
add_task(async function init_navigate() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
|
gBrowser.loadURI("about:blank");
|
|
|
|
await waitForMessage(port, "RemotePage:Unload");
|
|
|
|
// Port should be destroyed now
|
|
try {
|
|
port.addMessageListener("Foo", failOnMessage);
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
port.sendAsyncMessage("Foo");
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
|
|
await loaded;
|
|
|
|
gBrowser.goBack();
|
|
port = await waitForPort(TEST_URL, false);
|
|
|
|
port.sendAsyncMessage("Ping2");
|
|
await waitForMessage(port, "Pong2");
|
|
port.destroy();
|
|
|
|
gBrowser.removeCurrentTab();
|
|
});
|
|
|
|
// Test that opening a page creates a port, sends the load event and then
|
|
// closing the tab sends the unload event
|
|
add_task(async function init_close() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
|
gBrowser.removeCurrentTab();
|
|
await unloadPromise;
|
|
|
|
// Port should be destroyed now
|
|
try {
|
|
port.addMessageListener("Foo", failOnMessage);
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
port.sendAsyncMessage("Foo");
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
});
|
|
|
|
// Tests that we can send messages to individual pages even when more than one
|
|
// is open
|
|
add_task(async function multiple_ports() {
|
|
let port1 = await waitForPort(TEST_URL);
|
|
is(port1.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
let port2 = await waitForPort(TEST_URL);
|
|
is(port2.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
port2.addMessageListener("Pong", failOnMessage);
|
|
port1.sendAsyncMessage("Ping", { str: "foobar", counter: 0 });
|
|
let message = await waitForMessage(port1, "Pong");
|
|
port2.removeMessageListener("Pong", failOnMessage);
|
|
is(message.data.str, "foobar", "String should pass through");
|
|
is(message.data.counter, 1, "Counter should be incremented");
|
|
|
|
port1.addMessageListener("Pong", failOnMessage);
|
|
port2.sendAsyncMessage("Ping", { str: "foobaz", counter: 5 });
|
|
message = await waitForMessage(port2, "Pong");
|
|
port1.removeMessageListener("Pong", failOnMessage);
|
|
is(message.data.str, "foobaz", "String should pass through");
|
|
is(message.data.counter, 6, "Counter should be incremented");
|
|
|
|
let unloadPromise = waitForMessage(port2, "RemotePage:Unload");
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(port2.browser));
|
|
await unloadPromise;
|
|
|
|
try {
|
|
port2.addMessageListener("Pong", failOnMessage);
|
|
ok(false, "Should not have been able to add a new message listener to a destroyed port.");
|
|
} catch (e) {
|
|
ok(true, "Should not have been able to add a new message listener to a destroyed port.");
|
|
}
|
|
|
|
port1.sendAsyncMessage("Ping", { str: "foobar", counter: 0 });
|
|
message = await waitForMessage(port1, "Pong");
|
|
is(message.data.str, "foobar", "String should pass through");
|
|
is(message.data.counter, 1, "Counter should be incremented");
|
|
|
|
unloadPromise = waitForMessage(port1, "RemotePage:Unload");
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(port1.browser));
|
|
await unloadPromise;
|
|
});
|
|
|
|
// Tests that swapping browser docshells doesn't break the ports
|
|
add_task(async function browser_switch() {
|
|
let port1 = await waitForPort(TEST_URL);
|
|
is(port1.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
let browser1 = gBrowser.selectedBrowser;
|
|
port1.sendAsyncMessage("SetCookie", { value: "om nom" });
|
|
|
|
let port2 = await waitForPort(TEST_URL);
|
|
is(port2.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
let browser2 = gBrowser.selectedBrowser;
|
|
port2.sendAsyncMessage("SetCookie", { value: "om nom nom" });
|
|
|
|
port2.addMessageListener("Cookie", failOnMessage);
|
|
port1.sendAsyncMessage("GetCookie");
|
|
let message = await waitForMessage(port1, "Cookie");
|
|
port2.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom", "Should have the right cookie");
|
|
|
|
port1.addMessageListener("Cookie", failOnMessage);
|
|
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
|
message = await waitForMessage(port2, "Cookie");
|
|
port1.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom nom", "Should have the right cookie");
|
|
|
|
swapDocShells(browser1, browser2);
|
|
is(port1.browser, browser2, "Should have noticed the swap");
|
|
is(port2.browser, browser1, "Should have noticed the swap");
|
|
|
|
// Cookies should have stayed the same
|
|
port2.addMessageListener("Cookie", failOnMessage);
|
|
port1.sendAsyncMessage("GetCookie");
|
|
message = await waitForMessage(port1, "Cookie");
|
|
port2.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom", "Should have the right cookie");
|
|
|
|
port1.addMessageListener("Cookie", failOnMessage);
|
|
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
|
message = await waitForMessage(port2, "Cookie");
|
|
port1.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom nom", "Should have the right cookie");
|
|
|
|
swapDocShells(browser1, browser2);
|
|
is(port1.browser, browser1, "Should have noticed the swap");
|
|
is(port2.browser, browser2, "Should have noticed the swap");
|
|
|
|
// Cookies should have stayed the same
|
|
port2.addMessageListener("Cookie", failOnMessage);
|
|
port1.sendAsyncMessage("GetCookie");
|
|
message = await waitForMessage(port1, "Cookie");
|
|
port2.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom", "Should have the right cookie");
|
|
|
|
port1.addMessageListener("Cookie", failOnMessage);
|
|
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
|
message = await waitForMessage(port2, "Cookie");
|
|
port1.removeMessageListener("Cookie", failOnMessage);
|
|
is(message.data.value, "om nom nom", "Should have the right cookie");
|
|
|
|
let unloadPromise = waitForMessage(port2, "RemotePage:Unload");
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(browser2));
|
|
await unloadPromise;
|
|
|
|
unloadPromise = waitForMessage(port1, "RemotePage:Unload");
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(browser1));
|
|
await unloadPromise;
|
|
});
|
|
|
|
// Tests that removeMessageListener in chrome works
|
|
add_task(async function remove_chrome_listener() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
// This relies on messages sent arriving in the same order. Pong will be
|
|
// sent back before Pong2 so if removeMessageListener fails the test will fail
|
|
port.addMessageListener("Pong", failOnMessage);
|
|
port.removeMessageListener("Pong", failOnMessage);
|
|
port.sendAsyncMessage("Ping", { str: "remove_listener", counter: 27 });
|
|
port.sendAsyncMessage("Ping2");
|
|
await waitForMessage(port, "Pong2");
|
|
|
|
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
|
gBrowser.removeCurrentTab();
|
|
await unloadPromise;
|
|
});
|
|
|
|
// Tests that removeMessageListener in content works
|
|
add_task(async function remove_content_listener() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
// This relies on messages sent arriving in the same order. Pong3 would be
|
|
// sent back before Pong2 so if removeMessageListener fails the test will fail
|
|
port.addMessageListener("Pong3", failOnMessage);
|
|
port.sendAsyncMessage("Ping3");
|
|
port.sendAsyncMessage("Ping2");
|
|
await waitForMessage(port, "Pong2");
|
|
|
|
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
|
gBrowser.removeCurrentTab();
|
|
await unloadPromise;
|
|
});
|
|
|
|
// Test RemotePages works
|
|
add_task(async function remote_pages_basic() {
|
|
let pages = new RemotePages(TEST_URL);
|
|
let port = await waitForPage(pages);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
// Listening to global messages should work
|
|
let unloadPromise = waitForMessage(pages, "RemotePage:Unload", port);
|
|
gBrowser.removeCurrentTab();
|
|
await unloadPromise;
|
|
|
|
pages.destroy();
|
|
|
|
// RemotePages should be destroyed now
|
|
try {
|
|
pages.addMessageListener("Foo", failOnMessage);
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
|
|
try {
|
|
pages.sendAsyncMessage("Foo");
|
|
ok(false, "Should have seen exception");
|
|
} catch (e) {
|
|
ok(true, "Should have seen exception");
|
|
}
|
|
});
|
|
|
|
// Test that properties exist on the target port provided to listeners
|
|
add_task(async function check_port_properties() {
|
|
let pages = new RemotePages(TEST_URL);
|
|
|
|
const expectedProperties = [
|
|
"addMessageListener",
|
|
"browser",
|
|
"destroy",
|
|
"loaded",
|
|
"portID",
|
|
"removeMessageListener",
|
|
"sendAsyncMessage",
|
|
"url"
|
|
];
|
|
function checkProperties(port, description) {
|
|
const expected = [];
|
|
const unexpected = [];
|
|
for (const key in port) {
|
|
(expectedProperties.includes(key) ? expected : unexpected).push(key);
|
|
}
|
|
is(`${expected.sort()}`, expectedProperties, `${description} has expected keys`);
|
|
is(`${unexpected.sort()}`, "", `${description} should not have unexpected keys`);
|
|
}
|
|
|
|
function portFrom(message, extraFn = () => {}) {
|
|
return new Promise(resolve => {
|
|
function onMessage({target}) {
|
|
pages.removeMessageListener(message, onMessage);
|
|
resolve(target);
|
|
}
|
|
pages.addMessageListener(message, onMessage);
|
|
extraFn();
|
|
});
|
|
}
|
|
|
|
let portFromInit = await portFrom("RemotePage:Init", () =>
|
|
(gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TEST_URL)));
|
|
checkProperties(portFromInit, "inited port");
|
|
ok(["about:blank", TEST_URL].includes(portFromInit.browser.currentURI.spec),
|
|
`inited port browser is either still blank or already at the target url - got ${portFromInit.browser.currentURI.spec}`);
|
|
is(portFromInit.loaded, false, "inited port has not been loaded yet");
|
|
is(portFromInit.url, TEST_URL, "got expected url");
|
|
|
|
let portFromLoad = await portFrom("RemotePage:Load");
|
|
is(portFromLoad, portFromInit, "got the same port from init and load");
|
|
checkProperties(portFromLoad, "loaded port");
|
|
is(portFromInit.browser.currentURI.spec, TEST_URL, "loaded port has browser with actual url");
|
|
is(portFromInit.loaded, true, "loaded port is now loaded");
|
|
is(portFromInit.url, TEST_URL, "still got expected url");
|
|
|
|
let portFromUnload = await portFrom("RemotePage:Unload", () =>
|
|
BrowserTestUtils.removeTab(gBrowser.selectedTab));
|
|
is(portFromUnload, portFromInit, "got the same port from init and unload");
|
|
checkProperties(portFromUnload, "unloaded port");
|
|
is(portFromInit.browser, null, "unloaded port has no browser");
|
|
is(portFromInit.loaded, false, "unloaded port is now not loaded");
|
|
is(portFromInit.url, TEST_URL, "still got expected url");
|
|
|
|
pages.destroy();
|
|
});
|
|
|
|
// Test sending messages to all remote pages works
|
|
add_task(async function remote_pages_multiple_pages() {
|
|
let pages = new RemotePages(TEST_URL);
|
|
let port1 = await waitForPage(pages);
|
|
let port2 = await waitForPage(pages);
|
|
|
|
let pongPorts = [];
|
|
await new Promise((resolve) => {
|
|
function listener({ name, target, data }) {
|
|
is(name, "Pong", "Should have seen the right response.");
|
|
is(data.str, "remote_pages", "String should pass through");
|
|
is(data.counter, 43, "Counter should be incremented");
|
|
pongPorts.push(target);
|
|
if (pongPorts.length == 2)
|
|
resolve();
|
|
}
|
|
|
|
pages.addMessageListener("Pong", listener);
|
|
pages.sendAsyncMessage("Ping", { str: "remote_pages", counter: 42 });
|
|
});
|
|
|
|
// We don't make any guarantees about which order messages are sent to known
|
|
// pages so the pongs could have come back in any order.
|
|
isnot(pongPorts[0], pongPorts[1], "Should have received pongs from different ports");
|
|
ok(pongPorts.includes(port1), "Should have seen a pong from port1");
|
|
ok(pongPorts.includes(port2), "Should have seen a pong from port2");
|
|
|
|
// After destroy we should see no messages
|
|
pages.addMessageListener("RemotePage:Unload", failOnMessage);
|
|
pages.destroy();
|
|
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(port1.browser));
|
|
gBrowser.removeTab(gBrowser.getTabForBrowser(port2.browser));
|
|
});
|
|
|
|
// Test that RemotePages with multiple urls works
|
|
add_task(async function remote_pages_multiple_urls() {
|
|
const TEST_URLS = [TEST_URL, TEST_URL.replace(".html", "2.html")];
|
|
const pages = new RemotePages(TEST_URLS);
|
|
|
|
const ports = [];
|
|
// Load two pages for each url
|
|
for (const [i, url] of TEST_URLS.entries()) {
|
|
const port = await waitForPage(pages, url);
|
|
is(port.browser, gBrowser.selectedBrowser, `port${i} is for the correct browser`);
|
|
ports.push(port);
|
|
ports.push(await waitForPage(pages, url));
|
|
}
|
|
|
|
let unloadPromise = waitForMessage(pages, "RemotePage:Unload", ports.pop());
|
|
gBrowser.removeCurrentTab();
|
|
await unloadPromise;
|
|
|
|
const pongPorts = new Set();
|
|
await new Promise(resolve => {
|
|
function listener({ name, target, data }) {
|
|
is(name, "Pong", "Should have seen the right response.");
|
|
is(data.str, "FAKE_DATA", "String should pass through");
|
|
is(data.counter, 1235, "Counter should be incremented");
|
|
pongPorts.add(target);
|
|
if (pongPorts.size === ports.length)
|
|
resolve();
|
|
}
|
|
|
|
pages.addMessageListener("Pong", listener);
|
|
pages.sendAsyncMessage("Ping", {str: "FAKE_DATA", counter: 1234});
|
|
});
|
|
|
|
ports.forEach(port => ok(pongPorts.has(port)));
|
|
|
|
pages.destroy();
|
|
ports.forEach(port => gBrowser.removeTab(gBrowser.getTabForBrowser(port.browser)));
|
|
});
|
|
|
|
// Test sending various types of data across the boundary
|
|
add_task(async function send_data() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
let data = {
|
|
integer: 45,
|
|
real: 45.78,
|
|
str: "foobar",
|
|
array: [1, 2, 3, 5, 27]
|
|
};
|
|
|
|
port.sendAsyncMessage("SendData", data);
|
|
let message = await waitForMessage(port, "ReceivedData");
|
|
|
|
ok(message.data.result, message.data.status);
|
|
|
|
gBrowser.removeCurrentTab();
|
|
});
|
|
|
|
// Test sending an object of data across the boundary
|
|
add_task(async function send_data2() {
|
|
let port = await waitForPort(TEST_URL);
|
|
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
|
|
|
let data = {
|
|
integer: 45,
|
|
real: 45.78,
|
|
str: "foobar",
|
|
array: [1, 2, 3, 5, 27]
|
|
};
|
|
|
|
port.sendAsyncMessage("SendData2", {data});
|
|
let message = await waitForMessage(port, "ReceivedData2");
|
|
|
|
ok(message.data.result, message.data.status);
|
|
|
|
gBrowser.removeCurrentTab();
|
|
});
|
|
|
|
add_task(async function get_ports_for_browser() {
|
|
let pages = new RemotePages(TEST_URL);
|
|
let port = await waitForPage(pages);
|
|
// waitForPage creates a new tab and selects it by default, so
|
|
// the selected tab should be the one hosting this port.
|
|
let browser = gBrowser.selectedBrowser;
|
|
let foundPorts = pages.portsForBrowser(browser);
|
|
is(foundPorts.length, 1, "There should only be one port for this simple page");
|
|
is(foundPorts[0], port, "Should find the port");
|
|
|
|
pages.destroy();
|
|
gBrowser.removeCurrentTab();
|
|
});
|