219 lines
7.8 KiB
JavaScript
219 lines
7.8 KiB
JavaScript
import { render, screen } from "@testing-library/react";
|
|
import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
import { MemoryRouter } from "react-router-dom";
|
|
import App from "@/app/App.jsx";
|
|
import { AppProviders } from "@/app/providers.jsx";
|
|
import { adminRoutes } from "@/app/router/routeConfig";
|
|
import { setAccessToken } from "@/shared/api/request";
|
|
|
|
beforeEach(() => {
|
|
window.localStorage.clear();
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn(async () => new Response(JSON.stringify({ code: 401, message: "unauthorized" }), { status: 401 })),
|
|
);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
test("renders login route", async () => {
|
|
renderWithRoute("/login");
|
|
|
|
expect(await screen.findByText("HYApp 管理平台")).toBeInTheDocument();
|
|
});
|
|
|
|
test("redirects protected route to login when unauthenticated", async () => {
|
|
renderWithRoute("/system/users");
|
|
|
|
expect(await screen.findByText("HYApp 管理平台")).toBeInTheDocument();
|
|
});
|
|
|
|
test("renders resource list route with an authenticated session", async () => {
|
|
setAccessToken("test-token");
|
|
vi.mocked(fetch).mockImplementation(async (input) => {
|
|
const url = String(input);
|
|
if (url.includes("/v1/auth/refresh") || url.includes("/v1/auth/me")) {
|
|
return jsonResponse({
|
|
accessToken: "test-token",
|
|
permissions: ["resource:view"],
|
|
user: { userId: 1, username: "admin" },
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/apps")) {
|
|
return jsonResponse({ items: [{ appCode: "lalu", name: "Lalu" }], total: 1 });
|
|
}
|
|
if (url.includes("/v1/admin/navigation/menus")) {
|
|
return jsonResponse([]);
|
|
}
|
|
if (url.includes("/v1/admin/resources")) {
|
|
return jsonResponse({ items: [], page: 1, pageSize: 50, total: 0 });
|
|
}
|
|
return jsonResponse(null);
|
|
});
|
|
|
|
renderWithRoute("/resources");
|
|
|
|
expect((await screen.findAllByText("资源列表")).length).toBeGreaterThan(0);
|
|
});
|
|
|
|
test("renders cp config route with an authenticated session", async () => {
|
|
setAccessToken("test-token");
|
|
vi.mocked(fetch).mockImplementation(async (input) => {
|
|
const url = String(input);
|
|
if (url.includes("/v1/auth/refresh") || url.includes("/v1/auth/me")) {
|
|
return jsonResponse({
|
|
accessToken: "test-token",
|
|
permissions: ["cp-config:view"],
|
|
user: { userId: 1, username: "admin" },
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/apps")) {
|
|
return jsonResponse({ items: [{ appCode: "lalu", name: "Lalu" }], total: 1 });
|
|
}
|
|
if (url.includes("/v1/admin/navigation/menus")) {
|
|
return jsonResponse([]);
|
|
}
|
|
if (url.includes("/v1/admin/resource-groups")) {
|
|
return jsonResponse({ items: [], page: 1, pageSize: 50, total: 0 });
|
|
}
|
|
if (url.includes("/v1/admin/activity/cp/config")) {
|
|
return jsonResponse({
|
|
appCode: "lalu",
|
|
relations: [
|
|
cpRelationFixture("cp", "CP", 1),
|
|
cpRelationFixture("brother", "兄弟", 5),
|
|
cpRelationFixture("sister", "姐妹", 5),
|
|
],
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/activity/cp/relationships")) {
|
|
return jsonResponse({
|
|
items: [
|
|
{
|
|
relationshipId: "cp_1001_1002",
|
|
relationType: "cp",
|
|
status: "active",
|
|
userA: { displayUserId: "1001", userId: "1001", username: "A" },
|
|
userB: { displayUserId: "1002", userId: "1002", username: "B" },
|
|
intimacyValue: 12000,
|
|
level: 2,
|
|
durationDays: 3,
|
|
gift: { giftId: "rose", giftName: "Rose", giftCount: 1, giftValue: 100 },
|
|
formedAtMs: 1760000000000,
|
|
},
|
|
],
|
|
page: 1,
|
|
pageSize: 50,
|
|
total: 1,
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/activity/cp/applications")) {
|
|
return jsonResponse({ items: [], page: 1, pageSize: 50, total: 0 });
|
|
}
|
|
return jsonResponse(null);
|
|
});
|
|
|
|
renderWithRoute("/activities/cp-config");
|
|
|
|
expect((await screen.findAllByText("CP配置")).length).toBeGreaterThan(0);
|
|
expect(await screen.findByText("已加载 1 条 · 共 1 条")).toBeInTheDocument();
|
|
expect(screen.queryByText("共 1 条")).not.toBeInTheDocument();
|
|
});
|
|
|
|
test("renders cp weekly rank route with an authenticated session", async () => {
|
|
setAccessToken("test-token");
|
|
vi.mocked(fetch).mockImplementation(async (input) => {
|
|
const url = String(input);
|
|
if (url.includes("/v1/auth/refresh") || url.includes("/v1/auth/me")) {
|
|
return jsonResponse({
|
|
accessToken: "test-token",
|
|
permissions: ["cp-weekly-rank:view"],
|
|
user: { userId: 1, username: "admin" },
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/apps")) {
|
|
return jsonResponse({ items: [{ appCode: "lalu", name: "Lalu" }], total: 1 });
|
|
}
|
|
if (url.includes("/v1/admin/navigation/menus")) {
|
|
return jsonResponse([]);
|
|
}
|
|
if (url.includes("/v1/admin/resource-groups")) {
|
|
return jsonResponse({ items: [], page: 1, pageSize: 50, total: 0 });
|
|
}
|
|
if (url.includes("/v1/admin/activity/cp-weekly-rank/config")) {
|
|
return jsonResponse({
|
|
activityCode: "cp_weekly_rank",
|
|
enabled: true,
|
|
relationType: "cp",
|
|
rewards: [
|
|
{ rankNo: 1, resourceGroupId: 1001 },
|
|
{ rankNo: 2, resourceGroupId: 1002 },
|
|
{ rankNo: 3, resourceGroupId: 1003 },
|
|
],
|
|
topCount: 3,
|
|
});
|
|
}
|
|
if (url.includes("/v1/admin/activity/cp-weekly-rank/settlements")) {
|
|
return jsonResponse({
|
|
items: [
|
|
{
|
|
periodStartMs: 1760918400000,
|
|
periodEndMs: 1761523200000,
|
|
rankNo: 1,
|
|
relationshipId: "cp_1001_1002",
|
|
score: 12000,
|
|
settlementId: "settlement_1",
|
|
status: "granted",
|
|
userId: "1001",
|
|
},
|
|
],
|
|
total: 1,
|
|
});
|
|
}
|
|
return jsonResponse(null);
|
|
});
|
|
|
|
renderWithRoute("/activities/cp-weekly-rank");
|
|
|
|
expect((await screen.findAllByText("CP排行活动")).length).toBeGreaterThan(0);
|
|
expect(await screen.findByText("已发放")).toBeInTheDocument();
|
|
});
|
|
|
|
test("admin routes declare menu code and permission", () => {
|
|
expect(adminRoutes.length).toBeGreaterThan(0);
|
|
expect(adminRoutes.every((route) => route.menuCode && route.permission)).toBe(true);
|
|
});
|
|
|
|
function renderWithRoute(route) {
|
|
return render(
|
|
<AppProviders>
|
|
<MemoryRouter initialEntries={[route]}>
|
|
<App />
|
|
</MemoryRouter>
|
|
</AppProviders>,
|
|
);
|
|
}
|
|
|
|
function jsonResponse(data) {
|
|
return new Response(JSON.stringify({ code: 0, data }), { status: 200 });
|
|
}
|
|
|
|
function cpRelationFixture(relationType, displayName, maxCountPerUser) {
|
|
return {
|
|
relationType,
|
|
displayName,
|
|
maxCountPerUser,
|
|
applicationExpireHours: 24,
|
|
status: "active",
|
|
levels: Array.from({ length: 5 }, (_, index) => ({
|
|
level: index + 1,
|
|
intimacyThreshold: index * 10000,
|
|
rewardResourceGroupId: 0,
|
|
levelIconUrl: "",
|
|
status: "active",
|
|
})),
|
|
};
|
|
}
|