I'm using Jest to perform unit tests on my classes that handle the data that comes through Binance's webscoket streams. I use binance-api-node. I would like to simulate the event that sends a candle to test data reception in my test class. In my class I have a method called config.
class Klines extends Observable {
...
config() {
// DOC: https://www.npmjs.com/package/binance-api-node#candles-1
// Configures monitoring of Candles type Websocket events client.ws.candles
client.ws.candles(this.symbol, this.interval, (candle) => {
this.addCandle(candle);
});
}
...
}
I am unable to simulate the client.ws.candles event to test my class 100% using Jest. Would anyone know how to mock this event?
My test is working, but i cant test the line 61 this.addCandle(candle);.
Thanks.
My Kline.ts file:
import { CandleChartInterval } from "binance-api-node";
import { HistoricCandles, Kline, WSCandle } from "./Kline";
import client from "./Client";
import Observable from "./Observable";
export class Klines extends Observable {
klines: Kline[] = new Array<Kline>();
symbol: string;
interval: CandleChartInterval;
limit: number;
/**
* Constructor for creating a new instance of the class.
*
* @param {string} symbol - the symbol for the instance
* @param {CandleChartInterval} interval - the interval for the instance
* @param {number} limit - the limit for the instance (default is 500)
*/
constructor(
symbol: string,
interval: CandleChartInterval,
limit: number = 500
) {
super();
this.symbol = symbol;
this.interval = interval;
this.limit = limit;
}
/**
* Retrieves historical klines and adds them to the klines array.
*
* @param {void}
* @return {Promise<void>}
*/
async getHistoricalKlines() {
const candles = await client.candles({
symbol: this.symbol,
interval: this.interval,
limit: this.limit,
});
candles.forEach((candle) => this.addKline(new Kline(candle)));
}
/**
* Method to start the process asynchronously.
*
* @return {Promise<void>} A promise that resolves when the process has started.
*/
async start() {
await this.getHistoricalKlines();
this.config();
}
/**
* Configures the client's WebSocket connection to receive candles for a specific symbol and interval.
*
* @param {type} symbol - the symbol for which to receive candles
* @param {type} interval - the interval at which to receive candles
* @return {type} - no return value
*/
config() {
client.ws.candles(this.symbol, this.interval, (candle) => {
this.addCandle(candle);
});
}
addCandle(candle: WSCandle) {
if (candle.isFinal) {
this.addKline(new Kline(candle));
} else {
this.klines.pop();
this.addKline(new Kline(candle));
}
}
addKline(kline: Kline) {
this.klines.push(kline);
if (this.klines.length > this.limit) {
this.klines.shift();
}
}
/**
* Get the open times from the klines.
*
* @return {Date[]} array of open times
*/
getOpenTimes(): Date[] {
return this.klines.map((kline) => {
return kline.openTime;
});
}
/**
* Get an array of opening prices from the klines.
*
* @return {number[]} array of opening prices
*/
getOpens(): number[] {
return this.klines.map((kline) => {
return kline.open;
});
}
/**
* Retrieves an array of high values from the klines.
*
* @return {number[]} array of high values
*/
getHighs(): number[] {
return this.klines.map((kline) => {
return kline.high;
});
}
/**
* Get an array of low values from the klines.
*
* @return {number[]} array of low values
*/
getLows(): number[] {
return this.klines.map((kline) => {
return kline.low;
});
}
/**
* Get an array of close prices from the klines.
*
* @return {number[]} array of close prices
*/
getCloses(): number[] {
return this.klines.map((kline) => {
return kline.close;
});
}
/**
* Retrieves an array of volumes from the klines.
*
* @return {number[]} array of volumes
*/
getVolumes(): number[] {
return this.klines.map((kline) => {
return kline.volume;
});
}
/**
* Get an array of close times.
*
* @return {Date[]} array of close times
*/
getCloseTimes(): Date[] {
return this.klines.map((kline) => {
return kline.closeTime;
});
}
}
My teste file:
import { mocked } from "jest-mock";
jest.mock("../src/lib/Client");
import client from "../src/lib/Client";
import candles from "./Candles.data";
import { HistoricCandles, WSCandle } from "../src/lib/Kline";
import { Klines } from "../src/lib/Klines";
import { CandleChartInterval } from "binance-api-node";
import wscandle from "./WSCancle.data";
const mockedClient = mocked(client, { shallow: true });
const data: HistoricCandles = candles;
const wsdata: WSCandle = wscandle;
describe("Klines", () => {
afterEach(() => {
jest.restoreAllMocks();
});
beforeEach(() => {
mockedClient.candles.mockResolvedValue(data);
});
test("Should return a Klines", async () => {
const klines = new Klines("SOLUSDT", CandleChartInterval.ONE_MINUTE, 5);
expect(klines).toBeDefined();
expect(klines.symbol).toBe("SOLUSDT");
await klines.start();
expect(klines.getCloseTimes().length).toBe(5);
});
test("Should add a candle event kline", async () => {
const klines = new Klines("SOLUSDT", CandleChartInterval.ONE_MINUTE, 11);
await klines.start();
expect(klines.getCloseTimes().length).toBe(10);
klines.addCandle(wsdata);
expect(klines.getCloseTimes().length).toBe(11);
});
test("Should not add a candle event if kline is not final", async () => {
const klines = new Klines("SOLUSDT", CandleChartInterval.ONE_MINUTE, 11);
await klines.start();
expect(klines.getCloseTimes().length).toBe(10);
wsdata.isFinal = false;
klines.addCandle(wsdata);
expect(klines.getCloseTimes().length).toBe(10);
});
test("Should have 10 elements in each property", async () => {
const klines = new Klines("SOLUSDT", CandleChartInterval.ONE_MINUTE, 11);
await klines.start();
wsdata.isFinal = true;
klines.addCandle(wsdata);
expect(klines.getCloseTimes().length).toBe(11);
expect(klines.getCloses().length).toBe(11);
expect(klines.getHighs().length).toBe(11);
expect(klines.getLows().length).toBe(11);
expect(klines.getOpenTimes().length).toBe(11);
expect(klines.getOpens().length).toBe(11);
expect(klines.getVolumes().length).toBe(11);
});
});
I see this code to emulate the event client.ws.user, but i cant replicate it to client.ws.candles. I dont understand how it works.
jest.mock("../src/lib/Client", () => {
return {
ws: {
user: jest.fn(),
},
// accountInfoData: jest.fn().mockResolvedValue(accountInfoData);
accountInfo: jest.fn().mockResolvedValue({
balances: [
{ asset: "BTC", free: "0.5", locked: "0.1" },
{ asset: "ETH", free: "1.5", locked: "0.3" },
{ asset: "SOL", free: "0", locked: "0.3" },
],
}),
};
});
\\ inside the test, this code trigger the event client.ws.user. But i dont know how it works!
const mockBalancesEvent: { eventType: string; balances: AssetBalance[] } =
outboundAccountPosition;
// Simulate the event by calling the callback function passed to client.ws.user
const userEventCallback = (client.ws.user as jest.Mock).mock.calls[0][0];
await userEventCallback(mockBalancesEvent);