Skip to content

Commit 3eed509

Browse files
authoredMay 14, 2024··
Convert E2E tests to Typescript (#257)
* Convert E2E tests to typescript Signed-off-by: Levko Kravets <[email protected]> * Adjust Typescript configs for building and linting scenarios Signed-off-by: Levko Kravets <[email protected]> * Update tests Signed-off-by: Levko Kravets <[email protected]> --------- Signed-off-by: Levko Kravets <[email protected]>
1 parent fb817b5 commit 3eed509

18 files changed

+413
-272
lines changed
 

‎.eslintrc

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
}
2525
]
2626
}
27+
},
28+
{
29+
"files": ["*.test.js", "*.test.ts"],
30+
"rules": {
31+
"no-unused-expressions": "off",
32+
"@typescript-eslint/no-unused-expressions": "off"
33+
}
2734
}
2835
]
2936
}

‎package-lock.json

+156-87
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+6-4
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
"e2e": "nyc --reporter=lcov --report-dir=${NYC_REPORT_DIR:-coverage_e2e} mocha --config tests/e2e/.mocharc.js",
1717
"test": "nyc --reporter=lcov --report-dir=${NYC_REPORT_DIR:-coverage_unit} mocha --config tests/unit/.mocharc.js",
1818
"update-version": "node bin/update-version.js && prettier --write ./lib/version.ts",
19-
"build": "npm run update-version && tsc",
20-
"watch": "tsc -w",
19+
"build": "npm run update-version && tsc --project tsconfig.build.json",
20+
"watch": "tsc --project tsconfig.build.json --watch",
2121
"type-check": "tsc --noEmit",
2222
"prettier": "prettier . --check",
2323
"prettier:fix": "prettier . --write",
24-
"lint": "eslint lib/** --ext .js,.ts",
24+
"lint": "eslint lib/** tests/e2e/** --ext .js,.ts",
2525
"lint:fix": "eslint lib/** --ext .js,.ts --fix"
2626
},
2727
"repository": {
@@ -48,11 +48,13 @@
4848
"license": "Apache 2.0",
4949
"devDependencies": {
5050
"@types/chai": "^4.3.14",
51+
"@types/http-proxy": "^1.17.14",
5152
"@types/lz4": "^0.6.4",
5253
"@types/mocha": "^10.0.6",
5354
"@types/node": "^18.11.9",
5455
"@types/node-fetch": "^2.6.4",
5556
"@types/node-int64": "^0.4.29",
57+
"@types/sinon": "^17.0.3",
5658
"@types/thrift": "^0.10.11",
5759
"@types/uuid": "^8.3.4",
5860
"@typescript-eslint/eslint-plugin": "^5.44.0",
@@ -70,7 +72,7 @@
7072
"mocha": "^10.2.0",
7173
"nyc": "^15.1.0",
7274
"prettier": "^2.8.4",
73-
"sinon": "^14.0.0",
75+
"sinon": "^17.0.1",
7476
"ts-node": "^10.9.2",
7577
"typescript": "^4.9.3"
7678
},

‎tests/e2e/.mocharc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const allSpecs = 'tests/e2e/**/*.test.js';
3+
const allSpecs = 'tests/e2e/**/*.test.ts';
44

55
const argvSpecs = process.argv.slice(4);
66

‎tests/e2e/arrow.test.js ‎tests/e2e/arrow.test.ts

+29-18
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const logger = require('./utils/logger')(config.logger);
5-
const { DBSQLClient } = require('../../lib');
6-
const ArrowResultHandler = require('../../lib/result/ArrowResultHandler').default;
7-
const ArrowResultConverter = require('../../lib/result/ArrowResultConverter').default;
8-
const ResultSlicer = require('../../lib/result/ResultSlicer').default;
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
5+
import IDBSQLSession from '../../lib/contracts/IDBSQLSession';
6+
import ArrowResultHandler from '../../lib/result/ArrowResultHandler';
7+
import ArrowResultConverter from '../../lib/result/ArrowResultConverter';
8+
import ResultSlicer from '../../lib/result/ResultSlicer';
9+
10+
import config from './utils/config';
911

1012
const fixtures = require('../fixtures/compatibility');
1113
const { expected: expectedColumn } = require('../fixtures/compatibility/column');
1214
const { expected: expectedArrow } = require('../fixtures/compatibility/arrow');
1315
const { expected: expectedArrowNativeTypes } = require('../fixtures/compatibility/arrow_native_types');
16+
1417
const { fixArrowResult } = fixtures;
1518

16-
async function openSession(customConfig) {
19+
async function openSession(customConfig: Partial<ClientConfig> = {}) {
1720
const client = new DBSQLClient();
1821

1922
const clientConfig = client.getConfig();
@@ -29,23 +32,23 @@ async function openSession(customConfig) {
2932
});
3033

3134
return connection.openSession({
32-
initialCatalog: config.database[0],
33-
initialSchema: config.database[1],
35+
initialCatalog: config.catalog,
36+
initialSchema: config.schema,
3437
});
3538
}
3639

37-
async function execute(session, statement) {
40+
async function execute(session: IDBSQLSession, statement: string) {
3841
const operation = await session.executeStatement(statement);
3942
const result = await operation.fetchAll();
4043
await operation.close();
4144
return result;
4245
}
4346

44-
async function deleteTable(session, tableName) {
47+
async function deleteTable(session: IDBSQLSession, tableName: string) {
4548
await execute(session, `DROP TABLE IF EXISTS ${tableName}`);
4649
}
4750

48-
async function initializeTable(session, tableName) {
51+
async function initializeTable(session: IDBSQLSession, tableName: string) {
4952
await deleteTable(session, tableName);
5053

5154
const createTable = fixtures.createTableSql.replace(/\$\{table_name\}/g, tableName);
@@ -58,15 +61,15 @@ async function initializeTable(session, tableName) {
5861
describe('Arrow support', () => {
5962
const tableName = `dbsql_nodejs_sdk_e2e_arrow_${config.tableSuffix}`;
6063

61-
function createTest(testBody, customConfig) {
64+
function createTest(
65+
testBody: (session: IDBSQLSession) => void | Promise<void>,
66+
customConfig: Partial<ClientConfig> = {},
67+
) {
6268
return async () => {
6369
const session = await openSession(customConfig);
6470
try {
6571
await initializeTable(session, tableName);
6672
await testBody(session);
67-
} catch (error) {
68-
logger(error);
69-
throw error;
7073
} finally {
7174
await deleteTable(session, tableName);
7275
await session.close();
@@ -82,6 +85,7 @@ describe('Arrow support', () => {
8285
const result = await operation.fetchAll();
8386
expect(result).to.deep.equal(expectedColumn);
8487

88+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
8589
const resultHandler = await operation.getResultHandler();
8690
expect(resultHandler).to.be.instanceof(ResultSlicer);
8791
expect(resultHandler.source).to.be.not.instanceof(ArrowResultConverter);
@@ -103,6 +107,7 @@ describe('Arrow support', () => {
103107
const result = await operation.fetchAll();
104108
expect(fixArrowResult(result)).to.deep.equal(expectedArrow);
105109

110+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
106111
const resultHandler = await operation.getResultHandler();
107112
expect(resultHandler).to.be.instanceof(ResultSlicer);
108113
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);
@@ -126,6 +131,7 @@ describe('Arrow support', () => {
126131
const result = await operation.fetchAll();
127132
expect(fixArrowResult(result)).to.deep.equal(expectedArrowNativeTypes);
128133

134+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
129135
const resultHandler = await operation.getResultHandler();
130136
expect(resultHandler).to.be.instanceof(ResultSlicer);
131137
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);
@@ -155,16 +161,20 @@ describe('Arrow support', () => {
155161
`);
156162

157163
// We use some internals here to check that server returned response with multiple batches
164+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
158165
const resultHandler = await operation.getResultHandler();
159166
expect(resultHandler).to.be.instanceof(ResultSlicer);
160167
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);
161168
expect(resultHandler.source.source).to.be.instanceof(ArrowResultHandler);
162169

170+
// @ts-expect-error TS2339: Property _data does not exist on type IOperation
163171
sinon.spy(operation._data, 'fetchNext');
164172

165173
const result = await resultHandler.fetchNext({ limit: rowsCount });
166174

175+
// @ts-expect-error TS2339: Property _data does not exist on type IOperation
167176
expect(operation._data.fetchNext.callCount).to.be.eq(1);
177+
// @ts-expect-error TS2339: Property _data does not exist on type IOperation
168178
const rawData = await operation._data.fetchNext.firstCall.returnValue;
169179
// We don't know exact count of batches returned, it depends on server's configuration,
170180
// but with much enough rows there should be more than one result batch
@@ -181,6 +191,7 @@ describe('Arrow support', () => {
181191
const result = await operation.fetchAll();
182192
expect(fixArrowResult(result)).to.deep.equal(expectedArrow);
183193

194+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
184195
const resultHandler = await operation.getResultHandler();
185196
expect(resultHandler).to.be.instanceof(ResultSlicer);
186197
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);

‎tests/e2e/batched_fetch.test.js ‎tests/e2e/batched_fetch.test.ts

+26-16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const logger = require('./utils/logger')(config.logger);
5-
const { DBSQLClient } = require('../../lib');
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
65

7-
async function openSession(customConfig) {
6+
import config from './utils/config';
7+
8+
async function openSession(customConfig: Partial<ClientConfig> = {}) {
89
const client = new DBSQLClient();
910

1011
const clientConfig = client.getConfig();
@@ -20,8 +21,8 @@ async function openSession(customConfig) {
2021
});
2122

2223
return connection.openSession({
23-
initialCatalog: config.database[0],
24-
initialSchema: config.database[1],
24+
initialCatalog: config.catalog,
25+
initialSchema: config.schema,
2526
});
2627
}
2728

@@ -34,15 +35,15 @@ describe('Data fetching', () => {
3435

3536
it('fetch chunks should return a max row set of chunkSize', async () => {
3637
const session = await openSession({ arrowEnabled: false });
38+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
3739
sinon.spy(session.context.driver, 'fetchResults');
3840
try {
3941
// set `maxRows` to null to disable direct results so all the data are fetched through `driver.fetchResults`
4042
const operation = await session.executeStatement(query, { maxRows: null });
41-
let chunkedOp = await operation
42-
.fetchChunk({ maxRows: 10, disableBuffering: true })
43-
.catch((error) => logger(error));
44-
expect(chunkedOp.length).to.be.equal(10);
43+
const chunk = await operation.fetchChunk({ maxRows: 10, disableBuffering: true });
44+
expect(chunk.length).to.be.equal(10);
4545
// we explicitly requested only one chunk
46+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
4647
expect(session.context.driver.fetchResults.callCount).to.equal(1);
4748
} finally {
4849
await session.close();
@@ -62,8 +63,11 @@ describe('Data fetching', () => {
6263
let chunkCount = 0;
6364

6465
while (hasMoreRows) {
65-
let chunkedOp = await operation.fetchChunk({ maxRows: 300 });
66+
// eslint-disable-next-line no-await-in-loop
67+
const chunkedOp = await operation.fetchChunk({ maxRows: 300 });
6668
chunkCount += 1;
69+
70+
// eslint-disable-next-line no-await-in-loop
6771
hasMoreRows = await operation.hasMoreRows();
6872

6973
const isLastChunk = !hasMoreRows;
@@ -78,13 +82,15 @@ describe('Data fetching', () => {
7882

7983
it('fetch all should fetch all records', async () => {
8084
const session = await openSession({ arrowEnabled: false });
85+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
8186
sinon.spy(session.context.driver, 'fetchResults');
8287
try {
8388
// set `maxRows` to null to disable direct results so all the data are fetched through `driver.fetchResults`
8489
const operation = await session.executeStatement(query, { maxRows: null });
85-
let all = await operation.fetchAll({ maxRows: 200 });
90+
const all = await operation.fetchAll({ maxRows: 200 });
8691
expect(all.length).to.be.equal(1000);
8792
// 1000/200 = 5 chunks + one extra request to ensure that there's no more data
93+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
8894
expect(session.context.driver.fetchResults.callCount).to.equal(6);
8995
} finally {
9096
await session.close();
@@ -93,13 +99,15 @@ describe('Data fetching', () => {
9399

94100
it('should fetch all records if they fit within directResults response', async () => {
95101
const session = await openSession({ arrowEnabled: false });
102+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
96103
sinon.spy(session.context.driver, 'fetchResults');
97104
try {
98105
// here `maxRows` enables direct results with limit of the first batch
99106
const operation = await session.executeStatement(query, { maxRows: 1000 });
100-
let all = await operation.fetchAll();
107+
const all = await operation.fetchAll();
101108
expect(all.length).to.be.equal(1000);
102109
// all the data returned immediately from direct results, so no additional requests
110+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
103111
expect(session.context.driver.fetchResults.callCount).to.equal(0);
104112
} finally {
105113
await session.close();
@@ -108,15 +116,17 @@ describe('Data fetching', () => {
108116

109117
it('should fetch all records if only part of them fit within directResults response', async () => {
110118
const session = await openSession({ arrowEnabled: false });
119+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
111120
sinon.spy(session.context.driver, 'fetchResults');
112121
try {
113122
// here `maxRows` enables direct results with limit of the first batch
114123
const operation = await session.executeStatement(query, { maxRows: 200 });
115124
// here `maxRows` sets limit for `driver.fetchResults`
116-
let all = await operation.fetchAll({ maxRows: 200 });
125+
const all = await operation.fetchAll({ maxRows: 200 });
117126
expect(all.length).to.be.equal(1000);
118127
// 1 chunk returned immediately from direct results + 4 remaining chunks + one extra chunk to ensure
119128
// that there's no more data
129+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
120130
expect(session.context.driver.fetchResults.callCount).to.equal(5);
121131
} finally {
122132
await session.close();

‎tests/e2e/cloudfetch.test.js ‎tests/e2e/cloudfetch.test.ts

+21-13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const { DBSQLClient } = require('../../lib');
5-
const CloudFetchResultHandler = require('../../lib/result/CloudFetchResultHandler').default;
6-
const ArrowResultConverter = require('../../lib/result/ArrowResultConverter').default;
7-
const ResultSlicer = require('../../lib/result/ResultSlicer').default;
8-
9-
async function openSession(customConfig) {
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
5+
import CloudFetchResultHandler from '../../lib/result/CloudFetchResultHandler';
6+
import ArrowResultConverter from '../../lib/result/ArrowResultConverter';
7+
import ResultSlicer from '../../lib/result/ResultSlicer';
8+
9+
import config from './utils/config';
10+
11+
async function openSession(customConfig: Partial<ClientConfig> = {}) {
1012
const client = new DBSQLClient();
1113

1214
const clientConfig = client.getConfig();
@@ -22,8 +24,8 @@ async function openSession(customConfig) {
2224
});
2325

2426
return connection.openSession({
25-
initialCatalog: config.database[0],
26-
initialSchema: config.database[1],
27+
initialCatalog: config.catalog,
28+
initialSchema: config.schema,
2729
});
2830
}
2931

@@ -54,6 +56,7 @@ describe('CloudFetch', () => {
5456
await operation.finished();
5557

5658
// Check if we're actually getting data via CloudFetch
59+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
5760
const resultHandler = await operation.getResultHandler();
5861
expect(resultHandler).to.be.instanceof(ResultSlicer);
5962
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);
@@ -69,10 +72,12 @@ describe('CloudFetch', () => {
6972
expect(cfResultHandler.pendingLinks.length).to.be.equal(0);
7073
expect(cfResultHandler.downloadTasks.length).to.be.equal(0);
7174

75+
// @ts-expect-error TS2339: Property _data does not exist on type IOperation
7276
sinon.spy(operation._data, 'fetchNext');
7377

7478
const chunk = await operation.fetchChunk({ maxRows: 100000, disableBuffering: true });
7579
// Count links returned from server
80+
// @ts-expect-error TS2339: Property _data does not exist on type IOperation
7681
const resultSet = await operation._data.fetchNext.firstCall.returnValue;
7782
const resultLinksCount = resultSet?.resultLinks?.length ?? 0;
7883

@@ -82,9 +87,11 @@ describe('CloudFetch', () => {
8287
expect(cfResultHandler.downloadTasks.length).to.be.equal(cloudFetchConcurrentDownloads - 1);
8388

8489
let fetchedRowCount = chunk.length;
90+
// eslint-disable-next-line no-await-in-loop
8591
while (await operation.hasMoreRows()) {
86-
const chunk = await operation.fetchChunk({ maxRows: 100000, disableBuffering: true });
87-
fetchedRowCount += chunk.length;
92+
// eslint-disable-next-line no-await-in-loop
93+
const ch = await operation.fetchChunk({ maxRows: 100000, disableBuffering: true });
94+
fetchedRowCount += ch.length;
8895
}
8996

9097
expect(fetchedRowCount).to.be.equal(queriedRowsCount);
@@ -114,6 +121,7 @@ describe('CloudFetch', () => {
114121
await operation.finished();
115122

116123
// Check if we're actually getting data via CloudFetch
124+
// @ts-expect-error TS2339: Property getResultHandler does not exist on type IOperation
117125
const resultHandler = await operation.getResultHandler();
118126
expect(resultHandler).to.be.instanceof(ResultSlicer);
119127
expect(resultHandler.source).to.be.instanceof(ArrowResultConverter);

‎tests/e2e/data_types.test.js ‎tests/e2e/data_types.test.ts

+13-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const logger = require('./utils/logger')(config.logger);
5-
const { DBSQLClient } = require('../../lib');
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
5+
import IDBSQLSession from '../../lib/contracts/IDBSQLSession';
66

7-
async function openSession(customConfig) {
7+
import config from './utils/config';
8+
9+
async function openSession(customConfig: Partial<ClientConfig> = {}) {
810
const client = new DBSQLClient();
911

1012
const clientConfig = client.getConfig();
@@ -20,21 +22,21 @@ async function openSession(customConfig) {
2022
});
2123

2224
return connection.openSession({
23-
initialCatalog: config.database[0],
24-
initialSchema: config.database[1],
25+
initialCatalog: config.catalog,
26+
initialSchema: config.schema,
2527
});
2628
}
2729

28-
const execute = async (session, statement) => {
30+
const execute = async (session: IDBSQLSession, statement: string) => {
2931
const operation = await session.executeStatement(statement);
3032
const result = await operation.fetchAll();
3133
await operation.close();
3234
return result;
3335
};
3436

35-
function removeTrailingMetadata(columns) {
37+
function removeTrailingMetadata(columns: Array<any>) {
3638
const result = [];
37-
for (let i = 0; i < columns.length; i++) {
39+
for (let i = 0; i < columns.length; i += 1) {
3840
const col = columns[i];
3941
if (col.col_name === '') {
4042
break;
@@ -187,9 +189,6 @@ describe('Data types', () => {
187189
dat: '2014-01-17',
188190
},
189191
]);
190-
} catch (error) {
191-
logger(error);
192-
throw error;
193192
} finally {
194193
await execute(session, `DROP TABLE IF EXISTS ${table}`);
195194
await session.close();
@@ -231,9 +230,6 @@ describe('Data types', () => {
231230
month_interval: '0-1',
232231
},
233232
]);
234-
} catch (error) {
235-
logger(error);
236-
throw error;
237233
} finally {
238234
await execute(session, `DROP TABLE IF EXISTS ${table}`);
239235
await session.close();
@@ -356,9 +352,6 @@ describe('Data types', () => {
356352
},
357353
},
358354
]);
359-
} catch (error) {
360-
logger(error);
361-
throw error;
362355
} finally {
363356
await execute(session, `DROP TABLE IF EXISTS ${table}`);
364357
await execute(session, `DROP TABLE IF EXISTS ${helperTable}`);

‎tests/e2e/iterators.test.js ‎tests/e2e/iterators.test.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const { DBSQLClient } = require('../../lib');
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
55

6-
async function openSession(customConfig) {
6+
import config from './utils/config';
7+
8+
async function openSession(customConfig: Partial<ClientConfig>) {
79
const client = new DBSQLClient();
810

911
const clientConfig = client.getConfig();
@@ -19,12 +21,12 @@ async function openSession(customConfig) {
1921
});
2022

2123
return connection.openSession({
22-
initialCatalog: config.database[0],
23-
initialSchema: config.database[1],
24+
initialCatalog: config.catalog,
25+
initialSchema: config.schema,
2426
});
2527
}
2628

27-
function arrayChunks(arr, chunkSize) {
29+
function arrayChunks<T>(arr: Array<T>, chunkSize: number): Array<Array<T>> {
2830
const result = [];
2931

3032
while (arr.length > 0) {
@@ -38,6 +40,7 @@ function arrayChunks(arr, chunkSize) {
3840
describe('Iterators', () => {
3941
it('should iterate over all chunks', async () => {
4042
const session = await openSession({ arrowEnabled: false });
43+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
4144
sinon.spy(session.context.driver, 'fetchResults');
4245
try {
4346
const expectedRowsCount = 10;
@@ -65,6 +68,7 @@ describe('Iterators', () => {
6568

6669
it('should iterate over all rows', async () => {
6770
const session = await openSession({ arrowEnabled: false });
71+
// @ts-expect-error TS2339: Property context does not exist on type IDBSQLSession
6872
sinon.spy(session.context.driver, 'fetchResults');
6973
try {
7074
const expectedRowsCount = 10;

‎tests/e2e/proxy.test.js ‎tests/e2e/proxy.test.ts

+31-15
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1-
const { expect } = require('chai');
2-
const sinon = require('sinon');
3-
const httpProxy = require('http-proxy');
4-
const https = require('https');
5-
const config = require('./utils/config');
6-
const { DBSQLClient } = require('../../lib');
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import httpProxy from 'http-proxy';
4+
import { IncomingHttpHeaders, ClientRequest, OutgoingHttpHeaders } from 'http';
5+
import https from 'https';
6+
import { DBSQLClient } from '../../lib';
7+
import { ProxyOptions } from '../../lib/connection/contracts/IConnectionOptions';
8+
9+
import config from './utils/config';
710

811
class HttpProxyMock {
9-
constructor(target, port) {
10-
this.requests = [];
12+
public readonly requests: Array<{
13+
method: string;
14+
url: string;
15+
requestHeaders: OutgoingHttpHeaders;
16+
responseHeaders: IncomingHttpHeaders;
17+
}> = [];
18+
19+
public readonly config: ProxyOptions;
20+
21+
public readonly target = `https://${config.host}`;
1122

23+
public readonly proxy: httpProxy;
24+
25+
constructor(target: string, port: number) {
1226
this.config = {
1327
protocol: 'http',
1428
host: 'localhost',
1529
port,
1630
};
1731

18-
this.target = `https://${config.host}`;
19-
2032
this.proxy = httpProxy.createServer({
2133
target: this.target,
2234
agent: new https.Agent({
@@ -25,21 +37,23 @@ class HttpProxyMock {
2537
});
2638

2739
this.proxy.on('proxyRes', (proxyRes) => {
28-
const req = proxyRes.req;
40+
const req = (proxyRes as any).req as ClientRequest;
2941
this.requests.push({
3042
method: req.method?.toUpperCase(),
3143
url: `${req.protocol}//${req.host}${req.path}`,
3244
requestHeaders: { ...req.getHeaders() },
33-
responseHeaders: proxyRes.headers,
45+
responseHeaders: { ...proxyRes.headers },
3446
});
3547
});
3648

3749
this.proxy.listen(port);
50+
// eslint-disable-next-line no-console
3851
console.log(`Proxy listening at ${this.config.host}:${this.config.port} -> ${this.target}`);
3952
}
4053

4154
close() {
4255
this.proxy.close(() => {
56+
// eslint-disable-next-line no-console
4357
console.log(`Proxy stopped at ${this.config.host}:${this.config.port}`);
4458
});
4559
}
@@ -53,7 +67,9 @@ describe('Proxy', () => {
5367

5468
// Our proxy mock is HTTP -> HTTPS, but DBSQLClient is hard-coded to use HTTPS.
5569
// Here we override default behavior to make DBSQLClient work with HTTP proxy
70+
// @ts-expect-error TS2341: Property getConnectionOptions is private
5671
const originalGetConnectionOptions = client.getConnectionOptions;
72+
// @ts-expect-error TS2341: Property getConnectionOptions is private
5773
client.getConnectionOptions = (...args) => {
5874
const result = originalGetConnectionOptions.apply(client, args);
5975
result.https = false;
@@ -71,9 +87,9 @@ describe('Proxy', () => {
7187
proxy: proxy.config,
7288
});
7389

74-
const session = await connection.openSession({
75-
initialCatalog: config.database[0],
76-
initialSchema: config.database[1],
90+
await connection.openSession({
91+
initialCatalog: config.catalog,
92+
initialSchema: config.schema,
7793
});
7894

7995
expect(proxy.requests.length).to.be.gte(1);

‎tests/e2e/query_parameters.test.js ‎tests/e2e/query_parameters.test.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
const { expect, AssertionError } = require('chai');
2-
const Int64 = require('node-int64');
3-
const config = require('./utils/config');
4-
const { DBSQLClient, DBSQLParameter, DBSQLParameterType } = require('../../lib');
5-
const ParameterError = require('../../lib/errors/ParameterError').default;
1+
import { expect, AssertionError } from 'chai';
2+
import Int64 from 'node-int64';
3+
import { DBSQLClient, DBSQLParameter, DBSQLParameterType } from '../../lib';
4+
import ParameterError from '../../lib/errors/ParameterError';
5+
6+
import config from './utils/config';
67

78
const openSession = async () => {
89
const client = new DBSQLClient();
@@ -14,8 +15,8 @@ const openSession = async () => {
1415
});
1516

1617
return connection.openSession({
17-
initialCatalog: config.database[0],
18-
initialSchema: config.database[1],
18+
initialCatalog: config.catalog,
19+
initialSchema: config.schema,
1920
});
2021
};
2122

‎tests/e2e/staging_ingestion.test.js ‎tests/e2e/staging_ingestion.test.ts

+15-18
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
1-
const { expect } = require('chai');
2-
const fs = require('fs');
3-
const path = require('path');
4-
const os = require('os');
5-
const uuid = require('uuid');
6-
const config = require('./utils/config');
7-
const { DBSQLClient } = require('../../lib');
8-
const StagingError = require('../../lib/errors/StagingError').default;
1+
import { expect } from 'chai';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import os from 'os';
5+
import * as uuid from 'uuid';
6+
import { DBSQLClient } from '../../lib';
7+
import StagingError from '../../lib/errors/StagingError';
98

10-
describe('Staging Test', () => {
11-
const catalog = config.database[0];
12-
const schema = config.database[1];
13-
const volume = config.volume;
9+
import config from './utils/config';
1410

11+
describe('Staging Test', () => {
1512
const localPath = fs.mkdtempSync(path.join(os.tmpdir(), 'databricks-sql-tests-'));
1613

17-
before(() => {
18-
expect(catalog).to.not.be.undefined;
19-
expect(schema).to.not.be.undefined;
20-
expect(volume).to.not.be.undefined;
21-
});
22-
2314
after(() => {
2415
fs.rmSync(localPath, {
2516
recursive: true,
@@ -28,6 +19,8 @@ describe('Staging Test', () => {
2819
});
2920

3021
it('put staging data and receive it', async () => {
22+
const { catalog, schema, volume } = config;
23+
3124
const client = new DBSQLClient();
3225
await client.connect({
3326
host: config.host,
@@ -59,6 +52,8 @@ describe('Staging Test', () => {
5952
});
6053

6154
it('put staging data and remove it', async () => {
55+
const { catalog, schema, volume } = config;
56+
6257
const client = new DBSQLClient();
6358
await client.connect({
6459
host: config.host,
@@ -101,6 +96,8 @@ describe('Staging Test', () => {
10196
});
10297

10398
it('delete non-existent data', async () => {
99+
const { catalog, schema, volume } = config;
100+
104101
const client = new DBSQLClient();
105102
await client.connect({
106103
host: config.host,

‎tests/e2e/timeouts.test.js ‎tests/e2e/timeouts.test.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
const { expect, AssertionError } = require('chai');
2-
const sinon = require('sinon');
3-
const config = require('./utils/config');
4-
const { DBSQLClient } = require('../../lib');
1+
import { expect, AssertionError } from 'chai';
2+
import sinon from 'sinon';
3+
import { DBSQLClient } from '../../lib';
4+
import { ClientConfig } from '../../lib/contracts/IClientContext';
55

6-
async function openSession(socketTimeout, customConfig) {
6+
import config from './utils/config';
7+
8+
async function openSession(socketTimeout: number | undefined, customConfig: Partial<ClientConfig> = {}) {
79
const client = new DBSQLClient();
810

911
const clientConfig = client.getConfig();
@@ -20,8 +22,8 @@ async function openSession(socketTimeout, customConfig) {
2022
});
2123

2224
return connection.openSession({
23-
initialCatalog: config.database[0],
24-
initialSchema: config.database[1],
25+
initialCatalog: config.catalog,
26+
initialSchema: config.schema,
2527
});
2628
}
2729

@@ -33,7 +35,7 @@ describe('Timeouts', () => {
3335
await openSession(undefined, { socketTimeout });
3436
expect.fail('It should throw an error');
3537
} catch (error) {
36-
if (error instanceof AssertionError) {
38+
if (error instanceof AssertionError || !(error instanceof Error)) {
3739
throw error;
3840
}
3941
expect(error.message).to.be.eq('Request timed out');
@@ -45,7 +47,7 @@ describe('Timeouts', () => {
4547
await openSession(socketTimeout);
4648
expect.fail('It should throw an error');
4749
} catch (error) {
48-
if (error instanceof AssertionError) {
50+
if (error instanceof AssertionError || !(error instanceof Error)) {
4951
throw error;
5052
}
5153
expect(error.message).to.be.eq('Request timed out');

‎tests/e2e/utils/config.js

-26
This file was deleted.

‎tests/e2e/utils/config.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Create file named `config.local.js` in the same directory and override config there
2+
3+
interface E2EConfig {
4+
// Host, like ****.cloud.databricks.com
5+
host: string;
6+
// API path: /sql/2.0/warehouses/****************
7+
path: string;
8+
// Access token: dapi********************************
9+
token: string;
10+
// Catalog and schema to use for testing
11+
catalog: string;
12+
schema: string;
13+
// UC Volume to use for testing
14+
volume: string;
15+
// Suffix used for tables that will be created during tests
16+
tableSuffix: string;
17+
}
18+
19+
function validateConfig(config: Partial<E2EConfig>): E2EConfig | never {
20+
let isConfigValid = true;
21+
22+
for (const key of Object.keys(config)) {
23+
const value = config[key as keyof E2EConfig] ?? undefined;
24+
if (value === undefined) {
25+
isConfigValid = false;
26+
// eslint-disable-next-line no-console
27+
console.error(`\u26A0\uFE0F Config option '${key}' is missing`);
28+
}
29+
}
30+
31+
if (!isConfigValid) {
32+
// eslint-disable-next-line no-console
33+
console.log();
34+
process.exit(1);
35+
}
36+
37+
// Now, when we checked all the options, we can safely cast to `E2EConfig`
38+
return config as E2EConfig;
39+
}
40+
41+
function loadOverrides(): object {
42+
try {
43+
const result = require('./config.local'); // eslint-disable-line global-require
44+
if (typeof result === 'object' && result !== null) {
45+
return result;
46+
}
47+
} catch (e) {
48+
// ignore
49+
}
50+
return {};
51+
}
52+
53+
export default validateConfig({
54+
host: process.env.E2E_HOST,
55+
path: process.env.E2E_PATH,
56+
token: process.env.E2E_ACCESS_TOKEN,
57+
catalog: process.env.E2E_CATALOG,
58+
schema: process.env.E2E_SCHEMA,
59+
volume: process.env.E2E_VOLUME,
60+
tableSuffix: process.env.E2E_TABLE_SUFFIX,
61+
...loadOverrides(),
62+
});

‎tests/e2e/utils/logger.js

-22
This file was deleted.

‎tsconfig.build.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "./dist/" /* Redirect output structure to the directory. */,
5+
"rootDir": "./lib/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
6+
},
7+
"exclude": ["./tests/**/*", "./dist/**/*"]
8+
}

‎tsconfig.json

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{
22
"compilerOptions": {
3-
"target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
4-
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
3+
"target": "ES6",
4+
"module": "commonjs",
55
"declaration": true,
66
"sourceMap": true,
7-
"outDir": "./dist/" /* Redirect output structure to the directory. */,
8-
"rootDir": "./lib/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
9-
"strict": true /* Enable all strict type-checking options. */,
10-
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
11-
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
12-
}
7+
"strict": true,
8+
"esModuleInterop": true,
9+
"forceConsistentCasingInFileNames": true
10+
},
11+
"exclude": ["./dist/**/*"]
1312
}

0 commit comments

Comments
 (0)
Please sign in to comment.