diff --git a/extensions/schema-compare/media/connect.svg b/extensions/schema-compare/media/connect.svg new file mode 100644 index 0000000000..29e7182774 --- /dev/null +++ b/extensions/schema-compare/media/connect.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/schema-compare/media/selectConnection.svg b/extensions/schema-compare/media/selectConnection.svg new file mode 100644 index 0000000000..44d7aa82f9 --- /dev/null +++ b/extensions/schema-compare/media/selectConnection.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts index 43756fcc13..97a92f901e 100644 --- a/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts +++ b/extensions/schema-compare/src/dialogs/schemaCompareDialog.ts @@ -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; private initDialogPromise: Promise = new Promise((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 { + 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 { + protected async populateServerDropdown(isTarget: boolean, passivelyPopulate: boolean = false): Promise { 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 { 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; } + diff --git a/extensions/schema-compare/src/localizedConstants.ts b/extensions/schema-compare/src/localizedConstants.ts index 9a2d1a1eb3..a00c8ce4fe 100644 --- a/extensions/schema-compare/src/localizedConstants.ts +++ b/extensions/schema-compare/src/localizedConstants.ts @@ -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"); diff --git a/extensions/schema-compare/src/schemaCompareMainWindow.ts b/extensions/schema-compare/src/schemaCompareMainWindow.ts index fd99603fbe..d8da54f506 100644 --- a/extensions/schema-compare/src/schemaCompareMainWindow.ts +++ b/extensions/schema-compare/src/schemaCompareMainWindow.ts @@ -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; }); diff --git a/extensions/schema-compare/src/test/schemaCompare.test.ts b/extensions/schema-compare/src/test/schemaCompare.test.ts index 6dc9c0d2ba..4828d91bd1 100644 --- a/extensions/schema-compare/src/test/schemaCompare.test.ts +++ b/extensions/schema-compare/src/test/schemaCompare.test.ts @@ -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(); 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(); 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(); 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(); mockExtensionContext.setup(x => x.extensionPath).returns(() => ''); diff --git a/extensions/schema-compare/src/test/schemaCompareDialog.test.ts b/extensions/schema-compare/src/test/schemaCompareDialog.test.ts index 10ec1b54c9..697510428c 100644 --- a/extensions/schema-compare/src/test/schemaCompareDialog.test.ts +++ b/extensions/schema-compare/src/test/schemaCompareDialog.test.ts @@ -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(); @@ -33,7 +40,7 @@ describe('SchemaCompareDialog.openDialog @DacFx@', function (): void { it('Should be correct when created.', async function (): Promise { 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 { + const getConnectionsResults: azdata.connection.ConnectionProfile[] = [{ ...mockConnectionProfile }]; + sinon.stub(azdata.connection, 'getCurrentConnection').resolves(undefined); + sinon.stub(azdata.connection, 'openConnectionDialog').resolves(Promise.resolve(mockConnectionProfile)); + sinon.stub(azdata.connection, 'getConnections').resolves(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 { + sinon.stub(azdata.connection, 'getCurrentConnection').resolves({ ...mockConnectionProfile }); + sinon.stub(azdata.connection, 'openConnectionDialog').resolves(Promise.resolve(mockConnectionProfile2)); + sinon.stub(azdata.connection, 'getConnections').resolves(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}`); + }); }); diff --git a/extensions/schema-compare/src/test/testSchemaCompareDialog.ts b/extensions/schema-compare/src/test/testSchemaCompareDialog.ts new file mode 100644 index 0000000000..646e66bd04 --- /dev/null +++ b/extensions/schema-compare/src/test/testSchemaCompareDialog.ts @@ -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; + } +} diff --git a/extensions/schema-compare/src/test/testUtils.ts b/extensions/schema-compare/src/test/testUtils.ts index 7940a1aef8..dfc9af8188 100644 --- a/extensions/schema-compare/src/test/testUtils.ts +++ b/extensions/schema-compare/src/test/testUtils.ts @@ -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,