Additional tests for the import wizard (#11273)

* Setting up tests on import extension

* -Added API wrappers for all the azdata and vscode APIs to make them easily mockable
-Added some unit tests for the import extension
-Some code logic separations

* -added code report for the import extension in ci

* Did some more code refractoring

* -Added json report generation

* updated vscodetestcoverage to latest version in import extension.

* -remove duplicate codecoverageConfig.json

* -Added some modifyColumnPage tests

* pushing temp changes

* -Added some more testcases

* -Added tests using available vscode and azdata apis

* some minor comment change

* removed unnecessary test

* added accidently removed test

* Added some comments

* fixed some broken tests and added comments in fileConfigPage

* code clean up and some more comments

* fixed the prosePreviewPage test and the download test

* added getter and setters

* Increasing timeout and fixing a comment

* removed unnecessary comments and some other code cleanup

* Deleting dotnet files before redownloading them

* - made changes in the PR
- Moved extensioncode to utils.test for better reusability

* added some 'should' messages
This commit is contained in:
Aasim Khan
2020-07-10 15:34:44 -07:00
committed by GitHub
parent 30e8edd875
commit df8f5ae3a6
13 changed files with 820 additions and 48 deletions

View File

@@ -12,6 +12,8 @@ export const configLogDebugInfo = 'logDebugInfo';
export const sqlConfigSectionName = 'sql';
export const mssqlProvider = 'MSSQL';
export const summaryErrorSymbol = '✗ ';
export const supportedProviders = [mssqlProvider];
// Links

View File

@@ -3,29 +3,42 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as TypeMoq from 'typemoq';
import { ApiWrapper } from '../../common/apiWrapper';
import MainController from '../../controllers/mainController';
import { TestExtensionContext } from '../utils.test';
import * as constants from '../../common/constants';
import * as should from 'should';
import * as path from 'path';
import { ImportTestUtils, TestExtensionContext } from '../utils.test';
describe('Main Controller', function () {
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let testExtensionContext: TestExtensionContext;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let extensionPath: string;
this.beforeEach(function () {
mockExtensionContext = TypeMoq.Mock.ofType(TestExtensionContext, TypeMoq.MockBehavior.Loose);
beforeEach(async function () {
extensionPath = await ImportTestUtils.getExtensionPath();
// creating a mock Extension Context with current extensionPath
testExtensionContext = await ImportTestUtils.getTestExtensionContext();
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper);
});
it('Should create new instance successfully', async function () {
// mocking createOutputChannel in API wrapper
mockApiWrapper.setup(x => x.createOutputChannel(TypeMoq.It.isAny()));
it('Should download required binaries and register flatFileImportStartCommand after activate is called', async function () {
this.timeout(50000);
// creating a Main Controller
new MainController(mockExtensionContext.object, mockApiWrapper.object);
// verifying if the output channel is created
mockApiWrapper.verify(x => x.createOutputChannel(TypeMoq.It.isAny()), TypeMoq.Times.once());
// using vscode and azdata APIs available during tests
mockApiWrapper.callBase = true;
let mainController = new MainController(testExtensionContext, mockApiWrapper.object);
await mainController.activate();
// verifying that the task is registered.
mockApiWrapper.verify(x => x.registerTask(constants.flatFileImportStartCommand, TypeMoq.It.isAny()), TypeMoq.Times.once());
//Checking if .net code files are downloaded
should.equal(await ImportTestUtils.checkPathExists(path.join(extensionPath, 'flatfileimportservice')), true);
});
});

View File

@@ -16,4 +16,3 @@ describe('Service utitlities test', function () {
should(ensure({ 'testkey': 'testval' }, 'testkey')).equal('testval');
});
});

View File

@@ -6,6 +6,8 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { ImportDataModel, ColumnMetadata } from '../wizard/api/models';
import { FlatFileProvider, PROSEDiscoveryParams, InsertDataParams, GetColumnInfoParams, ChangeColumnSettingsParams, PROSEDiscoveryResponse, InsertDataResponse, ChangeColumnSettingsResponse, GetColumnInfoResponse } from '../services/contracts';
import * as fs from 'fs';
export class ImportTestUtils {
@@ -34,6 +36,22 @@ export class ImportTestUtils {
options: {}
} as azdata.connection.ConnectionProfile;
}
public static async checkPathExists(path: string): Promise<boolean> {
return fs.promises.access(path, fs.constants.F_OK)
.then(() => true)
.catch(() => false);
}
public static async getExtensionPath(): Promise<string> {
return await vscode.extensions.getExtension('Microsoft.import').extensionPath;
}
public static async getTestExtensionContext(): Promise<TestExtensionContext> {
let testContext = new TestExtensionContext();
testContext.extensionPath = await vscode.extensions.getExtension('Microsoft.import').extensionPath;
return testContext;
}
}
export class TestQueryProvider implements azdata.QueryProvider {
@@ -211,3 +229,20 @@ export class TestImportDataModel implements ImportDataModel {
filePath: string;
fileType: string;
}
export class TestFlatFileProvider implements FlatFileProvider {
providerId?: string;
sendPROSEDiscoveryRequest(params: PROSEDiscoveryParams): Thenable<PROSEDiscoveryResponse> {
throw new Error('Method not implemented.');
}
sendInsertDataRequest(params: InsertDataParams): Thenable<InsertDataResponse> {
throw new Error('Method not implemented.');
}
sendGetColumnInfoRequest(params: GetColumnInfoParams): Thenable<GetColumnInfoResponse> {
throw new Error('Method not implemented.');
}
sendChangeColumnSettingsRequest(params: ChangeColumnSettingsParams): Thenable<ChangeColumnSettingsResponse> {
throw new Error('Method not implemented.');
}
}

View File

@@ -18,7 +18,7 @@ describe('import extension wizard pages', function () {
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockImportModel: TypeMoq.IMock<ImportDataModel>;
this.beforeEach(function () {
beforeEach(function () {
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper);
mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, TypeMoq.It.isAny(), mockApiWrapper.object);
mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose);
@@ -59,13 +59,16 @@ describe('import extension wizard pages', function () {
let serverValues = await importPage.getServerValues();
should(serverValues).undefined();
// getServer should be undefined for null active connections
should.equal(serverValues, undefined, 'getServer should be undefined for no active connections');
// mocking getActive connection returns empty array
mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return [] as azdata.connection.Connection[]; });
serverValues = await importPage.getServerValues();
should(serverValues).undefined();
// getServer should be undefined for empty active connections
should.equal(serverValues, undefined, 'getServer should be undefined for empty active conections');
});
it('getServerValue return active server value first', async function () {
@@ -101,6 +104,7 @@ describe('import extension wizard pages', function () {
mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return testActiveConnections; });
mockImportModel.object.server = ImportTestUtils.getTestServer();
// the second connection should be the first element in the array as it is active
let expectedConnectionValues = [
{
connection: testActiveConnections[1],

View File

@@ -11,22 +11,37 @@ import { ImportDataModel } from '../../../wizard/api/models';
import { TestImportDataModel, TestQueryProvider } from '../../utils.test';
import { FileConfigPage } from '../../../wizard/pages/fileConfigPage';
import * as should from 'should';
import { ImportPage } from '../../../wizard/api/importPage';
import * as constants from '../../../common/constants';
describe('import extension wizard pages', function () {
describe('File config page', function () {
let mockFlatFileWizard: TypeMoq.IMock<FlatFileWizard>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockImportModel: TypeMoq.IMock<ImportDataModel>;
let fileConfigPage: FileConfigPage;
let wizard: azdata.window.Wizard;
let page: azdata.window.WizardPage;
let pages: Map<number, ImportPage> = new Map<number, ImportPage>();
this.beforeEach(function () {
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper);
mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, TypeMoq.It.isAny(), mockApiWrapper.object);
mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose);
// using the actual vscode and azdata apis.
mockApiWrapper.callBase = true;
wizard = mockApiWrapper.object.createWizard(constants.wizardNameText);
page = mockApiWrapper.object.createWizardPage(constants.page1NameText);
});
it('get schema returns active schema first', async function () {
mockApiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny()));
it('getSchema returns active schema first', async function () {
let mockQueryProvider = TypeMoq.Mock.ofType(TestQueryProvider);
// mock result for the schema query
let schemaQueryResult: azdata.SimpleExecuteResult = {
rowCount: 3,
rows: [
@@ -41,26 +56,211 @@ describe('import extension wizard pages', function () {
]
],
columnInfo: undefined
}
};
// setting the default schema for the current connection. This schema should be the first value in the dropdown array
mockImportModel.object.schema = 'schema2';
// expected schema values for the dropdown that will be created
let expectedSchemaValues = [
{ displayName: 'schema2', name: 'schema2' }, // This should be the first database as it is active in the extension.
{ displayName: 'schema1', name: 'schema1' },
{ displayName: 'schema3', name: 'schema3' }
];
mockImportModel.object.schema = 'schema2';
// creating a mock connection
mockImportModel.object.server = {
providerName: 'MSSQL',
connectionId: 'testConnectionId',
options: {}
};
mockQueryProvider.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => { return schemaQueryResult });
// setting up mocks to return test objects created earlier
mockQueryProvider.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => { return schemaQueryResult; });
mockApiWrapper.setup(x => x.getProvider<azdata.QueryProvider>(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return mockQueryProvider.object; });
let importPage = new FileConfigPage(mockFlatFileWizard.object, TypeMoq.It.isAny(), mockImportModel.object, TypeMoq.It.isAny(), TypeMoq.It.isAny(), mockApiWrapper.object);
let actualSchemaValues = await importPage.getSchemaValues();
let fileConfigPage = new FileConfigPage(mockFlatFileWizard.object, TypeMoq.It.isAny(), mockImportModel.object, TypeMoq.It.isAny(), TypeMoq.It.isAny(), mockApiWrapper.object);
let actualSchemaValues = await fileConfigPage.getSchemaValues();
should(expectedSchemaValues).deepEqual(actualSchemaValues);
});
it('checking if all components are initialized properly', async function () {
await new Promise(function (resolve) {
page.registerContent(async (view) => {
fileConfigPage = new FileConfigPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, fileConfigPage);
await fileConfigPage.start();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
// checking if all the required components are correctly initialized
should.notEqual(fileConfigPage.serverDropdown, undefined, 'serverDropdown should not be undefined');
should.notEqual(fileConfigPage.databaseDropdown, undefined, 'databaseDropdown should not be undefined');
should.notEqual(fileConfigPage.fileTextBox, undefined, 'fileTextBox should not be undefined');
should.notEqual(fileConfigPage.fileButton, undefined, 'fileButton should not be undefined');
should.notEqual(fileConfigPage.tableNameTextBox, undefined, 'tableNameTextBox should not be undefined');
should.notEqual(fileConfigPage.schemaDropdown, undefined, 'schemaDropdown should not be undefined');
should.notEqual(fileConfigPage.form, undefined, 'form should not be undefined');
should.notEqual(fileConfigPage.databaseLoader, undefined, 'databaseLoader should not be undefined');
should.notEqual(fileConfigPage.schemaLoader, undefined, 'schemaLoader should not be undefined');
await fileConfigPage.onPageLeave();
await fileConfigPage.cleanup();
});
it('Dropdown values are correctly set', async function () {
// using the actual vscode and azdata apis.
mockApiWrapper.callBase = true;
wizard = mockApiWrapper.object.createWizard(constants.wizardNameText);
page = mockApiWrapper.object.createWizardPage(constants.page1NameText);
// creating mock server values
let testActiveConnections: azdata.connection.Connection[] = [
{
providerName: 'MSSQL',
connectionId: 'testConnection1Id',
options: {
user: 'testcon1user',
server: 'testcon1server',
database: 'testdb1'
}
},
{
providerName: 'MSSQL',
connectionId: 'testConnection2Id',
options: {
user: 'testcon2user',
server: 'testcon2server',
database: 'testdb2'
}
},
{
providerName: 'PGSQL',
connectionId: 'testConnection3Id',
options: {
user: undefined, // setting it undefined to check if function return user as 'default
server: 'testcon3server',
database: 'testdb3'
}
}
];
mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return testActiveConnections; });
// creating a test active connection. This connection will be the first value in server dropdown array
let testServerConnection: azdata.connection.Connection = {
providerName: 'MSSQL',
connectionId: 'testConnection2Id',
options: {
// default database. This datatabe will be the first value in the database dropdown
database: 'testdb2',
user: 'testcon2user',
server: 'testcon2server'
}
};
mockImportModel.object.server = testServerConnection;
mockImportModel.object.server.options = testServerConnection.options;
// expected values for the server dropdown
let expectedConnectionValues = [
{
connection: testActiveConnections[1],
displayName: 'testcon2server (testcon2user)',
name: 'testConnection2Id'
},
{
connection: testActiveConnections[0],
displayName: 'testcon1server (testcon1user)',
name: 'testConnection1Id'
},
{
connection: testActiveConnections[2],
displayName: 'testcon3server (default)',
name: 'testConnection3Id'
}
];
// creating mock database values
let databases: string[] = ['testdb1', 'testdb2', 'testdb3'];
mockApiWrapper.setup(x => x.listDatabases(TypeMoq.It.isAnyString())).returns(async () => { return databases; });
mockImportModel.object.database = 'testdb2';
// expected values for the database dropdown
let expectedDatabaseDropdownValues = [
{
displayName: 'testdb2',
name: 'testdb2'
},
{
displayName: 'testdb1',
name: 'testdb1'
},
{
displayName: 'testdb3',
name: 'testdb3'
}
];
// mock result for the schema query
let schemaQueryResult: azdata.SimpleExecuteResult = {
rowCount: 3,
rows: [
[
{ displayValue: 'schema1', isNull: false, invariantCultureDisplayValue: 'schema1' }
],
[
{ displayValue: 'schema2', isNull: false, invariantCultureDisplayValue: 'schema2' }
],
[
{ displayValue: 'schema3', isNull: false, invariantCultureDisplayValue: 'schema3' }
]
],
columnInfo: undefined
};
mockImportModel.object.schema = 'schema2';
// expected values for the schema dropdown
let expectedSchemaValues = [
{ displayName: 'schema2', name: 'schema2' }, // This should be the first database as it is active in the extension.
{ displayName: 'schema1', name: 'schema1' },
{ displayName: 'schema3', name: 'schema3' }
];
let mockQueryProvider = TypeMoq.Mock.ofType(TestQueryProvider);
mockApiWrapper.setup(x => x.getProvider(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return mockQueryProvider.object; });
mockQueryProvider.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => { return schemaQueryResult; });
await new Promise(function (resolve) {
page.registerContent(async (view) => {
fileConfigPage = new FileConfigPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, fileConfigPage);
await fileConfigPage.start();
await fileConfigPage.setupNavigationValidator();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
await fileConfigPage.onPageEnter();
should.deepEqual(fileConfigPage.serverDropdown.value, expectedConnectionValues[0]);
should.deepEqual(fileConfigPage.serverDropdown.values, expectedConnectionValues);
should.deepEqual(fileConfigPage.databaseDropdown.value, expectedDatabaseDropdownValues[0]);
should.deepEqual(fileConfigPage.databaseDropdown.values, expectedDatabaseDropdownValues);
should.deepEqual(fileConfigPage.schemaDropdown.value, expectedSchemaValues[0]);
should.deepEqual(fileConfigPage.schemaDropdown.values, expectedSchemaValues);
});
});

View File

@@ -0,0 +1,109 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import { ApiWrapper } from '../../../common/apiWrapper';
import * as constants from '../../../common/constants';
import { FlatFileWizard } from '../../../wizard/flatFileWizard';
import * as should from 'should';
import { ModifyColumnsPage } from '../../../wizard/pages/modifyColumnsPage';
import { ImportDataModel } from '../../../wizard/api/models';
import { TestImportDataModel, TestFlatFileProvider } from '../../utils.test';
import { ImportPage } from '../../../wizard/api/importPage';
import { FlatFileProvider } from '../../../services/contracts';
describe('import extension modify Column Page', function () {
let wizard: azdata.window.Wizard;
let page: azdata.window.WizardPage;
let modifyColumnsPage: ModifyColumnsPage;
let mockFlatFileWizard: TypeMoq.IMock<FlatFileWizard>;
let mockImportModel: TypeMoq.IMock<ImportDataModel>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let pages: Map<number, ImportPage> = new Map<number, ImportPage>();
let mockFlatFileProvider: TypeMoq.IMock<FlatFileProvider>;
beforeEach(function () {
// Keeping the original behaviour of apiWrapper until some setup is needed to mock stuff
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper, TypeMoq.MockBehavior.Loose);
mockApiWrapper.callBase = true;
mockFlatFileProvider = TypeMoq.Mock.ofType(TestFlatFileProvider);
mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, mockFlatFileProvider.object, mockApiWrapper.object);
mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose);
wizard = mockApiWrapper.object.createWizard(constants.wizardNameText);
page = mockApiWrapper.object.createWizardPage(constants.page3NameText);
});
it('checking if all components are initialized properly', async function () {
await new Promise(function (resolve) {
page.registerContent(async (view) => {
modifyColumnsPage = new ModifyColumnsPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, modifyColumnsPage);
await modifyColumnsPage.start();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
// checking if all the components are initialized properly
should.notEqual(modifyColumnsPage.table, undefined, 'table should not be undefined');
should.notEqual(modifyColumnsPage.text, undefined, 'text should not be undefined');
should.notEqual(modifyColumnsPage.loading, undefined, 'loading should not be undefined');
should.notEqual(modifyColumnsPage.form, undefined, 'form should not be undefined');
});
it('handleImport updates table value correctly when import is successful', async function() {
let testProseColumns = [
{
columnName: 'column1',
dataType: 'nvarchar(50)',
primaryKey: false,
nullable: false
},
{
columnName: 'column2',
dataType: 'nvarchar(50)',
primaryKey: false,
nullable: false
}
];
let testTableData = [
[ 'column1', 'nvarchar(50)', false, false],
[ 'column2', 'nvarchar(50)', false, false]
];
mockImportModel.object.proseColumns = testProseColumns;
await new Promise(function (resolve) {
page.registerContent(async (view) => {
modifyColumnsPage = new ModifyColumnsPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, modifyColumnsPage);
await modifyColumnsPage.start();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
await modifyColumnsPage.onPageEnter();
// checking if all the required components are correctly initialized
should.deepEqual(modifyColumnsPage.table.data, testTableData);
});
});

View File

@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import { ApiWrapper } from '../../../common/apiWrapper';
import * as constants from '../../../common/constants';
import { FlatFileWizard } from '../../../wizard/flatFileWizard';
import * as should from 'should';
import { ImportDataModel } from '../../../wizard/api/models';
import { TestImportDataModel } from '../../utils.test';
import { ImportPage } from '../../../wizard/api/importPage';
import { ProsePreviewPage } from '../../../wizard/pages/prosePreviewPage';
describe('import extension prose preview tests', function () {
// declaring mock variables
let mockFlatFileWizard: TypeMoq.IMock<FlatFileWizard>;
let mockImportModel: TypeMoq.IMock<ImportDataModel>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
// declaring instance variables
let wizard: azdata.window.Wizard;
let page: azdata.window.WizardPage;
let pages: Map<number, ImportPage> = new Map<number, ImportPage>();
let prosePreviewPage: ProsePreviewPage;
beforeEach(async function () {
// initializing mock variables
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper);
mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, TypeMoq.It.isAny(), mockApiWrapper);
mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose);
// using the actual vscode and azdata apis.
mockApiWrapper.callBase = true;
// creating a wizard and adding page that will contain the fileConfigPage
wizard = mockApiWrapper.object.createWizard(constants.wizardNameText);
page = mockApiWrapper.object.createWizardPage(constants.page2NameText);
});
it('checking if all components are initialized properly', async function () {
// Opening the wizard and initializing the page as ProsePreviewPage
await new Promise(function (resolve) {
page.registerContent(async (view) => {
prosePreviewPage = new ProsePreviewPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, prosePreviewPage);
await prosePreviewPage.start();
await prosePreviewPage.setupNavigationValidator();
await prosePreviewPage.onPageEnter();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
// checking if all the required components are correctly initialized
should.notEqual(prosePreviewPage.table, undefined, 'table should not be undefined');
should.notEqual(prosePreviewPage.refresh, undefined, 'refresh should not be undefined');
should.notEqual(prosePreviewPage.loading, undefined, 'loading should not be undefined');
should.notEqual(prosePreviewPage.form, undefined, 'form should not be undefined');
should.notEqual(prosePreviewPage.resultTextComponent, undefined, 'resultTextComponent should not be undefined');
// calling the clean up code
await prosePreviewPage.onPageLeave();
await prosePreviewPage.cleanup();
});
});

View File

@@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import { ApiWrapper } from '../../../common/apiWrapper';
import * as constants from '../../../common/constants';
import { FlatFileWizard } from '../../../wizard/flatFileWizard';
import * as should from 'should';
import { ImportDataModel } from '../../../wizard/api/models';
import { TestImportDataModel, TestFlatFileProvider } from '../../utils.test';
import { ImportPage } from '../../../wizard/api/importPage';
import { SummaryPage } from '../../../wizard/pages/summaryPage';
import { FlatFileProvider, InsertDataResponse } from '../../../services/contracts';
describe('import extension summary page tests', function () {
let mockFlatFileWizard: TypeMoq.IMock<FlatFileWizard>;
let mockImportModel: TypeMoq.IMock<ImportDataModel>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockFlatFileProvider: TypeMoq.IMock<FlatFileProvider>;
let summaryPage: SummaryPage;
let wizard: azdata.window.Wizard;
let page: azdata.window.WizardPage;
let pages: Map<number, ImportPage> = new Map<number, ImportPage>();
beforeEach(async function () {
// Keeping the original behaviour of apiWrapper until some setup is needed to mock stuff
mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper, TypeMoq.MockBehavior.Loose);
mockApiWrapper.callBase = true;
mockFlatFileProvider = TypeMoq.Mock.ofType(TestFlatFileProvider);
mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, mockFlatFileProvider.object, mockApiWrapper.object);
mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose);
wizard = mockApiWrapper.object.createWizard(constants.wizardNameText);
page = mockApiWrapper.object.createWizardPage(constants.page4NameText);
});
it('checking if all components are initialized properly', async function () {
await new Promise(function (resolve) {
page.registerContent(async (view) => {
summaryPage = new SummaryPage(mockFlatFileWizard.object, page, mockImportModel.object, view, TypeMoq.It.isAny(), mockApiWrapper.object);
pages.set(1, summaryPage);
await summaryPage.start();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
// checking if all the required components are correctly initialized
should.notEqual(summaryPage.table, undefined, 'table should not be undefined');
should.notEqual(summaryPage.statusText, undefined, 'statusText should not be undefined');
should.notEqual(summaryPage.loading, undefined, 'loading should not be undefined');
should.notEqual(summaryPage.form, undefined, 'form should not be undefined');
await summaryPage.onPageLeave();
await summaryPage.cleanup();
});
it('handle import updates status Text correctly', async function () {
// Creating a test Connection
let testServerConnection: azdata.connection.Connection = {
providerName: 'testProviderName',
connectionId: 'testConnectionId',
options: {}
};
// setting up connection objects in model
mockImportModel.object.server = testServerConnection;
mockImportModel.object.database = 'testDatabase';
mockImportModel.object.schema = 'testSchema';
mockImportModel.object.filePath = 'testFilePath';
// Creating test columns
let testProseColumns = [
{
columnName: 'column1',
dataType: 'nvarchar(50)',
primaryKey: false,
nullable: false
},
{
columnName: 'column2',
dataType: 'nvarchar(50)',
primaryKey: false,
nullable: false
}
];
mockImportModel.object.proseColumns = testProseColumns;
// setting up a test table insert response from FlatFileProvider
let testSendInsertDataRequestResponse: InsertDataResponse = {
result: {
success: true,
errorMessage: ''
}
};
mockFlatFileProvider.setup(x => x.sendInsertDataRequest(TypeMoq.It.isAny())).returns(async () => { return testSendInsertDataRequestResponse; });
await new Promise(function (resolve) {
page.registerContent(async (view) => {
summaryPage = new SummaryPage(mockFlatFileWizard.object, page, mockImportModel.object, view, mockFlatFileProvider.object, mockApiWrapper.object);
pages.set(1, summaryPage);
await summaryPage.start();
summaryPage.setupNavigationValidator();
resolve();
});
wizard.generateScriptButton.hidden = true;
wizard.pages = [page];
wizard.open();
});
// Entering the page. This method will try to create table using FlatFileProvider
await summaryPage.onPageEnter();
// In case of success we should see the success message
should.equal(summaryPage.statusText.value, constants.updateText);
// In case of a failure we should see the error message
testSendInsertDataRequestResponse = {
result: {
success: false,
errorMessage: 'testError'
}
};
// mocking the insertDataRequest to fail
mockFlatFileProvider.setup(x => x.sendInsertDataRequest(TypeMoq.It.isAny())).returns(async () => { return testSendInsertDataRequestResponse; });
// Entering the page. This method will try to create table using FlatFileProvider
await summaryPage.onPageEnter();
should.equal(summaryPage.statusText.value, constants.summaryErrorSymbol + 'testError');
});
});

View File

@@ -10,16 +10,89 @@ import * as constants from '../../common/constants';
export class FileConfigPage extends ImportPage {
private serverDropdown: azdata.DropDownComponent;
private databaseDropdown: azdata.DropDownComponent;
private fileTextBox: azdata.InputBoxComponent;
private fileButton: azdata.ButtonComponent;
private tableNameTextBox: azdata.InputBoxComponent;
private schemaDropdown: azdata.DropDownComponent;
private form: azdata.FormContainer;
private _serverDropdown: azdata.DropDownComponent;
private _databaseDropdown: azdata.DropDownComponent;
private _fileTextBox: azdata.InputBoxComponent;
private _fileButton: azdata.ButtonComponent;
private _tableNameTextBox: azdata.InputBoxComponent;
private _schemaDropdown: azdata.DropDownComponent;
private _form: azdata.FormContainer;
private _databaseLoader: azdata.LoadingComponent;
private _schemaLoader: azdata.LoadingComponent;
public get serverDropdown(): azdata.DropDownComponent {
return this._serverDropdown;
}
public set serverDropdown(serverDropdown: azdata.DropDownComponent) {
this._serverDropdown = serverDropdown;
}
public get databaseDropdown(): azdata.DropDownComponent {
return this._databaseDropdown;
}
public set databaseDropdown(databaseDropdown: azdata.DropDownComponent) {
this._databaseDropdown = databaseDropdown;
}
public get fileTextBox(): azdata.InputBoxComponent {
return this._fileTextBox;
}
public set fileTextBox(fileTextBox: azdata.InputBoxComponent) {
this._fileTextBox = fileTextBox;
}
public get fileButton(): azdata.ButtonComponent {
return this._fileButton;
}
public set fileButton(fileButton: azdata.ButtonComponent) {
this._fileButton = fileButton;
}
public get tableNameTextBox(): azdata.InputBoxComponent {
return this._tableNameTextBox;
}
public set tableNameTextBox(tableNameTextBox: azdata.InputBoxComponent) {
this._tableNameTextBox = tableNameTextBox;
}
public get schemaDropdown(): azdata.DropDownComponent {
return this._schemaDropdown;
}
public set schemaDropdown(schemaDropdown: azdata.DropDownComponent) {
this._schemaDropdown = schemaDropdown;
}
public get form(): azdata.FormContainer {
return this._form;
}
public set form(form: azdata.FormContainer) {
this._form = form;
}
public get databaseLoader(): azdata.LoadingComponent {
return this._databaseLoader;
}
public set databaseLoader(databaseLoader: azdata.LoadingComponent) {
this._databaseLoader = databaseLoader;
}
public get schemaLoader(): azdata.LoadingComponent {
return this._schemaLoader;
}
public set schemaLoader(schemaLoader: azdata.LoadingComponent) {
this._schemaLoader = schemaLoader;
}
private databaseLoader: azdata.LoadingComponent;
private schemaLoader: azdata.LoadingComponent;
private tableNames: string[] = [];

View File

@@ -45,10 +45,43 @@ export class ModifyColumnsPage extends ImportPage {
{ name: 'varchar(50)', displayName: 'varchar(50)' },
{ name: 'varchar(MAX)', displayName: 'varchar(MAX)' }
];
private table: azdata.DeclarativeTableComponent;
private loading: azdata.LoadingComponent;
private text: azdata.TextComponent;
private form: azdata.FormContainer;
private _table: azdata.DeclarativeTableComponent;
private _loading: azdata.LoadingComponent;
private _text: azdata.TextComponent;
private _form: azdata.FormContainer;
public get table(): azdata.DeclarativeTableComponent {
return this._table;
}
public set table(table: azdata.DeclarativeTableComponent) {
this._table = table;
}
public get loading(): azdata.LoadingComponent {
return this._loading;
}
public set loading(loading: azdata.LoadingComponent) {
this._loading = loading;
}
public get text(): azdata.TextComponent {
return this._text;
}
public set text(text: azdata.TextComponent) {
this._text = text;
}
public get form(): azdata.FormContainer {
return this._form;
}
public set form(form: azdata.FormContainer) {
this._form = form;
}
private static convertMetadata(column: ColumnMetadata): any[] {
return [column.columnName, column.dataType, false, column.nullable];

View File

@@ -9,12 +9,60 @@ import * as constants from '../../common/constants';
export class ProsePreviewPage extends ImportPage {
private table: azdata.TableComponent;
private loading: azdata.LoadingComponent;
private form: azdata.FormContainer;
private refresh: azdata.ButtonComponent;
private resultTextComponent: azdata.TextComponent;
private isSuccess: boolean;
private _table: azdata.TableComponent;
private _loading: azdata.LoadingComponent;
private _form: azdata.FormContainer;
private _refresh: azdata.ButtonComponent;
private _resultTextComponent: azdata.TextComponent;
private _isSuccess: boolean;
public get table(): azdata.TableComponent {
return this._table;
}
public set table(table: azdata.TableComponent) {
this._table = table;
}
public get loading(): azdata.LoadingComponent {
return this._loading;
}
public set loading(loading: azdata.LoadingComponent) {
this._loading = loading;
}
public get form(): azdata.FormContainer {
return this._form;
}
public set form(form: azdata.FormContainer) {
this._form = form;
}
public get refresh(): azdata.ButtonComponent {
return this._refresh;
}
public set refresh(refresh: azdata.ButtonComponent) {
this._refresh = refresh;
}
public get resultTextComponent(): azdata.TextComponent {
return this._resultTextComponent;
}
public set resultTextComponent(resultTextComponent: azdata.TextComponent) {
this._resultTextComponent = resultTextComponent;
}
public get isSuccess(): boolean {
return this._isSuccess;
}
public set isSuccess(isSuccess: boolean) {
this._isSuccess = isSuccess;
}
async start(): Promise<boolean> {
this.table = this.view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({

View File

@@ -10,10 +10,42 @@ import { InsertDataResponse } from '../../services/contracts';
import * as constants from '../../common/constants';
export class SummaryPage extends ImportPage {
private table: azdata.TableComponent;
private statusText: azdata.TextComponent;
private loading: azdata.LoadingComponent;
private form: azdata.FormContainer;
private _table: azdata.TableComponent;
private _statusText: azdata.TextComponent;
private _loading: azdata.LoadingComponent;
private _form: azdata.FormContainer;
public get table(): azdata.TableComponent {
return this._table;
}
public set table(table: azdata.TableComponent) {
this._table = table;
}
public get statusText(): azdata.TextComponent {
return this._statusText;
}
public set statusText(statusText: azdata.TextComponent) {
this._statusText = statusText;
}
public get loading(): azdata.LoadingComponent {
return this._loading;
}
public set loading(loading: azdata.LoadingComponent) {
this._loading = loading;
}
public get form(): azdata.FormContainer {
return this._form;
}
public set form(form: azdata.FormContainer) {
this._form = form;
}
async start(): Promise<boolean> {
this.table = this.view.modelBuilder.table().component();
@@ -101,7 +133,7 @@ export class SummaryPage extends ImportPage {
let updateText: string;
if (!result || !result.result.success) {
updateText = '✗ ';
updateText = constants.summaryErrorSymbol;
if (!result) {
updateText += err;
} else {