fune/remote/shared/test/xpcshell/test_Navigate.js
Julian Descottes 46373aef81 Bug 1832891 - [remote] Set timeout to 5s for waitForInitialNavigation for new contexts r=webdriver-reviewers,whimboo
Extending the timeout only when we explicitly create a new window or tab should be safe.
On the other hand, initial windows from the browser or new tabs created by the browser UI can remain on the initial document forever, for instance on Android.
So for those cases we keep the current unloadTimeout value.

Differential Revision: https://phabricator.services.mozilla.com/D179710
2023-06-06 13:55:39 +00:00

879 lines
27 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
const {
DEFAULT_UNLOAD_TIMEOUT,
getUnloadTimeoutMultiplier,
ProgressListener,
waitForInitialNavigationCompleted,
} = ChromeUtils.importESModule(
"chrome://remote/content/shared/Navigate.sys.mjs"
);
const CURRENT_URI = Services.io.newURI("http://foo.bar/");
const INITIAL_URI = Services.io.newURI("about:blank");
const TARGET_URI = Services.io.newURI("http://foo.cheese/");
const TARGET_URI_IS_ERROR_PAGE = Services.io.newURI("doesnotexist://");
const TARGET_URI_WITH_HASH = Services.io.newURI("http://foo.cheese/#foo");
function wait(time) {
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
return new Promise(resolve => setTimeout(resolve, time));
}
class MockRequest {
constructor(uri) {
this.originalURI = uri;
}
get QueryInterface() {
return ChromeUtils.generateQI(["nsIRequest", "nsIChannel"]);
}
}
class MockWebProgress {
constructor(browsingContext) {
this.browsingContext = browsingContext;
this.documentRequest = null;
this.isLoadingDocument = false;
this.listener = null;
this.progressListenerRemoved = false;
}
addProgressListener(listener) {
if (this.listener) {
throw new Error("Cannot register listener twice");
}
this.listener = listener;
}
removeProgressListener(listener) {
if (listener === this.listener) {
this.listener = null;
this.progressListenerRemoved = true;
} else {
throw new Error("Unknown listener");
}
}
sendLocationChange(options = {}) {
const { flag = 0 } = options;
this.documentRequest = null;
if (flag & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
this.browsingContext.currentURI = TARGET_URI_WITH_HASH;
} else if (flag & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
this.browsingContext.currentURI = TARGET_URI_IS_ERROR_PAGE;
}
this.listener?.onLocationChange(
this,
this.documentRequest,
TARGET_URI_WITH_HASH,
flag
);
return new Promise(executeSoon);
}
sendStartState(options = {}) {
const { coop = false, isInitial = false } = options;
if (coop) {
this.browsingContext = new MockTopContext(this);
}
if (!this.browsingContext.currentWindowGlobal) {
this.browsingContext.currentWindowGlobal = {};
}
this.browsingContext.currentWindowGlobal.isInitialDocument = isInitial;
this.isLoadingDocument = true;
const uri = isInitial ? INITIAL_URI : TARGET_URI;
this.documentRequest = new MockRequest(uri);
this.listener?.onStateChange(
this,
this.documentRequest,
Ci.nsIWebProgressListener.STATE_START,
null
);
return new Promise(executeSoon);
}
sendStopState(options = {}) {
const { errorFlag = 0 } = options;
this.browsingContext.currentURI = this.documentRequest.originalURI;
this.isLoadingDocument = false;
this.documentRequest = null;
this.listener?.onStateChange(
this,
this.documentRequest,
Ci.nsIWebProgressListener.STATE_STOP,
errorFlag
);
return new Promise(executeSoon);
}
}
class MockTopContext {
constructor(webProgress = null) {
this.currentURI = CURRENT_URI;
this.currentWindowGlobal = { isInitialDocument: true };
this.id = 7;
this.top = this;
this.webProgress = webProgress || new MockWebProgress(this);
}
}
const hasPromiseResolved = async function (promise) {
let resolved = false;
promise.finally(() => (resolved = true));
// Make sure microtasks have time to run.
await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
return resolved;
};
const hasPromiseRejected = async function (promise) {
let rejected = false;
promise.catch(() => (rejected = true));
// Make sure microtasks have time to run.
await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
return rejected;
};
add_task(
async function test_waitForInitialNavigation_initialDocumentNoWindowGlobal() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
// In some cases there might be no window global yet.
delete browsingContext.currentWindowGlobal;
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
await webProgress.sendStartState({ isInitial: true });
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is initial document"
);
equal(
currentURI.spec,
INITIAL_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, INITIAL_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_initialDocumentNotLoaded() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
await webProgress.sendStartState({ isInitial: true });
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is initial document"
);
equal(
currentURI.spec,
INITIAL_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, INITIAL_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_initialDocumentLoadingAndNoAdditionalLoad() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: true });
ok(webProgress.isLoadingDocument, "Document is loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is initial document"
);
equal(
currentURI.spec,
INITIAL_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, INITIAL_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_initialDocumentFinishedLoadingNoAdditionalLoad() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: true });
await webProgress.sendStopState();
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is initial document"
);
equal(
currentURI.spec,
INITIAL_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, INITIAL_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_initialDocumentLoadingAndAdditionalLoad() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: true });
ok(webProgress.isLoadingDocument, "Document is loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
await wait(100);
await webProgress.sendStartState({ isInitial: false });
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(
currentURI.spec,
TARGET_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_initialDocumentFinishedLoadingAndAdditionalLoad() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: true });
await webProgress.sendStopState();
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await wait(100);
await webProgress.sendStartState({ isInitial: false });
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(
currentURI.spec,
TARGET_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_notInitialDocumentNotLoading() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
await webProgress.sendStartState({ isInitial: false });
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(
currentURI.spec,
TARGET_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_notInitialDocumentAlreadyLoading() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: false });
ok(webProgress.isLoadingDocument, "Document is loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(
currentURI.spec,
TARGET_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
}
);
add_task(
async function test_waitForInitialNavigation_notInitialDocumentFinishedLoading() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: false });
await webProgress.sendStopState();
ok(!webProgress.isLoadingDocument, "Document is not loading");
const { currentURI, targetURI } = await waitForInitialNavigationCompleted(
webProgress
);
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(
currentURI.spec,
TARGET_URI.spec,
"Expected current URI has been set"
);
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
}
);
add_task(async function test_waitForInitialNavigation_resolveWhenStarted() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState({ isInitial: true });
ok(webProgress.isLoadingDocument, "Document is already loading");
const { currentURI, targetURI } = await waitForInitialNavigationCompleted(
webProgress,
{
resolveWhenStarted: true,
}
);
ok(webProgress.isLoadingDocument, "Document is still loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is initial document"
);
equal(currentURI.spec, CURRENT_URI.spec, "Expected current URI has been set");
equal(targetURI.spec, INITIAL_URI.spec, "Expected target URI has been set");
});
add_task(async function test_waitForInitialNavigation_crossOrigin() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
await webProgress.sendStartState({ coop: true });
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
await webProgress.sendStopState();
const { currentURI, targetURI } = await navigated;
notEqual(
browsingContext,
webProgress.browsingContext,
"Got new browsing context"
);
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
!webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Is not initial document"
);
equal(currentURI.spec, TARGET_URI.spec, "Expected current URI has been set");
equal(targetURI.spec, TARGET_URI.spec, "Expected target URI has been set");
});
add_task(async function test_waitForInitialNavigation_unloadTimeout_default() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
// Stop the navigation on an initial page which is not loading anymore.
// This situation happens with new tabs on Android, even though they are on
// the initial document, they will not start another navigation on their own.
await webProgress.sendStartState({ isInitial: true });
await webProgress.sendStopState();
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress);
// Start a timer longer than the timeout which will be used by
// waitForInitialNavigationCompleted, and check that navigated resolves first.
const waitForMoreThanDefaultTimeout = wait(
DEFAULT_UNLOAD_TIMEOUT * 1.5 * getUnloadTimeoutMultiplier()
);
await Promise.race([navigated, waitForMoreThanDefaultTimeout]);
ok(
await hasPromiseResolved(navigated),
"waitForInitialNavigationCompleted has resolved"
);
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Document is still on the initial document"
);
});
add_task(async function test_waitForInitialNavigation_unloadTimeout_longer() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
// Stop the navigation on an initial page which is not loading anymore.
// This situation happens with new tabs on Android, even though they are on
// the initial document, they will not start another navigation on their own.
await webProgress.sendStartState({ isInitial: true });
await webProgress.sendStopState();
ok(!webProgress.isLoadingDocument, "Document is not loading");
const navigated = waitForInitialNavigationCompleted(webProgress, {
unloadTimeout: DEFAULT_UNLOAD_TIMEOUT * 3,
});
// Start a timer longer than the default timeout of the Navigate module.
// However here we used a custom timeout, so we expect that the navigation
// will not be done yet by the time this timer is done.
const waitForMoreThanDefaultTimeout = wait(
DEFAULT_UNLOAD_TIMEOUT * 1.5 * getUnloadTimeoutMultiplier()
);
await Promise.race([navigated, waitForMoreThanDefaultTimeout]);
// The promise should not have resolved because we didn't reached the custom
// timeout which is 3 times the default one.
ok(
!(await hasPromiseResolved(navigated)),
"waitForInitialNavigationCompleted has not resolved yet"
);
// The navigation should eventually resolve once we reach the custom timeout.
await navigated;
ok(!webProgress.isLoadingDocument, "Document is not loading");
ok(
webProgress.browsingContext.currentWindowGlobal.isInitialDocument,
"Document is still on the initial document"
);
});
add_task(async function test_ProgressListener_expectNavigation() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress, {
expectNavigation: true,
unloadTimeout: 10,
});
const navigated = progressListener.start();
// Wait for unloadTimeout to finish in case it started
await wait(30);
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved yet");
await webProgress.sendStartState();
await webProgress.sendStopState();
ok(await hasPromiseResolved(navigated), "Listener has resolved");
});
add_task(
async function test_ProgressListener_expectNavigation_initialDocumentFinishedLoading() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress, {
expectNavigation: true,
unloadTimeout: 10,
});
const navigated = progressListener.start();
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved yet");
await webProgress.sendStartState({ isInitial: true });
await webProgress.sendStopState();
// Wait for unloadTimeout to finish in case it started
await wait(30);
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved yet");
await webProgress.sendStartState();
await webProgress.sendStopState();
ok(await hasPromiseResolved(navigated), "Listener has resolved");
}
);
add_task(async function test_ProgressListener_isStarted() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress);
ok(!progressListener.isStarted);
progressListener.start();
ok(progressListener.isStarted);
progressListener.stop();
ok(!progressListener.isStarted);
});
add_task(async function test_ProgressListener_notWaitForExplicitStart() {
// Create a webprogress and start it before creating the progress listener.
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState();
// Create the progress listener for a webprogress already in a navigation.
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: false,
});
const navigated = progressListener.start();
// Send stop state to complete the initial navigation
await webProgress.sendStopState();
ok(
await hasPromiseResolved(navigated),
"Listener has resolved after initial navigation"
);
});
add_task(async function test_ProgressListener_waitForExplicitStart() {
// Create a webprogress and start it before creating the progress listener.
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState();
// Create the progress listener for a webprogress already in a navigation.
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: true,
});
const navigated = progressListener.start();
// Send stop state to complete the initial navigation
await webProgress.sendStopState();
ok(
!(await hasPromiseResolved(navigated)),
"Listener has not resolved after initial navigation"
);
// Start a new navigation
await webProgress.sendStartState();
ok(
!(await hasPromiseResolved(navigated)),
"Listener has not resolved after starting new navigation"
);
// Finish the new navigation
await webProgress.sendStopState();
ok(
await hasPromiseResolved(navigated),
"Listener resolved after finishing the new navigation"
);
});
add_task(
async function test_ProgressListener_waitForExplicitStartAndResolveWhenStarted() {
// Create a webprogress and start it before creating the progress listener.
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState();
// Create the progress listener for a webprogress already in a navigation.
const progressListener = new ProgressListener(webProgress, {
resolveWhenStarted: true,
waitForExplicitStart: true,
});
const navigated = progressListener.start();
// Send stop state to complete the initial navigation
await webProgress.sendStopState();
ok(
!(await hasPromiseResolved(navigated)),
"Listener has not resolved after initial navigation"
);
// Start a new navigation
await webProgress.sendStartState();
ok(
await hasPromiseResolved(navigated),
"Listener resolved after starting the new navigation"
);
}
);
add_task(
async function test_ProgressListener_resolveWhenNavigatingInsideDocument() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress);
const navigated = progressListener.start();
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved");
// Send hash change location change notification to complete the navigation
await webProgress.sendLocationChange({
flag: Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT,
});
ok(await hasPromiseResolved(navigated), "Listener has resolved");
const { currentURI, targetURI } = progressListener;
equal(
currentURI.spec,
TARGET_URI_WITH_HASH.spec,
"Expected current URI has been set"
);
equal(
targetURI.spec,
TARGET_URI_WITH_HASH.spec,
"Expected target URI has been set"
);
}
);
add_task(async function test_ProgressListener_ignoreCacheError() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress);
const navigated = progressListener.start();
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved");
await webProgress.sendStartState();
await webProgress.sendStopState({
errorFlag: Cr.NS_ERROR_PARSED_DATA_CACHED,
});
ok(await hasPromiseResolved(navigated), "Listener has resolved");
});
add_task(async function test_ProgressListener_navigationRejectedOnErrorPage() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: false,
});
const navigated = progressListener.start();
await webProgress.sendStartState();
await webProgress.sendLocationChange({
flag:
Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT |
Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE,
});
ok(
await hasPromiseRejected(navigated),
"Listener has rejected in location change for error page"
);
});
add_task(async function test_ProgressListener_navigationRejectedOnStopState() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: false,
});
const navigated = progressListener.start();
await webProgress.sendStartState();
await webProgress.sendStopState({ errorFlag: Cr.NS_BINDING_ABORTED });
ok(
await hasPromiseRejected(navigated),
"Listener has rejected in stop state for erroneous navigation"
);
});
add_task(async function test_ProgressListener_stopIfStarted() {
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
const progressListener = new ProgressListener(webProgress);
const navigated = progressListener.start();
progressListener.stopIfStarted();
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved");
await webProgress.sendStartState();
progressListener.stopIfStarted();
ok(await hasPromiseResolved(navigated), "Listener has resolved");
});
add_task(async function test_ProgressListener_stopIfStarted_alreadyStarted() {
// Create an already navigating browsing context.
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState();
// Create a progress listener which accepts already ongoing navigations.
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: false,
});
const navigated = progressListener.start();
// stopIfStarted should stop the listener because of the ongoing navigation.
progressListener.stopIfStarted();
ok(await hasPromiseResolved(navigated), "Listener has resolved");
});
add_task(
async function test_ProgressListener_stopIfStarted_alreadyStarted_waitForExplicitStart() {
// Create an already navigating browsing context.
const browsingContext = new MockTopContext();
const webProgress = browsingContext.webProgress;
await webProgress.sendStartState();
// Create a progress listener which rejects already ongoing navigations.
const progressListener = new ProgressListener(webProgress, {
waitForExplicitStart: true,
});
const navigated = progressListener.start();
// stopIfStarted will not stop the listener for the existing navigation.
progressListener.stopIfStarted();
ok(!(await hasPromiseResolved(navigated)), "Listener has not resolved");
// stopIfStarted will stop the listener when called after starting a new
// navigation.
await webProgress.sendStartState();
progressListener.stopIfStarted();
ok(await hasPromiseResolved(navigated), "Listener has resolved");
}
);