77 lines
2.2 KiB
TypeScript
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");
|
|
});
|
|
});
|