First set of test for SchemaCompareDialog (#11444)

* Add a test for SchemaCompareDialog and update the product code with deferred promise

* Update test to verify that button clicked worked

* Addressed comments

* Updated verifyButtonsState to use should instead of console.log
This commit is contained in:
Sakshi Sharma
2020-08-04 01:10:46 -07:00
committed by GitHub
parent eeb1f7cf3e
commit 381a32929f
6 changed files with 262 additions and 148 deletions

View File

@@ -7,22 +7,16 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as loc from '../localizedConstants'; import * as loc from '../localizedConstants';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow'; import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { promises as fs } from 'fs';
import { TelemetryReporter, TelemetryViews } from '../telemetry'; import { TelemetryReporter, TelemetryViews } from '../telemetry';
import { getEndpointName, getRootPath } from '../utils'; import { getEndpointName, getRootPath, exists } from '../utils';
import * as mssql from '../../../mssql'; import * as mssql from '../../../mssql';
const titleFontSize: number = 13; const titleFontSize: number = 13;
async function exists(path: string): Promise<boolean> { interface Deferred<T> {
try { resolve: (result: T | Promise<T>) => void;
await fs.access(path); reject: (reason: any) => void;
return true;
} catch (e) {
return false;
}
} }
export class SchemaCompareDialog { export class SchemaCompareDialog {
public dialog: azdata.window.Dialog; public dialog: azdata.window.Dialog;
public dialogName: string; public dialogName: string;
@@ -53,15 +47,17 @@ export class SchemaCompareDialog {
private targetDbEditable: string; private targetDbEditable: string;
private previousSource: mssql.SchemaCompareEndpointInfo; private previousSource: mssql.SchemaCompareEndpointInfo;
private previousTarget: mssql.SchemaCompareEndpointInfo; private previousTarget: mssql.SchemaCompareEndpointInfo;
private initDialogComplete: Deferred<void>;
private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
constructor(private schemaCompareResult: SchemaCompareMainWindow) { constructor(private schemaCompareMainWindow: SchemaCompareMainWindow, private view?: azdata.ModelView) {
this.previousSource = schemaCompareResult.sourceEndpointInfo; this.previousSource = schemaCompareMainWindow.sourceEndpointInfo;
this.previousTarget = schemaCompareResult.targetEndpointInfo; this.previousTarget = schemaCompareMainWindow.targetEndpointInfo;
} }
protected initializeDialog(): void { protected async initializeDialog(): Promise<void> {
this.schemaCompareTab = azdata.window.createTab(loc.SchemaCompareLabel); this.schemaCompareTab = azdata.window.createTab(loc.SchemaCompareLabel);
this.initializeSchemaCompareTab(); await this.initializeSchemaCompareTab();
this.dialog.content = [this.schemaCompareTab]; this.dialog.content = [this.schemaCompareTab];
} }
@@ -73,7 +69,7 @@ export class SchemaCompareDialog {
} }
this.dialog = azdata.window.createModelViewDialog(loc.SchemaCompareLabel); this.dialog = azdata.window.createModelViewDialog(loc.SchemaCompareLabel);
this.initializeDialog(); await this.initializeDialog();
this.dialog.okButton.label = loc.OkButtonText; this.dialog.okButton.label = loc.OkButtonText;
this.dialog.okButton.enabled = false; this.dialog.okButton.enabled = false;
@@ -83,11 +79,12 @@ export class SchemaCompareDialog {
this.dialog.cancelButton.onClick(async () => await this.cancel()); this.dialog.cancelButton.onClick(async () => await this.cancel());
azdata.window.openDialog(this.dialog); azdata.window.openDialog(this.dialog);
await this.initDialogPromise;
} }
protected async execute(): Promise<void> { public async execute(): Promise<void> {
if (this.sourceIsDacpac) { if (this.sourceIsDacpac) {
this.schemaCompareResult.sourceEndpointInfo = { this.schemaCompareMainWindow.sourceEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Dacpac, endpointType: mssql.SchemaCompareEndpointType.Dacpac,
serverDisplayName: '', serverDisplayName: '',
serverName: '', serverName: '',
@@ -99,7 +96,7 @@ export class SchemaCompareDialog {
} else { } else {
let ownerUri = await azdata.connection.getUriForConnection((this.sourceServerDropdown.value as ConnectionDropdownValue).connection.connectionId); let ownerUri = await azdata.connection.getUriForConnection((this.sourceServerDropdown.value as ConnectionDropdownValue).connection.connectionId);
this.schemaCompareResult.sourceEndpointInfo = { this.schemaCompareMainWindow.sourceEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Database, endpointType: mssql.SchemaCompareEndpointType.Database,
serverDisplayName: (this.sourceServerDropdown.value as ConnectionDropdownValue).displayName, serverDisplayName: (this.sourceServerDropdown.value as ConnectionDropdownValue).displayName,
serverName: (this.sourceServerDropdown.value as ConnectionDropdownValue).name, serverName: (this.sourceServerDropdown.value as ConnectionDropdownValue).name,
@@ -111,7 +108,7 @@ export class SchemaCompareDialog {
} }
if (this.targetIsDacpac) { if (this.targetIsDacpac) {
this.schemaCompareResult.targetEndpointInfo = { this.schemaCompareMainWindow.targetEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Dacpac, endpointType: mssql.SchemaCompareEndpointType.Dacpac,
serverDisplayName: '', serverDisplayName: '',
serverName: '', serverName: '',
@@ -123,7 +120,7 @@ export class SchemaCompareDialog {
} else { } else {
let ownerUri = await azdata.connection.getUriForConnection((this.targetServerDropdown.value as ConnectionDropdownValue).connection.connectionId); let ownerUri = await azdata.connection.getUriForConnection((this.targetServerDropdown.value as ConnectionDropdownValue).connection.connectionId);
this.schemaCompareResult.targetEndpointInfo = { this.schemaCompareMainWindow.targetEndpointInfo = {
endpointType: mssql.SchemaCompareEndpointType.Database, endpointType: mssql.SchemaCompareEndpointType.Database,
serverDisplayName: (this.targetServerDropdown.value as ConnectionDropdownValue).displayName, serverDisplayName: (this.targetServerDropdown.value as ConnectionDropdownValue).displayName,
serverName: (this.targetServerDropdown.value as ConnectionDropdownValue).name, serverName: (this.targetServerDropdown.value as ConnectionDropdownValue).name,
@@ -141,15 +138,15 @@ export class SchemaCompareDialog {
}).send(); }).send();
// update source and target values that are displayed // update source and target values that are displayed
this.schemaCompareResult.updateSourceAndTarget(); this.schemaCompareMainWindow.updateSourceAndTarget();
const sourceEndpointChanged = this.endpointChanged(this.previousSource, this.schemaCompareResult.sourceEndpointInfo); const sourceEndpointChanged = this.endpointChanged(this.previousSource, this.schemaCompareMainWindow.sourceEndpointInfo);
const targetEndpointChanged = this.endpointChanged(this.previousTarget, this.schemaCompareResult.targetEndpointInfo); const targetEndpointChanged = this.endpointChanged(this.previousTarget, this.schemaCompareMainWindow.targetEndpointInfo);
// show recompare message if it isn't the initial population of source and target // show recompare message if it isn't the initial population of source and target
if (this.previousSource && this.previousTarget if (this.previousSource && this.previousTarget
&& (sourceEndpointChanged || targetEndpointChanged)) { && (sourceEndpointChanged || targetEndpointChanged)) {
this.schemaCompareResult.setButtonsForRecompare(); this.schemaCompareMainWindow.setButtonsForRecompare();
let message = loc.differentSourceMessage; let message = loc.differentSourceMessage;
if (sourceEndpointChanged && targetEndpointChanged) { if (sourceEndpointChanged && targetEndpointChanged) {
@@ -160,7 +157,7 @@ export class SchemaCompareDialog {
vscode.window.showWarningMessage(message, loc.YesButtonText, loc.NoButtonText).then((result) => { vscode.window.showWarningMessage(message, loc.YesButtonText, loc.NoButtonText).then((result) => {
if (result === loc.YesButtonText) { if (result === loc.YesButtonText) {
this.schemaCompareResult.startCompare(); this.schemaCompareMainWindow.startCompare();
} }
}); });
} }
@@ -177,10 +174,14 @@ export class SchemaCompareDialog {
protected async cancel(): Promise<void> { protected async cancel(): Promise<void> {
} }
private initializeSchemaCompareTab(): void { private async initializeSchemaCompareTab(): Promise<void> {
this.schemaCompareTab.registerContent(async view => { this.schemaCompareTab.registerContent(async view => {
this.sourceTextBox = view.modelBuilder.inputBox().withProperties({ if (isNullOrUndefined(this.view)) {
value: this.schemaCompareResult.sourceEndpointInfo ? this.schemaCompareResult.sourceEndpointInfo.packageFilePath : '', this.view = view;
}
this.sourceTextBox = this.view.modelBuilder.inputBox().withProperties({
value: this.schemaCompareMainWindow.sourceEndpointInfo ? this.schemaCompareMainWindow.sourceEndpointInfo.packageFilePath : '',
width: 275, width: 275,
ariaLabel: loc.sourceFile ariaLabel: loc.sourceFile
}).component(); }).component();
@@ -189,8 +190,8 @@ export class SchemaCompareDialog {
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
this.targetTextBox = view.modelBuilder.inputBox().withProperties({ this.targetTextBox = this.view.modelBuilder.inputBox().withProperties({
value: this.schemaCompareResult.targetEndpointInfo ? this.schemaCompareResult.targetEndpointInfo.packageFilePath : '', value: this.schemaCompareMainWindow.targetEndpointInfo ? this.schemaCompareMainWindow.targetEndpointInfo.packageFilePath : '',
width: 275, width: 275,
ariaLabel: loc.targetFile ariaLabel: loc.targetFile
}).component(); }).component();
@@ -199,36 +200,36 @@ export class SchemaCompareDialog {
this.dialog.okButton.enabled = await this.shouldEnableOkayButton(); this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
this.sourceServerComponent = await this.createSourceServerDropdown(view); this.sourceServerComponent = await this.createSourceServerDropdown();
await this.populateServerDropdown(false); await this.populateServerDropdown(false);
this.sourceDatabaseComponent = await this.createSourceDatabaseDropdown(view); this.sourceDatabaseComponent = await this.createSourceDatabaseDropdown();
if ((this.sourceServerDropdown.value as ConnectionDropdownValue)) { if ((this.sourceServerDropdown.value as ConnectionDropdownValue)) {
await this.populateDatabaseDropdown((this.sourceServerDropdown.value as ConnectionDropdownValue).connection, false); await this.populateDatabaseDropdown((this.sourceServerDropdown.value as ConnectionDropdownValue).connection, false);
} }
this.targetServerComponent = await this.createTargetServerDropdown(view); this.targetServerComponent = await this.createTargetServerDropdown();
await this.populateServerDropdown(true); await this.populateServerDropdown(true);
this.targetDatabaseComponent = await this.createTargetDatabaseDropdown(view); this.targetDatabaseComponent = await this.createTargetDatabaseDropdown();
if ((this.targetServerDropdown.value as ConnectionDropdownValue)) { if ((this.targetServerDropdown.value as ConnectionDropdownValue)) {
await this.populateDatabaseDropdown((this.targetServerDropdown.value as ConnectionDropdownValue).connection, true); await this.populateDatabaseDropdown((this.targetServerDropdown.value as ConnectionDropdownValue).connection, true);
} }
this.sourceDacpacComponent = await this.createFileBrowser(view, false, this.schemaCompareResult.sourceEndpointInfo); this.sourceDacpacComponent = await this.createFileBrowser(false, this.schemaCompareMainWindow.sourceEndpointInfo);
this.targetDacpacComponent = await this.createFileBrowser(view, true, this.schemaCompareResult.targetEndpointInfo); this.targetDacpacComponent = await this.createFileBrowser(true, this.schemaCompareMainWindow.targetEndpointInfo);
let sourceRadioButtons = await this.createSourceRadiobuttons(view); let sourceRadioButtons = await this.createSourceRadiobuttons();
let targetRadioButtons = await this.createTargetRadiobuttons(view); let targetRadioButtons = await this.createTargetRadiobuttons();
this.sourceNoActiveConnectionsText = await this.createNoActiveConnectionsText(view); this.sourceNoActiveConnectionsText = await this.createNoActiveConnectionsText();
this.targetNoActiveConnectionsText = await this.createNoActiveConnectionsText(view); this.targetNoActiveConnectionsText = await this.createNoActiveConnectionsText();
let sourceComponents = []; let sourceComponents = [];
let targetComponents = []; let targetComponents = [];
// start source and target with either dacpac or database selection based on what the previous value was // start source and target with either dacpac or database selection based on what the previous value was
if (this.schemaCompareResult.sourceEndpointInfo && this.schemaCompareResult.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
sourceComponents = [ sourceComponents = [
sourceRadioButtons, sourceRadioButtons,
this.sourceServerComponent, this.sourceServerComponent,
@@ -241,7 +242,7 @@ export class SchemaCompareDialog {
]; ];
} }
if (this.schemaCompareResult.targetEndpointInfo && this.schemaCompareResult.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
targetComponents = [ targetComponents = [
targetRadioButtons, targetRadioButtons,
this.targetServerComponent, this.targetServerComponent,
@@ -254,7 +255,7 @@ export class SchemaCompareDialog {
]; ];
} }
this.formBuilder = <azdata.FormBuilder>view.modelBuilder.formContainer() this.formBuilder = <azdata.FormBuilder>this.view.modelBuilder.formContainer()
.withFormItems([ .withFormItems([
{ {
title: loc.SourceTitle, title: loc.SourceTitle,
@@ -273,25 +274,26 @@ export class SchemaCompareDialog {
}); });
let formModel = this.formBuilder.component(); let formModel = this.formBuilder.component();
await view.initializeModel(formModel); await this.view.initializeModel(formModel);
if (this.sourceIsDacpac) { if (this.sourceIsDacpac) {
await this.sourceDacpacRadioButton.focus(); await this.sourceDacpacRadioButton.focus();
} else { } else {
await this.sourceDatabaseRadioButton.focus(); await this.sourceDatabaseRadioButton.focus();
} }
this.initDialogComplete.resolve();
}); });
} }
private createFileBrowser(view: azdata.ModelView, isTarget: boolean, endpoint: mssql.SchemaCompareEndpointInfo): azdata.FormComponent { private createFileBrowser(isTarget: boolean, endpoint: mssql.SchemaCompareEndpointInfo): azdata.FormComponent {
let currentTextbox = isTarget ? this.targetTextBox : this.sourceTextBox; let currentTextbox = isTarget ? this.targetTextBox : this.sourceTextBox;
if (isTarget) { if (isTarget) {
this.targetFileButton = view.modelBuilder.button().withProperties({ this.targetFileButton = this.view.modelBuilder.button().withProperties({
label: '•••', label: '•••',
title: loc.selectTargetFile, title: loc.selectTargetFile,
ariaLabel: loc.selectTargetFile ariaLabel: loc.selectTargetFile
}).component(); }).component();
} else { } else {
this.sourceFileButton = view.modelBuilder.button().withProperties({ this.sourceFileButton = this.view.modelBuilder.button().withProperties({
label: '•••', label: '•••',
title: loc.selectSourceFile, title: loc.selectSourceFile,
ariaLabel: loc.selectSourceFile ariaLabel: loc.selectSourceFile
@@ -333,14 +335,14 @@ export class SchemaCompareDialog {
}; };
} }
private createSourceRadiobuttons(view: azdata.ModelView): azdata.FormComponent { private createSourceRadiobuttons(): azdata.FormComponent {
this.sourceDacpacRadioButton = view.modelBuilder.radioButton() this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'source', name: 'source',
label: loc.DacpacRadioButtonLabel label: loc.DacpacRadioButtonLabel
}).component(); }).component();
this.sourceDatabaseRadioButton = view.modelBuilder.radioButton() this.sourceDatabaseRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'source', name: 'source',
label: loc.DatabaseRadioButtonLabel label: loc.DatabaseRadioButtonLabel
@@ -370,14 +372,14 @@ export class SchemaCompareDialog {
}); });
// if source is currently a db, show it in the server and db dropdowns // if source is currently a db, show it in the server and db dropdowns
if (this.schemaCompareResult.sourceEndpointInfo && this.schemaCompareResult.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.schemaCompareMainWindow.sourceEndpointInfo && this.schemaCompareMainWindow.sourceEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
this.sourceDatabaseRadioButton.checked = true; this.sourceDatabaseRadioButton.checked = true;
this.sourceIsDacpac = false; this.sourceIsDacpac = false;
} else { } else {
this.sourceDacpacRadioButton.checked = true; this.sourceDacpacRadioButton.checked = true;
this.sourceIsDacpac = true; this.sourceIsDacpac = true;
} }
let flexRadioButtonsModel = view.modelBuilder.flexContainer() let flexRadioButtonsModel = this.view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' }) .withLayout({ flexFlow: 'column' })
.withItems([this.sourceDacpacRadioButton, this.sourceDatabaseRadioButton]) .withItems([this.sourceDacpacRadioButton, this.sourceDatabaseRadioButton])
.withProperties({ ariaRole: 'radiogroup' }) .withProperties({ ariaRole: 'radiogroup' })
@@ -389,14 +391,14 @@ export class SchemaCompareDialog {
}; };
} }
private createTargetRadiobuttons(view: azdata.ModelView): azdata.FormComponent { private createTargetRadiobuttons(): azdata.FormComponent {
let dacpacRadioButton = view.modelBuilder.radioButton() let dacpacRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'target', name: 'target',
label: loc.DacpacRadioButtonLabel label: loc.DacpacRadioButtonLabel
}).component(); }).component();
let databaseRadioButton = view.modelBuilder.radioButton() let databaseRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'target', name: 'target',
label: loc.DatabaseRadioButtonLabel label: loc.DatabaseRadioButtonLabel
@@ -426,7 +428,7 @@ export class SchemaCompareDialog {
}); });
// if target is currently a db, show it in the server and db dropdowns // if target is currently a db, show it in the server and db dropdowns
if (this.schemaCompareResult.targetEndpointInfo && this.schemaCompareResult.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) { if (this.schemaCompareMainWindow.targetEndpointInfo && this.schemaCompareMainWindow.targetEndpointInfo.endpointType === mssql.SchemaCompareEndpointType.Database) {
databaseRadioButton.checked = true; databaseRadioButton.checked = true;
this.targetIsDacpac = false; this.targetIsDacpac = false;
} else { } else {
@@ -434,7 +436,7 @@ export class SchemaCompareDialog {
this.targetIsDacpac = true; this.targetIsDacpac = true;
} }
let flexRadioButtonsModel = view.modelBuilder.flexContainer() let flexRadioButtonsModel = this.view.modelBuilder.flexContainer()
.withLayout({ flexFlow: 'column' }) .withLayout({ flexFlow: 'column' })
.withItems([dacpacRadioButton, databaseRadioButton] .withItems([dacpacRadioButton, databaseRadioButton]
) )
@@ -461,8 +463,8 @@ export class SchemaCompareDialog {
return !isNullOrUndefined(filename) && await exists(filename) && (filename.toLocaleLowerCase().endsWith('.dacpac')); return !isNullOrUndefined(filename) && await exists(filename) && (filename.toLocaleLowerCase().endsWith('.dacpac'));
} }
protected createSourceServerDropdown(view: azdata.ModelView): azdata.FormComponent { protected createSourceServerDropdown(): azdata.FormComponent {
this.sourceServerDropdown = view.modelBuilder.dropDown().withProperties( this.sourceServerDropdown = this.view.modelBuilder.dropDown().withProperties(
{ {
editable: true, editable: true,
fireOnTextChange: true, fireOnTextChange: true,
@@ -487,8 +489,8 @@ export class SchemaCompareDialog {
}; };
} }
protected createTargetServerDropdown(view: azdata.ModelView): azdata.FormComponent { protected createTargetServerDropdown(): azdata.FormComponent {
this.targetServerDropdown = view.modelBuilder.dropDown().withProperties( this.targetServerDropdown = this.view.modelBuilder.dropDown().withProperties(
{ {
editable: true, editable: true,
fireOnTextChange: true, fireOnTextChange: true,
@@ -532,7 +534,7 @@ export class SchemaCompareDialog {
return undefined; return undefined;
} }
let endpointInfo = isTarget ? this.schemaCompareResult.targetEndpointInfo : this.schemaCompareResult.sourceEndpointInfo; let endpointInfo = isTarget ? this.schemaCompareMainWindow.targetEndpointInfo : this.schemaCompareMainWindow.sourceEndpointInfo;
// reverse list so that most recent connections are first // reverse list so that most recent connections are first
cons.reverse(); cons.reverse();
@@ -585,8 +587,8 @@ export class SchemaCompareDialog {
return values; return values;
} }
protected createSourceDatabaseDropdown(view: azdata.ModelView): azdata.FormComponent { protected createSourceDatabaseDropdown(): azdata.FormComponent {
this.sourceDatabaseDropdown = view.modelBuilder.dropDown().withProperties( this.sourceDatabaseDropdown = this.view.modelBuilder.dropDown().withProperties(
{ {
editable: true, editable: true,
fireOnTextChange: true, fireOnTextChange: true,
@@ -604,8 +606,8 @@ export class SchemaCompareDialog {
}; };
} }
protected createTargetDatabaseDropdown(view: azdata.ModelView): azdata.FormComponent { protected createTargetDatabaseDropdown(): azdata.FormComponent {
this.targetDatabaseDropdown = view.modelBuilder.dropDown().withProperties( this.targetDatabaseDropdown = this.view.modelBuilder.dropDown().withProperties(
{ {
editable: true, editable: true,
fireOnTextChange: true, fireOnTextChange: true,
@@ -648,7 +650,7 @@ export class SchemaCompareDialog {
} }
protected async getDatabaseValues(connectionId: string, isTarget: boolean): Promise<string[]> { protected async getDatabaseValues(connectionId: string, isTarget: boolean): Promise<string[]> {
let endpointInfo = isTarget ? this.schemaCompareResult.targetEndpointInfo : this.schemaCompareResult.sourceEndpointInfo; let endpointInfo = isTarget ? this.schemaCompareMainWindow.targetEndpointInfo : this.schemaCompareMainWindow.sourceEndpointInfo;
let idx = -1; let idx = -1;
let count = -1; let count = -1;
@@ -672,8 +674,8 @@ export class SchemaCompareDialog {
return values; return values;
} }
protected createNoActiveConnectionsText(view: azdata.ModelView): azdata.FormComponent { protected createNoActiveConnectionsText(): azdata.FormComponent {
let noActiveConnectionsText = view.modelBuilder.text().withProperties({ value: loc.NoActiveConnectionsLabel }).component(); let noActiveConnectionsText = this.view.modelBuilder.text().withProperties({ value: loc.NoActiveConnectionsLabel }).component();
return { return {
component: noActiveConnectionsText, component: noActiveConnectionsText,

View File

@@ -28,23 +28,6 @@ before(function (): void {
testContext = createContext(); testContext = createContext();
}); });
describe('SchemaCompareDialog.openDialog', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
});
it('Should be correct when created.', async function (): Promise<void> {
let schemaCompareResult = new SchemaCompareMainWindow(testContext.apiWrapper.object, undefined, mockExtensionContext.object);
let dialog = new SchemaCompareDialog(schemaCompareResult);
await dialog.openDialog();
should(dialog.dialog.title).equal('Schema Compare');
should(dialog.dialog.okButton.label).equal('OK');
should(dialog.dialog.okButton.enabled).equal(false); // Should be false when open
});
});
describe('SchemaCompareMainWindow.start', function (): void { describe('SchemaCompareMainWindow.start', function (): void {
before(() => { before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
@@ -162,10 +145,18 @@ describe('SchemaCompareMainWindow.execute', function (): void {
await result.execute(); await result.execute();
//Generate script button and apply button should be disabled for dacpac comparison //Generate script button and apply button should be disabled for dacpac comparison
should(result.verifyButtonsState( {compareButtonState: true, optionsButtonState: true, switchButtonState: true, result.verifyButtonsState( {
openScmpButtonState: true, saveScmpButtonState: true, cancelCompareButtonState: false, compareButtonState: true,
selectSourceButtonState: true, selectTargetButtonState: true, generateScriptButtonState: false, optionsButtonState: true,
applyButtonState: false} )).equal(true); switchButtonState: true,
openScmpButtonState: true,
saveScmpButtonState: true,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: false,
applyButtonState: false
} );
}); });
it('Should disable script button and apply button for Schema Compare service for database', async function (): Promise<void> { it('Should disable script button and apply button for Schema Compare service for database', async function (): Promise<void> {
@@ -183,10 +174,18 @@ describe('SchemaCompareMainWindow.execute', function (): void {
await result.execute(); await result.execute();
//Generate script button and apply button should be enabled for database comparison //Generate script button and apply button should be enabled for database comparison
should(result.verifyButtonsState( {compareButtonState: true, optionsButtonState: true, switchButtonState: true, result.verifyButtonsState( {
openScmpButtonState: true, saveScmpButtonState: true, cancelCompareButtonState: false, compareButtonState: true,
selectSourceButtonState: true, selectTargetButtonState: true, generateScriptButtonState: true, optionsButtonState: true,
applyButtonState: true} )).equal(true); switchButtonState: true,
openScmpButtonState: true,
saveScmpButtonState: true,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: true,
applyButtonState: true
} );
}); });
}); });
@@ -213,10 +212,18 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
result.updateSourceAndTarget(); result.updateSourceAndTarget();
should(result.verifyButtonsState( {compareButtonState: false, optionsButtonState: false, switchButtonState: false, result.verifyButtonsState( {
openScmpButtonState: true, saveScmpButtonState: false, cancelCompareButtonState: false, compareButtonState: false,
selectSourceButtonState: true, selectTargetButtonState: true, generateScriptButtonState: false, optionsButtonState: false,
applyButtonState: false} )).equal(true); switchButtonState: false,
openScmpButtonState: true,
saveScmpButtonState: false,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: false,
applyButtonState: false
} );
}); });
it('Should set buttons appropriately when source endpoint is empty and target endpoint is populated', async function (): Promise<void> { it('Should set buttons appropriately when source endpoint is empty and target endpoint is populated', async function (): Promise<void> {
@@ -234,10 +241,18 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
result.updateSourceAndTarget(); result.updateSourceAndTarget();
should(result.verifyButtonsState( {compareButtonState: false, optionsButtonState: false, switchButtonState: true, result.verifyButtonsState( {
openScmpButtonState: true, saveScmpButtonState: false, cancelCompareButtonState: false, compareButtonState: false,
selectSourceButtonState: true, selectTargetButtonState: true, generateScriptButtonState: false, optionsButtonState: false,
applyButtonState: false} )).equal(true); switchButtonState: true,
openScmpButtonState: true,
saveScmpButtonState: false,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: false,
applyButtonState: false
} );
}); });
it('Should set buttons appropriately when source and target endpoints are populated', async function (): Promise<void> { it('Should set buttons appropriately when source and target endpoints are populated', async function (): Promise<void> {
@@ -255,10 +270,18 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
result.updateSourceAndTarget(); result.updateSourceAndTarget();
should(result.verifyButtonsState( {compareButtonState: true, optionsButtonState: true, switchButtonState: true, result.verifyButtonsState( {
openScmpButtonState: true, saveScmpButtonState: true, cancelCompareButtonState: false, compareButtonState: true,
selectSourceButtonState: true, selectTargetButtonState: true, generateScriptButtonState: false, optionsButtonState: true,
applyButtonState: false} )).equal(true); switchButtonState: true,
openScmpButtonState: true,
saveScmpButtonState: true,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: false,
applyButtonState: false
} );
}); });
}); });

View File

@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as should from 'should';
import * as vscode from 'vscode';
import * as TypeMoq from 'typemoq';
import * as loc from '../localizedConstants';
import 'mocha';
import { SchemaCompareDialog } from './../dialogs/schemaCompareDialog';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { createContext, TestContext } from './testContext';
import { setDacpacEndpointInfo } from './testUtils';
import { SchemaCompareMainWindowTest } from './testSchemaCompareMainWindow';
// Mock test data
const mocksource: string = 'source.dacpac';
const mocktarget: string = 'target.dacpac';
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let testContext: TestContext;
before(function (): void {
testContext = createContext();
});
describe('SchemaCompareDialog.openDialog', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
});
it('Should be correct when created.', async function (): Promise<void> {
let schemaCompareResult = new SchemaCompareMainWindow(testContext.apiWrapper.object, undefined, mockExtensionContext.object);
let dialog = new SchemaCompareDialog(schemaCompareResult);
await dialog.openDialog();
should(dialog.dialog.title).equal(loc.SchemaCompareLabel);
should(dialog.dialog.okButton.label).equal(loc.OkButtonText);
should(dialog.dialog.okButton.enabled).equal(false); // Should be false when open
});
it('Simulate ok button- with both endpoints set to dacpac', async function (): Promise<void> {
let schemaCompareResult = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, undefined, mockExtensionContext.object);
await schemaCompareResult.start(undefined);
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
let dialog = new SchemaCompareDialog(schemaCompareResult);
await dialog.openDialog();
await dialog.execute();
// Confirm that ok button got clicked
schemaCompareResult.verifyButtonsState( {
compareButtonState: true,
optionsButtonState: true,
switchButtonState: true,
openScmpButtonState: true,
saveScmpButtonState: true,
cancelCompareButtonState: false,
selectSourceButtonState: true,
selectTargetButtonState: true,
generateScriptButtonState: false,
applyButtonState: false
} );
});
});

View File

@@ -5,6 +5,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as mssql from '../../../mssql'; import * as mssql from '../../../mssql';
import * as should from 'should';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow'; import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { ApiWrapper } from '../common/apiWrapper'; import { ApiWrapper } from '../common/apiWrapper';
@@ -34,26 +35,7 @@ export class SchemaCompareMainWindowTest extends SchemaCompareMainWindow {
return this.comparisonResult; return this.comparisonResult;
} }
// only for test public verifyButtonsState(buttonState: ButtonState): void {
public getButtonsState(): ButtonState {
let buttonObject: ButtonState = {
compareButtonState: this.compareButton.enabled,
optionsButtonState: this.optionsButton.enabled,
switchButtonState: this.switchButton.enabled,
openScmpButtonState: this.openScmpButton.enabled,
saveScmpButtonState: this.saveScmpButton.enabled,
cancelCompareButtonState: this.cancelCompareButton.enabled,
selectSourceButtonState: this.selectSourceButton.enabled,
selectTargetButtonState: this.selectTargetButton.enabled,
generateScriptButtonState: this.generateScriptButton.enabled,
applyButtonState: this.applyButton.enabled
};
return buttonObject;
}
public verifyButtonsState(buttonState: ButtonState): boolean {
let result: boolean = false; let result: boolean = false;
if (this.compareButton.enabled === buttonState.compareButtonState && if (this.compareButton.enabled === buttonState.compareButtonState &&
@@ -69,6 +51,15 @@ export class SchemaCompareMainWindowTest extends SchemaCompareMainWindow {
result = true; result = true;
} }
return result; should(result).equal(true, `CompareButton: (Actual) ${this.compareButton.enabled} (Expected) ${buttonState.compareButtonState}
OptionsButton: (Actual) ${this.optionsButton.enabled} (Expected) ${buttonState.optionsButtonState}
SwitchButton: (Actual) ${this.switchButton.enabled} (Expected) ${buttonState.switchButtonState}
OpenScmpButton: (Actual) ${this.openScmpButton.enabled} (Expected) ${buttonState.openScmpButtonState}
SaveScmpButton: (Actual) ${this.saveScmpButton.enabled} (Expected) ${buttonState.saveScmpButtonState}
CancelCompareButton: (Actual) ${this.cancelCompareButton.enabled} (Expected) ${buttonState.cancelCompareButtonState}
SelectSourceButton: (Actual) ${this.selectSourceButton.enabled} (Expected) ${buttonState.selectSourceButtonState}
SelectTargetButton: (Actual) ${this.selectTargetButton.enabled} (Expected) ${buttonState.selectTargetButtonState}
GenerateScriptButton: (Actual) ${this.generateScriptButton.enabled} (Expected) ${buttonState.generateScriptButtonState}
ApplyButton: (Actual) ${this.applyButton.enabled} (Expected) ${buttonState.applyButtonState}`);
} }
} }

View File

@@ -8,8 +8,12 @@ import * as azdata from 'azdata';
import * as mssql from '../../../mssql'; import * as mssql from '../../../mssql';
import * as loc from '../localizedConstants'; import * as loc from '../localizedConstants';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import {getEndpointName, verifyConnectionAndGetOwnerUri } from '../utils'; import * as path from 'path';
import {mockDacpacEndpoint, mockDatabaseEndpoint, mockFilePath, mockConnectionInfo, shouldThrowSpecificError, mockConnectionResult, mockConnectionProfile} from './testUtils'; import * as uuid from 'uuid';
import * as os from 'os';
import { promises as fs } from 'fs';
import { getEndpointName, verifyConnectionAndGetOwnerUri, exists } from '../utils';
import { mockDacpacEndpoint, mockDatabaseEndpoint, mockFilePath, mockConnectionInfo, shouldThrowSpecificError, mockConnectionResult, mockConnectionProfile } from './testUtils';
import { createContext, TestContext } from './testContext'; import { createContext, TestContext } from './testContext';
let testContext: TestContext; let testContext: TestContext;
@@ -24,8 +28,8 @@ describe('utils: Tests to verify getEndpointName', function (): void {
}); });
it('Should get endpoint information from ConnectionInfo', () => { it('Should get endpoint information from ConnectionInfo', () => {
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.connectionDetails = {...mockConnectionInfo}; testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
should(getEndpointName(testDatabaseEndpoint)).equal('My Server.My Database'); should(getEndpointName(testDatabaseEndpoint)).equal('My Server.My Database');
}); });
@@ -33,7 +37,7 @@ describe('utils: Tests to verify getEndpointName', function (): void {
it('Should get correct endpoint information from SchemaCompareEndpointInfo', () => { it('Should get correct endpoint information from SchemaCompareEndpointInfo', () => {
let dbName = 'My Database'; let dbName = 'My Database';
let serverName = 'My Server'; let serverName = 'My Server';
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.databaseName = dbName; testDatabaseEndpoint.databaseName = dbName;
testDatabaseEndpoint.serverName = serverName; testDatabaseEndpoint.serverName = serverName;
@@ -55,7 +59,7 @@ describe('utils: Basic tests to verify verifyConnectionAndGetOwnerUri', function
it('Should return undefined for endpoint as database and no ConnectionInfo', async function (): Promise<void> { it('Should return undefined for endpoint as database and no ConnectionInfo', async function (): Promise<void> {
let ownerUri = undefined; let ownerUri = undefined;
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.connectionDetails = undefined; testDatabaseEndpoint.connectionDetails = undefined;
ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object); ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object);
@@ -71,9 +75,9 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
it('Should throw an error asking to make a connection', async function (): Promise<void> { it('Should throw an error asking to make a connection', async function (): Promise<void> {
let getConnectionsResults: azdata.connection.ConnectionProfile[] = []; let getConnectionsResults: azdata.connection.ConnectionProfile[] = [];
let connection = {...mockConnectionResult}; let connection = { ...mockConnectionResult };
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.connectionDetails = {...mockConnectionInfo}; testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
const getConnectionString = loc.getConnectionString('test'); const getConnectionString = loc.getConnectionString('test');
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
@@ -85,10 +89,10 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
}); });
it('Should throw an error for login failure', async function (): Promise<void> { it('Should throw an error for login failure', async function (): Promise<void> {
let getConnectionsResults: azdata.connection.ConnectionProfile[] = [{...mockConnectionProfile}]; let getConnectionsResults: azdata.connection.ConnectionProfile[] = [{ ...mockConnectionProfile }];
let connection = {...mockConnectionResult}; let connection = { ...mockConnectionResult };
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.connectionDetails = {...mockConnectionInfo}; testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); }); testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
@@ -100,9 +104,9 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
it('Should throw an error for login failure with openConnectionDialog but no ownerUri', async function (): Promise<void> { it('Should throw an error for login failure with openConnectionDialog but no ownerUri', async function (): Promise<void> {
let getConnectionsResults: azdata.connection.ConnectionProfile[] = []; let getConnectionsResults: azdata.connection.ConnectionProfile[] = [];
let connection = {...mockConnectionResult}; let connection = { ...mockConnectionResult };
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
testDatabaseEndpoint.connectionDetails = {...mockConnectionInfo}; testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); }); testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
@@ -115,10 +119,10 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
it('Should not throw an error and set ownerUri appropriately', async function (): Promise<void> { it('Should not throw an error and set ownerUri appropriately', async function (): Promise<void> {
let ownerUri = undefined; let ownerUri = undefined;
let connection = {...mockConnectionResult}; let connection = { ...mockConnectionResult };
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = {...mockDatabaseEndpoint}; let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
let expectedOwnerUri: string = 'providerName:MSSQL|authenticationType:SqlLogin|database:My Database|server:My Server|user:My User|databaseDisplayName:My Database'; let expectedOwnerUri: string = 'providerName:MSSQL|authenticationType:SqlLogin|database:My Database|server:My Server|user:My User|databaseDisplayName:My Database';
testDatabaseEndpoint.connectionDetails = {...mockConnectionInfo}; testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(expectedOwnerUri); }); testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(expectedOwnerUri); });
@@ -128,3 +132,18 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
should(ownerUri).equal(expectedOwnerUri); should(ownerUri).equal(expectedOwnerUri);
}); });
}); });
describe('utils: Test to verify exists method', () => {
it('Should run as expected', async () => {
const filename = path.join(os.tmpdir(), `SchemaCompareUtilsTest_${uuid.v4()}`);
try {
should(await exists(filename)).be.false();
await fs.writeFile(filename, '');
should(await exists(filename)).be.true();
} finally {
try {
await fs.unlink(filename);
} catch { /* no-op */ }
}
});
});

View File

@@ -9,6 +9,7 @@ import * as mssql from '../../mssql';
import * as os from 'os'; import * as os from 'os';
import * as loc from './localizedConstants'; import * as loc from './localizedConstants';
import { ApiWrapper } from './common/apiWrapper'; import { ApiWrapper } from './common/apiWrapper';
import { promises as fs } from 'fs';
export interface IPackageInfo { export interface IPackageInfo {
name: string; name: string;
@@ -84,7 +85,7 @@ function connectionInfoToConnectionProfile(details: azdata.ConnectionInfo): azda
}; };
} }
export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompareEndpointInfo, caller: string, apiWrapper: ApiWrapper): Promise<string> { export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompareEndpointInfo, caller: string, apiWrapper: ApiWrapper): Promise<string | undefined> {
let ownerUri = undefined; let ownerUri = undefined;
if (endpoint.endpointType === mssql.SchemaCompareEndpointType.Database && endpoint.connectionDetails) { if (endpoint.endpointType === mssql.SchemaCompareEndpointType.Database && endpoint.connectionDetails) {
@@ -132,3 +133,12 @@ export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompa
export function getRootPath(): string { export function getRootPath(): string {
return vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : os.homedir(); return vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : os.homedir();
} }
export async function exists(path: string): Promise<boolean> {
try {
await fs.access(path);
return true;
} catch (e) {
return false;
}
}