diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 2c3ecb669ab..0a193453e0f 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -66,7 +66,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { async capturePage(windowId: number): Promise { await this.whenUnfrozen(windowId); - const window = this.windowsMainService.getWindowById(windowId); + const window = this.windowsMainService.getWindowById(windowId) ?? this.windowsMainService.getLastActiveWindow(); // fallback to active window to ensure we capture window if (!window?.win) { throw new Error('Invalid window'); } diff --git a/test/automation/src/application.ts b/test/automation/src/application.ts index f2277140f71..c34221c5621 100644 --- a/test/automation/src/application.ts +++ b/test/automation/src/application.ts @@ -109,15 +109,28 @@ export class Application { } private async checkWindowReady(code: Code): Promise { + this.logger.log('checkWindowReady: begin'); + await code.waitForWindowIds(ids => ids.length > 0); await code.waitForElement('.monaco-workbench'); - if (this.remote) { - await code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', ' TestResolver', undefined, 2000); + // Web or remote: wait for a remote connection state change + if (this.remote || this.web) { + await code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', undefined, s => { + this.logger.log(`checkWindowReady: remote indicator text is ${s}`); + + // The absence of "Opening Remote" is not a strict + // indicator for a successful connection, but we + // want to avoid hanging here until timeout because + // this method is potentially called from a location + // that has no tracing enabled making it hard to + // diagnose this. As such, as soon as the connection + // state changes away from the "Opening Remote..." one + // we return. + return !s.includes('Opening Remote'); + }, 300 /* = 30s of retry */); } - if (this.web) { - await code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', undefined, s => !s.includes('Opening Remote'), 2000); - } + this.logger.log('checkWindowReady: end'); } } diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index 086d4fe8b31..156cb7816e9 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -290,8 +290,10 @@ export class Code { private async getActiveWindowId(): Promise { if (typeof this._activeWindowId !== 'number') { + this.logger.log('getActiveWindowId(): begin'); const windows = await this.driver.getWindowIds(); this._activeWindowId = windows[0]; + this.logger.log(`getActiveWindowId(): end (windowId=${this._activeWindowId})`); } return this._activeWindowId; diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index 421605cb831..89883f2a062 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -5,7 +5,7 @@ import { join } from 'path'; import { Application, ApplicationOptions, Logger, Quality } from '../../../../automation'; -import { getRandomUserDataDir, startApp, timeout, installDiagnosticsHandler, installAppAfterHandler } from '../../utils'; +import { createApp, timeout, installDiagnosticsHandler, installAppAfterHandler, getRandomUserDataDir } from '../../utils'; export function setup(ensureStableCode: () => string | undefined, logger: Logger) { describe('Data Loss (insiders -> insiders)', () => { @@ -17,7 +17,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger installAppAfterHandler(() => app); it('verifies opened editors are restored', async function () { - app = await startApp(this.defaultOptions); + app = createApp(this.defaultOptions); + await app.start(); // Open 3 editors await app.workbench.quickaccess.openFile(join(app.workspacePathOrFolder, 'bin', 'www')); @@ -38,7 +39,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger }); it('verifies editors can save and restore', async function () { - app = await startApp(this.defaultOptions); + app = createApp(this.defaultOptions); + await app.start(); const textToType = 'Hello, Code'; @@ -74,7 +76,8 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger }); async function testHotExit(restartDelay: number | undefined, autoSave: boolean | undefined) { - app = await startApp(this.defaultOptions); + app = createApp(this.defaultOptions); + await app.start(); if (autoSave) { await app.workbench.settingsEditor.addUserSetting('files.autoSave', '"afterDelay"'); @@ -129,10 +132,13 @@ export function setup(ensureStableCode: () => string | undefined, logger: Logger this.skip(); } - // On macOS, the stable app fails to launch on first try, - // so let's retry this once - // https://github.com/microsoft/vscode/pull/127799 + // macOS: the first launch of stable Code will trigger + // additional checks in the OS (notarization validation) + // so it can take a very long time. as such we increase + // the timeout and install a retry handler to make sure + // we do not fail as a consequence. if (process.platform === 'darwin') { + this.timeout(2 * 60 * 1000); this.retries(2); } diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 67a33d6ba34..c958c286db4 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -311,6 +311,7 @@ async function setup(): Promise { logger.log('Smoketest setup done!\n'); } +// Before main suite (before all tests) before(async function () { this.timeout(2 * 60 * 1000); // allow two minutes for setup @@ -333,6 +334,7 @@ before(async function () { await setup(); }); +// After main suite (after all tests) after(async function () { try { let deleted = false; diff --git a/test/smoke/src/utils.ts b/test/smoke/src/utils.ts index 6344fff9bf9..d8114603aac 100644 --- a/test/smoke/src/utils.ts +++ b/test/smoke/src/utils.ts @@ -88,7 +88,8 @@ export function installDiagnosticsHandler(logger: Logger, appFn?: () => Applicat function installAppBeforeHandler(optionsTransform?: (opts: ApplicationOptions) => ApplicationOptions) { before(async function () { - this.app = await startApp(this.defaultOptions, optionsTransform); + this.app = createApp(this.defaultOptions, optionsTransform); + await this.app.start(); }); } @@ -105,7 +106,7 @@ export function installAppAfterHandler(appFn?: () => Application | undefined, jo }); } -export async function startApp(options: ApplicationOptions, optionsTransform?: (opts: ApplicationOptions) => ApplicationOptions): Promise { +export function createApp(options: ApplicationOptions, optionsTransform?: (opts: ApplicationOptions) => ApplicationOptions): Application { if (optionsTransform) { options = optionsTransform({ ...options }); } @@ -115,8 +116,6 @@ export async function startApp(options: ApplicationOptions, optionsTransform?: ( userDataDir: getRandomUserDataDir(options) }); - await app.start(); - return app; }