"use strict";
Services.prefs.setBoolPref("dom.manifest.enabled", true);
const { ManifestObtainer } = ChromeUtils.import(
"resource://gre/modules/ManifestObtainer.jsm"
);
const remoteURL =
"http://mochi.test:8888/browser/dom/manifest/test/resource.sjs";
const defaultURL = new URL(
"http://example.org/browser/dom/manifest/test/resource.sjs"
);
defaultURL.searchParams.set("Content-Type", "text/html; charset=utf-8");
requestLongerTimeout(4);
const tests = [
// Fetch tests.
{
body: ``,
run(manifest) {
is(manifest, null, "Manifest without a href yields a null manifest.");
},
},
{
body: ``,
run(manifest) {
is(manifest, null, "Manifest without a href yields a null manifest.");
},
},
{
body: `
`,
run(manifest) {
is(
manifest.name,
"pass-1",
"Manifest is first `link` where @rel contains token manifest."
);
},
},
{
body: `
`,
run(manifest) {
is(
manifest.name,
"pass-2",
"Manifest is first `link` where @rel contains token manifest."
);
},
},
{
body: ``,
run(err) {
is(
err.name,
"TypeError",
"By default, manifest cannot load cross-origin."
);
},
},
// CORS Tests.
{
get body() {
const body = 'body={"name": "pass-4"}';
const CORS = `Access-Control-Allow-Origin=${defaultURL.origin}`;
const link = ``;
return link;
},
run(manifest) {
is(manifest.name, "pass-4", "CORS enabled, manifest must be fetched.");
},
},
{
get body() {
const body = 'body={"name": "fail"}';
const CORS = "Access-Control-Allow-Origin=http://not-here";
const link = ``;
return link;
},
run(err) {
is(
err.name,
"TypeError",
"Fetch blocked by CORS - origin does not match."
);
},
},
{
body: ``,
run(err) {
is(
err.name,
"TypeError",
"Trying to load from about:whatever is TypeError."
);
},
},
{
body: ``,
run(err) {
is(
err.name,
"TypeError",
"Trying to load from file://whatever is a TypeError."
);
},
},
// URL parsing tests
{
body: ``,
run(err) {
is(err.name, "TypeError", "Trying to load invalid URL is a TypeError.");
},
},
];
function makeTestURL({ body }) {
const url = new URL(defaultURL);
url.searchParams.set("body", encodeURIComponent(body));
return url.href;
}
add_task(async function() {
const promises = tests
.map(test => ({
gBrowser,
testRunner: testObtainingManifest(test),
url: makeTestURL(test),
}))
.reduce((collector, tabOpts) => {
const promise = BrowserTestUtils.withNewTab(tabOpts, tabOpts.testRunner);
collector.push(promise);
return collector;
}, []);
await Promise.all(promises);
function testObtainingManifest(aTest) {
return async function(aBrowser) {
try {
const manifest = await ManifestObtainer.browserObtainManifest(aBrowser);
aTest.run(manifest);
} catch (e) {
aTest.run(e);
}
};
}
});
add_task(async () => {
// This loads a generic html page.
const url = new URL(defaultURL);
// The body get injected into the page on the server.
const body = ``;
url.searchParams.set("body", encodeURIComponent(body));
// Let's open a tab!
const tabOpts = {
gBrowser,
url: url.href,
};
// Let's do the test
await BrowserTestUtils.withNewTab(tabOpts, async aBrowser => {
const obtainerOpts = {
checkConformance: true, // gives us back "moz_manifest_url" member
};
const manifest = await ManifestObtainer.browserObtainManifest(
aBrowser,
obtainerOpts
);
is(manifest.name, "conformance check");
ok("moz_manifest_url" in manifest, "Has a moz_manifest_url member");
const testString = defaultURL.origin + defaultURL.pathname;
ok(
manifest.moz_manifest_url.startsWith(testString),
`Expect to start with with the testString, but got ${manifest.moz_manifest_url} instead,`
);
// Clean up!
gBrowser.removeTab(gBrowser.getTabForBrowser(aBrowser));
});
});
/*
* e10s race condition tests
* Open a bunch of tabs and load manifests
* in each tab. They should all return pass.
*/
add_task(async function() {
const defaultPath = "/browser/dom/manifest/test/manifestLoader.html";
const tabURLs = [
`http://example.com:80${defaultPath}`,
`http://example.org:80${defaultPath}`,
`http://example.org:8000${defaultPath}`,
`http://mochi.test:8888${defaultPath}`,
`http://sub1.test1.example.com:80${defaultPath}`,
`http://sub1.test1.example.org:80${defaultPath}`,
`http://sub1.test1.example.org:8000${defaultPath}`,
`http://sub1.test1.mochi.test:8888${defaultPath}`,
`http://sub1.test2.example.com:80${defaultPath}`,
`http://sub1.test2.example.org:80${defaultPath}`,
`http://sub1.test2.example.org:8000${defaultPath}`,
`http://sub2.test1.example.com:80${defaultPath}`,
`http://sub2.test1.example.org:80${defaultPath}`,
`http://sub2.test1.example.org:8000${defaultPath}`,
`http://sub2.test2.example.com:80${defaultPath}`,
`http://sub2.test2.example.org:80${defaultPath}`,
`http://sub2.test2.example.org:8000${defaultPath}`,
`http://sub2.xn--lt-uia.mochi.test:8888${defaultPath}`,
`http://test1.example.com:80${defaultPath}`,
`http://test1.example.org:80${defaultPath}`,
`http://test1.example.org:8000${defaultPath}`,
`http://test1.mochi.test:8888${defaultPath}`,
`http://test2.example.com:80${defaultPath}`,
`http://test2.example.org:80${defaultPath}`,
`http://test2.example.org:8000${defaultPath}`,
`http://test2.mochi.test:8888${defaultPath}`,
`http://test:80${defaultPath}`,
`http://www.example.com:80${defaultPath}`,
];
// Open tabs an collect corresponding browsers
let browsers = tabURLs.map(
url => BrowserTestUtils.addTab(gBrowser, url).linkedBrowser
);
// Once all the pages have loaded, run a bunch of tests in "parallel".
await Promise.all(
(function*() {
for (let browser of browsers) {
yield BrowserTestUtils.browserLoaded(browser);
}
})()
);
// Flood random browsers with requests. Once promises settle, check that
// responses all pass.
const results = await Promise.all(
(function*() {
for (let browser of randBrowsers(browsers, 50)) {
yield ManifestObtainer.browserObtainManifest(browser);
}
})()
);
const pass = results.every(manifest => manifest.name === "pass");
ok(pass, "Expect every manifest to have name equal to `pass`.");
// cleanup
browsers
.map(browser => gBrowser.getTabForBrowser(browser))
.forEach(tab => gBrowser.removeTab(tab));
// Helper generator, spits out random browsers
function* randBrowsers(aBrowsers, aMax) {
for (let i = 0; i < aMax; i++) {
const randNum = Math.round(Math.random() * (aBrowsers.length - 1));
yield aBrowsers[randNum];
}
}
});