diff --git a/src/sql/workbench/services/connection/browser/connectionDialogService.ts b/src/sql/workbench/services/connection/browser/connectionDialogService.ts index 7305910af8..5bb31d506e 100644 --- a/src/sql/workbench/services/connection/browser/connectionDialogService.ts +++ b/src/sql/workbench/services/connection/browser/connectionDialogService.ts @@ -153,12 +153,15 @@ export class ConnectionDialogService implements IConnectionDialogService { } private handleOnConnect(params: INewConnectionParams, profile?: IConnectionProfile): void { + this._logService.debug('ConnectionDialogService: onConnect event is received'); if (!this._connecting) { + this._logService.debug('ConnectionDialogService: Start connecting'); this._connecting = true; this.handleProviderOnConnecting(); if (!profile) { let result = this.uiController.validateConnection(); if (!result.isValid) { + this._logService.debug('ConnectionDialogService: Connection is invalid'); this._connecting = false; this._connectionDialog.resetConnection(); return; @@ -259,14 +262,17 @@ export class ConnectionDialogService implements IConnectionDialogService { } } else if (connectionResult && connectionResult.errorHandled) { this._connectionDialog.resetConnection(); + this._logService.debug(`ConnectionDialogService: Error handled and connection reset - Error: ${connectionResult.errorMessage}`); } else { this._connectionDialog.resetConnection(); this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack); + this._logService.debug(`ConnectionDialogService: Connection error: ${connectionResult.errorMessage}`); } } catch (err) { this._connecting = false; this._connectionDialog.resetConnection(); this.showErrorDialog(Severity.Error, this._connectionErrorTitle, err); + this._logService.debug(`ConnectionDialogService: Error encountered while connecting ${err}`); } } diff --git a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts index fe2d2c243c..6e0da97932 100644 --- a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts @@ -335,12 +335,14 @@ export class ConnectionDialogWidget extends Modal { } private connect(element?: IConnectionProfile): void { + this.logService.debug('ConnectionDialogWidget: Connect button is clicked'); if (this._connectButton.enabled) { this._connecting = true; this._connectButton.enabled = false; this._providerTypeSelectBox.disable(); this.spinner = true; this._onConnect.fire(element); + this.logService.debug('ConnectionDialogWidget: onConnect event is fired'); } } diff --git a/test/automation/src/sql/configurePythonDialog.ts b/test/automation/src/sql/configurePythonDialog.ts index 2279e09e6b..5511cd84d0 100644 --- a/test/automation/src/sql/configurePythonDialog.ts +++ b/test/automation/src/sql/configurePythonDialog.ts @@ -5,12 +5,13 @@ import { Code } from '../code'; import { Dialog } from './dialog'; +import { NotificationToast } from './notificationToast'; const CONFIGURE_PYTHON_DIALOG_TITLE = 'Configure Python to run Python 3 kernel'; export class ConfigurePythonDialog extends Dialog { - constructor(code: Code) { + constructor(code: Code, private notificationToast: NotificationToast) { super(CONFIGURE_PYTHON_DIALOG_TITLE, code); } @@ -25,13 +26,23 @@ export class ConfigurePythonDialog extends Dialog { const newPythonInstallation = '.modal .modal-body input[aria-label="New Python installation"]'; await this.code.waitAndClick(newPythonInstallation); + // Wait for the python install location to be loaded before clicking the next button. + // There may be a timing issue where the smoke test attempts to go to the next page before + // the contents are loaded, causing the test to fail. + const pythonInstallLocationDropdownValue = `${dialog} select[aria-label="Python Install Location"] option`; + await this.code.waitForElement(pythonInstallLocationDropdownValue); + + await this.notificationToast.closeNotificationToasts(); + const nextButton = '.modal-dialog .modal-content .modal-footer .right-footer .footer-button a[aria-label="Next"][aria-disabled="false"]'; - await this.code.waitForElement(nextButton); - await this.code.dispatchKeybinding('enter'); + await this.code.waitAndClick(dialog); + await this.code.waitAndClick(nextButton); + + await this.notificationToast.closeNotificationToasts(); const installButton = '.modal-dialog .modal-content .modal-footer .right-footer .footer-button a[aria-label="Install"][aria-disabled="false"]'; - await this.code.waitForElement(installButton); - await this.code.dispatchKeybinding('enter'); + await this.code.waitAndClick(dialog); + await this.code.waitAndClick(installButton); await this.waitForDialogGone(); return this._waitForInstallationComplete(); diff --git a/test/automation/src/sql/connectionDialog.ts b/test/automation/src/sql/connectionDialog.ts index c1b34584b6..74147928bb 100644 --- a/test/automation/src/sql/connectionDialog.ts +++ b/test/automation/src/sql/connectionDialog.ts @@ -5,12 +5,13 @@ import { Code } from '../code'; import { Dialog } from './dialog'; +import { NotificationToast } from './notificationToast'; const CONNECTION_DIALOG_TITLE = 'Connection'; export class ConnectionDialog extends Dialog { - constructor(code: Code) { + constructor(code: Code, private notificationToast: NotificationToast) { super(CONNECTION_DIALOG_TITLE, code); } @@ -30,8 +31,10 @@ export class ConnectionDialog extends Dialog { private static readonly CONNECT_BUTTON_SELECTOR = '.modal .modal-footer a[aria-label="Connect"]:not(.disabled)'; async connect(): Promise { + await this.notificationToast.closeNotificationToasts(); + await this.code.waitAndClick(ConnectionDialog.CONNECT_BUTTON_SELECTOR); - return this.waitForDialogGone(); + await this.waitForDialogGone(); } } diff --git a/test/automation/src/sql/notificationToast.ts b/test/automation/src/sql/notificationToast.ts new file mode 100644 index 0000000000..d7003094cc --- /dev/null +++ b/test/automation/src/sql/notificationToast.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Code } from '../code'; + +export class NotificationToast { + + constructor(private readonly code: Code) { } + + async closeNotificationToasts() { + const notificationToastSelector = 'div[class="notifications-toasts visible"]'; + const notificationToastCloseButton = `a[class="action-label codicon codicon-notifications-clear"][role="button"]`; + let numberOfToasts = 0; + + await this.code.waitForElements(notificationToastSelector, false, result => { + numberOfToasts = result.length; + return true; + }); + + for (let i = 0; i < numberOfToasts; i++) { + await this.code.waitAndClick(notificationToastSelector); + await this.code.waitAndClick(notificationToastCloseButton); + } + } +} diff --git a/test/automation/src/workbench.ts b/test/automation/src/workbench.ts index 604ba10509..33e51f1bc1 100644 --- a/test/automation/src/workbench.ts +++ b/test/automation/src/workbench.ts @@ -28,6 +28,7 @@ import { QueryEditors } from './sql/queryEditors'; import { QueryEditor } from './sql/queryEditor'; import { Notebook as SqlNotebook } from './sql/notebook'; import { ConfigurePythonDialog } from './sql/configurePythonDialog'; +import { NotificationToast } from './sql/notificationToast'; // {{END}} export interface Commands { @@ -60,6 +61,7 @@ export class Workbench { readonly queryEditor: QueryEditor; readonly sqlNotebook: SqlNotebook; readonly configurePythonDialog: ConfigurePythonDialog; + readonly notificationToast: NotificationToast; // {{END}} constructor(code: Code, userDataPath: string) { @@ -79,12 +81,13 @@ export class Workbench { this.keybindingsEditor = new KeybindingsEditor(code); this.terminal = new Terminal(code, this.quickaccess); // {{SQL CARBON EDIT}} - this.connectionDialog = new ConnectionDialog(code); + this.notificationToast = new NotificationToast(code); + this.connectionDialog = new ConnectionDialog(code, this.notificationToast); this.profiler = new Profiler(code, this.quickaccess); this.queryEditors = new QueryEditors(code, this.editors); this.queryEditor = new QueryEditor(code); this.sqlNotebook = new SqlNotebook(code, this.quickaccess, this.quickinput, this.editors); - this.configurePythonDialog = new ConfigurePythonDialog(code); + this.configurePythonDialog = new ConfigurePythonDialog(code, this.notificationToast); // {{END}} this.notebook = new Notebook(this.quickaccess, code); }