Dacpac extensions tests - for investigation (#11192)

* Adding some tests for dacpac extension to understand how coverage gets affected

* Added config page tests

* Fixing PR issues
This commit is contained in:
Udeesha Gautam
2020-07-11 13:45:50 -07:00
committed by GitHub
parent d2bdd2bace
commit ab9fceec70
6 changed files with 431 additions and 6 deletions

View File

@@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { DacFxDataModel } from '../wizard/api/models';
import { DeployConfigPage } from '../wizard/pages/deployConfigPage';
import { ExtractConfigPage } from '../wizard/pages/extractConfigPage';
import { DataTierApplicationWizard } from '../wizard/dataTierApplicationWizard';
export class TestDeployConfigPage extends DeployConfigPage {
constructor(instance: DataTierApplicationWizard, wizardPage: azdata.window.WizardPage, model: DacFxDataModel, view: azdata.ModelView) {
super(instance, wizardPage, model, view);
}
get Model(): DacFxDataModel {
return this.model;
}
SetDatabaseDropDown(): void {
this.databaseDropdown.value = { name: 'DummyDatabase', displayName: 'DummyDatabase' };
}
SetFileName(): void {
this.fileTextBox.value = 'DummyDacpac';
}
}
export class TestExtractConfigPage extends ExtractConfigPage {
constructor(instance: DataTierApplicationWizard, wizardPage: azdata.window.WizardPage, model: DacFxDataModel, view: azdata.ModelView) {
super(instance, wizardPage, model, view);
}
get Model(): DacFxDataModel {
return this.model;
}
}

View File

@@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as should from 'should';
import { DataTierApplicationWizard, PageName } from '../wizard/dataTierApplicationWizard';
import { DacFxDataModel } from '../wizard/api/models';
import { TestContext, createContext } from './testContext';
import { TestDeployConfigPage, TestExtractConfigPage } from './DacFxTestConfigPages';
let wizard: DataTierApplicationWizard;
let testContext: TestContext;
describe('Dacfx Wizard Pages', function (): void {
beforeEach(async function (): Promise<void> {
wizard = new DataTierApplicationWizard();
wizard.model = <DacFxDataModel>{};
wizard.model.server = undefined;
});
it('Should open and edit deploy config page correctly', async () => {
testContext = createContext();
wizard.setPages();
let deployConfigPage = new TestDeployConfigPage(wizard, wizard.pages.get(PageName.deployConfig).wizardPage, wizard.model, testContext.viewContext.view);
await deployConfigPage.start();
// Validate state after start
should.equal(deployConfigPage.Model.upgradeExisting, true);
should.equal(deployConfigPage.Model.filePath, undefined);
should.equal(deployConfigPage.Model.database, undefined);
// Adding file name in test box should update model path and db
deployConfigPage.SetFileName();
testContext.viewContext.onTextChanged.fire(undefined);
should.equal(deployConfigPage.Model.filePath, 'DummyDacpac');
should.equal(deployConfigPage.Model.database, 'DummyDacpac');
// Choosing database should update model db but not path
deployConfigPage.SetDatabaseDropDown();
testContext.viewContext.onValueChanged.fire(undefined);
should.equal(deployConfigPage.Model.filePath, 'DummyDacpac');
should.equal(deployConfigPage.Model.database, 'DummyDatabase');
// Changing radio buttons should affect model correctly
testContext.viewContext.newDatabaseRadioOnClick.fire(undefined);
should.equal(deployConfigPage.Model.upgradeExisting, false);
testContext.viewContext.updateExistingRadioOnClick.fire(undefined);
should.equal(deployConfigPage.Model.upgradeExisting, true);
});
it('Should open and edit extract config page correctly', async () => {
testContext = createContext();
wizard.setPages();
let extractConfigPage = new TestExtractConfigPage(wizard, wizard.pages.get(PageName.deployConfig).wizardPage, wizard.model, testContext.viewContext.view);
await extractConfigPage.start();
// Validate state after start
should.equal(extractConfigPage.Model.version, '1.0.0.0');
should.equal(extractConfigPage.Model.filePath, '');
should.equal(extractConfigPage.Model.database, undefined);
// Note : no need to test above function from deploy page since they are from common base class
// on text change event value in text box should overwrite model value
extractConfigPage.Model.version = 'dummy';
testContext.viewContext.onTextChanged.fire(undefined);
should.equal(extractConfigPage.Model.version, '1.0.0.0');
// Should autocorrect file name to correct extension type
extractConfigPage.Model.filePath = 'DummyPath';
await extractConfigPage.onPageLeave();
should.equal(extractConfigPage.Model.filePath, 'DummyPath.dacpac');
});
});

View File

@@ -5,14 +5,17 @@
import * as vscode from 'vscode';
import * as path from 'path';
import * as azdata from 'azdata';
import * as loc from '../localizedConstants';
export interface TestContext {
context: vscode.ExtensionContext;
viewContext: ViewTestContext;
}
export function createContext(): TestContext {
let extensionPath = path.join(__dirname, '..', '..');
let viewContext = createViewContext();
return {
context: {
subscriptions: [],
@@ -32,6 +35,235 @@ export function createContext(): TestContext {
extensionUri: vscode.Uri.parse(''),
environmentVariableCollection: undefined as any,
extensionMode: undefined as any
}
},
viewContext: viewContext
};
}
export interface ViewTestContext {
view: azdata.ModelView;
onClick: vscode.EventEmitter<any>;
onTextChanged: vscode.EventEmitter<any>;
onValueChanged: vscode.EventEmitter<any>;
newDatabaseRadioOnClick: vscode.EventEmitter<any>;
updateExistingRadioOnClick: vscode.EventEmitter<any>;
}
export function createViewContext(): ViewTestContext {
let onClick: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
let onTextChanged: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
let onValueChanged: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
let newDatabaseRadioOnClick: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
let updateExistingRadioOnClick: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
let componentBase: azdata.Component = {
id: '',
updateProperties: () => Promise.resolve(),
updateProperty: () => Promise.resolve(),
updateCssStyles: undefined!,
onValidityChanged: undefined!,
valid: true,
validate: undefined!,
focus: () => Promise.resolve()
};
let button: azdata.ButtonComponent = Object.assign({}, componentBase, {
onDidClick: onClick.event
});
let radioButton = () => {
let button: azdata.RadioButtonComponent = Object.assign({}, componentBase, {
name: '',
label: '',
checked: false,
onDidClick: onClick.event,
});
return button;
};
let checkbox: azdata.CheckBoxComponent = Object.assign({}, componentBase, {
checked: true,
onChanged: onClick.event
});
let container = {
clearItems: () => { },
addItems: () => { },
addItem: () => { },
removeItem: () => true,
insertItem: () => { },
items: [] as any[],
setLayout: () => { },
setItemLayout: () => { }
};
let form: azdata.FormContainer = Object.assign({}, componentBase, container, {
});
let flex: azdata.FlexContainer = Object.assign({}, componentBase, container, {
});
let div: azdata.DivContainer = Object.assign({}, componentBase, container, {
onDidClick: onClick.event
});
let buttonBuilder: azdata.ComponentBuilder<azdata.ButtonComponent> = {
component: () => button,
withProperties: () => buttonBuilder,
withValidation: () => buttonBuilder
};
let radioButtonBuilder = () => {
let button = radioButton();
let builder: azdata.ComponentBuilder<azdata.RadioButtonComponent> = {
component: () => button,
withProperties: (properties) => {
if ((properties as any).label === loc.newDatabase) {
button.label = loc.newDatabase;
button.onDidClick = newDatabaseRadioOnClick.event;
}
else if ((properties as any).label === loc.upgradeExistingDatabase) {
button.label = loc.upgradeExistingDatabase;
button.onDidClick = updateExistingRadioOnClick.event;
}
return builder;
},
withValidation: () => builder
};
return builder;
};
let checkBoxBuilder: azdata.ComponentBuilder<azdata.CheckBoxComponent> = {
component: () => checkbox,
withProperties: () => checkBoxBuilder,
withValidation: () => checkBoxBuilder
};
let inputBox: () => azdata.InputBoxComponent = () => Object.assign({}, componentBase, {
onTextChanged: onTextChanged.event,
onEnterKeyPressed: onClick.event,
value: ''
});
let dropdown: () => azdata.DropDownComponent = () => Object.assign({}, componentBase, {
onValueChanged: onValueChanged.event,
value: {
name: '',
displayName: ''
},
values: []
});
let table: () => azdata.TableComponent = () => Object.assign({}, componentBase, {
data: [] as any[][],
columns: [] as string[],
onRowSelected: onClick.event,
});
let loadingComponent: () => azdata.LoadingComponent = () => Object.assign({}, componentBase, {
loading: false,
component: undefined!
});
let tableBuilder: azdata.ComponentBuilder<azdata.TableComponent> = {
component: () => table(),
withProperties: () => tableBuilder,
withValidation: () => tableBuilder
};
let loadingBuilder: azdata.LoadingComponentBuilder = {
component: () => loadingComponent(),
withProperties: () => loadingBuilder,
withValidation: () => loadingBuilder,
withItem: () => loadingBuilder
};
let formBuilder: azdata.FormBuilder = Object.assign({}, {
component: () => form,
addFormItem: () => { },
insertFormItem: () => { },
removeFormItem: () => true,
addFormItems: () => { },
withFormItems: () => formBuilder,
withProperties: () => formBuilder,
withValidation: () => formBuilder,
withItems: () => formBuilder,
withLayout: () => formBuilder
});
let flexBuilder: azdata.FlexBuilder = Object.assign({}, {
component: () => flex,
withProperties: () => flexBuilder,
withValidation: () => flexBuilder,
withItems: () => flexBuilder,
withLayout: () => flexBuilder
});
let divBuilder: azdata.DivBuilder = Object.assign({}, {
component: () => div,
withProperties: () => divBuilder,
withValidation: () => divBuilder,
withItems: () => divBuilder,
withLayout: () => divBuilder
});
let inputBoxBuilder: azdata.ComponentBuilder<azdata.InputBoxComponent> = {
component: () => {
let r = inputBox();
return r;
},
withProperties: () => inputBoxBuilder,
withValidation: () => inputBoxBuilder
};
let dropdownBuilder: azdata.ComponentBuilder<azdata.DropDownComponent> = {
component: () => {
let r = dropdown();
return r;
},
withProperties: () => dropdownBuilder,
withValidation: () => dropdownBuilder
};
let view: azdata.ModelView = {
onClosed: undefined!,
connection: undefined!,
serverInfo: undefined!,
valid: true,
onValidityChanged: undefined!,
validate: undefined!,
initializeModel: () => { return Promise.resolve(); },
modelBuilder: {
radioCardGroup: undefined!,
navContainer: undefined!,
divContainer: () => divBuilder,
flexContainer: () => flexBuilder,
splitViewContainer: undefined!,
dom: undefined!,
card: () => undefined!,
inputBox: () => inputBoxBuilder,
checkBox: () => checkBoxBuilder!,
radioButton: () => radioButtonBuilder(),
webView: undefined!,
editor: undefined!,
diffeditor: undefined!,
text: () => inputBoxBuilder,
image: () => undefined!,
button: () => buttonBuilder,
dropDown: () => dropdownBuilder,
tree: undefined!,
listBox: undefined!,
table: () => tableBuilder,
declarativeTable: () => undefined!,
dashboardWidget: undefined!,
dashboardWebview: undefined!,
formContainer: () => formBuilder,
groupContainer: () => undefined!,
toolbarContainer: undefined!,
loadingComponent: () => loadingBuilder,
fileBrowserTree: undefined!,
hyperlink: () => undefined!,
tabbedPanel: undefined!,
separator: undefined!,
propertiesContainer: undefined!
}
};
return {
view: view,
onClick: onClick,
onTextChanged: onTextChanged,
onValueChanged: onValueChanged,
newDatabaseRadioOnClick: newDatabaseRadioOnClick,
updateExistingRadioOnClick: updateExistingRadioOnClick,
};
}

View File

@@ -6,10 +6,21 @@
import 'mocha';
import * as should from 'should';
import * as loc from '../localizedConstants';
import { DataTierApplicationWizard, Operation } from '../wizard/dataTierApplicationWizard';
import { DataTierApplicationWizard, Operation, PageName } from '../wizard/dataTierApplicationWizard';
import { DacFxDataModel } from '../wizard/api/models';
import { TestContext, createContext } from './testContext';
import { DeployConfigPage } from '../wizard/pages/deployConfigPage';
import { ExportConfigPage } from '../wizard/pages/exportConfigPage';
import { ExtractConfigPage } from '../wizard/pages/extractConfigPage';
import { ImportConfigPage } from '../wizard/pages/importConfigPage';
import { DacFxSummaryPage } from '../wizard/pages/dacFxSummaryPage';
import { SelectOperationPage } from '../wizard/pages/selectOperationpage';
import { DeployPlanPage } from '../wizard/pages/deployPlanPage';
import { BasePage } from '../wizard/api/basePage';
let wizard: DataTierApplicationWizard;
let testContext: TestContext;
describe('Dacfx wizard', function (): void {
beforeEach(async function (): Promise<void> {
wizard = new DataTierApplicationWizard();
@@ -24,6 +35,32 @@ describe('Dacfx wizard', function (): void {
should.notEqual(wizard.pages, undefined);
should.equal(wizard.pages.size, 7);
should.equal(wizard.wizard.pages.length, 4);
should.equal(wizard.pages.get(PageName.selectOperation).wizardPage.title, loc.selectOperationPageName);
});
it('Should initialize wizard with correct page order', async () => {
wizard.setPages();
wizard.selectedOperation = Operation.deploy;
should.equal(wizard.getPage(1), wizard.pages.get(PageName.deployConfig));
wizard.model.upgradeExisting = false;
should.equal(wizard.getPage(2), wizard.pages.get(PageName.summary));
wizard.model.upgradeExisting = true;
should.equal(wizard.getPage(2), wizard.pages.get(PageName.deployPlan));
should.equal(wizard.getPage(3), wizard.pages.get(PageName.summary));
wizard.selectedOperation = Operation.export;
should.equal(wizard.getPage(1), wizard.pages.get(PageName.exportConfig));
should.equal(wizard.getPage(2), wizard.pages.get(PageName.summary));
wizard.selectedOperation = Operation.extract;
should.equal(wizard.getPage(1), wizard.pages.get(PageName.extractConfig));
should.equal(wizard.getPage(2), wizard.pages.get(PageName.summary));
wizard.selectedOperation = Operation.import;
should.equal(wizard.getPage(1), wizard.pages.get(PageName.importConfig));
should.equal(wizard.getPage(2), wizard.pages.get(PageName.summary));
});
it('Should determine summary page correctly', async () => {
@@ -70,4 +107,42 @@ describe('Dacfx wizard', function (): void {
wizard.setDoneButton(Operation.export);
should.equal(wizard.selectedOperation, Operation.export);
});
it('Should start all pages - Set 1', async () => {
testContext = createContext();
wizard.setPages();
let selectOperationPage = new SelectOperationPage(wizard, wizard.pages.get(PageName.selectOperation).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(selectOperationPage);
let deployConfigPage = new DeployConfigPage(wizard, wizard.pages.get(PageName.deployConfig).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(deployConfigPage);
let deployPlanPage = new DeployPlanPage(wizard, wizard.pages.get(PageName.deployPlan).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(deployPlanPage);
let dacFxSummaryPage = new DacFxSummaryPage(wizard, wizard.pages.get(PageName.summary).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(dacFxSummaryPage);
});
it('Should start all pages - Set 2', async () => {
testContext = createContext();
wizard.setPages();
let exportConfigPage = new ExportConfigPage(wizard, wizard.pages.get(PageName.exportConfig).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(exportConfigPage);
let extractConfigPage = new ExtractConfigPage(wizard, wizard.pages.get(PageName.exportConfig).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(extractConfigPage);
let importConfigPage = new ImportConfigPage(wizard, wizard.pages.get(PageName.importConfig).wizardPage, wizard.model, testContext.viewContext.view);
await validateStartPage(importConfigPage);
});
async function validateStartPage(page: BasePage) : Promise<void> {
let result = false;
result = await page.start();
should.equal(result, true);
}
});

View File

@@ -306,7 +306,7 @@ export class DataTierApplicationWizard {
await service.generateDeployScript(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.script);
}
private getPage(idx: number): Page {
public getPage(idx: number): Page {
let page: Page;
if (idx === 1) {

View File

@@ -104,13 +104,13 @@ export class DeployConfigPage extends DacFxConfigPage {
private async createRadiobuttons(): Promise<azdata.FormComponent> {
let upgradeRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'updateExisting',
name: 'updateExistingOrCreateNew',
label: loc.upgradeExistingDatabase,
}).component();
let newRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'updateExisting',
name: 'updateExistingOrCreateNew',
label: loc.newDatabase,
}).component();