diff options
Diffstat (limited to 'toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html')
-rw-r--r-- | toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html b/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html new file mode 100644 index 000000000..2287fd9b1 --- /dev/null +++ b/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html @@ -0,0 +1,559 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for simple WebExtension</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="head.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<script type="text/javascript"> +"use strict"; + +/* globals sendMouseEvent */ + +function backgroundScript() { + const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; + const URL = BASE + "/file_WebNavigation_page1.html"; + + const EVENTS = [ + "onTabReplaced", + "onBeforeNavigate", + "onCommitted", + "onDOMContentLoaded", + "onCompleted", + "onErrorOccurred", + "onReferenceFragmentUpdated", + "onHistoryStateUpdated", + ]; + + let expectedTabId = -1; + + function gotEvent(event, details) { + if (!details.url.startsWith(BASE)) { + return; + } + browser.test.log(`Got ${event} ${details.url} ${details.frameId} ${details.parentFrameId}`); + + if (expectedTabId == -1) { + browser.test.assertTrue(details.tabId !== undefined, "tab ID defined"); + expectedTabId = details.tabId; + } + + browser.test.assertEq(details.tabId, expectedTabId, "correct tab"); + + browser.test.sendMessage("received", {url: details.url, event}); + + if (details.url == URL) { + browser.test.assertEq(details.frameId, 0, "root frame ID correct"); + browser.test.assertEq(details.parentFrameId, -1, "root parent frame ID correct"); + } else { + browser.test.assertEq(details.parentFrameId, 0, "parent frame ID correct"); + browser.test.assertTrue(details.frameId != 0, "frame ID probably okay"); + } + + browser.test.assertTrue(details.frameId !== undefined); + browser.test.assertTrue(details.parentFrameId !== undefined); + } + + let listeners = {}; + for (let event of EVENTS) { + listeners[event] = gotEvent.bind(null, event); + browser.webNavigation[event].addListener(listeners[event]); + } + + browser.test.sendMessage("ready"); +} + +const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; +const URL = BASE + "/file_WebNavigation_page1.html"; +const FRAME = BASE + "/file_WebNavigation_page2.html"; +const FRAME2 = BASE + "/file_WebNavigation_page3.html"; +const FRAME_PUSHSTATE = BASE + "/file_WebNavigation_page3_pushState.html"; +const REDIRECT = BASE + "/redirection.sjs"; +const REDIRECTED = BASE + "/dummy_page.html"; +const CLIENT_REDIRECT = BASE + "/file_webNavigation_clientRedirect.html"; +const CLIENT_REDIRECT_HTTPHEADER = BASE + "/file_webNavigation_clientRedirect_httpHeaders.html"; +const FRAME_CLIENT_REDIRECT = BASE + "/file_webNavigation_frameClientRedirect.html"; +const FRAME_REDIRECT = BASE + "/file_webNavigation_frameRedirect.html"; +const FRAME_MANUAL = BASE + "/file_webNavigation_manualSubframe.html"; +const FRAME_MANUAL_PAGE1 = BASE + "/file_webNavigation_manualSubframe_page1.html"; +const FRAME_MANUAL_PAGE2 = BASE + "/file_webNavigation_manualSubframe_page2.html"; +const INVALID_PAGE = "https://invalid.localhost/"; + +const REQUIRED = [ + "onBeforeNavigate", + "onCommitted", + "onDOMContentLoaded", + "onCompleted", +]; + +var received = []; +var completedResolve; +var waitingURL, waitingEvent; + +function loadAndWait(win, event, url, script) { + received = []; + waitingEvent = event; + waitingURL = url; + dump(`RUN ${script}\n`); + script(); + return new Promise(resolve => { completedResolve = resolve; }); +} + +add_task(function* webnav_transitions_props() { + function backgroundScriptTransitions() { + const EVENTS = [ + "onCommitted", + "onCompleted", + ]; + + function gotEvent(event, details) { + browser.test.log(`Got ${event} ${details.url} ${details.transitionType} ${details.transitionQualifiers && JSON.stringify(details.transitionQualifiers)}`); + + browser.test.sendMessage("received", {url: details.url, details, event}); + } + + let listeners = {}; + for (let event of EVENTS) { + listeners[event] = gotEvent.bind(null, event); + browser.webNavigation[event].addListener(listeners[event]); + } + + browser.test.sendMessage("ready"); + } + + let extensionData = { + manifest: { + permissions: [ + "webNavigation", + ], + }, + background: backgroundScriptTransitions, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + + extension.onMessage("received", ({url, event, details}) => { + received.push({url, event, details}); + + if (event == waitingEvent && url == waitingURL) { + completedResolve(); + } + }); + + yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); + info("webnavigation extension loaded"); + + let win = window.open(); + + yield loadAndWait(win, "onCompleted", URL, () => { win.location = URL; }); + + // transitionType: reload + received = []; + yield loadAndWait(win, "onCompleted", URL, () => { win.location.reload(); }); + + let found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "reload", + "Got the expected 'reload' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers), + "transitionQualifiers found in the OnCommitted events"); + } + + // transitionType: auto_subframe + found = received.find((data) => (data.event == "onCommitted" && data.url == FRAME)); + + ok(found, "Got the sub-frame onCommitted event"); + + if (found) { + is(found.details.transitionType, "auto_subframe", + "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers), + "transitionQualifiers found in the OnCommitted events"); + } + + // transitionType: form_submit + received = []; + yield loadAndWait(win, "onCompleted", URL, () => { + win.document.querySelector("form").submit(); + }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "form_submit", + "Got the expected 'form_submit' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers), + "transitionQualifiers found in the OnCommitted events"); + } + + // transitionQualifier: server_redirect + received = []; + yield loadAndWait(win, "onCompleted", REDIRECTED, () => { win.location = REDIRECT; }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "link", + "Got the expected 'link' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers) && + found.details.transitionQualifiers.find((q) => q == "server_redirect"), + "Got the expected 'server_redirect' transitionQualifiers in the OnCommitted events"); + } + + // transitionQualifier: forward_back + received = []; + yield loadAndWait(win, "onCompleted", URL, () => { win.history.back(); }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "link", + "Got the expected 'link' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers) && + found.details.transitionQualifiers.find((q) => q == "forward_back"), + "Got the expected 'forward_back' transitionQualifiers in the OnCommitted events"); + } + + // transitionQualifier: client_redirect + // (from meta http-equiv tag) + received = []; + yield loadAndWait(win, "onCompleted", REDIRECTED, () => { + win.location = CLIENT_REDIRECT; + }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "link", + "Got the expected 'link' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers) && + found.details.transitionQualifiers.find((q) => q == "client_redirect"), + "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); + } + + // transitionQualifier: client_redirect + // (from http headers) + received = []; + yield loadAndWait(win, "onCompleted", REDIRECTED, () => { + win.location = CLIENT_REDIRECT_HTTPHEADER; + }); + + found = received.find((data) => (data.event == "onCommitted" && + data.url == CLIENT_REDIRECT_HTTPHEADER)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "link", + "Got the expected 'link' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers) && + found.details.transitionQualifiers.find((q) => q == "client_redirect"), + "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); + } + + // transitionQualifier: client_redirect (sub-frame) + // (from meta http-equiv tag) + received = []; + yield loadAndWait(win, "onCompleted", REDIRECTED, () => { + win.location = FRAME_CLIENT_REDIRECT; + }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "auto_subframe", + "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); + ok(Array.isArray(found.details.transitionQualifiers) && + found.details.transitionQualifiers.find((q) => q == "client_redirect"), + "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); + } + + // transitionQualifier: server_redirect (sub-frame) + received = []; + yield loadAndWait(win, "onCompleted", REDIRECTED, () => { win.location = FRAME_REDIRECT; }); + + found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECT)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "auto_subframe", + "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); + // BUG 1264936: currently the server_redirect is not detected in sub-frames + // once we fix it we can test it here: + // + // ok(Array.isArray(found.details.transitionQualifiers) && + // found.details.transitionQualifiers.find((q) => q == "server_redirect"), + // "Got the expected 'server_redirect' transitionQualifiers in the OnCommitted events"); + } + + // transitionType: manual_subframe + received = []; + yield loadAndWait(win, "onCompleted", FRAME_MANUAL, () => { win.location = FRAME_MANUAL; }); + found = received.find((data) => (data.event == "onCommitted" && + data.url == FRAME_MANUAL_PAGE1)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "auto_subframe", + "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); + } + + received = []; + yield loadAndWait(win, "onCompleted", FRAME_MANUAL_PAGE2, () => { + let el = win.document.querySelector("iframe") + .contentDocument.querySelector("a"); + sendMouseEvent({type: "click"}, el, win); + }); + + found = received.find((data) => (data.event == "onCommitted" && + data.url == FRAME_MANUAL_PAGE2)); + + ok(found, "Got the onCommitted event"); + + if (found) { + is(found.details.transitionType, "manual_subframe", + "Got the expected 'manual_subframe' transitionType in the OnCommitted event"); + } + + // cleanup phase + win.close(); + + yield extension.unload(); + info("webnavigation extension unloaded"); +}); + +add_task(function* webnav_ordering() { + let extensionData = { + manifest: { + permissions: [ + "webNavigation", + ], + }, + background: backgroundScript, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + + extension.onMessage("received", ({url, event}) => { + received.push({url, event}); + + if (event == waitingEvent && url == waitingURL) { + completedResolve(); + } + }); + + yield extension.startup(); + yield extension.awaitMessage("ready"); + info("webnavigation extension loaded"); + + let win = window.open(); + + yield loadAndWait(win, "onCompleted", URL, () => { win.location = URL; }); + + function checkRequired(url) { + for (let event of REQUIRED) { + let found = false; + for (let r of received) { + if (r.url == url && r.event == event) { + found = true; + } + } + ok(found, `Received event ${event} from ${url}`); + } + } + + checkRequired(URL); + checkRequired(FRAME); + + function checkBefore(action1, action2) { + function find(action) { + for (let i = 0; i < received.length; i++) { + if (received[i].url == action.url && received[i].event == action.event) { + return i; + } + } + return -1; + } + + let index1 = find(action1); + let index2 = find(action2); + ok(index1 != -1, `Action ${JSON.stringify(action1)} happened`); + ok(index2 != -1, `Action ${JSON.stringify(action2)} happened`); + ok(index1 < index2, `Action ${JSON.stringify(action1)} happened before ${JSON.stringify(action2)}`); + } + + // As required in the webNavigation API documentation: + // If a navigating frame contains subframes, its onCommitted is fired before any + // of its children's onBeforeNavigate; while onCompleted is fired after + // all of its children's onCompleted. + checkBefore({url: URL, event: "onCommitted"}, {url: FRAME, event: "onBeforeNavigate"}); + checkBefore({url: FRAME, event: "onCompleted"}, {url: URL, event: "onCompleted"}); + + // As required in the webNAvigation API documentation, check the event sequence: + // onBeforeNavigate -> onCommitted -> onDOMContentLoaded -> onCompleted + let expectedEventSequence = [ + "onBeforeNavigate", "onCommitted", "onDOMContentLoaded", "onCompleted", + ]; + + for (let i = 1; i < expectedEventSequence.length; i++) { + let after = expectedEventSequence[i]; + let before = expectedEventSequence[i - 1]; + checkBefore({url: URL, event: before}, {url: URL, event: after}); + checkBefore({url: FRAME, event: before}, {url: FRAME, event: after}); + } + + yield loadAndWait(win, "onCompleted", FRAME2, () => { win.frames[0].location = FRAME2; }); + + checkRequired(FRAME2); + + let navigationSequence = [ + { + action: () => { win.frames[0].document.getElementById("elt").click(); }, + waitURL: `${FRAME2}#ref`, + expectedEvent: "onReferenceFragmentUpdated", + description: "clicked an anchor link", + }, + { + action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); }, + waitURL: `${FRAME2}#ref2`, + expectedEvent: "onReferenceFragmentUpdated", + description: "history.pushState, same pathname, different hash", + }, + { + action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); }, + waitURL: `${FRAME2}#ref2`, + expectedEvent: "onHistoryStateUpdated", + description: "history.pushState, same pathname, same hash", + }, + { + action: () => { + win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param1=value#ref2`); + }, + waitURL: `${FRAME2}?query_param1=value#ref2`, + expectedEvent: "onHistoryStateUpdated", + description: "history.pushState, same pathname, same hash, different query params", + }, + { + action: () => { + win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param2=value#ref3`); + }, + waitURL: `${FRAME2}?query_param2=value#ref3`, + expectedEvent: "onHistoryStateUpdated", + description: "history.pushState, same pathname, different hash, different query params", + }, + { + action: () => { win.frames[0].history.pushState(null, "History PushState", FRAME_PUSHSTATE); }, + waitURL: FRAME_PUSHSTATE, + expectedEvent: "onHistoryStateUpdated", + description: "history.pushState, different pathname", + }, + ]; + + for (let navigation of navigationSequence) { + let {expectedEvent, waitURL, action, description} = navigation; + info(`Waiting ${expectedEvent} from ${waitURL} - ${description}`); + yield loadAndWait(win, expectedEvent, waitURL, action); + info(`Received ${expectedEvent} from ${waitURL} - ${description}`); + } + + for (let i = navigationSequence.length - 1; i > 0; i--) { + let {waitURL: fromURL, expectedEvent} = navigationSequence[i]; + let {waitURL} = navigationSequence[i - 1]; + info(`Waiting ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`); + yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.back(); }); + info(`Received ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`); + } + + for (let i = 0; i < navigationSequence.length - 1; i++) { + let {waitURL: fromURL} = navigationSequence[i]; + let {waitURL, expectedEvent} = navigationSequence[i + 1]; + info(`Waiting ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`); + yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.forward(); }); + info(`Received ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`); + } + + win.close(); + + yield extension.unload(); + info("webnavigation extension unloaded"); +}); + +add_task(function* webnav_error_event() { + function backgroundScriptErrorEvent() { + browser.webNavigation.onErrorOccurred.addListener((details) => { + browser.test.log(`Got onErrorOccurred ${details.url} ${details.error}`); + + browser.test.sendMessage("received", {url: details.url, details, event: "onErrorOccurred"}); + }); + + browser.test.sendMessage("ready"); + } + + let extensionData = { + manifest: { + permissions: [ + "webNavigation", + ], + }, + background: backgroundScriptErrorEvent, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + + extension.onMessage("received", ({url, event, details}) => { + received.push({url, event, details}); + + if (event == waitingEvent && url == waitingURL) { + completedResolve(); + } + }); + + yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); + info("webnavigation extension loaded"); + + let win = window.open(); + + received = []; + yield loadAndWait(win, "onErrorOccurred", INVALID_PAGE, () => { win.location = INVALID_PAGE; }); + + let found = received.find((data) => (data.event == "onErrorOccurred" && + data.url == INVALID_PAGE)); + + ok(found, "Got the onErrorOccurred event"); + + if (found) { + ok(found.details.error.match(/Error code [0-9]+/), + "Got the expected error string in the onErrorOccurred event"); + } + + // cleanup phase + win.close(); + + yield extension.unload(); + info("webnavigation extension unloaded"); +}); +</script> + +</body> +</html> |