151 lines
3.9 KiB
JavaScript
151 lines
3.9 KiB
JavaScript
import {
|
|
describe,
|
|
it,
|
|
expect,
|
|
vi,
|
|
beforeEach,
|
|
afterEach,
|
|
beforeAll,
|
|
} from "vitest";
|
|
import nock from "nock";
|
|
import { BigNumber } from "bignumber.js";
|
|
import { Bot } from "../src/bot.js";
|
|
|
|
vi.mock("console", () => ({
|
|
log: vi.fn(),
|
|
error: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../src/db.js", () => ({
|
|
insertIntoDB: vi.fn(),
|
|
initDB: vi.fn(),
|
|
}));
|
|
|
|
describe("Test Suite", () => {
|
|
const PAIR = "BTC-USD";
|
|
const INTERVAL = 100;
|
|
const THRESHOLD = 0.01;
|
|
|
|
let bot;
|
|
|
|
beforeAll(() => {
|
|
// Ensure BigNumber config matches what we expect
|
|
BigNumber.config({
|
|
DECIMAL_PLACES: 10,
|
|
ROUNDING_MODE: BigNumber.ROUND_HALF_UP,
|
|
});
|
|
});
|
|
|
|
beforeEach(() => {
|
|
bot = new Bot(PAIR, INTERVAL, THRESHOLD);
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
bot.stop();
|
|
vi.runAllTimers();
|
|
vi.useRealTimers();
|
|
nock.cleanAll();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("Initialization and first fetch", () => {
|
|
it("should set lastPrice on first successful API call", async () => {
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { ask: "60000.50", bid: "59990.00", currency: "USD" });
|
|
|
|
await bot.check();
|
|
|
|
expect(bot.lastPrice).toBeDefined();
|
|
expect(bot.lastPrice.toFixed(2)).toBe("60000.50");
|
|
});
|
|
});
|
|
|
|
describe("Price change detection", () => {
|
|
beforeEach(async () => {
|
|
// Establish baseline
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { ask: "50000.00" });
|
|
await bot.check();
|
|
nock.cleanAll();
|
|
});
|
|
|
|
it("should NOT alert when change is below threshold", async () => {
|
|
const alertSpy = vi.spyOn(bot, "alert");
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { ask: "50004.99" }); // +0.00998%
|
|
|
|
await bot.check();
|
|
|
|
expect(alertSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should alert when price moves exactly 0.01% (threshold)", async () => {
|
|
const alertSpy = vi.spyOn(bot, "alert");
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { ask: "50005.00" });
|
|
|
|
await bot.check();
|
|
|
|
// Check specifically for arguments passed to alert
|
|
expect(alertSpy).toHaveBeenCalledWith("UP", "50005.00", 0.01);
|
|
});
|
|
|
|
it("should alert on downward move", async () => {
|
|
const alertSpy = vi.spyOn(bot, "alert");
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { ask: "49500.00" }); // -1%
|
|
|
|
await bot.check();
|
|
|
|
expect(alertSpy).toHaveBeenCalledWith("DOWN", "49500.00", -1);
|
|
});
|
|
});
|
|
|
|
describe("Alert method", () => {
|
|
it("should log correct message for price increase", () => {
|
|
bot.lastPrice = new BigNumber("50000");
|
|
const consoleSpy = vi.spyOn(console, "log");
|
|
|
|
bot.alert("UP", "50500.00", 1);
|
|
|
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("UP"));
|
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("1.00%"));
|
|
});
|
|
});
|
|
|
|
describe("Polling mechanism", () => {
|
|
it("should repeatedly call check()", async () => {
|
|
const checkSpy = vi.spyOn(bot, "check").mockResolvedValue();
|
|
|
|
bot.start();
|
|
|
|
vi.advanceTimersByTime(INTERVAL * 3);
|
|
await Promise.resolve();
|
|
|
|
expect(checkSpy).toHaveBeenCalledTimes(4);
|
|
});
|
|
});
|
|
|
|
describe("Error handling", () => {
|
|
it("should bubble up errors when check() is called directly", async () => {
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.replyWithError("Connection Error");
|
|
|
|
await expect(bot.check()).rejects.toThrow("Connection Error");
|
|
});
|
|
|
|
it("should reject invalid data formats", async () => {
|
|
nock("https://api.uphold.com")
|
|
.get(`/v0/ticker/${PAIR}`)
|
|
.reply(200, { bid: "100" });
|
|
await expect(bot.check()).rejects.toThrow("Invalid data format");
|
|
});
|
|
});
|
|
});
|