Add units tests for Notebook Actions (#8595)

This commit is contained in:
Cory Rivera
2019-12-09 15:37:40 -08:00
committed by GitHub
parent 4fc6f4a13e
commit 184d4bbe27
6 changed files with 327 additions and 117 deletions

View File

@@ -17,16 +17,14 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
import { noKernel } from 'sql/workbench/services/notebook/browser/sessionManager';
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
import { NotebookModel } from 'sql/workbench/contrib/notebook/browser/models/notebookModel';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ILogService } from 'vs/platform/log/common/log';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CellType } from 'sql/workbench/contrib/notebook/common/models/contracts';
import { NotebookComponent } from 'sql/workbench/contrib/notebook/browser/notebook.component';
import { getErrorMessage } from 'vs/base/common/errors';
import { INotebookModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { TreeUpdateUtils } from 'sql/workbench/contrib/objectExplorer/browser/treeUpdateUtils';
import { find, firstIndex } from 'vs/base/common/arrays';
import { INotebookEditor } from 'sql/workbench/services/notebook/browser/notebookService';
const msgLoading = localize('loading', "Loading kernels...");
const msgChanging = localize('changing', "Changing kernel...");
@@ -36,7 +34,6 @@ const msgLoadingContexts = localize('loadingContexts', "Loading contexts...");
const msgChangeConnection = localize('changeConnection', "Change Connection");
const msgSelectConnection = localize('selectConnection', "Select Connection");
const msgLocalHost = localize('localhost', "localhost");
const HIDE_ICON_CLASS = ' hideIcon';
// Action to add a cell to notebook based on cell type(code/markdown).
export class AddCellAction extends Action {
@@ -47,7 +44,7 @@ export class AddCellAction extends Action {
) {
super(id, label, cssClass);
}
public run(context: NotebookComponent): Promise<boolean> {
public run(context: INotebookEditor): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
try {
context.addCell(this.cellType);
@@ -59,7 +56,6 @@ export class AddCellAction extends Action {
}
}
// Action to clear outputs of all code cells.
export class ClearAllOutputsAction extends Action {
constructor(
@@ -67,7 +63,7 @@ export class ClearAllOutputsAction extends Action {
) {
super(id, label, cssClass);
}
public run(context: NotebookComponent): Promise<boolean> {
public run(context: INotebookEditor): Promise<boolean> {
return context.clearAllOutputs();
}
}
@@ -106,99 +102,6 @@ export abstract class ToggleableAction extends Action {
}
}
export interface IActionStateData {
className?: string;
label?: string;
tooltip?: string;
hideIcon?: boolean;
commandId?: string;
}
export class IMultiStateData<T> {
private _stateMap = new Map<T, IActionStateData>();
constructor(mappings: { key: T, value: IActionStateData }[], private _state: T, private _baseClass?: string) {
if (mappings) {
mappings.forEach(s => this._stateMap.set(s.key, s.value));
}
}
public set state(value: T) {
if (!this._stateMap.has(value)) {
throw new Error('State value must be in stateMap');
}
this._state = value;
}
public updateStateData(state: T, updater: (data: IActionStateData) => void): void {
let data = this._stateMap.get(state);
if (data) {
updater(data);
}
}
public get classes(): string {
let classVal = this.getStateValueOrDefault<string>((data) => data.className, '');
let classes = this._baseClass ? `${this._baseClass} ` : '';
classes += classVal;
if (this.getStateValueOrDefault<boolean>((data) => data.hideIcon, false)) {
classes += HIDE_ICON_CLASS;
}
return classes;
}
public get label(): string {
return this.getStateValueOrDefault<string>((data) => data.label, '');
}
public get tooltip(): string {
return this.getStateValueOrDefault<string>((data) => data.tooltip, '');
}
public get commandId(): string {
return this.getStateValueOrDefault<string>((data) => data.commandId, '');
}
private getStateValueOrDefault<U>(getter: (data: IActionStateData) => U, defaultVal?: U): U {
let data = this._stateMap.get(this._state);
return data ? getter(data) : defaultVal;
}
}
export abstract class MultiStateAction<T> extends Action {
constructor(
id: string,
protected states: IMultiStateData<T>,
private _keybindingService: IKeybindingService,
private readonly logService: ILogService) {
super(id, '');
this.updateLabelAndIcon();
}
private updateLabelAndIcon() {
let keyboardShortcut: string;
try {
// If a keyboard shortcut exists for the command id passed in, append that to the label
if (this.states.commandId !== '') {
let binding = this._keybindingService.lookupKeybinding(this.states.commandId);
keyboardShortcut = binding ? binding.getLabel() : undefined;
}
} catch (error) {
this.logService.error(error);
}
this.label = this.states.label;
this.tooltip = keyboardShortcut ? this.states.tooltip + ` (${keyboardShortcut})` : this.states.tooltip;
this.class = this.states.classes;
}
protected updateState(state: T): void {
this.states.state = state;
this.updateLabelAndIcon();
}
}
export class TrustedAction extends ToggleableAction {
// Constants
private static readonly trustedLabel = localize('trustLabel', "Trusted");
@@ -231,7 +134,7 @@ export class TrustedAction extends ToggleableAction {
this.toggle(value);
}
public run(context: NotebookComponent): Promise<boolean> {
public run(context: INotebookEditor): Promise<boolean> {
let self = this;
return new Promise<boolean>((resolve, reject) => {
try {
@@ -259,7 +162,7 @@ export class RunAllCellsAction extends Action {
) {
super(id, label, cssClass);
}
public async run(context: NotebookComponent): Promise<boolean> {
public async run(context: INotebookEditor): Promise<boolean> {
try {
await context.runAllCells();
return true;
@@ -291,15 +194,15 @@ export class CollapseCellsAction extends ToggleableAction {
public get isCollapsed(): boolean {
return this.state.isOn;
}
public set isCollapsed(value: boolean) {
private setCollapsed(value: boolean) {
this.toggle(value);
}
public run(context: NotebookComponent): Promise<boolean> {
public run(context: INotebookEditor): Promise<boolean> {
let self = this;
return new Promise<boolean>((resolve, reject) => {
try {
self.isCollapsed = !self.isCollapsed;
self.setCollapsed(!self.isCollapsed);
context.cells.forEach(cell => {
cell.isCollapsed = self.isCollapsed;
});
@@ -421,7 +324,7 @@ export class AttachToDropdown extends SelectBox {
}
// Load "Attach To" dropdown with the values corresponding to Kernel dropdown
public async loadAttachToDropdown(model: INotebookModel, currentKernel: string, showSelectConnection?: boolean): Promise<void> {
public loadAttachToDropdown(model: INotebookModel, currentKernel: string, showSelectConnection?: boolean): void {
let connProviderIds = this.model.getApplicableConnectionProviderIds(currentKernel);
if ((connProviderIds && connProviderIds.length === 0) || currentKernel === noKernel) {
this.setOptions([msgLocalHost]);
@@ -438,9 +341,9 @@ export class AttachToDropdown extends SelectBox {
public doChangeContext(connection?: ConnectionProfile, hideErrorMessage?: boolean): void {
if (this.value === msgChangeConnection || this.value === msgSelectConnection) {
this.openConnectionDialog();
this.openConnectionDialog().catch(err => this._notificationService.error(getErrorMessage(err)));
} else {
this.model.changeContext(this.value, connection, hideErrorMessage).then(ok => undefined, err => this._notificationService.error(getErrorMessage(err)));
this.model.changeContext(this.value, connection, hideErrorMessage).catch(err => this._notificationService.error(getErrorMessage(err)));
}
}
@@ -506,7 +409,7 @@ export class NewNotebookAction extends Action {
public static readonly ID = 'notebook.command.new';
public static readonly LABEL = localize('newNotebookAction', "New Notebook");
private static readonly INTERNAL_NEW_NOTEBOOK_CMD_ID = '_notebook.command.new';
public static readonly INTERNAL_NEW_NOTEBOOK_CMD_ID = '_notebook.command.new';
constructor(
id: string,
label: string,
@@ -527,5 +430,4 @@ export class NewNotebookAction extends Action {
}
return this.commandService.executeCommand(NewNotebookAction.INTERNAL_NEW_NOTEBOOK_CMD_ID, { connectionProfile: connProfile });
}
}