Update Schema Compare dialog to start a new connection (#15193)

* Update SC dialog to start a new connection

* Functionally complete

* Fix target db to pick correct database

* Address comments

* Added test+fixed one missing scenario

* Address comments + add one more test
This commit is contained in:
Sakshi Sharma
2021-04-29 09:53:38 -07:00
committed by GitHub
parent e42da81005
commit e695a01538
9 changed files with 241 additions and 62 deletions

View File

@@ -0,0 +1,3 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 9.5C2 9.03646 2.08854 8.59115 2.26562 8.16406C2.44271 7.73698 2.69531 7.35677 3.02344 7.02344L4.79688 5.25781L9.74219 10.2031L7.97656 11.9766C7.64844 12.3047 7.27083 12.5573 6.84375 12.7344C6.41667 12.9115 5.96875 13 5.5 13C5.11979 13 4.7526 12.9427 4.39844 12.8281C4.04427 12.7135 3.71354 12.5391 3.40625 12.3047L0.851562 14.8516L0.148438 14.1484L2.69531 11.5938C2.46615 11.2917 2.29427 10.9635 2.17969 10.6094C2.0651 10.2552 2.00521 9.88542 2 9.5ZM5.5 12C5.83333 12 6.15104 11.9375 6.45312 11.8125C6.75521 11.6875 7.02604 11.5052 7.26562 11.2656L8.32812 10.2031L4.79688 6.67188L3.73438 7.73438C3.5 7.96875 3.32031 8.23698 3.19531 8.53906C3.07031 8.84115 3.00521 9.16146 3 9.5C3 9.84375 3.0651 10.1667 3.19531 10.4688C3.32552 10.7708 3.5026 11.0365 3.72656 11.2656C3.95052 11.4948 4.21615 11.6745 4.52344 11.8047C4.83073 11.9349 5.15625 12 5.5 12ZM12.3047 3.40625C12.5339 3.70833 12.7057 4.03646 12.8203 4.39062C12.9349 4.74479 12.9948 5.11458 13 5.5C13 5.96354 12.9115 6.40885 12.7344 6.83594C12.5573 7.26302 12.3047 7.64323 11.9766 7.97656L10.2031 9.74219L5.25781 4.79688L7.02344 3.02344C7.35156 2.69531 7.72917 2.44271 8.15625 2.26562C8.58333 2.08854 9.03125 2 9.5 2C9.88021 2 10.2474 2.05729 10.6016 2.17188C10.9557 2.28646 11.2865 2.46094 11.5938 2.69531L14.1484 0.148438L14.8516 0.851562L12.3047 3.40625ZM11.2656 7.26562C11.5 7.03125 11.6797 6.76302 11.8047 6.46094C11.9297 6.15885 11.9948 5.83854 12 5.5C12 5.15625 11.9349 4.83333 11.8047 4.53125C11.6745 4.22917 11.4948 3.96615 11.2656 3.74219C11.0365 3.51823 10.7708 3.33854 10.4688 3.20312C10.1667 3.06771 9.84375 3 9.5 3C9.16667 3 8.84896 3.0625 8.54688 3.1875C8.24479 3.3125 7.97396 3.49479 7.73438 3.73438L6.67188 4.79688L10.2031 8.32812L11.2656 7.26562Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M2.00816 9.49995C2.00713 9.03996 2.09707 8.5843 2.27281 8.15919C2.44855 7.73409 2.70661 7.34794 3.03216 7.02295L4.68016 5.37495L9.63316 10.3279L7.98516 11.9769C7.65992 12.3021 7.2737 12.5598 6.84864 12.7354C6.42358 12.9109 5.96804 13.0008 5.50816 12.9999C5.13179 13.0009 4.75771 12.9415 4.40016 12.8239C4.04405 12.7076 3.71005 12.5321 3.41216 12.3049L0.860156 14.8519L0.160156 14.1519L2.70016 11.5939C2.47227 11.296 2.29646 10.9616 2.18016 10.6049C2.06422 10.2482 2.00615 9.8751 2.00816 9.49995ZM5.50816 12.0229C5.80194 12.0292 6.09449 11.9831 6.37216 11.8869C6.61668 11.7972 6.84678 11.6722 7.05516 11.5159C7.27008 11.3536 7.4708 11.1733 7.65516 10.9769C7.84516 10.7729 8.04949 10.5619 8.26816 10.3439L4.66816 6.74395C4.45416 6.95795 4.24449 7.16128 4.03916 7.35395C3.83924 7.53839 3.65494 7.73908 3.48816 7.95395C3.32685 8.16355 3.19651 8.39525 3.10116 8.64195C3.00022 8.91547 2.95138 9.20546 2.95716 9.49695C2.95057 9.99708 3.09549 10.4875 3.37285 10.9037C3.65021 11.3199 4.04704 11.6425 4.51116 11.8289C4.82761 11.9582 5.16634 12.0241 5.50816 12.0229ZM13.0082 5.49995C13.0087 5.95979 12.9187 6.41523 12.7431 6.84024C12.5676 7.26526 12.31 7.65152 11.9852 7.97695L10.3292 9.62495L5.38316 4.67995L7.03216 3.02295C7.35564 2.69807 7.74413 2.44521 8.17216 2.28095C8.9523 1.97914 9.8117 1.95058 10.6102 2.19995C10.9656 2.31203 11.3006 2.48088 11.6022 2.69995L14.1572 0.147949L14.8572 0.847949L12.3132 3.40595C12.5398 3.70468 12.7156 4.03886 12.8332 4.39495C12.95 4.75161 13.009 5.12465 13.0082 5.49995ZM10.3522 8.26595C10.5652 8.05795 10.7752 7.85495 10.9812 7.65995C11.1802 7.47256 11.3631 7.26885 11.5282 7.05095C11.6874 6.83852 11.8175 6.6058 11.9152 6.35895C12.0179 6.08442 12.0681 5.79303 12.0632 5.49995C12.0664 5.16515 12.002 4.83315 11.8738 4.52385C11.7456 4.21455 11.5563 3.93432 11.3172 3.69995C11.0828 3.47239 10.8067 3.29211 10.5042 3.16895C10.1867 3.04001 9.84682 2.97509 9.50416 2.97795C9.21038 2.97188 8.91795 3.01932 8.64116 3.11795C8.39657 3.21027 8.1655 3.33506 7.95416 3.48895C7.73806 3.64837 7.5372 3.82747 7.35416 4.02395C7.16416 4.22795 6.95982 4.43895 6.74116 4.65695L10.3522 8.26595ZM16.0082 13.9999H14.0082V15.9999H13.0082V13.9999H11.0082V12.9999H13.0082V10.9999H14.0082V12.9999H16.0082V13.9999Z" fill="#0078D4"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -6,6 +6,7 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as loc from '../localizedConstants';
import * as path from 'path';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { TelemetryReporter, TelemetryViews } from '../telemetry';
import { getEndpointName, getRootPath, exists } from '../utils';
@@ -27,18 +28,18 @@ export class SchemaCompareDialog {
private sourceTextBox: azdata.InputBoxComponent;
private sourceFileButton: azdata.ButtonComponent;
private sourceServerComponent: azdata.FormComponent;
private sourceServerDropdown: azdata.DropDownComponent;
protected sourceServerDropdown: azdata.DropDownComponent;
private sourceConnectionButton: azdata.ButtonComponent;
private sourceDatabaseComponent: azdata.FormComponent;
private sourceDatabaseDropdown: azdata.DropDownComponent;
private sourceNoActiveConnectionsText: azdata.FormComponent;
private targetDacpacComponent: azdata.FormComponent;
private targetTextBox: azdata.InputBoxComponent;
private targetFileButton: azdata.ButtonComponent;
private targetServerComponent: azdata.FormComponent;
private targetServerDropdown: azdata.DropDownComponent;
protected targetServerDropdown: azdata.DropDownComponent;
private targetConnectionButton: azdata.ButtonComponent;
private targetDatabaseComponent: azdata.FormComponent;
private targetDatabaseDropdown: azdata.DropDownComponent;
private targetNoActiveConnectionsText: azdata.FormComponent;
private formBuilder: azdata.FormBuilder;
private sourceIsDacpac: boolean;
private targetIsDacpac: boolean;
@@ -50,7 +51,12 @@ export class SchemaCompareDialog {
private initDialogComplete: Deferred<void>;
private initDialogPromise: Promise<void> = new Promise<void>((resolve, reject) => this.initDialogComplete = { resolve, reject });
constructor(private schemaCompareMainWindow: SchemaCompareMainWindow, private view?: azdata.ModelView) {
private textBoxWidth: number = 280;
public promise;
public promise2;
constructor(private schemaCompareMainWindow: SchemaCompareMainWindow, private view?: azdata.ModelView, private extensionContext?: vscode.ExtensionContext) {
this.previousSource = schemaCompareMainWindow.sourceEndpointInfo;
this.previousTarget = schemaCompareMainWindow.targetEndpointInfo;
}
@@ -182,7 +188,7 @@ export class SchemaCompareDialog {
this.sourceTextBox = this.view.modelBuilder.inputBox().withProperties({
value: this.schemaCompareMainWindow.sourceEndpointInfo ? this.schemaCompareMainWindow.sourceEndpointInfo.packageFilePath : '',
width: 275,
width: this.textBoxWidth,
ariaLabel: loc.sourceFile
}).component();
@@ -192,7 +198,7 @@ export class SchemaCompareDialog {
this.targetTextBox = this.view.modelBuilder.inputBox().withProperties({
value: this.schemaCompareMainWindow.targetEndpointInfo ? this.schemaCompareMainWindow.targetEndpointInfo.packageFilePath : '',
width: 275,
width: this.textBoxWidth,
ariaLabel: loc.targetFile
}).component();
@@ -214,9 +220,6 @@ export class SchemaCompareDialog {
let sourceRadioButtons = this.createSourceRadiobuttons();
let targetRadioButtons = this.createTargetRadiobuttons();
this.sourceNoActiveConnectionsText = this.createNoActiveConnectionsText();
this.targetNoActiveConnectionsText = this.createNoActiveConnectionsText();
let sourceComponents = [];
let targetComponents = [];
@@ -345,23 +348,20 @@ export class SchemaCompareDialog {
// show dacpac file browser
this.sourceDacpacRadioButton.onDidClick(async () => {
this.sourceIsDacpac = true;
this.formBuilder.removeFormItem(this.sourceNoActiveConnectionsText);
this.formBuilder.removeFormItem(this.sourceServerComponent);
this.formBuilder.removeFormItem(this.sourceDatabaseComponent);
this.formBuilder.insertFormItem(this.sourceDacpacComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
// show server and db dropdowns or 'No active connections' text
// show server and db dropdowns
this.sourceDatabaseRadioButton.onDidClick(async () => {
this.sourceIsDacpac = false;
if ((this.sourceServerDropdown.value as ConnectionDropdownValue)) {
this.formBuilder.insertFormItem(this.sourceServerComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize });
} else {
this.formBuilder.insertFormItem(this.sourceNoActiveConnectionsText, 2, { horizontal: true, titleFontSize: titleFontSize });
}
this.formBuilder.insertFormItem(this.sourceServerComponent, 2, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.removeFormItem(this.sourceDacpacComponent);
this.populateServerDropdown(false);
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
@@ -401,23 +401,20 @@ export class SchemaCompareDialog {
// show dacpac file browser
dacpacRadioButton.onDidClick(async () => {
this.targetIsDacpac = true;
this.formBuilder.removeFormItem(this.targetNoActiveConnectionsText);
this.formBuilder.removeFormItem(this.targetServerComponent);
this.formBuilder.removeFormItem(this.targetDatabaseComponent);
this.formBuilder.addFormItem(this.targetDacpacComponent, { horizontal: true, titleFontSize: titleFontSize });
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
// show server and db dropdowns or 'No active connections' text
// show server and db dropdowns
databaseRadioButton.onDidClick(async () => {
this.targetIsDacpac = false;
this.formBuilder.removeFormItem(this.targetDacpacComponent);
if ((this.targetServerDropdown.value as ConnectionDropdownValue)) {
this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize });
} else {
this.formBuilder.addFormItem(this.targetNoActiveConnectionsText, { horizontal: true, titleFontSize: titleFontSize });
}
this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize });
this.populateServerDropdown(true);
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
});
@@ -462,17 +459,22 @@ export class SchemaCompareDialog {
{
editable: true,
fireOnTextChange: true,
ariaLabel: loc.sourceServer
ariaLabel: loc.sourceServer,
width: this.textBoxWidth
}
).component();
this.sourceConnectionButton = this.createConnectionButton(false);
this.sourceServerDropdown.onValueChanged(async (value) => {
if (this.sourceServerDropdown.values.findIndex(x => this.matchesValue(x, value as string)) === -1) {
if (value.selected && this.sourceServerDropdown.values.findIndex(x => this.matchesValue(x, value.selected)) === -1) {
await this.sourceDatabaseDropdown.updateProperties({
values: [],
value: ' '
});
}
else {
this.sourceConnectionButton.iconPath = path.join(this.extensionContext.extensionPath, 'media', 'connect.svg');
await this.populateDatabaseDropdown((this.sourceServerDropdown.value as ConnectionDropdownValue).connection, false);
}
});
@@ -482,26 +484,57 @@ export class SchemaCompareDialog {
return {
component: this.sourceServerDropdown,
title: loc.ServerDropdownLabel
title: loc.ServerDropdownLabel,
actions: [this.sourceConnectionButton]
};
}
private createConnectionButton(isTarget: boolean): azdata.ButtonComponent {
const selectConnectionButton = this.view.modelBuilder.button().withProperties({
ariaLabel: loc.selectConnection,
iconPath: path.join(this.extensionContext.extensionPath, 'media', 'selectConnection.svg'),
height: '20px',
width: '20px'
}).component();
selectConnectionButton.onDidClick(async () => {
await this.connectionButtonClick(isTarget);
selectConnectionButton.iconPath = path.join(this.extensionContext.extensionPath, 'media', 'connect.svg');
});
return selectConnectionButton;
}
public async connectionButtonClick(isTarget: boolean): Promise<void> {
let connection = await azdata.connection.openConnectionDialog();
if (connection) {
this.connectionId = connection.connectionId;
this.promise = this.populateServerDropdown(isTarget);
this.promise2 = this.populateServerDropdown(!isTarget, true); // passively populate the other server dropdown as well to add the new connections
}
}
protected createTargetServerDropdown(): azdata.FormComponent {
this.targetServerDropdown = this.view.modelBuilder.dropDown().withProperties(
{
editable: true,
fireOnTextChange: true,
ariaLabel: loc.targetServer
ariaLabel: loc.targetServer,
width: this.textBoxWidth
}
).component();
this.targetConnectionButton = this.createConnectionButton(true);
this.targetServerDropdown.onValueChanged(async (value) => {
if (this.targetServerDropdown.values.findIndex(x => this.matchesValue(x, value as string)) === -1) {
if (value.selected && this.targetServerDropdown.values.findIndex(x => this.matchesValue(x, value.selected)) === -1) {
await this.targetDatabaseDropdown.updateProperties({
values: [],
value: ' '
});
}
else {
this.targetConnectionButton.iconPath = path.join(this.extensionContext.extensionPath, 'media', 'connect.svg');
await this.populateDatabaseDropdown((this.targetServerDropdown.value as ConnectionDropdownValue).connection, true);
}
});
@@ -511,25 +544,39 @@ export class SchemaCompareDialog {
return {
component: this.targetServerDropdown,
title: loc.ServerDropdownLabel
title: loc.ServerDropdownLabel,
actions: [this.targetConnectionButton]
};
}
protected async populateServerDropdown(isTarget: boolean): Promise<void> {
protected async populateServerDropdown(isTarget: boolean, passivelyPopulate: boolean = false): Promise<void> {
const currentDropdown = isTarget ? this.targetServerDropdown : this.sourceServerDropdown;
if (passivelyPopulate && isNullOrUndefined(currentDropdown.value)) {
passivelyPopulate = false; // Populate the dropdown if it is empty
}
currentDropdown.loading = true;
const values = await this.getServerValues(isTarget);
if (values && values.length > 0) {
await currentDropdown.updateProperties({
values: values,
value: values[0]
});
if (passivelyPopulate) { // only update the dropdown values, not the selected value
await currentDropdown.updateProperties({
values: values
});
} else {
await currentDropdown.updateProperties({
values: values,
value: values[0]
});
}
}
currentDropdown.loading = false;
await this.populateDatabaseDropdown((currentDropdown.value as ConnectionDropdownValue).connection, isTarget);
if (!passivelyPopulate && currentDropdown.value) {
await this.populateDatabaseDropdown((currentDropdown.value as ConnectionDropdownValue).connection, isTarget);
}
}
protected async getServerValues(isTarget: boolean): Promise<{ connection: azdata.connection.ConnectionProfile, displayName: string, name: string }[]> {
@@ -539,6 +586,10 @@ export class SchemaCompareDialog {
return undefined;
}
// Update connection icon to "connected" state
let connectionButton = isTarget ? this.targetConnectionButton : this.sourceConnectionButton;
connectionButton.iconPath = path.join(this.extensionContext.extensionPath, 'media', 'connect.svg');
let endpointInfo = isTarget ? this.schemaCompareMainWindow.targetEndpointInfo : this.schemaCompareMainWindow.sourceEndpointInfo;
// reverse list so that most recent connections are first
cons.reverse();
@@ -603,7 +654,8 @@ export class SchemaCompareDialog {
{
editable: true,
fireOnTextChange: true,
ariaLabel: loc.sourceDatabase
ariaLabel: loc.sourceDatabase,
width: this.textBoxWidth
}
).component();
this.sourceDatabaseDropdown.onValueChanged(async (value) => {
@@ -622,7 +674,8 @@ export class SchemaCompareDialog {
{
editable: true,
fireOnTextChange: true,
ariaLabel: loc.targetDatabase
ariaLabel: loc.targetDatabase,
width: this.textBoxWidth
}
).component();
this.targetDatabaseDropdown.onValueChanged(async (value) => {
@@ -643,7 +696,10 @@ export class SchemaCompareDialog {
protected async populateDatabaseDropdown(connectionProfile: azdata.connection.ConnectionProfile, isTarget: boolean): Promise<void> {
const currentDropdown = isTarget ? this.targetDatabaseDropdown : this.sourceDatabaseDropdown;
currentDropdown.loading = true;
await currentDropdown.updateProperties({ values: [], value: null });
await currentDropdown.updateProperties({
values: [],
value: undefined
});
let values = [];
try {
@@ -687,21 +743,13 @@ export class SchemaCompareDialog {
}
return values;
}
protected createNoActiveConnectionsText(): azdata.FormComponent {
let noActiveConnectionsText = this.view.modelBuilder.text().withProperties({ value: loc.NoActiveConnectionsLabel }).component();
return {
component: noActiveConnectionsText,
title: ''
};
}
}
interface ConnectionDropdownValue extends azdata.CategoryValue {
export interface ConnectionDropdownValue extends azdata.CategoryValue {
connection: azdata.connection.ConnectionProfile;
}
function isNullOrUndefined(val: any): boolean {
return val === null || val === undefined;
}

View File

@@ -17,7 +17,6 @@ export const DatabaseRadioButtonLabel: string = localize('schemaCompare.database
export const RadioButtonsLabel: string = localize('schemaCompare.radioButtonsLabel', "Type");
export const ServerDropdownLabel: string = localize('schemaCompareDialog.serverDropdownTitle', "Server");
export const DatabaseDropdownLabel: string = localize('schemaCompareDialog.databaseDropdownTitle', "Database");
export const NoActiveConnectionsLabel: string = localize('schemaCompare.noActiveConnectionsText', "No active connections");
export const SchemaCompareLabel: string = localize('schemaCompare.dialogTitle', "Schema Compare");
export const differentSourceMessage: string = localize('schemaCompareDialog.differentSourceMessage', "A different source schema has been selected. Compare to see the comparison?");
export const differentTargetMessage: string = localize('schemaCompareDialog.differentTargetMessage', "A different target schema has been selected. Compare to see the comparison?");
@@ -82,6 +81,7 @@ export const saveScmp: string = localize('schemaCompare.saveScmpButton', "Save .
export const saveScmpDescription: string = localize('schemaCompare.saveScmpButtonTitle', "Save source and target, options, and excluded elements");
export const save: string = localize('schemaCompare.saveFile', "Save");
export function getConnectionString(caller: string): string { return localize('schemaCompare.GetConnectionString', "Do you want to connect to {0}?", caller); }
export const selectConnection: string = localize('schemaCompare.selectConnection', "Select connection");
// options
export const IgnoreTableOptions: string = localize('SchemaCompare.IgnoreTableOptions', "Ignore Table Options");

View File

@@ -899,7 +899,7 @@ export class SchemaCompareMainWindow {
this.selectSourceButton.onDidClick(async () => {
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSelectSource');
this.schemaCompareDialog = new SchemaCompareDialog(this);
this.schemaCompareDialog = new SchemaCompareDialog(this, undefined, this.extensionContext);
this.promise = this.schemaCompareDialog.openDialog();
await this.promise;
});
@@ -913,7 +913,7 @@ export class SchemaCompareMainWindow {
this.selectTargetButton.onDidClick(async () => {
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSelectTarget');
this.schemaCompareDialog = new SchemaCompareDialog(this);
this.schemaCompareDialog = new SchemaCompareDialog(this, undefined, this.extensionContext);
this.promise = await this.schemaCompareDialog.openDialog();
await this.promise;
});

View File

@@ -93,7 +93,7 @@ let showErrorMessageSpy: any;
let showWarningMessageStub: any;
let showOpenDialogStub: any;
describe('SchemaCompareMainWindow.results', function (): void {
describe('SchemaCompareMainWindow.results @DacFx@', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
@@ -370,7 +370,7 @@ describe('SchemaCompareMainWindow.results', function (): void {
});
let showErrorMessageStub: any;
describe('SchemaCompareMainWindow.execute', function (): void {
describe('SchemaCompareMainWindow.execute @DacFx@', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
@@ -507,7 +507,7 @@ describe('SchemaCompareMainWindow.execute', function (): void {
});
describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
describe('SchemaCompareMainWindow.updateSourceAndTarget @DacFx@', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
@@ -602,7 +602,7 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
});
describe('SchemaCompareMainWindow: Button clicks', function (): void {
describe('SchemaCompareMainWindow: Button clicks @DacFx@', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');

View File

@@ -7,12 +7,15 @@ import * as should from 'should';
import * as vscode from 'vscode';
import * as TypeMoq from 'typemoq';
import * as loc from '../localizedConstants';
import * as sinon from 'sinon';
import * as azdata from 'azdata';
import 'mocha';
import { SchemaCompareDialog } from './../dialogs/schemaCompareDialog';
import { ConnectionDropdownValue, SchemaCompareDialog } from './../dialogs/schemaCompareDialog';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
import { createContext, TestContext } from './testContext';
import { setDacpacEndpointInfo } from './testUtils';
import { mockConnectionProfile, mockConnectionProfile2, setDacpacEndpointInfo } from './testUtils';
import { SchemaCompareMainWindowTest } from './testSchemaCompareMainWindow';
import { SchemaCompareDialogTest } from './testSchemaCompareDialog';
// Mock test data
const mocksource: string = 'source.dacpac';
@@ -25,6 +28,10 @@ before(function (): void {
testContext = createContext();
});
afterEach(() => {
sinon.restore();
});
describe('SchemaCompareDialog.openDialog @DacFx@', function (): void {
before(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
@@ -33,7 +40,7 @@ describe('SchemaCompareDialog.openDialog @DacFx@', function (): void {
it('Should be correct when created.', async function (): Promise<void> {
let schemaCompareResult = new SchemaCompareMainWindow(undefined, mockExtensionContext.object);
let dialog = new SchemaCompareDialog(schemaCompareResult);
let dialog = new SchemaCompareDialog(schemaCompareResult, undefined, mockExtensionContext.object);
await dialog.openDialog();
should(dialog.dialog.title).equal(loc.SchemaCompareLabel);
@@ -47,7 +54,7 @@ describe('SchemaCompareDialog.openDialog @DacFx@', function (): void {
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
let dialog = new SchemaCompareDialog(schemaCompareResult);
let dialog = new SchemaCompareDialog(schemaCompareResult, undefined, mockExtensionContext.object);
await dialog.openDialog();
await dialog.execute();
@@ -66,4 +73,59 @@ describe('SchemaCompareDialog.openDialog @DacFx@', function (): void {
applyButtonState: false
});
});
it('Verify server dropdown gets populated appropriately', async function (): Promise<void> {
const getConnectionsResults: azdata.connection.ConnectionProfile[] = [{ ...mockConnectionProfile }];
sinon.stub(azdata.connection, 'getCurrentConnection').resolves(undefined);
sinon.stub(azdata.connection, 'openConnectionDialog').resolves(<any>Promise.resolve(mockConnectionProfile));
sinon.stub(azdata.connection, 'getConnections').resolves(<any>Promise.resolve(getConnectionsResults));
sinon.stub(azdata.connection, 'listDatabases').resolves(['My Database']);
let schemaCompareResult = new SchemaCompareMainWindow(undefined, mockExtensionContext.object);
let dialog = new SchemaCompareDialogTest(schemaCompareResult, undefined, mockExtensionContext.object);
should.equal(dialog.getSourceServerDropdownValue(), undefined);
should.equal(dialog.getTargetServerDropdownValue(), undefined);
await dialog.openDialog();
await dialog.connectionButtonClick(false);
await dialog.promise;
await dialog.promise2;
// Confirm source server dropdown has the new connection as its value
should.notEqual(dialog.getSourceServerDropdownValue(), undefined);
should((dialog.getSourceServerDropdownValue() as ConnectionDropdownValue).connection).deepEqual(mockConnectionProfile, `SourceDropdownValue: (Actual) ${(dialog.getSourceServerDropdownValue() as ConnectionDropdownValue).connection} (Expected) ${mockConnectionProfile}`);
// Target server dropdown passively populated with the new connection, since it wasn't pre-populated
should.notEqual(dialog.getTargetServerDropdownValue(), undefined);
should((dialog.getTargetServerDropdownValue() as ConnectionDropdownValue).connection).deepEqual(mockConnectionProfile, `TargetDropdownValue: (Actual) ${(dialog.getTargetServerDropdownValue() as ConnectionDropdownValue).connection} (Expected) ${mockConnectionProfile}`);
});
it('Verify source server dropdown does not get updated when target server is updated', async function (): Promise<void> {
sinon.stub(azdata.connection, 'getCurrentConnection').resolves({ ...mockConnectionProfile });
sinon.stub(azdata.connection, 'openConnectionDialog').resolves(<any>Promise.resolve(mockConnectionProfile2));
sinon.stub(azdata.connection, 'getConnections').resolves(<any>Promise.resolve([{ ...mockConnectionProfile }, { ...mockConnectionProfile2 }]));
sinon.stub(azdata.connection, 'listDatabases').resolves(['My Database']);
let schemaCompareResult = new SchemaCompareMainWindow(undefined, mockExtensionContext.object);
let dialog = new SchemaCompareDialogTest(schemaCompareResult, undefined, mockExtensionContext.object);
should.equal(dialog.getSourceServerDropdownValue(), undefined);
should.equal(dialog.getTargetServerDropdownValue(), undefined);
await dialog.openDialog();
await dialog.connectionButtonClick(true); // openConnectionDialog for target server
await dialog.promise;
await dialog.promise2;
// Confirm source server dropdown has the current connection (from getCurrentConnection) as its value (and doesn't get updated to what target server is)
should.notEqual(dialog.getSourceServerDropdownValue(), undefined);
should((dialog.getSourceServerDropdownValue() as ConnectionDropdownValue).connection).deepEqual(mockConnectionProfile, `SourceDropdownValue: (Actual) ${(dialog.getSourceServerDropdownValue() as ConnectionDropdownValue).connection} (Expected) ${mockConnectionProfile}`);
// Confirm target server dropdown has the new connection (from openConnectionDialog) as its value
should.notEqual(dialog.getTargetServerDropdownValue(), undefined);
should((dialog.getTargetServerDropdownValue() as ConnectionDropdownValue).connection).deepEqual(mockConnectionProfile2, `TargetDropdownValue: (Actual) ${(dialog.getTargetServerDropdownValue() as ConnectionDropdownValue).connection} (Expected) ${mockConnectionProfile2}`);
});
});

View File

@@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* 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 * as vscode from 'vscode';
import { SchemaCompareDialog } from '../dialogs/schemaCompareDialog';
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
export class SchemaCompareDialogTest extends SchemaCompareDialog {
constructor(
schemaCompareMainWindow: SchemaCompareMainWindow,
view: azdata.ModelView,
extensionContext: vscode.ExtensionContext) {
super(schemaCompareMainWindow, view, extensionContext);
}
// only for test
public getSourceServerDropdownValue(): string | azdata.CategoryValue {
if (this.sourceServerDropdown) {
return this.sourceServerDropdown.value;
}
return undefined;
}
public getTargetServerDropdownValue(): string | azdata.CategoryValue {
if (this.targetServerDropdown) {
return this.targetServerDropdown.value;
}
return undefined;
}
}

View File

@@ -47,6 +47,28 @@ export const mockConnectionProfile: azdata.connection.ConnectionProfile = {
}
};
export const mockConnectionProfile2: azdata.connection.ConnectionProfile = {
providerId: 'My Provider2',
connectionId: 'My Id2',
connectionName: 'My Connection2',
serverName: 'My Server2',
databaseName: 'My Database2',
userName: 'My User2',
password: 'My Pwd2',
authenticationType: 'SqlLogin',
savePassword: false,
groupFullName: 'My groupName2',
groupId: 'My GroupId2',
saveProfile: true,
options: {
server: 'My Server2',
database: 'My Database2',
user: 'My User2',
password: 'My Pwd2',
authenticationType: 'SqlLogin'
}
};
export const mockConnectionResult: azdata.ConnectionResult = {
connected: false,
connectionId: undefined,