Tests for channels and notifications

Restructured the notifications and channels as services.
This commit is contained in:
Nick Chen 2017-07-03 14:12:10 -07:00 коммит произвёл Nick Chen
Родитель f205358162
Коммит 9a31f80fe6
25 изменённых файлов: 532 добавлений и 262 удалений

31
.vscode/settings.json поставляемый
Просмотреть файл

@ -1,14 +1,19 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
"typescript.tsdk": "./node_modules/typescript/lib",
"editor.tabSize": 2,
"editor.formatOnSave": true,
"prettier.singleQuote": true,
"rewrap.wrappingColumn": 80
}
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/.vscode-test": true
},
"search.exclude": {
"**/out": true
},
"typescript.tsdk": "./node_modules/typescript/lib",
"editor.tabSize": 2,
"editor.formatOnSave": true,
"prettier.singleQuote": true,
"rewrap.wrappingColumn": 80,
"typescript.check.tscVersion": false
}

Просмотреть файл

@ -35,7 +35,7 @@ export class CliCommandExecutor {
export class CommandExecution {
public readonly command: Command;
public readonly cancellationToken?: CancellationToken;
public readonly processExitSubject: Observable<number | string>;
public readonly processExitSubject: Observable<number | string | null>;
public readonly stdoutSubject: Observable<Buffer | string>;
public readonly stderrSubject: Observable<Buffer | string>;
@ -50,7 +50,10 @@ export class CommandExecution {
let timerSubscriber: Subscription | null;
// Process
this.processExitSubject = Observable.fromEvent(childProcess, 'exit');
this.processExitSubject = Observable.fromEvent(
childProcess,
'exit'
) as Observable<number | string | null>;
this.processExitSubject.subscribe(next => {
if (timerSubscriber) {
timerSubscriber.unsubscribe();

Просмотреть файл

@ -17,7 +17,7 @@ describe('CommandExecutor tests', () => {
const exitCode = await new Promise<string>((resolve, reject) => {
execution.processExitSubject.subscribe(
data => {
resolve(data.toString());
resolve(data !== null ? data.toString() : '');
},
err => {
reject(err);
@ -45,7 +45,7 @@ describe('CommandExecutor tests', () => {
const exitCode = await new Promise<string>((resolve, reject) => {
execution.processExitSubject.subscribe(
data => {
resolve(data.toString());
resolve(data !== null ? data.toString() : '');
},
err => {
reject(err);

Просмотреть файл

@ -24,7 +24,7 @@
"mocha": "3.2.0",
"nyc": "^11.0.2",
"typescript": "2.4.0",
"vscode": "1.1.0"
"vscode": "1.1.2"
},
"scripts": {
"vscode:prepublish": "tsc -p ./",

Просмотреть файл

@ -17,6 +17,7 @@
"categories": ["Other"],
"dependencies": {
"@salesforce/salesforcedx-utils-vscode": "0.1.0",
"rxjs": "^5.4.1",
"vscode-nls": "^2.0.2"
},
"devDependencies": {
@ -24,11 +25,13 @@
"@types/mocha": "2.2.38",
"@types/node": "^6.0.40",
"@types/path-exists": "^1.0.29",
"@types/sinon": "^2.3.2",
"chai": "^4.0.2",
"mocha": "3.2.0",
"nyc": "^11.0.2",
"sinon": "^2.3.6",
"typescript": "2.4.0",
"vscode": "1.1.0"
"vscode": "1.1.2"
},
"scripts": {
"vscode:prepublish": "tsc -p ./",

Просмотреть файл

@ -0,0 +1,49 @@
import * as vscode from 'vscode';
import { localize } from '../messages';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
export const DEFAULT_SFDX_CHANNEL = vscode.window.createOutputChannel(
localize('channel_name')
);
export class ChannelService {
private readonly channel: vscode.OutputChannel;
private static instance: ChannelService;
public constructor(channel?: vscode.OutputChannel) {
this.channel = channel || DEFAULT_SFDX_CHANNEL;
}
public static getInstance(channel?: vscode.OutputChannel) {
if (!ChannelService.instance) {
ChannelService.instance = new ChannelService(channel);
}
return ChannelService.instance;
}
public streamCommandOutput(execution: CommandExecution) {
this.channel.append(localize('channel_starting_message'));
this.channel.appendLine(execution.command.toString());
this.channel.appendLine('');
execution.stderrSubject.subscribe(data =>
this.channel.append(data.toString())
);
execution.stdoutSubject.subscribe(data =>
this.channel.append(data.toString())
);
execution.processExitSubject.subscribe(data => {
this.channel.append(execution.command.toString());
this.channel.append(' ');
if (data !== null) {
this.channel.appendLine(
localize('channel_end_with_exit_code', data.toString())
);
} else {
this.channel.appendLine(localize('channel_end'));
}
});
}
}

Просмотреть файл

@ -1,32 +1,4 @@
import * as vscode from 'vscode';
import { get } from '../messages';
import { ChannelService } from './channelService';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
export const DEFAULT_SFDX_CHANNEL = vscode.window.createOutputChannel(
get('channel_name')
);
export function streamCommandOutput(execution: CommandExecution) {
DEFAULT_SFDX_CHANNEL.append(get('channel_starting_message'));
DEFAULT_SFDX_CHANNEL.appendLine(execution.command.toString());
DEFAULT_SFDX_CHANNEL.appendLine('');
execution.stderrSubject.subscribe(data =>
DEFAULT_SFDX_CHANNEL.append(data.toString())
);
execution.stdoutSubject.subscribe(data =>
DEFAULT_SFDX_CHANNEL.append(data.toString())
);
execution.processExitSubject.subscribe(data => {
DEFAULT_SFDX_CHANNEL.append(execution.command.toString());
if (data) {
DEFAULT_SFDX_CHANNEL.appendLine(
get('channel_end_with_exit_code', data.toString())
);
} else {
DEFAULT_SFDX_CHANNEL.appendLine(get('channel_end'));
}
});
}
export const channelService = ChannelService.getInstance();
export { DEFAULT_SFDX_CHANNEL } from './channelService';

Просмотреть файл

@ -4,8 +4,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceApexTestRun(testClass?: string) {
@ -52,8 +52,11 @@ function runTestClass(testClass: string) {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}
@ -68,8 +71,11 @@ function runAllTests() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}
@ -85,7 +91,10 @@ function runTestSuite(testSuiteName: string) {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -3,8 +3,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceAuthWebLogin() {
@ -19,7 +19,10 @@ export function forceAuthWebLogin() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationTokenSource.token);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -4,8 +4,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceOrgCreate() {
@ -35,8 +35,11 @@ export function forceOrgCreate() {
{ cwd: rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}
});

Просмотреть файл

@ -3,8 +3,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceOrgOpen() {
@ -16,7 +16,10 @@ export function forceOrgOpen() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -3,8 +3,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceSourcePull() {
@ -16,7 +16,10 @@ export function forceSourcePull() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -3,8 +3,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceSourcePush() {
@ -16,7 +16,10 @@ export function forceSourcePush() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -3,8 +3,8 @@ import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { streamCommandOutput } from '../channels';
import { reportExecutionStatus } from '../notifications';
import { channelService } from '../channels';
import { notificationService } from '../notifications';
import { CancellableStatusBar } from '../statuses';
export function forceSourceStatus() {
@ -16,7 +16,10 @@ export function forceSourceStatus() {
{ cwd: vscode.workspace.rootPath }
).execute(cancellationToken);
streamCommandOutput(execution);
reportExecutionStatus(execution, cancellationToken);
channelService.streamCommandOutput(execution);
notificationService.reportCommandExecutionStatus(
execution,
cancellationToken
);
CancellableStatusBar.show(execution, cancellationTokenSource);
}

Просмотреть файл

@ -2,7 +2,7 @@ import util = require('util');
const locale = 'en_US';
export let get = function(label: string, ...args: any[]): string {
export let localize = function(label: string, ...args: any[]): string {
if (!messages[locale]) {
throw new Error("Locale '" + locale + "' doesn't exist");
}
@ -39,6 +39,11 @@ const messages: Messages = {
channel_name: 'SalesforceDX CLI',
channel_starting_message: 'Starting ',
channel_end_with_exit_code: 'ended with exit code %s',
channel_end: 'ended'
channel_end: 'ended',
notification_successful_execution_message: 'Successfully executed %s',
notification_canceled_execution_message: '%s canceled',
notification_unsuccessful_execution_message: 'Failed to execute %s',
notification_show_button_text: 'Show'
}
};

Просмотреть файл

@ -1,30 +1,3 @@
import * as vscode from 'vscode';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { DEFAULT_SFDX_CHANNEL } from '../channels';
import { NotificationService } from './notificationService';
export function reportExecutionStatus(
execution: CommandExecution,
cancellationToken?: vscode.CancellationToken
) {
execution.processExitSubject.subscribe(async data => {
if (data !== null && data !== 'undefined' && data.toString() === '0') {
const selection = await vscode.window.showInformationMessage(
`Successfully executed ${execution.command}`,
'Show'
);
if (selection && selection === 'Show') {
DEFAULT_SFDX_CHANNEL.show();
}
} else {
if (cancellationToken && cancellationToken.isCancellationRequested) {
vscode.window.showWarningMessage(`${execution.command} canceled`);
DEFAULT_SFDX_CHANNEL.show();
} else {
vscode.window.showErrorMessage(
`Failed to execute ${execution.command}`
);
DEFAULT_SFDX_CHANNEL.show();
}
}
});
}
export const notificationService = NotificationService.getInstance();

Просмотреть файл

@ -0,0 +1,69 @@
import * as vscode from 'vscode';
import { Observable } from 'rxjs/Observable';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import { DEFAULT_SFDX_CHANNEL } from '../channels';
import { localize } from '../messages';
export class NotificationService {
private readonly channel: vscode.OutputChannel;
private static instance: NotificationService;
public constructor(channel?: vscode.OutputChannel) {
this.channel = channel || DEFAULT_SFDX_CHANNEL;
}
public static getInstance(channel?: vscode.OutputChannel) {
if (!NotificationService.instance) {
NotificationService.instance = new NotificationService(channel);
}
return NotificationService.instance;
}
public reportCommandExecutionStatus(
execution: CommandExecution,
cancellationToken?: vscode.CancellationToken
) {
// https://stackoverflow.com/questions/38168581/observablet-is-not-a-class-derived-from-observablet
this.reportExecutionStatus(
execution.command.command.toString(),
(execution.processExitSubject as any) as Observable<
number | string | null
>,
cancellationToken
);
}
public reportExecutionStatus(
executionName: string,
observable: Observable<number | string | null>,
cancellationToken?: vscode.CancellationToken
) {
observable.subscribe(async data => {
if (data !== null && data.toString() === '0') {
const showButtonText = localize('notification_show_button_text');
const selection = await vscode.window.showInformationMessage(
localize('notification_successful_execution_message', executionName),
showButtonText
);
if (selection && selection === showButtonText) {
this.channel.show();
}
} else {
if (cancellationToken && cancellationToken.isCancellationRequested) {
vscode.window.showWarningMessage(
localize('notification_canceled_execution_message', executionName)
);
this.channel.show();
} else {
vscode.window.showErrorMessage(
localize(
'notification_unsuccessful_execution_message',
executionName
)
);
this.channel.show();
}
}
});
}
}

Просмотреть файл

@ -1,6 +1,101 @@
export {
CANCEL_EXECUTION_COMMAND,
PassiveStatusBar,
CancellableStatusBar,
cancelCommandExecution
} from './status';
import {
CancellationTokenSource,
StatusBarItem,
StatusBarAlignment,
window
} from 'vscode';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
export const CANCEL_EXECUTION_COMMAND = 'internal.cancel.execution.command';
const ALIGNMENT = StatusBarAlignment.Left;
const PRIORITY = -10;
const statusBarItem: StatusBarItem = window.createStatusBarItem(
ALIGNMENT,
PRIORITY
);
let statusTimer: NodeJS.Timer | null;
let cancellationTokenSource: CancellationTokenSource | null;
export class PassiveStatusBar {
public static show(execution: CommandExecution) {
return new PassiveStatusBar(execution);
}
private constructor(execution: CommandExecution) {
resetStatusBarItem();
statusBarItem.text = `$(clock) ${execution.command}`;
if (statusTimer) {
clearInterval(statusTimer);
}
statusTimer = setInterval(
() => (statusBarItem.text = statusBarItem.text + '.'),
1000
);
execution.processExitSubject.subscribe(data => {
if (statusTimer) {
clearInterval(statusTimer);
}
statusBarItem.hide();
});
statusBarItem.show();
}
}
export class CancellableStatusBar {
public static show(
execution: CommandExecution,
token: CancellationTokenSource
) {
return new CancellableStatusBar(execution, token);
}
private constructor(
execution: CommandExecution,
token: CancellationTokenSource
) {
resetStatusBarItem();
statusBarItem.text = `$(x) ${execution.command}`;
statusBarItem.tooltip = 'Click to cancel the command';
statusBarItem.command = CANCEL_EXECUTION_COMMAND;
cancellationTokenSource = token;
if (statusTimer) {
clearInterval(statusTimer);
}
statusTimer = setInterval(
() => (statusBarItem.text = statusBarItem.text + '.'),
1000
);
execution.processExitSubject.subscribe(data => {
if (statusTimer) {
clearInterval(statusTimer);
}
statusBarItem.hide();
});
statusBarItem.show();
}
}
function resetStatusBarItem() {
statusBarItem.text = '';
statusBarItem.tooltip = '';
statusBarItem.command = undefined;
}
export function cancelCommandExecution() {
if (cancellationTokenSource) {
cancellationTokenSource.cancel();
resetStatusBarItem();
if (statusTimer) {
clearInterval(statusTimer);
}
}
}

Просмотреть файл

@ -1,101 +0,0 @@
import {
CancellationTokenSource,
StatusBarItem,
StatusBarAlignment,
window
} from 'vscode';
import { CommandExecution } from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
export const CANCEL_EXECUTION_COMMAND = 'internal.cancel.execution.command';
const ALIGNMENT = StatusBarAlignment.Left;
const PRIORITY = -10;
const statusBarItem: StatusBarItem = window.createStatusBarItem(
ALIGNMENT,
PRIORITY
);
let statusTimer: NodeJS.Timer | null;
let cancellationTokenSource: CancellationTokenSource | null;
export class PassiveStatusBar {
public static show(execution: CommandExecution) {
return new PassiveStatusBar(execution);
}
private constructor(execution: CommandExecution) {
resetStatusBarItem();
statusBarItem.text = `$(clock) ${execution.command}`;
if (statusTimer) {
clearInterval(statusTimer);
}
statusTimer = setInterval(
() => (statusBarItem.text = statusBarItem.text + '.'),
1000
);
execution.processExitSubject.subscribe(data => {
if (statusTimer) {
clearInterval(statusTimer);
}
statusBarItem.hide();
});
statusBarItem.show();
}
}
export class CancellableStatusBar {
public static show(
execution: CommandExecution,
token: CancellationTokenSource
) {
return new CancellableStatusBar(execution, token);
}
private constructor(
execution: CommandExecution,
token: CancellationTokenSource
) {
resetStatusBarItem();
statusBarItem.text = `$(x) ${execution.command}`;
statusBarItem.tooltip = 'Click to cancel the command';
statusBarItem.command = CANCEL_EXECUTION_COMMAND;
cancellationTokenSource = token;
if (statusTimer) {
clearInterval(statusTimer);
}
statusTimer = setInterval(
() => (statusBarItem.text = statusBarItem.text + '.'),
1000
);
execution.processExitSubject.subscribe(data => {
if (statusTimer) {
clearInterval(statusTimer);
}
statusBarItem.hide();
});
statusBarItem.show();
}
}
function resetStatusBarItem() {
statusBarItem.text = '';
statusBarItem.tooltip = '';
statusBarItem.command = undefined;
}
export function cancelCommandExecution() {
if (cancellationTokenSource) {
cancellationTokenSource.cancel();
resetStatusBarItem();
if (statusTimer) {
clearInterval(statusTimer);
}
}
}

Просмотреть файл

@ -1,11 +1,90 @@
import { expect } from 'chai';
import { OutputChannel, ViewColumn } from 'vscode';
import { EOL } from 'os';
import {
CliCommandExecutor,
SfdxCommandBuilder
} from '@salesforce/salesforcedx-utils-vscode/out/src/cli';
import {
DEFAULT_SFDX_CHANNEL,
ChannelService
} from '../../src/channels/channelService';
import { DEFAULT_SFDX_CHANNEL } from '../../src/channels';
class MockChannel implements OutputChannel {
public readonly name = 'MockChannel';
public value = '';
describe('Channel tests', () => {
public append(value: string): void {
this.value += value;
}
public appendLine(value: string): void {
this.value += value;
this.value += EOL;
}
// These methods are not mocked or needed
// tslint:disable:no-empty
public clear(): void {}
public show(preserveFocus?: boolean | undefined): void;
public show(
column?: ViewColumn | undefined,
preserveFocus?: boolean | undefined
): void;
public show(column?: any, preserveFocus?: any) {}
public hide(): void {}
public dispose(): void {}
// tslint:enable:no-empty
}
describe('Channel', () => {
describe('Default SFDX channel', () => {
let mChannel: MockChannel;
let channelService: ChannelService;
beforeEach(() => {
mChannel = new MockChannel();
channelService = new ChannelService(mChannel);
});
it('Should have proper name', () => {
expect(DEFAULT_SFDX_CHANNEL.name).to.equal('SalesforceDX CLI');
});
it('Should pipe stdout on successful command execution', async () => {
const execution = new CliCommandExecutor(
new SfdxCommandBuilder().withArg('force').withArg('--help').build(),
{}
).execute();
channelService.streamCommandOutput(execution);
await new Promise<string>((resolve, reject) => {
execution.processExitSubject.subscribe(data => {
resolve();
});
});
expect(mChannel.value).to.contain(
'Usage: sfdx COMMAND [command-specific-options]'
);
expect(mChannel.value).to.contain('ended with exit code 0');
});
it('Should pipe stderr on unsuccessful command execution', async () => {
const execution = new CliCommandExecutor(
new SfdxCommandBuilder().withArg('force').withArg('--unknown').build(),
{}
).execute();
channelService.streamCommandOutput(execution);
await new Promise<string>((resolve, reject) => {
execution.processExitSubject.subscribe(data => {
resolve();
});
});
expect(mChannel.value).to.contain('Error: Unexpected flag --unknown');
expect(mChannel.value).to.contain('ended with exit code 2');
});
});
});

Просмотреть файл

@ -1,14 +0,0 @@
import { expect } from 'chai';
// Defines a Mocha test suite to group tests of similar kind together
describe('Extension Tests', () => {
// Defines a Mocha unit test
it('Something 1', () => {
expect([1, 2, 3].indexOf(5)).to.equal(-1);
expect([1, 2, 3].indexOf(1)).to.equal(0);
});
it('Something 1', () => {
expect([1, 2, 3].indexOf(5)).to.equal(-1);
expect([1, 2, 3].indexOf(1)).to.equal(0);
});
});

Просмотреть файл

@ -0,0 +1,108 @@
import { SinonStub, assert, stub } from 'sinon';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { CancellationTokenSource, window } from 'vscode';
import { NotificationService } from '../../src/notifications/notificationService';
import { DEFAULT_SFDX_CHANNEL } from '../../src/channels/channelService';
import { localize } from '../../src/messages';
const SHOW_BUTTON_TEXT = localize('notification_show_button_text');
// tslint:disable:no-empty
describe('Notifications', () => {
let mShowInformation: SinonStub;
let mShowWarningMessage: SinonStub;
let mShowErrorMessage: SinonStub;
let mShow: SinonStub;
beforeEach(() => {
mShow = stub(DEFAULT_SFDX_CHANNEL, 'show');
mShowInformation = stub(window, 'showInformationMessage').returns(
Promise.resolve(null)
);
mShowWarningMessage = stub(window, 'showWarningMessage').returns(
Promise.resolve(null)
);
mShowErrorMessage = stub(window, 'showErrorMessage').returns(
Promise.resolve(null)
);
});
afterEach(() => {
mShow.restore();
mShowInformation.restore();
mShowWarningMessage.restore();
mShowErrorMessage.restore();
});
it('Should notify successful execution', async () => {
const observable = new ReplaySubject<number | string | null>();
observable.next(0);
const notificationService = NotificationService.getInstance();
await notificationService.reportExecutionStatus('mock command', observable);
assert.notCalled(mShow);
assert.calledWith(
mShowInformation,
'Successfully executed mock command',
SHOW_BUTTON_TEXT
);
assert.notCalled(mShowWarningMessage);
assert.notCalled(mShowErrorMessage);
});
it('Should notify successful and show channel as requested', async () => {
// For this particular test, we need it to return a different value
mShowInformation.restore();
mShowInformation = stub(window, 'showInformationMessage').returns(
Promise.resolve(SHOW_BUTTON_TEXT)
);
const observable = new ReplaySubject<number | string | null>();
observable.next(0);
const notificationService = NotificationService.getInstance();
await notificationService.reportExecutionStatus('mock command', observable);
assert.calledOnce(mShow);
assert.calledWith(
mShowInformation,
'Successfully executed mock command',
SHOW_BUTTON_TEXT
);
assert.notCalled(mShowWarningMessage);
assert.notCalled(mShowErrorMessage);
});
it('Should notify cancellation', async () => {
const observable = new ReplaySubject<number | string | null>();
observable.next(null);
const cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.cancel();
const notificationService = NotificationService.getInstance();
await notificationService.reportExecutionStatus(
'mock command',
observable,
cancellationTokenSource.token
);
assert.calledOnce(mShow);
assert.notCalled(mShowInformation);
assert.calledWith(mShowWarningMessage, 'mock command canceled');
assert.notCalled(mShowErrorMessage);
});
it('Should notify unsuccessful execution', async () => {
const ABNORMAL_EXIT = -1;
const observable = new ReplaySubject<number | string | null>();
observable.next(ABNORMAL_EXIT);
const notificationService = NotificationService.getInstance();
await notificationService.reportExecutionStatus('mock command', observable);
assert.calledOnce(mShow);
assert.notCalled(mShowInformation);
assert.notCalled(mShowWarningMessage);
assert.calledWith(mShowErrorMessage, 'Failed to execute mock command');
});
});

Просмотреть файл

@ -1,23 +1,16 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": [
"dom",
"es6"
],
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
"noImplicitAny": true,
"rootDir": ".",
"outDir": "out",
"preserveConstEnums": true,
"strict": true
},
"exclude": [
"node_modules",
".vscode-test",
"out"
]
}
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": ["dom", "es6"],
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
"noImplicitAny": true,
"rootDir": ".",
"outDir": "out",
"preserveConstEnums": true,
"strict": true
},
"exclude": ["node_modules", ".vscode-test", "out"]
}

Просмотреть файл

@ -19,10 +19,12 @@
"@types/chai": "^4.0.0",
"@types/mocha": "2.2.38",
"@types/node": "^6.0.40",
"@types/sinon": "^2.3.2",
"chai": "^4.0.2",
"mocha": "3.2.0",
"typescript": "2.3.4",
"vscode": "1.1.0"
"sinon": "^2.3.6",
"typescript": "2.4.0",
"vscode": "1.1.2"
},
"scripts": {
"vscode:prepublish": "tsc -p ./",

Просмотреть файл

@ -19,10 +19,12 @@
"@types/chai": "^4.0.0",
"@types/mocha": "2.2.38",
"@types/node": "^6.0.40",
"@types/sinon": "^2.3.2",
"chai": "^4.0.2",
"mocha": "3.2.0",
"typescript": "2.3.4",
"vscode": "1.1.0"
"sinon": "^2.3.6",
"typescript": "2.4.0",
"vscode": "1.1.2"
},
"scripts": {
"vscode:prepublish": "tsc -p ./",