Add notebook smoketests
parent
c19d0dcd9b
commit
9bc11824c3
|
@ -27,6 +27,12 @@
|
|||
"mocha": "^2.3.3"
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "vscode-notebook-tests.createNewNotebook",
|
||||
"title": "Create New Notebook"
|
||||
}
|
||||
],
|
||||
"notebookProvider": [
|
||||
{
|
||||
"viewType": "notebookCoreTest",
|
||||
|
@ -37,6 +43,16 @@
|
|||
"excludeFileNamePattern": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"viewType": "notebookSmokeTest",
|
||||
"displayName": "Notebook Smoke Test",
|
||||
"selector": [
|
||||
{
|
||||
"filenamePattern": "*.smoke-nb",
|
||||
"excludeFileNamePattern": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as child_process from 'child_process';
|
||||
import * as path from 'path';
|
||||
|
||||
function wait(ms: number): Promise<void> {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
export function smokeTestActivate(context: vscode.ExtensionContext): any {
|
||||
context.subscriptions.push(vscode.commands.registerCommand('vscode-notebook-tests.createNewNotebook', async () => {
|
||||
const workspacePath = vscode.workspace.workspaceFolders![0].uri.fsPath;
|
||||
const notebookPath = path.join(workspacePath, 'test.smoke-nb');
|
||||
child_process.execSync('echo \'\' > ' + notebookPath);
|
||||
await wait(500);
|
||||
await vscode.commands.executeCommand('vscode.open', vscode.Uri.file(notebookPath));
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookSmokeTest', {
|
||||
onDidChangeNotebook: new vscode.EventEmitter<vscode.NotebookDocumentEditEvent>().event,
|
||||
openNotebook: async (_resource: vscode.Uri) => {
|
||||
const dto: vscode.NotebookData = {
|
||||
languages: ['typescript'],
|
||||
metadata: {},
|
||||
cells: [
|
||||
{
|
||||
source: 'code()',
|
||||
language: 'typescript',
|
||||
cellKind: vscode.CellKind.Code,
|
||||
outputs: [],
|
||||
metadata: {
|
||||
custom: { testCellMetadata: 123 }
|
||||
}
|
||||
},
|
||||
{
|
||||
source: 'Markdown Cell',
|
||||
language: 'markdown',
|
||||
cellKind: vscode.CellKind.Markdown,
|
||||
outputs: [],
|
||||
metadata: {
|
||||
custom: { testCellMetadata: 123 }
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return dto;
|
||||
},
|
||||
executeCell: async (_document: vscode.NotebookDocument, _cell: vscode.NotebookCell | undefined, _token: vscode.CancellationToken) => {
|
||||
if (!_cell) {
|
||||
_cell = _document.cells[0];
|
||||
}
|
||||
|
||||
_cell.outputs = [{
|
||||
outputKind: vscode.CellOutputKind.Rich,
|
||||
data: {
|
||||
'text/html': ['test output']
|
||||
}
|
||||
}];
|
||||
return;
|
||||
},
|
||||
saveNotebook: async (_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
|
||||
return;
|
||||
},
|
||||
saveNotebookAs: async (_targetResource: vscode.Uri, _document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) => {
|
||||
return;
|
||||
}
|
||||
}));
|
||||
}
|
|
@ -4,8 +4,11 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { smokeTestActivate } from './notebookSmokeTestMain';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): any {
|
||||
smokeTestActivate(context);
|
||||
|
||||
context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookCoreTest', {
|
||||
onDidChangeNotebook: new vscode.EventEmitter<vscode.NotebookDocumentEditEvent>().event,
|
||||
openNotebook: async (_resource: vscode.Uri) => {
|
||||
|
|
|
@ -148,11 +148,7 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
|
|||
|
||||
if (codePath) {
|
||||
// running against a build: copy the test resolver extension
|
||||
const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver');
|
||||
if (!fs.existsSync(testResolverExtPath)) {
|
||||
const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver');
|
||||
await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c()));
|
||||
}
|
||||
copyExtension(options, 'vscode-test-resolver');
|
||||
}
|
||||
args.push('--enable-proposed-api=vscode.vscode-test-resolver');
|
||||
const remoteDataDir = `${options.userDataDir}-server`;
|
||||
|
@ -160,6 +156,9 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
|
|||
env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir;
|
||||
}
|
||||
|
||||
copyExtension(options, 'vscode-notebook-tests');
|
||||
args.push('--enable-proposed-api=vscode.vscode-notebook-tests');
|
||||
|
||||
if (!codePath) {
|
||||
args.unshift(repoPath);
|
||||
}
|
||||
|
@ -185,6 +184,14 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
|
|||
return connect(connectDriver, child, outPath, handle, options.logger);
|
||||
}
|
||||
|
||||
async function copyExtension(options: SpawnOptions, extId: string): Promise<void> {
|
||||
const testResolverExtPath = path.join(options.extensionsPath, extId);
|
||||
if (!fs.existsSync(testResolverExtPath)) {
|
||||
const orig = path.join(repoPath, 'extensions', extId);
|
||||
await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c()));
|
||||
}
|
||||
}
|
||||
|
||||
async function poll<T>(
|
||||
fn: () => Thenable<T>,
|
||||
acceptFn: (result: T) => boolean,
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Code } from './code';
|
||||
import { QuickAccess } from './quickaccess';
|
||||
|
||||
const activeRowSelector = `.notebook-editor .monaco-list-row.focused`;
|
||||
|
||||
export class Notebook {
|
||||
|
||||
constructor(
|
||||
private readonly quickAccess: QuickAccess,
|
||||
private readonly code: Code) {
|
||||
}
|
||||
|
||||
async openNotebook() {
|
||||
await this.quickAccess.runCommand('vscode-notebook-tests.createNewNotebook');
|
||||
await this.code.waitForElement(activeRowSelector);
|
||||
await this.focusFirstCell();
|
||||
await this.waitForActiveCellEditorContents('code()');
|
||||
}
|
||||
|
||||
async focusNextCell() {
|
||||
await this.code.dispatchKeybinding('down');
|
||||
}
|
||||
|
||||
async focusFirstCell() {
|
||||
await this.quickAccess.runCommand('notebook.focusTop');
|
||||
}
|
||||
|
||||
async editCell() {
|
||||
await this.code.dispatchKeybinding('enter');
|
||||
}
|
||||
|
||||
async stopEditingCell() {
|
||||
await this.code.dispatchKeybinding('esc');
|
||||
}
|
||||
|
||||
async waitForTypeInEditor(text: string): Promise<any> {
|
||||
const editor = `${activeRowSelector} .monaco-editor`;
|
||||
|
||||
await this.code.waitForElement(editor);
|
||||
|
||||
const textarea = `${editor} textarea`;
|
||||
await this.code.waitForActiveElement(textarea);
|
||||
|
||||
await this.code.waitForTypeInEditor(textarea, text);
|
||||
|
||||
await this._waitForActiveCellEditorContents(c => c.indexOf(text) > -1);
|
||||
}
|
||||
|
||||
async waitForActiveCellEditorContents(contents: string): Promise<any> {
|
||||
return this._waitForActiveCellEditorContents(str => str === contents);
|
||||
}
|
||||
|
||||
private async _waitForActiveCellEditorContents(accept: (contents: string) => boolean): Promise<any> {
|
||||
const selector = `${activeRowSelector} .monaco-editor .view-lines`;
|
||||
return this.code.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));
|
||||
}
|
||||
|
||||
async waitForMarkdownContents(markdownSelector: string, text: string): Promise<void> {
|
||||
const selector = `${activeRowSelector} .markdown ${markdownSelector}`;
|
||||
await this.code.waitForTextContent(selector, text);
|
||||
}
|
||||
|
||||
async insertNotebookCell(kind: 'markdown' | 'code'): Promise<void> {
|
||||
if (kind === 'markdown') {
|
||||
await this.quickAccess.runCommand('notebook.cell.insertMarkdownCellBelow');
|
||||
} else {
|
||||
await this.quickAccess.runCommand('notebook.cell.insertCodeCellBelow');
|
||||
}
|
||||
}
|
||||
|
||||
async deleteActiveCell(): Promise<void> {
|
||||
await this.quickAccess.runCommand('notebook.cell.delete');
|
||||
}
|
||||
|
||||
async focusInCellOutput(): Promise<void> {
|
||||
await this.quickAccess.runCommand('notebook.cell.focusInOutput');
|
||||
await this.code.waitForActiveElement('webview');
|
||||
}
|
||||
|
||||
async focusOutCellOutput(): Promise<void> {
|
||||
await this.quickAccess.runCommand('notebook.cell.focusOutOutput');
|
||||
}
|
||||
|
||||
async executeActiveCell(): Promise<void> {
|
||||
await this.quickAccess.runCommand('notebook.cell.execute');
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import { KeybindingsEditor } from './keybindings';
|
|||
import { Editors } from './editors';
|
||||
import { Code } from './code';
|
||||
import { Terminal } from './terminal';
|
||||
import { Notebook } from './notebook';
|
||||
|
||||
export interface Commands {
|
||||
runCommand(command: string): Promise<any>;
|
||||
|
@ -41,6 +42,7 @@ export class Workbench {
|
|||
readonly settingsEditor: SettingsEditor;
|
||||
readonly keybindingsEditor: KeybindingsEditor;
|
||||
readonly terminal: Terminal;
|
||||
readonly notebook: Notebook;
|
||||
|
||||
constructor(code: Code, userDataPath: string) {
|
||||
this.editors = new Editors(code);
|
||||
|
@ -58,5 +60,6 @@ export class Workbench {
|
|||
this.settingsEditor = new SettingsEditor(code, userDataPath, this.editors, this.editor, this.quickaccess);
|
||||
this.keybindingsEditor = new KeybindingsEditor(code);
|
||||
this.terminal = new Terminal(code, this.quickaccess);
|
||||
this.notebook = new Notebook(this.quickaccess, code);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import { Application } from '../../../../automation';
|
||||
|
||||
// function wait(ms: number): Promise<void> {
|
||||
// return new Promise(r => setTimeout(r, ms));
|
||||
// }
|
||||
|
||||
|
||||
export function setup() {
|
||||
describe.only('Notebooks', () => {
|
||||
after(async function () {
|
||||
const app = this.app as Application;
|
||||
cp.execSync('git checkout . --quiet', { cwd: app.workspacePathOrFolder });
|
||||
cp.execSync('git reset --hard origin/master --quiet', { cwd: app.workspacePathOrFolder });
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
const app = this.app as Application;
|
||||
await app.workbench.quickaccess.runCommand('workbench.action.files.save');
|
||||
await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor');
|
||||
});
|
||||
|
||||
it('inserts/edits code cell', async function () {
|
||||
const app = this.app as Application;
|
||||
await app.workbench.notebook.openNotebook();
|
||||
await app.workbench.notebook.focusNextCell();
|
||||
await app.workbench.notebook.insertNotebookCell('code');
|
||||
await app.workbench.notebook.waitForTypeInEditor('// some code');
|
||||
await app.workbench.notebook.stopEditingCell();
|
||||
});
|
||||
|
||||
it('inserts/edits markdown cell', async function () {
|
||||
const app = this.app as Application;
|
||||
await app.workbench.notebook.openNotebook();
|
||||
await app.workbench.notebook.focusNextCell();
|
||||
await app.workbench.notebook.insertNotebookCell('markdown');
|
||||
await app.workbench.notebook.waitForTypeInEditor('## hello2! ');
|
||||
await app.workbench.notebook.stopEditingCell();
|
||||
await app.workbench.notebook.waitForMarkdownContents('h2', 'hello2!');
|
||||
});
|
||||
|
||||
it('moves focus as it inserts/deletes a cell', async function () {
|
||||
const app = this.app as Application;
|
||||
await app.workbench.notebook.openNotebook();
|
||||
await app.workbench.notebook.insertNotebookCell('code');
|
||||
await app.workbench.notebook.waitForActiveCellEditorContents(' ');
|
||||
await app.workbench.notebook.stopEditingCell();
|
||||
await app.workbench.notebook.deleteActiveCell();
|
||||
await app.workbench.notebook.waitForMarkdownContents('p', 'Markdown Cell');
|
||||
});
|
||||
|
||||
it('moves focus in and out of output', async function () {
|
||||
const app = this.app as Application;
|
||||
await app.workbench.notebook.openNotebook();
|
||||
await app.workbench.notebook.executeActiveCell();
|
||||
await app.workbench.notebook.focusInCellOutput();
|
||||
await app.workbench.notebook.focusOutCellOutput();
|
||||
await app.workbench.notebook.waitForActiveCellEditorContents('code()');
|
||||
});
|
||||
});
|
||||
}
|
|
@ -25,6 +25,7 @@ import { setup as setupDataMigrationTests } from './areas/workbench/data-migrati
|
|||
import { setup as setupDataLossTests } from './areas/workbench/data-loss.test';
|
||||
import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test';
|
||||
import { setup as setupDataSearchTests } from './areas/search/search.test';
|
||||
import { setup as setupDataNotebookTests } from './areas/notebook/notebook.test';
|
||||
import { setup as setupDataLanguagesTests } from './areas/languages/languages.test';
|
||||
import { setup as setupDataEditorTests } from './areas/editor/editor.test';
|
||||
import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test';
|
||||
|
@ -315,6 +316,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
|
|||
if (!opts.web) { setupDataLossTests(); }
|
||||
if (!opts.web) { setupDataPreferencesTests(); }
|
||||
setupDataSearchTests();
|
||||
setupDataNotebookTests();
|
||||
setupDataLanguagesTests();
|
||||
setupDataEditorTests();
|
||||
setupDataStatusbarTests(!!opts.web);
|
||||
|
|
Loading…
Reference in New Issue