Skip to content

Commit 3eed509

Browse files
Convert E2E tests to Typescript (#257)
* Convert E2E tests to typescript Signed-off-by: Levko Kravets <levko.ne@gmail.com> * Adjust Typescript configs for building and linting scenarios Signed-off-by: Levko Kravets <levko.ne@gmail.com> * Update tests Signed-off-by: Levko Kravets <levko.ne@gmail.com> --------- Signed-off-by: Levko Kravets <levko.ne@gmail.com>
1 parent fb817b5 commit 3eed509

18 files changed

+413
-272
lines changed

.eslintrc

Lines changed: 7 additions & 0 deletions
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

Lines changed: 156 additions & 87 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 4 deletions
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

Lines changed: 1 addition & 1 deletion
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 renamed to tests/e2e/arrow.test.ts

Lines changed: 29 additions & 18 deletions
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 renamed to tests/e2e/batched_fetch.test.ts

Lines changed: 26 additions & 16 deletions
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 renamed to tests/e2e/cloudfetch.test.ts

Lines changed: 21 additions & 13 deletions
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);

0 commit comments

Comments
 (0)