Merge pull request #103 from tiagosiebler/#3/tests

feat(#3): add initial integration tests for public api calls
This commit is contained in:
Tiago
2021-06-24 00:45:41 +01:00
committed by GitHub
12 changed files with 4104 additions and 8 deletions

31
.circleci/config.yml Normal file
View File

@@ -0,0 +1,31 @@
version: 2.1
jobs:
test:
docker:
- image: cimg/node:15.1
steps:
- checkout
- restore_cache:
# See the configuration reference documentation for more details on using restore_cache and save_cache steps
# https://circleci.com/docs/2.0/configuration-reference/?section=reference#save_cache
keys:
- node-deps-v1-{{ .Branch }}-{{checksum "package-lock.json"}}
- run:
name: install packages
command: npm ci
- save_cache:
key: node-deps-v1-{{ .Branch }}-{{checksum "package-lock.json"}}
paths:
- ~/.npm
- run:
name: Run Build
command: npm run build
- run:
name: Run Tests
command: npm run test
workflows:
integrationtests:
jobs:
- test

View File

@@ -1,4 +1,5 @@
# bybit-api
[![Tests](https://circleci.com/gh/tiagosiebler/bybit-api.svg?style=shield)](https://circleci.com/gh/tiagosiebler/bybit-api)
[![npm version](https://img.shields.io/npm/v/bybit-api)][1] [![npm size](https://img.shields.io/bundlephobia/min/bybit-api/latest)][1] [![npm downloads](https://img.shields.io/npm/dt/bybit-api)][1]
[![last commit](https://img.shields.io/github/last-commit/tiagosiebler/bybit-api)][1]
[![CodeFactor](https://www.codefactor.io/repository/github/tiagosiebler/bybit-api/badge)](https://www.codefactor.io/repository/github/tiagosiebler/bybit-api)

28
jest.config.js Normal file
View File

@@ -0,0 +1,28 @@
// jest.config.js
module.exports = {
rootDir: './',
globals: {
__DEV__: true,
__PROD__: false
},
testEnvironment: 'node',
preset: "ts-jest",
verbose: true, // report individual test
bail: false, // enable to stop test when an error occur,
detectOpenHandles: false,
moduleDirectories: ['node_modules', 'src', 'test'],
testMatch: ['**/test/**/*.test.ts?(x)'],
testPathIgnorePatterns: ['node_modules/', 'dist/', '.json'],
collectCoverageFrom: [
'src/**/*.ts'
],
coverageThreshold: {
// coverage strategy
global: {
branches: 80,
functions: 80,
lines: 50,
statements: -10
}
}
};

3795
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,8 @@
"index.js"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "jest",
"test:watch": "jest --watch",
"clean": "rm -rf lib dist",
"build": "tsc",
"build:clean": "npm run clean && npm run build",
@@ -28,9 +29,12 @@
"ws": "^7.4.0"
},
"devDependencies": {
"@types/jest": "^26.0.23",
"@types/node": "^14.14.7",
"eslint": "^7.10.0",
"jest": "^27.0.4",
"source-map-loader": "^2.0.0",
"ts-jest": "^27.0.3",
"ts-loader": "^8.0.11",
"typescript": "^4.0.5",
"webpack": "^5.4.0",

View File

@@ -22,7 +22,8 @@ export class InverseClient extends SharedEndpoints {
restClientOptions: RestClientOptions = {},
requestOptions: AxiosRequestConfig = {}
) {
super()
super();
this.requestWrapper = new RequestWrapper(
key,
secret,

View File

@@ -22,7 +22,8 @@ export class InverseFuturesClient extends SharedEndpoints {
restClientOptions: RestClientOptions = {},
requestOptions: AxiosRequestConfig = {}
) {
super()
super();
this.requestWrapper = new RequestWrapper(
key,
secret,

View File

@@ -7,7 +7,7 @@ export class LinearClient extends SharedEndpoints {
protected requestWrapper: RequestWrapper;
/**
* @public Creates an instance of the inverse REST API client.
* @public Creates an instance of the linear REST API client.
*
* @param {string} key - your API key
* @param {string} secret - your API secret
@@ -22,7 +22,8 @@ export class LinearClient extends SharedEndpoints {
restClientOptions: RestClientOptions = {},
requestOptions: AxiosRequestConfig = {}
) {
super()
super();
this.requestWrapper = new RequestWrapper(
key,
secret,

View File

@@ -0,0 +1,70 @@
import { InverseFuturesClient } from "../../src/inverse-futures-client";
import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util";
describe('Public Inverse Futures REST API Endpoints', () => {
const useLivenet = true;
const api = new InverseFuturesClient(undefined, undefined, useLivenet, { disable_time_sync: true });
const symbol = 'BTCUSD';
const interval = '15';
const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60);
const from = Number(timestampOneHourAgo.toFixed(0));
describe('Inverse-Futures only endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError());
});
it('getKline()', async () => {
expect(
await api.getKline({ symbol, interval, from })
).toMatchObject(successResponseList());
});
it('getTrades()', async () => {
expect(await api.getTrades({ symbol })).toMatchObject(successResponseList());
});
it('getIndexPriceKline()', async () => {
expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getPremiumIndexKline()', async () => {
expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getLastFundingRate()', async () => {
expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject());
});
});
describe('Shared endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError());
});
it('getOrderBook()', async () => {
expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList());
});
it('getTickers()', async () => {
expect(await api.getTickers()).toMatchObject(successResponseList());
});
it('getSymbols()', async () => {
expect(await api.getSymbols()).toMatchObject(successResponseList());
});
it('getLiquidations()', async () => {
expect(await api.getLiquidations({ symbol })).toMatchObject(successResponseList());
});
it('getServerTime()', async () => {
expect(await api.getServerTime()).toMatchObject(successResponseObject());
});
it('getApiAnnouncements()', async () => {
expect(await api.getApiAnnouncements()).toMatchObject(successResponseList());
});
});
});

View File

@@ -0,0 +1,70 @@
import { InverseClient } from "../../src/inverse-client";
import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util";
describe('Public Inverse REST API Endpoints', () => {
const useLivenet = true;
const api = new InverseClient(undefined, undefined, useLivenet, { disable_time_sync: true });
const symbol = 'BTCUSD';
const interval = '15';
const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60);
const from = Number(timestampOneHourAgo.toFixed(0));
describe('Inverse only endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError());
});
it('getKline()', async () => {
expect(
await api.getKline({ symbol, interval, from })
).toMatchObject(successResponseList());
});
it('getTrades()', async () => {
expect(await api.getTrades({ symbol })).toMatchObject(successResponseList());
});
it('getIndexPriceKline()', async () => {
expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getPremiumIndexKline()', async () => {
expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getLastFundingRate()', async () => {
expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject());
});
});
describe('Shared endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError());
});
it('getOrderBook()', async () => {
expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList());
});
it('getTickers()', async () => {
expect(await api.getTickers()).toMatchObject(successResponseList());
});
it('getSymbols()', async () => {
expect(await api.getSymbols()).toMatchObject(successResponseList());
});
it('getLiquidations()', async () => {
expect(await api.getLiquidations({ symbol })).toMatchObject(successResponseList());
});
it('getServerTime()', async () => {
expect(await api.getServerTime()).toMatchObject(successResponseObject());
});
it('getApiAnnouncements()', async () => {
expect(await api.getApiAnnouncements()).toMatchObject(successResponseList());
});
});
});

View File

@@ -0,0 +1,70 @@
import { LinearClient } from "../../src/linear-client";
import { notAuthenticatedError, successResponseList, successResponseObject } from "../response.util";
describe('Public Linear REST API Endpoints', () => {
const useLivenet = true;
const api = new LinearClient(undefined, undefined, useLivenet, { disable_time_sync: true });
const symbol = 'BTCUSDT';
const interval = '15';
const timestampOneHourAgo = (new Date().getTime() / 1000) - (1000 * 60 * 60);
const from = Number(timestampOneHourAgo.toFixed(0));
describe('Linear only endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getPosition()).rejects.toMatchObject(notAuthenticatedError());
});
it('getKline()', async () => {
expect(
await api.getKline({ symbol, interval, from })
).toMatchObject(successResponseList());
});
it('getTrades()', async () => {
expect(await api.getTrades({ symbol })).toMatchObject(successResponseList());
});
it('getIndexPriceKline()', async () => {
expect(await api.getIndexPriceKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getPremiumIndexKline()', async () => {
expect(await api.getPremiumIndexKline({ symbol, interval, from })).toMatchObject(successResponseList());
});
it('getLastFundingRate()', async () => {
expect(await api.getLastFundingRate({ symbol })).toMatchObject(successResponseObject());
});
});
describe('Shared endpoints', () => {
it('should throw for unauthenticated private calls', async () => {
expect(() => api.getApiKeyInfo()).rejects.toMatchObject(notAuthenticatedError());
});
it('getOrderBook()', async () => {
expect(await api.getOrderBook({ symbol })).toMatchObject(successResponseList());
});
it('getTickers()', async () => {
expect(await api.getTickers()).toMatchObject(successResponseList());
});
it('getSymbols()', async () => {
expect(await api.getSymbols()).toMatchObject(successResponseList());
});
it('getLiquidations()', async () => {
expect(await api.getLiquidations({ symbol })).toMatchObject(successResponseList());
});
it('getServerTime()', async () => {
expect(await api.getServerTime()).toMatchObject(successResponseObject());
});
it('getApiAnnouncements()', async () => {
expect(await api.getApiAnnouncements()).toMatchObject(successResponseList());
});
});
});

26
test/response.util.ts Normal file
View File

@@ -0,0 +1,26 @@
export function successResponseList() {
return {
"ext_code": "",
"ext_info": "",
"result": expect.any(Array),
"ret_code": 0,
"ret_msg": "OK",
"time_now": expect.any(String),
};
};
export function successResponseObject() {
return {
"ext_code": "",
"ext_info": "",
"result": expect.any(Object),
"ret_code": 0,
"ret_msg": "OK",
"time_now": expect.any(String),
};
};
export function notAuthenticatedError() {
return new Error('Private endpoints require api and private keys set');
};