mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-17 15:20:58 +00:00
Replace hardcoded 9-symbol registry with dynamic TCBS-based resolution. Any VN stock ticker is now resolved on first use and cached in KV permanently. Portfolio flattened from 4 category maps to single assets map with automatic migration of old format. Crypto, gold, and currency exchange disabled with "coming soon" message.
60 lines
1.7 KiB
JavaScript
60 lines
1.7 KiB
JavaScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { createStore } from "../../../src/db/create-store.js";
|
|
import { comingSoonMessage, resolveSymbol } from "../../../src/modules/trading/symbols.js";
|
|
import { makeFakeKv } from "../../fakes/fake-kv-namespace.js";
|
|
|
|
/** Stub global.fetch to return TCBS-like response */
|
|
function stubFetch(hasData = true) {
|
|
global.fetch = vi.fn(() =>
|
|
Promise.resolve({
|
|
ok: true,
|
|
json: () => Promise.resolve(hasData ? { data: [{ close: 25 }] } : { data: [] }),
|
|
}),
|
|
);
|
|
}
|
|
|
|
describe("trading/symbols", () => {
|
|
let db;
|
|
|
|
beforeEach(() => {
|
|
db = createStore("trading", { KV: makeFakeKv() });
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("resolves a valid VN stock ticker via TCBS", async () => {
|
|
stubFetch();
|
|
const result = await resolveSymbol(db, "TCB");
|
|
expect(result).toEqual({ symbol: "TCB", category: "stock", label: "TCB" });
|
|
expect(global.fetch).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it("caches resolved symbol in KV", async () => {
|
|
stubFetch();
|
|
await resolveSymbol(db, "TCB");
|
|
// second call should use cache, not fetch
|
|
await resolveSymbol(db, "TCB");
|
|
expect(global.fetch).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it("is case-insensitive", async () => {
|
|
stubFetch();
|
|
const result = await resolveSymbol(db, "tcb");
|
|
expect(result.symbol).toBe("TCB");
|
|
});
|
|
|
|
it("returns null for invalid ticker", async () => {
|
|
stubFetch(false);
|
|
const result = await resolveSymbol(db, "NOPE");
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("returns null for empty input", async () => {
|
|
const result = await resolveSymbol(db, "");
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("comingSoonMessage returns string", () => {
|
|
expect(comingSoonMessage()).toContain("coming soon");
|
|
});
|
|
});
|