Files
stock-agent/tests/report.test.ts

77 lines
2.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { generateDailyReport } from "../src/agent/report";
import type { MarketDataProvider, WatchStock } from "../src/shared/types";
const watchlist: WatchStock[] = [
{
id: "AAPL",
symbol: "AAPL",
display: "AAPL",
market: "US",
name: "Apple",
addedAt: "2026-05-11T00:00:00.000Z"
},
{
id: "00700.HK",
symbol: "00700",
display: "00700.HK",
market: "HK",
name: "Tencent",
addedAt: "2026-05-11T00:00:00.000Z"
}
];
const provider: MarketDataProvider = {
async snapshot(stock) {
if (stock.display === "AAPL") {
return {
price: 100,
currency: "USD",
pe: 12,
forwardPe: 11,
revenueGrowth: 0.08,
profitGrowth: 0.05,
nextEarningsDate: "2026-05-13",
peers: [
{ display: "MSFT", pe: 28 },
{ display: "GOOGL", pe: 24 }
],
news: [{ title: "Apple supplier raises shipment guidance", url: "https://example.test/aapl" }]
};
}
return {
price: 380,
currency: "HKD",
pe: 22,
forwardPe: 20,
revenueGrowth: 0.02,
profitGrowth: -0.01,
nextEarningsDate: "2026-06-30",
peers: [{ display: "9988.HK", pe: 18 }],
news: []
};
}
};
describe("generateDailyReport", () => {
it("ranks earnings, related news, valuation mismatch, and buy advice across markets", async () => {
const report = await generateDailyReport(watchlist, provider, new Date("2026-05-11T00:00:00.000Z"));
expect(report.generatedAt).toBe("2026-05-11T00:00:00.000Z");
expect(report.items).toHaveLength(2);
expect(report.summary).toContain("US: 1");
expect(report.summary).toContain("HK: 1");
const apple = report.items.find((item) => item.stock.display === "AAPL");
expect(apple?.earnings.status).toBe("soon");
expect(apple?.valuation.label).toBe("discount");
expect(apple?.recommendation.action).toBe("buy_watch");
expect(apple?.news[0]?.title).toContain("supplier");
const tencent = report.items.find((item) => item.stock.display === "00700.HK");
expect(tencent?.valuation.label).toBe("premium");
expect(tencent?.recommendation.action).toBe("hold");
});
});