fune/remote/test/browser/head.js
Andreas Tolfsen 37c8f955e6 bug 1570378: remote: add bc test helper setup() for empty documents r=remote-protocol-reviewers,jdescottes
For many browser-chrome (bc) tests is does not matter what the
document is, as long as it is does not cause state to bleed over
from the previous test.

For these cases this patch introduces a shorthand, setup(), which
calls setupForURL(url) with an empty document generated by toDataURL("").

Differential Revision: https://phabricator.services.mozilla.com/D40216

--HG--
extra : moz-landing-system : lando
2019-08-05 11:43:58 +00:00

159 lines
4.5 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { RemoteAgent } = ChromeUtils.import(
"chrome://remote/content/RemoteAgent.jsm"
);
const { RemoteAgentError } = ChromeUtils.import(
"chrome://remote/content/Error.jsm"
);
/**
* Override `add_task` in order to translate chrome-remote-interface exceptions
* into something that logs better errors on stdout
*/
const original_add_task = add_task.bind(this);
this.add_task = function(test) {
original_add_task(async function() {
try {
await test();
} catch (e) {
// Display better error message with the server side stacktrace
// if an error happened on the server side:
if (e.response) {
throw RemoteAgentError.fromJSON(e.response);
} else {
throw e;
}
}
});
};
const CRI_URI =
"http://example.com/browser/remote/test/browser/chrome-remote-interface.js";
/**
* Create a test document in an invisible window.
* This window will be automatically closed on test teardown.
*/
function createTestDocument() {
const browser = Services.appShell.createWindowlessBrowser(true);
const webNavigation = browser.docShell.QueryInterface(Ci.nsIWebNavigation);
// Create a system principal content viewer to ensure there is a valid
// empty document using system principal and avoid any wrapper issues
// when using document's JS Objects.
const system = Services.scriptSecurityManager.getSystemPrincipal();
webNavigation.createAboutBlankContentViewer(system, system);
registerCleanupFunction(() => browser.close());
return webNavigation.document;
}
/**
* Retrieve an intance of CDP object from chrome-remote-interface library
*/
async function getCDP() {
// Instantiate a background test document in order to load the library
// as in a web page
const document = createTestDocument();
// Load chrome-remote-interface.js into this background test document
const script = document.createElement("script");
script.setAttribute("src", CRI_URI);
document.documentElement.appendChild(script);
await new Promise(resolve => {
script.addEventListener("load", resolve, { once: true });
});
const window = document.defaultView.wrappedJSObject;
// Implements `criRequest` to be called by chrome-remeote-interface
// library in order to do the cross-domain http request, which,
// in a regular Web page, is impossible.
window.criRequest = (options, callback) => {
const { host, port, path } = options;
const url = `http://${host}:${port}${path}`;
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
// Prevent "XML Parsing Error: syntax error" error messages
xhr.overrideMimeType("text/plain");
xhr.send(null);
xhr.onload = () => callback(null, xhr.responseText);
xhr.onerror = e => callback(e, null);
};
return window.CDP;
}
function getTargets(CDP) {
return new Promise((resolve, reject) => {
CDP.List(null, (err, targets) => {
if (err) {
reject(err);
return;
}
resolve(targets);
});
});
}
/**
* Set up test environment in same fashion as setupForURL(),
* except using an empty document.
*/
async function setup() {
return setupForURL(toDataURL(""));
}
/**
* Set up test environment by starting the remote agent, connecting
* the CDP client over loopback, and creating a fresh tab to avoid
* state bleedover from previous test.
*/
async function setupForURL(url) {
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
const CDP = await getCDP();
const client = await CDP({
target(list) {
// ensure we are debugging the right target, i.e. the requested URL
return list.find(target => target.url == url);
},
});
info("CDP client instantiated");
return { client, tab };
}
/** Creates a data URL for the given source document. */
function toDataURL(src, doctype = "html") {
let doc, mime;
switch (doctype) {
case "html":
mime = "text/html;charset=utf-8";
doc = `<!doctype html>\n<meta charset=utf-8>\n${src}`;
break;
default:
throw new Error("Unexpected doctype: " + doctype);
}
return `data:${mime},${encodeURIComponent(doc)}`;
}
/**
* Retrieve the value of a property on the content window.
*/
function getContentProperty(prop) {
info(`Retrieve ${prop} on the content window`);
return ContentTask.spawn(
gBrowser.selectedBrowser,
prop,
_prop => content[_prop]
);
}