Use azdata-test modelview stubs (#13818)

This commit is contained in:
Charles Gagnon
2020-12-16 16:28:02 -08:00
committed by GitHub
parent 7b06194199
commit 7f38e87ef3
13 changed files with 152 additions and 386 deletions

View File

@@ -524,6 +524,7 @@
"@types/semver": "^7.3.1",
"@types/sinon": "^9.0.8",
"@types/yamljs": "0.2.30",
"azdata-test": "^1.0.0",
"mocha": "^5.2.0",
"mocha-junit-reporter": "^1.17.0",
"mocha-multi-reporters": "^1.1.7",

View File

@@ -3,11 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as events from 'events';
import * as cp from 'promisify-child-process';
import * as TypeMoq from 'typemoq';
import { Readable } from 'stream';
export class TestChildProcessPromise<T> implements cp.ChildProcessPromise {
@@ -106,117 +103,3 @@ export class TestChildProcessPromise<T> implements cp.ChildProcessPromise {
throw new Error('Method not implemented.');
}
}
export type ComponentAndMockComponentBuilder<C, B> = {
component: C,
mockBuilder: TypeMoq.IMock<B>
};
export function createModelViewMock(): {
modelBuilder: TypeMoq.IMock<azdata.ModelBuilder>,
modelView: TypeMoq.IMock<azdata.ModelView>
} {
const mockModelView = TypeMoq.Mock.ofType<azdata.ModelView>();
const mockModelBuilder = TypeMoq.Mock.ofType<azdata.ModelBuilder>();
const mockTextBuilder = createMockComponentBuilder<azdata.TextComponent>();
const mockGroupContainerBuilder = createMockContainerBuilder<azdata.GroupContainer>();
const mockFormContainerBuilder = createMockFormContainerBuilder();
mockModelBuilder.setup(b => b.text()).returns(() => mockTextBuilder.mockBuilder.object);
mockModelBuilder.setup(b => b.groupContainer()).returns(() => mockGroupContainerBuilder.mockBuilder.object);
mockModelBuilder.setup(b => b.formContainer()).returns(() => mockFormContainerBuilder.object);
mockModelView.setup(mv => mv.modelBuilder).returns(() => mockModelBuilder.object);
return {
modelBuilder: mockModelBuilder,
modelView: mockModelView
};
}
export function createMockComponentBuilder<C extends azdata.Component, B extends azdata.ComponentBuilder<C, any> = azdata.ComponentBuilder<C, any>>(component?: C): ComponentAndMockComponentBuilder<C, B> {
const mockComponentBuilder = TypeMoq.Mock.ofType<B>();
// Create a mocked dynamic component if we don't have a stub instance to use.
// Note that we don't use ofInstance here for the component because there's some limitations around properties that I was
// hitting preventing me from easily using TypeMoq. Passing in the stub instance lets users control the object being stubbed - which means
// they can use things like sinon to then override specific functions if desired.
if (!component) {
const mockComponent = TypeMoq.Mock.ofType<C>();
// Need to setup then for when a dynamic mocked object is resolved otherwise the test will hang : https://github.com/florinn/typemoq/issues/66
mockComponent.setup((x: any) => x.then).returns(() => undefined);
component = mockComponent.object;
}
// For now just have these be passthrough - can hook up additional functionality later if needed
mockComponentBuilder.setup(b => b.withProperties(TypeMoq.It.isAny())).returns(() => mockComponentBuilder.object);
mockComponentBuilder.setup(b => b.withValidation(TypeMoq.It.isAny())).returns(() => mockComponentBuilder.object);
mockComponentBuilder.setup(b => b.component()).returns(() => component! /*mockComponent.object*/);
return {
component: component!,
mockBuilder: mockComponentBuilder
};
}
export function createMockContainerBuilder<C extends azdata.Container<any, any>, B extends azdata.ContainerBuilder<C, any, any, any> = azdata.ContainerBuilder<C, any, any, any>>(): ComponentAndMockComponentBuilder<C, B> {
const mockContainerBuilder = createMockComponentBuilder<C, B>();
// For now just have these be passthrough - can hook up additional functionality later if needed
mockContainerBuilder.mockBuilder.setup(b => b.withItems(TypeMoq.It.isAny(), undefined)).returns(() => mockContainerBuilder.mockBuilder.object);
mockContainerBuilder.mockBuilder.setup(b => b.withLayout(TypeMoq.It.isAny())).returns(() => mockContainerBuilder.mockBuilder.object);
return mockContainerBuilder;
}
export function createMockFormContainerBuilder(): TypeMoq.IMock<azdata.FormBuilder> {
const mockContainerBuilder = createMockContainerBuilder<azdata.FormContainer, azdata.FormBuilder>();
mockContainerBuilder.mockBuilder.setup(b => b.withFormItems(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => mockContainerBuilder.mockBuilder.object);
return mockContainerBuilder.mockBuilder;
}
export class StubInputBox implements azdata.InputBoxComponent {
readonly id = 'input-box';
public enabled: boolean = false;
onTextChanged: vscode.Event<any> = undefined!;
onEnterKeyPressed: vscode.Event<string> = undefined!;
updateProperties(properties: { [key: string]: any }): Thenable<void> { throw new Error('Not implemented'); }
updateProperty(key: string, value: any): Thenable<void> { throw new Error('Not implemented'); }
updateCssStyles(cssStyles: { [key: string]: string }): Thenable<void> { throw new Error('Not implemented'); }
readonly onValidityChanged: vscode.Event<boolean> = undefined!;
readonly valid: boolean = true;
validate(): Thenable<boolean> { throw new Error('Not implemented'); }
focus(): Thenable<void> { return Promise.resolve(); }
}
export class StubCheckbox implements azdata.CheckBoxComponent {
private _onChanged = new vscode.EventEmitter<void>();
private _checked = false;
readonly id = 'stub-checkbox';
public enabled: boolean = false;
get checked(): boolean {
return this._checked;
}
set checked(value: boolean) {
this._checked = value;
this._onChanged.fire();
}
onChanged: vscode.Event<any> = this._onChanged.event;
updateProperties(properties: { [key: string]: any }): Thenable<void> { throw new Error('Not implemented'); }
updateProperty(key: string, value: any): Thenable<void> { throw new Error('Not implemented'); }
updateCssStyles(cssStyles: { [key: string]: string }): Thenable<void> { throw new Error('Not implemented'); }
readonly onValidityChanged: vscode.Event<boolean> = undefined!;
readonly valid: boolean = true;
validate(): Thenable<boolean> { throw new Error('Not implemented'); }
focus(): Thenable<void> { return Promise.resolve(); }
}

View File

@@ -11,23 +11,29 @@ import { initializeWizardPage, InputComponent, InputComponentInfo, Validator, Wi
import { FieldType } from '../../../interfaces';
import { IToolsService } from '../../../services/toolsService';
import { Deferred } from '../../utils';
import { createMockComponentBuilder, createModelViewMock as createMockModelView, StubCheckbox, StubInputBox } from '../../stubs';
import { createModelViewMock } from 'azdata-test/out/mocks/modelView/modelViewMock';
import { StubCheckbox } from 'azdata-test/out/stubs/modelView/stubCheckbox';
import { StubInputBox } from 'azdata-test/out/stubs/modelView/stubInputBox';
import * as should from 'should';
import * as sinon from 'sinon';
describe('WizardPage', () => {
let mockModelBuilder: TypeMoq.IMock<azdata.ModelBuilder>;
let stubCheckbox: StubCheckbox;
let stubInputBox: StubInputBox;
let testWizardPage: WizardPageContext;
let contentRegistered: Deferred<void>;
before(function () {
contentRegistered = new Deferred<void>();
const mockWizardPage = TypeMoq.Mock.ofType<azdata.window.WizardPage>();
const mockModelView = createMockModelView();
mockModelBuilder = mockModelView.modelBuilder;
stubCheckbox = new StubCheckbox();
stubInputBox = new StubInputBox();
const mockModelView = createModelViewMock({
checkBox: () => stubCheckbox,
inputBox: () => stubInputBox
});
mockWizardPage.setup(p => p.registerContent(TypeMoq.It.isAny())).callback(async (handler: (view: azdata.ModelView) => Thenable<void>) => {
await handler(mockModelView.modelView.object);
await handler(mockModelView.modelViewMock.object);
contentRegistered.resolve();
});
const mockWizard = TypeMoq.Mock.ofType<azdata.window.Wizard>();
@@ -75,9 +81,7 @@ describe('WizardPage', () => {
});
it('dynamic enablement', async function (): Promise<void> {
const stubCheckbox = new StubCheckbox();
const mockCheckboxBuilder = createMockComponentBuilder<azdata.CheckBoxComponent>(stubCheckbox);
const stubInputBox = new StubInputBox();
// Stub out the enabled property so we can hook into when that's set to ensure we wait for the state to be updated
// before continuing the test
let enabled = false;
@@ -88,11 +92,8 @@ describe('WizardPage', () => {
sinon.stub(stubInputBox, 'enabled').get(() => {
return enabled;
});
const mockInputBoxBuilder = createMockComponentBuilder<azdata.InputBoxComponent>(stubInputBox);
// Used to ensure that we wait until the enabled state is updated for our mocked components before continuing
let enabledDeferred = new Deferred();
mockModelBuilder.setup(b => b.checkBox()).returns(() => mockCheckboxBuilder.mockBuilder.object);
mockModelBuilder.setup(b => b.inputBox()).returns(() => mockInputBoxBuilder.mockBuilder.object);
initializeWizardPage(testWizardPage);
await contentRegistered.promise;

View File

@@ -252,6 +252,13 @@
resolved "https://registry.yarnpkg.com/@types/yamljs/-/yamljs-0.2.30.tgz#d034e1d329e46e8d0f737c9a8db97f68f81b5382"
integrity sha1-0DTh0ynkbo0Pc3yajbl/aPgbU4I=
agent-base@4, agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
dependencies:
es6-promisify "^5.0.0"
ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
@@ -278,6 +285,16 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
azdata-test@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/azdata-test/-/azdata-test-1.0.0.tgz#b8821a5a313e6919dac8b8ef56f22dc8592cad2c"
integrity sha512-/QZkHeVKc0HbJtx45nFXNQLTe3lY8la37Re+YfBIzybMIul3FmBszwIyq9/MPHMhrjkvf5xDkEF+CuSlI4KeIA==
dependencies:
http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.4"
rimraf "^2.6.3"
typemoq "^2.1.0"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -406,6 +423,18 @@ diff@^4.0.2:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
es6-promise@^4.0.3:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
dependencies:
es6-promise "^4.0.3"
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -487,6 +516,22 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
http-proxy-agent@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
dependencies:
agent-base "4"
debug "3.1.0"
https-proxy-agent@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
dependencies:
agent-base "^4.3.0"
debug "^3.1.0"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"