/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; add_task(async function testBasicNavigation({ client }) { const { Page, Network } = client; await Page.enable(); await Network.enable(); const loadEventFired = Page.loadEventFired(); const requestEvent = Network.requestWillBeSent(); const { frameId, loaderId, errorText } = await Page.navigate({ url: PAGE_URL, }); const { loaderId: requestLoaderId } = await requestEvent; ok(!!loaderId, "Page.navigate returns loaderId"); is( loaderId, requestLoaderId, "Page.navigate returns same loaderId as corresponding request" ); is(errorText, undefined, "No errorText on a successful navigation"); await loadEventFired; const currentFrame = await getTopFrame(client); is(frameId, currentFrame.id, "Page.navigate returns expected frameId"); is(gBrowser.selectedBrowser.currentURI.spec, PAGE_URL, "Expected URL loaded"); }); add_task(async function testTwoNavigations({ client }) { const { Page, Network } = client; await Page.enable(); await Network.enable(); let requestEvent = Network.requestWillBeSent(); let loadEventFired = Page.loadEventFired(); const { frameId, loaderId, errorText } = await Page.navigate({ url: PAGE_URL, }); const { loaderId: requestLoaderId } = await requestEvent; await loadEventFired; is(gBrowser.selectedBrowser.currentURI.spec, PAGE_URL, "Expected URL loaded"); loadEventFired = Page.loadEventFired(); requestEvent = Network.requestWillBeSent(); const { frameId: frameId2, loaderId: loaderId2, errorText: errorText2, } = await Page.navigate({ url: PAGE_URL, }); const { loaderId: requestLoaderId2 } = await requestEvent; ok(!!loaderId, "Page.navigate returns loaderId"); ok(!!loaderId2, "Page.navigate returns loaderId"); isnot(loaderId, loaderId2, "Page.navigate returns different loaderIds"); is( loaderId, requestLoaderId, "Page.navigate returns same loaderId as corresponding request" ); is( loaderId2, requestLoaderId2, "Page.navigate returns same loaderId as corresponding request" ); is(errorText, undefined, "No errorText on a successful navigation"); is(errorText2, undefined, "No errorText on a successful navigation"); is(frameId, frameId2, "Page.navigate return same frameId"); await loadEventFired; is(gBrowser.selectedBrowser.currentURI.spec, PAGE_URL, "Expected URL loaded"); }); add_task(async function testRedirect({ client }) { const { Page, Network } = client; const sjsURL = "https://example.com/browser/remote/cdp/test/browser/page/sjs_redirect.sjs"; const redirectURL = `${sjsURL}?${PAGE_URL}`; await Page.enable(); await Network.enable(); const requestEvent = Network.requestWillBeSent(); const loadEventFired = Page.loadEventFired(); const { frameId, loaderId, errorText } = await Page.navigate({ url: redirectURL, }); const { loaderId: requestLoaderId } = await requestEvent; ok(!!loaderId, "Page.navigate returns loaderId"); is( loaderId, requestLoaderId, "Page.navigate returns same loaderId as original request" ); is(errorText, undefined, "No errorText on a successful navigation"); ok(!!frameId, "Page.navigate returns frameId"); await loadEventFired; is(gBrowser.selectedBrowser.currentURI.spec, PAGE_URL, "Expected URL loaded"); }); add_task(async function testUnknownHost({ client }) { const { Page } = client; const { frameId, loaderId, errorText } = await Page.navigate({ url: "https://example-does-not-exist.com", }); ok(!!frameId, "Page.navigate returns frameId"); ok(!!loaderId, "Page.navigate returns loaderId"); is(errorText, "NS_ERROR_UNKNOWN_HOST", "Failed navigation returns errorText"); }); add_task(async function testExpiredCertificate({ client }) { const { Page } = client; const { frameId, loaderId, errorText } = await Page.navigate({ url: "https://expired.example.com", }); ok(!!frameId, "Page.navigate returns frameId"); ok(!!loaderId, "Page.navigate returns loaderId"); is( errorText, "SEC_ERROR_EXPIRED_CERTIFICATE", "Failed navigation returns errorText" ); }); add_task(async function testUnknownCertificate({ client }) { const { Page, Network } = client; await Network.enable(); const requestEvent = Network.requestWillBeSent(); const { frameId, loaderId, errorText } = await Page.navigate({ url: "https://self-signed.example.com", }); const { loaderId: requestLoaderId } = await requestEvent; ok(!!frameId, "Page.navigate returns frameId"); ok(!!loaderId, "Page.navigate returns loaderId"); is( loaderId, requestLoaderId, "Page.navigate returns same loaderId as original request" ); is(errorText, "SSL_ERROR_UNKNOWN", "Failed navigation returns errorText"); }); add_task(async function testNotFound({ client }) { const { Page } = client; const { frameId, loaderId, errorText } = await Page.navigate({ url: "https://example.com/browser/remote/doesnotexist.html", }); ok(!!frameId, "Page.navigate returns frameId"); ok(!!loaderId, "Page.navigate returns loaderId"); is(errorText, undefined, "No errorText on a 404"); }); add_task(async function testInvalidURL({ client }) { const { Page } = client; let message = ""; for (let url of ["blah.com", "foo", "https\n//", "http", ""]) { message = ""; try { await Page.navigate({ url }); } catch (e) { message = e.response.message; } ok(message.includes("invalid URL"), `Invalid url ${url} causes error`); } for (let url of [2, {}, true]) { message = ""; try { await Page.navigate({ url }); } catch (e) { message = e.response.message; } ok( message.includes("string value expected"), `Invalid url ${url} causes error` ); } }); add_task(async function testDataURL({ client }) { const { Page } = client; const url = toDataURL("first"); await Page.enable(); const loadEventFired = Page.loadEventFired(); const frameNavigatedFired = Page.frameNavigated(); const { frameId, loaderId, errorText } = await Page.navigate({ url }); is(errorText, undefined, "No errorText on a successful navigation"); ok(!!loaderId, "Page.navigate returns loaderId"); await loadEventFired; const { frame } = await frameNavigatedFired; is(frame.loaderId, loaderId, "Page.navigate returns expected loaderId"); const currentFrame = await getTopFrame(client); is(frameId, currentFrame.id, "Page.navigate returns expected frameId"); is(gBrowser.selectedBrowser.currentURI.spec, url, "Expected URL loaded"); }); add_task(async function testFileURL({ client }) { const { AppConstants } = ChromeUtils.importESModule( "resource://gre/modules/AppConstants.sys.mjs" ); if (AppConstants.DEBUG) { // Bug 1634695 Navigating to a file URL forces the TabSession to destroy // abruptly and content domains are not properly destroyed, which creates // window leaks and fails the test in DEBUG mode. return; } const { Page } = client; const dir = getChromeDir(getResolvedURI(gTestPath)); dir.append("doc_empty.html"); // The file can be a symbolic link on local build. Normalize it to make sure // the path matches to the actual URI opened in the new tab. dir.normalize(); const url = Services.io.newFileURI(dir).spec; const browser = gBrowser.selectedTab.linkedBrowser; const loaded = BrowserTestUtils.browserLoaded(browser, false, url); const { /* frameId, */ loaderId, errorText } = await Page.navigate({ url }); is(errorText, undefined, "No errorText on a successful navigation"); ok(!!loaderId, "Page.navigate returns loaderId"); // Bug 1634693 Page.loadEventFired isn't emitted after file: navigation await loaded; is(browser.currentURI.spec, url, "Expected URL loaded"); // Bug 1634695 Navigating to file: returns wrong frame id and hangs // content page domain methods // const currentFrame = await getTopFrame(client); // ok(frameId === currentFrame.id, "Page.navigate returns expected frameId"); }); add_task(async function testAbout({ client }) { const { Page } = client; await Page.enable(); let loadEventFired = Page.loadEventFired(); let frameNavigatedFired = Page.frameNavigated(); const { frameId, loaderId, errorText } = await Page.navigate({ url: "about:blank", }); ok(!!loaderId, "Page.navigate returns loaderId"); is(errorText, undefined, "No errorText on a successful navigation"); await loadEventFired; const { frame } = await frameNavigatedFired; is(frame.loaderId, loaderId, "Page.navigate returns expected loaderId"); const currentFrame = await getTopFrame(client); is(frameId, currentFrame.id, "Page.navigate returns expected frameId"); is( gBrowser.selectedBrowser.currentURI.spec, "about:blank", "Expected URL loaded" ); }); add_task(async function testSameDocumentNavigation({ client }) { const { Page } = client; const { frameId, loaderId } = await Page.navigate({ url: PAGE_URL, }); ok(!!loaderId, "Page.navigate returns loaderId"); await Page.enable(); const navigatedWithinDocument = Page.navigatedWithinDocument(); info("Check that Page.navigate can navigate to an anchor"); const sameDocumentURL = `${PAGE_URL}#hash`; const { frameId: sameDocumentFrameId, loaderId: sameDocumentLoaderId } = await Page.navigate({ url: sameDocumentURL }); ok( !sameDocumentLoaderId, "Page.navigate does not return a loaderId for same document navigation" ); is( sameDocumentFrameId, frameId, "Page.navigate returned the expected frame id" ); const { frameId: navigatedFrameId, url } = await navigatedWithinDocument; is( frameId, navigatedFrameId, "navigatedWithinDocument returns the expected frameId" ); is(url, sameDocumentURL, "navigatedWithinDocument returns the expected url"); is( gBrowser.selectedBrowser.currentURI.spec, sameDocumentURL, "Expected URL loaded" ); info("Check that navigating to the same hash URL does not timeout"); const { frameId: sameHashFrameId, loaderId: sameHashLoaderId } = await Page.navigate({ url: sameDocumentURL }); ok( !sameHashLoaderId, "Page.navigate does not return a loaderId for same document navigation" ); is(sameHashFrameId, frameId, "Page.navigate returned the expected frame id"); }); async function getTopFrame(client) { const frames = await getFlattenedFrameTree(client); return Array.from(frames.values())[0]; }