Try to make smoke tests more stable (#15212)

* make sure dialog buttons are not disabled

* use 'enter' to close connect dialog

* retry clikcing the Connect button

* wait for dialog gone after reclicking

* pr comments + add logging

* use debug to log

* close toasts before clicking dialog buttons

* await close notification toast call

* click python wizard buttons instead of enter
This commit is contained in:
Lucy Zhang
2021-04-27 16:53:17 -04:00
committed by GitHub
parent c66a8ca171
commit 7e1c0076ba
6 changed files with 61 additions and 9 deletions

View File

@@ -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}`);
}
}

View File

@@ -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');
}
}

View File

@@ -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();

View File

@@ -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<void> {
await this.notificationToast.closeNotificationToasts();
await this.code.waitAndClick(ConnectionDialog.CONNECT_BUTTON_SELECTOR);
return this.waitForDialogGone();
await this.waitForDialogGone();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}