tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit d5812f45707d08f89e3de960685b9154e94f9f52
parent db7478bfd430bb946127529f79129a26a7067bc8
Author: Duncan McIntosh <dmcintosh@mozilla.com>
Date:   Fri,  5 Dec 2025 18:55:07 +0000

Bug 2001583 - Wait for restore-from-backup to get its state for the first time before running each test. r=hsohaney

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

Diffstat:
Mbrowser/components/backup/content/restore-from-backup.mjs | 9+++++++++
Mbrowser/components/backup/tests/browser/browser_settings_restore_from_backup.js | 185+++++++++++++++++++++++++------------------------------------------------------
2 files changed, 67 insertions(+), 127 deletions(-)

diff --git a/browser/components/backup/content/restore-from-backup.mjs b/browser/components/backup/content/restore-from-backup.mjs @@ -28,6 +28,14 @@ export default class RestoreFromBackup extends MozLitElement { */ #backupFileReadPromise = null; + /** + * Resolves when BackupUIParent sends state for the first time. + */ + get initializedPromise() { + return this.#initializedResolvers.promise; + } + #initializedResolvers = Promise.withResolvers(); + static properties = { _fileIconURL: { type: String }, aboutWelcomeEmbedded: { type: Boolean }, @@ -175,6 +183,7 @@ export default class RestoreFromBackup extends MozLitElement { this.getBackupFileInfo(path); } else if (event.type == "BackupUI:StateWasUpdated") { + this.#initializedResolvers.resolve(); if (this.#backupFileReadPromise) { this.#backupFileReadPromise.resolve(); this.#backupFileReadPromise = null; diff --git a/browser/components/backup/tests/browser/browser_settings_restore_from_backup.js b/browser/components/backup/tests/browser/browser_settings_restore_from_backup.js @@ -9,16 +9,6 @@ const { ERRORS } = ChromeUtils.importESModule( let TEST_PROFILE_PATH; -// Helper function for when we need to wait for the backup state to update and -// the UI to finish reacting to that. -async function makeStateUpdatedPromise(restoreFromBackupEl) { - await BrowserTestUtils.waitForEvent(window, "BackupUI:StateWasUpdated"); - // Wait for `restoreFromBackupEl` to handle this event. - await TestUtils.waitForTick(); - // Then wait for it to finish updating all the UI. - await restoreFromBackupEl.updateComplete; -} - add_setup(async () => { MockFilePicker.init(window.browsingContext); TEST_PROFILE_PATH = await IOUtils.createUniqueDirectory( @@ -41,13 +31,39 @@ add_setup(async () => { }); }); -async function waitInitialRequestStateSettled() { - // restore-from-backup.mjs is rendered quite late during the load. - // Bug 543435 caused a timing change such that withNewTab resolves right after - // that component dispatches BackupUI:InitWidget. So BackupUIParent hasn't yet - // received RequestState. If the RequestState / StateUpdate happens during the test - // that can mess things up, so wait a tick. See bug 2001583 - await new Promise(res => setTimeout(res)); +/** + * Gets most of the widgets that are used during tests. + * + * In addition to avoiding some boilerplate, this ensures that the first state + * update has been delivered. If we didn't wait, there'd be a timing problem; + * see bug 2001583 for more information. + * + * @param {Browser} browser + * The XUL browser containing the preferences page. + * @returns {{restoreFromBackup:HTMLElement, settings:HTMLElement}} + * Relevant widgets on the backup settings page. + */ +async function initializedBackupWidgets(browser) { + let settings = browser.contentDocument.querySelector("backup-settings"); + + await settings.updateComplete; + + Assert.ok( + settings.restoreFromBackupButtonEl, + "Button to restore backups should be found" + ); + + settings.restoreFromBackupButtonEl.click(); + await settings.updateComplete; + + let restoreFromBackup = settings.restoreFromBackupEl; + Assert.ok(restoreFromBackup, "restore-from-backup should be found"); + + await restoreFromBackup.initializedPromise; + return { + restoreFromBackup, + settings, + }; } /** @@ -55,7 +71,6 @@ async function waitInitialRequestStateSettled() { */ add_task(async function test_backup_failure() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); const mockBackupFilePath = await IOUtils.createUniqueFile( TEST_PROFILE_PATH, "backup.html" @@ -71,24 +86,12 @@ add_task(async function test_backup_failure() { }; MockFilePicker.returnValue = MockFilePicker.returnOK; - let settings = browser.contentDocument.querySelector("backup-settings"); - - await settings.updateComplete; - - Assert.ok( - settings.restoreFromBackupButtonEl, - "Button to restore backups should be found" - ); - - settings.restoreFromBackupButtonEl.click(); - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); - + let { restoreFromBackup } = await initializedBackupWidgets(browser); Services.fog.testResetFOG(); - let stateUpdatedPromise = makeStateUpdatedPromise(restoreFromBackup); + let stateUpdatedPromise = TestUtils.topicObserved( + "browser-backup-glean-sent" + ); restoreFromBackup.chooseButtonEl.click(); await stateUpdatedPromise; @@ -111,7 +114,6 @@ add_task(async function test_backup_failure() { */ add_task(async function test_restore_from_backup() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); // Info about our mock backup const date = new Date().getTime(); const deviceName = "test-device"; @@ -147,6 +149,7 @@ add_task(async function test_restore_from_backup() { healthTelemetryEnabled, }, backupFileToRestore: mockBackupFilePath, + backupFileCoarseLocation: "other", restoreID, recoveryErrorCode: ERRORS.NONE, }; @@ -172,26 +175,12 @@ add_task(async function test_restore_from_backup() { } ); - let settings = browser.contentDocument.querySelector("backup-settings"); - - await settings.updateComplete; - - Assert.ok( - settings.restoreFromBackupButtonEl, - "Button to restore backups should be found" - ); - - settings.restoreFromBackupButtonEl.click(); - - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); - + let { restoreFromBackup } = await initializedBackupWidgets(browser); Services.fog.testResetFOG(); - let stateUpdatedPromise = makeStateUpdatedPromise(restoreFromBackup); + let stateUpdatedPromise = TestUtils.topicObserved( + "browser-backup-glean-sent" + ); restoreFromBackup.chooseButtonEl.click(); await stateUpdatedPromise; @@ -267,7 +256,6 @@ add_task(async function test_restore_from_backup() { */ add_task(async function test_restore_uses_matching_initial_folder() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); const mockBackupFilePath = await IOUtils.createUniqueFile( TEST_PROFILE_PATH, "backup.html" @@ -291,20 +279,8 @@ add_task(async function test_restore_uses_matching_initial_folder() { }); MockFilePicker.returnValue = MockFilePicker.returnOK; - let settings = browser.contentDocument.querySelector("backup-settings"); - await settings.updateComplete; - - Assert.ok( - settings.restoreFromBackupButtonEl, - "Button to restore backups should be found" - ); - - settings.restoreFromBackupButtonEl.click(); - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); - + let { restoreFromBackup, settings } = + await initializedBackupWidgets(browser); let selectedFilePromise = BrowserTestUtils.waitForEvent( settings, "BackupUI:SelectNewFilepickerPath" @@ -324,7 +300,6 @@ add_task(async function test_restore_uses_matching_initial_folder() { */ add_task(async function test_restore_in_progress() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); let sandbox = sinon.createSandbox(); let bs = getAndMaybeInitBackupService(); @@ -343,23 +318,8 @@ add_task(async function test_restore_in_progress() { } ); - let settings = browser.contentDocument.querySelector("backup-settings"); - - await settings.updateComplete; - - Assert.ok( - settings.restoreFromBackupButtonEl, - "Button to restore backups should be found" - ); - - settings.restoreFromBackupButtonEl.click(); - - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); - + let { restoreFromBackup, settings } = + await initializedBackupWidgets(browser); Assert.equal( restoreFromBackup.filePicker.value, "", @@ -406,16 +366,15 @@ add_task(async function test_restore_in_progress() { ); restoreFromBackup.confirmButtonEl.click(); + await restorePromise; + restoreFromBackup.backupServiceState = { ...restoreFromBackup.backupServiceState, recoveryInProgress: true, }; // Re-render since we've manually changed the component's state await restoreFromBackup.requestUpdate(); - - await restorePromise; - - await settings.updateComplete; + await restoreFromBackup.updateComplete; Assert.ok( settings.restoreFromBackupDialogEl.open, @@ -442,10 +401,10 @@ add_task(async function test_restore_in_progress() { recoverResolve(); // Wait a tick of the event loop to let the BackupUIParent respond to // the promise resolution, and to send its message to the BackupUIChild. - await new Promise(resolve => SimpleTest.executeSoon(resolve)); + await TestUtils.waitForTick(); // Wait a second tick to let the BackupUIChild respond to the message // from BackupUIParent. - await new Promise(resolve => SimpleTest.executeSoon(resolve)); + await TestUtils.waitForTick(); await settings.updateComplete; @@ -469,20 +428,13 @@ add_task( await BrowserTestUtils.withNewTab( "about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); let sandbox = sinon.createSandbox(); - let settings = browser.contentDocument.querySelector("backup-settings"); - await settings.updateComplete; + let { restoreFromBackup } = await initializedBackupWidgets(browser); - Assert.ok( - settings.restoreFromBackupButtonEl, - "Restore button should exist" - ); - - settings.restoreFromBackupButtonEl.click(); - await settings.updateComplete; - let restoreFromBackup = settings.restoreFromBackupEl; - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); + restoreFromBackup.backupServiceState = { + ...restoreFromBackup.backupServiceState, + backupFileToRestore: "", + }; // When aboutWelcomeEmbedded is false, the file picker should be an input Assert.equal( @@ -553,20 +505,7 @@ add_task( */ add_task(async function test_restore_backup_file_info_display() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); - let settings = browser.contentDocument.querySelector("backup-settings"); - await settings.updateComplete; - - Assert.ok( - settings.restoreFromBackupButtonEl, - "Restore button should exist" - ); - - settings.restoreFromBackupButtonEl.click(); - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); + let { restoreFromBackup } = await initializedBackupWidgets(browser); // Initially, backup file info should not be displayed underneath the input let fileInfoSpan = restoreFromBackup.shadowRoot.querySelector( @@ -648,15 +587,7 @@ function assertNonEmbeddedSupportLink(link, linkName) { */ add_task(async function test_support_links_non_embedded() { await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => { - await waitInitialRequestStateSettled(); - let settings = browser.contentDocument.querySelector("backup-settings"); - await settings.updateComplete; - - settings.restoreFromBackupButtonEl.click(); - await settings.updateComplete; - - let restoreFromBackup = settings.restoreFromBackupEl; - Assert.ok(restoreFromBackup, "restore-from-backup should be found"); + let { restoreFromBackup } = await initializedBackupWidgets(browser); Assert.ok( !restoreFromBackup.aboutWelcomeEmbedded,