diff --git a/package.json b/package.json index bf0b303108..9a4339c117 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "azuredatastudio", "version": "1.31.0", - "distro": "e599a23f8864bdc10842093408f0e756f80df17b", + "distro": "9eab1e6d6180c1a560a4a50eb9e6e99641549329 ", "author": { "name": "Microsoft Corporation" }, diff --git a/test/automation/src/sql/addRemoteBookDialog.ts b/test/automation/src/sql/addRemoteBookDialog.ts new file mode 100644 index 0000000000..bf54857003 --- /dev/null +++ b/test/automation/src/sql/addRemoteBookDialog.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; +import { Dialog } from './dialog'; + +const ADD_REMOTE_BOOK_DIALOG_TITLE = 'New Jupyter Book (Preview)'; + +// The option inputs for this dialog are dynamically generated based on previous selections, so in order to ensure +// that the option we want to select exists we wait on the option element to be created first and then select it. +const LOCATION_SELECT_SELECTOR = '.modal .modal-body .select-container select[aria-label="Location"]'; +const LOCATION_OPTION_SELECTOR = (option: string) => `${LOCATION_SELECT_SELECTOR} option[value="${option}"]`; +const REPO_URL_INPUT_SELECTOR = '.modal .modal-body input[aria-label="Repository URL"]'; +const SEARCH_BUTTON_SELECTOR = '.modal .modal-body a[aria-label="Search"]:not(.disabled)'; +const RELEASES_SELECT_SELECTOR = '.modal .modal-body .select-container select[aria-label="Releases"]'; +const RELEASES_OPTION_SELECTOR = (release: string) => `${RELEASES_SELECT_SELECTOR} option[value="${release}"]`; +const JUPYTER_BOOK_SELECT_SELECTOR = '.modal .modal-body .select-container select[aria-label="Jupyter Book"]'; +const JUPYTER_BOOK_OPTION_SELECTOR = (jupyterBook: string) => `${JUPYTER_BOOK_SELECT_SELECTOR} option[value="${jupyterBook}"]`; +const VERSION_SELECT_SELECTOR = '.modal .modal-body .select-container select[aria-label="Version"]'; +const VERSION_OPTION_SELECTOR = (version: string) => `${VERSION_SELECT_SELECTOR} option[value="${version}"]`; +const LANGUAGE_SELECT_SELECTOR = '.modal .modal-body .select-container select[aria-label="Language"]'; +const LANGUAGE_OPTION_SELECTOR = (language: string) => `${LANGUAGE_SELECT_SELECTOR} option[value="${language}"]`; +const ADD_BUTTON_SELECTOR = '.modal .modal-footer a[aria-label="Add"]:not(.disabled)'; + +export class AddRemoteBookDialog extends Dialog { + + constructor(code: Code) { + super(ADD_REMOTE_BOOK_DIALOG_TITLE, code); + } + + async waitForDialog(): Promise { + await this.waitForNewDialog(); + } + + public async setLocation(location: string): Promise { + await this.code.waitForElement(LOCATION_OPTION_SELECTOR(location)); + await this.code.waitForSetValue(LOCATION_SELECT_SELECTOR, location); + } + + public async setRepoUrl(repoUrl: string): Promise { + await this.code.waitForSetValue(REPO_URL_INPUT_SELECTOR, repoUrl); + } + + public async search(): Promise { + await this.code.waitAndClick(SEARCH_BUTTON_SELECTOR); + } + + public async setRelease(release: string): Promise { + await this.code.waitForElement(RELEASES_OPTION_SELECTOR(release)); + await this.code.waitForSetValue(RELEASES_SELECT_SELECTOR, release); + } + + public async setJupyterBook(jupyterBook: string): Promise { + await this.code.waitForElement(JUPYTER_BOOK_OPTION_SELECTOR(jupyterBook)); + await this.code.waitForSetValue(JUPYTER_BOOK_SELECT_SELECTOR, jupyterBook); + } + + public async setVersion(version: string): Promise { + await this.code.waitForElement(VERSION_OPTION_SELECTOR(version)); + await this.code.waitForSetValue(VERSION_SELECT_SELECTOR, version); + } + + public async setLanguage(language: string): Promise { + await this.code.waitForElement(LANGUAGE_OPTION_SELECTOR(language)); + await this.code.waitForSetValue(LANGUAGE_SELECT_SELECTOR, language); + } + + async add(): Promise { + await this.code.waitAndClick(ADD_BUTTON_SELECTOR); + await this.waitForDialogGone(); + } +} diff --git a/test/automation/src/workbench.ts b/test/automation/src/workbench.ts index 8cdc77555a..5bf540e1df 100644 --- a/test/automation/src/workbench.ts +++ b/test/automation/src/workbench.ts @@ -30,6 +30,7 @@ import { Notebook as SqlNotebook } from './sql/notebook'; import { ConfigurePythonDialog } from './sql/configurePythonDialog'; import { CreateBookDialog } from './sql/createBookDialog'; import { NotificationToast } from './sql/notificationToast'; +import { AddRemoteBookDialog } from './sql/addRemoteBookDialog'; // {{END}} export interface Commands { @@ -64,6 +65,7 @@ export class Workbench { readonly createBookDialog: CreateBookDialog; readonly configurePythonDialog: ConfigurePythonDialog; readonly notificationToast: NotificationToast; + readonly addRemoteBookDialog: AddRemoteBookDialog; // {{END}} constructor(code: Code, userDataPath: string) { @@ -91,6 +93,7 @@ export class Workbench { this.sqlNotebook = new SqlNotebook(code, this.quickaccess, this.quickinput, this.editors); this.createBookDialog = new CreateBookDialog(code); this.configurePythonDialog = new ConfigurePythonDialog(code); + this.addRemoteBookDialog = new AddRemoteBookDialog(code); // {{END}} this.notebook = new Notebook(this.quickaccess, code); } diff --git a/test/smoke/src/sql/areas/notebook/addRemoteBook.test.ts b/test/smoke/src/sql/areas/notebook/addRemoteBook.test.ts new file mode 100644 index 0000000000..4363aa3b65 --- /dev/null +++ b/test/smoke/src/sql/areas/notebook/addRemoteBook.test.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Application } from '../../../../../automation'; +import { promises as fs } from 'fs'; +import * as path from 'path'; +import { assert } from 'console'; + +const AddRemoteBookCommand = 'Jupyter Books: Add Remote Jupyter Book'; +const JUPYTER_BOOK = 'CU'; +const VERSION = '1.0'; +const LANGUAGE = 'EN'; +export function setup() { + + describe('AddRemoteBookDialog', () => { + + it('can open remote book', async function () { + const app = this.app as Application; + await app.workbench.quickaccess.runCommand(AddRemoteBookCommand); + await app.workbench.addRemoteBookDialog.setLocation('GitHub'); + await app.workbench.addRemoteBookDialog.setRepoUrl('repos/microsoft/tigertoolbox'); + await app.workbench.addRemoteBookDialog.search(); + await app.workbench.addRemoteBookDialog.setRelease('SQL Server Big Data Clusters Operational Guide'); + await app.workbench.addRemoteBookDialog.setJupyterBook(JUPYTER_BOOK); + await app.workbench.addRemoteBookDialog.setVersion(VERSION); + await app.workbench.addRemoteBookDialog.setLanguage(LANGUAGE); + await app.workbench.addRemoteBookDialog.add(); + const bookExists = await fs.stat(path.join(app.workspacePathOrFolder, `${JUPYTER_BOOK}-${VERSION}-${LANGUAGE}`)); + assert(!!bookExists, 'Expected book was not created'); + }); + }); +} diff --git a/test/smoke/src/sql/areas/notebook/createBook.test.ts b/test/smoke/src/sql/areas/notebook/createBook.test.ts index 76a696b0b3..560e574845 100644 --- a/test/smoke/src/sql/areas/notebook/createBook.test.ts +++ b/test/smoke/src/sql/areas/notebook/createBook.test.ts @@ -61,6 +61,9 @@ export function setup() { // Try our best to clean up but don't fail the test if we can't } } + const app = this.app as Application; + // Workaround for error notification trying to read deleted books + await app.workbench.notificationToast.closeNotificationToasts(); }); }); } diff --git a/test/smoke/src/sql/main.ts b/test/smoke/src/sql/main.ts index 0e979af78b..99172313a1 100644 --- a/test/smoke/src/sql/main.ts +++ b/test/smoke/src/sql/main.ts @@ -8,6 +8,7 @@ import { setup as setupNotebookTests } from './areas/notebook/notebook.test'; import { setup as setupNotebookViewTests } from './areas/notebook/notebookView.test'; import { setup as setupImportTests } from './areas/import/import.test'; import { setup as setupCreateBookDialogTests } from './areas/notebook/createBook.test'; +import { setup as setupAddRemoteBookDialogTests } from './areas/notebook/addRemoteBook.test'; import { ApplicationOptions } from '../../../automation'; import * as yazl from 'yauzl'; import * as fs from 'fs'; @@ -24,6 +25,7 @@ export function main(isWeb: boolean = false): void { setupNotebookTests(); setupNotebookViewTests(); setupCreateBookDialogTests(); + setupAddRemoteBookDialogTests(); setupImportTests(); }