Add market watch and match hub workflows
这个提交包含在:
133
server/market.routes.test.ts
普通文件
133
server/market.routes.test.ts
普通文件
@@ -0,0 +1,133 @@
|
||||
import { describe, expect, it, vi, afterEach } from "vitest";
|
||||
import { appRouter } from "./routers";
|
||||
import type { TrpcContext } from "./_core/context";
|
||||
import * as db from "./db";
|
||||
|
||||
type AuthenticatedUser = NonNullable<TrpcContext["user"]>;
|
||||
|
||||
function createTestUser(overrides?: Partial<AuthenticatedUser>): AuthenticatedUser {
|
||||
return {
|
||||
id: 7,
|
||||
openId: "market-user-7",
|
||||
email: "market@example.com",
|
||||
name: "MarketTester",
|
||||
loginMethod: "username",
|
||||
role: "user",
|
||||
skillLevel: "beginner",
|
||||
trainingGoals: null,
|
||||
ntrpRating: 1.5,
|
||||
manualNtrpRating: null,
|
||||
manualNtrpCapturedAt: null,
|
||||
heightCm: null,
|
||||
weightKg: null,
|
||||
sprintSpeedScore: null,
|
||||
explosivePowerScore: null,
|
||||
agilityScore: null,
|
||||
enduranceScore: null,
|
||||
flexibilityScore: null,
|
||||
coreStabilityScore: null,
|
||||
shoulderMobilityScore: null,
|
||||
hipMobilityScore: null,
|
||||
assessmentNotes: null,
|
||||
totalSessions: 0,
|
||||
totalMinutes: 0,
|
||||
totalShots: 0,
|
||||
currentStreak: 0,
|
||||
longestStreak: 0,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
lastSignedIn: new Date(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function createMockContext(user: AuthenticatedUser | null): TrpcContext {
|
||||
return {
|
||||
user,
|
||||
sessionSid: user ? "market-session" : null,
|
||||
req: {
|
||||
protocol: "https",
|
||||
headers: {},
|
||||
} as TrpcContext["req"],
|
||||
res: {
|
||||
clearCookie: vi.fn(),
|
||||
cookie: vi.fn(),
|
||||
} as TrpcContext["res"],
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("market.watchRuleCreate", () => {
|
||||
it("creates a rule and queues a refresh task", async () => {
|
||||
const user = createTestUser();
|
||||
const caller = appRouter.createCaller(createMockContext(user));
|
||||
|
||||
vi.spyOn(db, "createRacketWatchRule").mockResolvedValueOnce(88);
|
||||
vi.spyOn(db, "createBackgroundTask").mockResolvedValueOnce("task-market-1");
|
||||
vi.spyOn(db, "getBackgroundTaskById").mockResolvedValueOnce({
|
||||
id: "task-market-1",
|
||||
userId: user.id,
|
||||
type: "market_watch_refresh",
|
||||
status: "queued",
|
||||
title: "Yonex ≤ ¥500 刷新",
|
||||
message: "监控规则已创建,后台开始抓取对应平台价格",
|
||||
progress: 0,
|
||||
payload: {},
|
||||
result: null,
|
||||
error: null,
|
||||
attempts: 0,
|
||||
maxAttempts: 3,
|
||||
workerId: null,
|
||||
runAfter: new Date(),
|
||||
lockedAt: null,
|
||||
startedAt: null,
|
||||
completedAt: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as Awaited<ReturnType<typeof db.getBackgroundTaskById>>);
|
||||
|
||||
const result = await caller.market.watchRuleCreate({
|
||||
brand: "Yonex",
|
||||
targetPrice: 500,
|
||||
modelKeyword: "98",
|
||||
pushEnabled: true,
|
||||
});
|
||||
|
||||
expect(result.ruleId).toBe(88);
|
||||
expect(result.taskId).toBeTruthy();
|
||||
expect(db.createRacketWatchRule).toHaveBeenCalledWith(expect.objectContaining({
|
||||
userId: user.id,
|
||||
brand: "Yonex",
|
||||
targetPrice: 500,
|
||||
pushEnabled: 1,
|
||||
isActive: 1,
|
||||
}));
|
||||
expect(db.createBackgroundTask).toHaveBeenCalledWith(expect.objectContaining({
|
||||
userId: user.id,
|
||||
type: "market_watch_refresh",
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("market.pushConfigUpdate", () => {
|
||||
it("updates the default webhook for admins", async () => {
|
||||
const admin = createTestUser({ role: "admin", id: 1, name: "Admin" });
|
||||
const caller = appRouter.createCaller(createMockContext(admin));
|
||||
|
||||
vi.spyOn(db, "updateAppSetting").mockResolvedValueOnce(undefined);
|
||||
vi.spyOn(db, "createAdminAuditLog").mockResolvedValueOnce(undefined);
|
||||
|
||||
const result = await caller.market.pushConfigUpdate({
|
||||
webhookUrl: "https://open.larksuite.com/open-apis/bot/v2/hook/demo",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ success: true });
|
||||
expect(db.updateAppSetting).toHaveBeenCalledWith("market_default_feishu_webhook", {
|
||||
value: "https://open.larksuite.com/open-apis/bot/v2/hook/demo",
|
||||
type: "string",
|
||||
});
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户