hyapp-admin-platform/src/features/host-org/pages/HostWithdrawalsPage.test.jsx
2026-07-02 14:21:32 +08:00

176 lines
6.0 KiB
JavaScript

import { fireEvent, render, screen } from "@testing-library/react";
import { afterEach, expect, test, vi } from "vitest";
import { HostWithdrawalsPage } from "./HostWithdrawalsPage.jsx";
import { useHostWithdrawalsPage } from "@/features/host-org/hooks/useHostWithdrawalsPage.js";
const mocks = vi.hoisted(() => ({
changeIdentity: vi.fn(),
changeKeyword: vi.fn(),
changeRecordType: vi.fn(),
changeStatus: vi.fn(),
changeTimeRange: vi.fn(),
dataTable: vi.fn(),
resetFilters: vi.fn(),
}));
vi.mock("@/features/host-org/hooks/useHostWithdrawalsPage.js", () => ({
useHostWithdrawalsPage: vi.fn(),
}));
vi.mock("@/shared/ui/DataTable.jsx", () => ({
DataTable: (props) => {
mocks.dataTable(props);
return (
<div data-testid="host-withdrawals-table">
{props.columns.map((column) => (
<div data-testid={`column-${column.key}`} key={column.key}>
{column.label}
</div>
))}
{props.items.map((item) => (
<div data-testid={`row-${item.id}`} key={item.id}>
{props.columns.map((column) => (
<div key={column.key}>{column.render ? column.render(item) : item[column.key]}</div>
))}
</div>
))}
</div>
);
},
}));
vi.mock("@/shared/ui/TimeRangeFilter.jsx", () => ({
TimeRangeFilter: ({ onChange }) => (
<button type="button" onClick={() => onChange({ endMs: "2000", startMs: "1000" })}>
时间
</button>
),
}));
afterEach(() => {
vi.clearAllMocks();
});
test("host withdrawals page renders salary transfer and withdrawal records", () => {
vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture());
render(<HostWithdrawalsPage />);
expect(screen.getByText("工资转币商")).toBeInTheDocument();
expect(screen.getByText("提现申请")).toBeInTheDocument();
expect(screen.getByText("Host")).toBeInTheDocument();
expect(screen.getByText("BD Leader/Admin")).toBeInTheDocument();
expect(screen.getByText("$123.45")).toBeInTheDocument();
expect(screen.getByText("1,112")).toBeInTheDocument();
expect(screen.getByText("已完成")).toBeInTheDocument();
expect(screen.getByText("待审核")).toBeInTheDocument();
expect(screen.getByText("USDT-TRC20")).toBeInTheDocument();
expect(screen.getByText("TRON9ADDRESS")).toBeInTheDocument();
expect(screen.getByText("tx-salary-1")).toBeInTheDocument();
expect(screen.getByText("9")).toBeInTheDocument();
});
test("host withdrawals filters are wired to the page hook", () => {
vi.mocked(useHostWithdrawalsPage).mockReturnValue(pageFixture({ hasActiveFilters: true }));
render(<HostWithdrawalsPage />);
const props = mocks.dataTable.mock.calls.at(-1)?.[0];
props.columns.find((column) => column.key === "recordType").filter.onChange("withdrawal");
props.columns.find((column) => column.key === "identity").filter.onChange("bd_leader_admin");
props.columns.find((column) => column.key === "sourceUser").filter.onChange("168557");
props.columns.find((column) => column.key === "status").filter.onChange("approved");
fireEvent.click(screen.getByRole("button", { name: "时间" }));
fireEvent.click(screen.getByRole("button", { name: "重置" }));
expect(mocks.changeRecordType).toHaveBeenCalledWith("withdrawal");
expect(mocks.changeIdentity).toHaveBeenCalledWith("bd_leader_admin");
expect(mocks.changeKeyword).toHaveBeenCalledWith("168557");
expect(mocks.changeStatus).toHaveBeenCalledWith("approved");
expect(mocks.changeTimeRange).toHaveBeenCalledWith({ endMs: "2000", startMs: "1000" });
expect(mocks.resetFilters).toHaveBeenCalled();
});
function pageFixture(patch = {}) {
return {
abilities: { canView: true },
changeIdentity: mocks.changeIdentity,
changeKeyword: mocks.changeKeyword,
changeRecordType: mocks.changeRecordType,
changeStatus: mocks.changeStatus,
changeTimeRange: mocks.changeTimeRange,
data: {
items: [salaryTransferFixture(), withdrawalFixture()],
page: 1,
pageSize: 50,
total: 2,
},
error: null,
hasActiveFilters: false,
identity: "",
keyword: "",
loading: false,
page: 1,
recordType: "",
reload: vi.fn(),
resetFilters: mocks.resetFilters,
setPage: vi.fn(),
status: "",
timeRange: { endMs: "", startMs: "" },
...patch,
};
}
function salaryTransferFixture() {
return {
coinAmount: 1112,
commandId: "cmd-salary-1",
createdAtMs: 1780000000000,
id: "salary_transfer:101",
identity: "host",
recordType: "salary_transfer",
salaryAssetType: "HOST_SALARY_USD",
sellerUser: {
displayUserId: "168556",
userId: "3001",
username: "Coin Seller",
},
sellerUserId: "3001",
sourceUser: {
displayUserId: "168577",
userId: "1001",
username: "Raj",
},
sourceUserId: "1001",
status: "completed",
transactionId: "tx-salary-1",
updatedAtMs: 1780000000000,
usdMinorAmount: 12345,
};
}
function withdrawalFixture() {
return {
applicationId: "9",
coinAmount: 0,
commandId: "freeze-cmd-9",
createdAtMs: 1780000001000,
freezeTransactionId: "freeze-tx-9",
id: "withdrawal:9",
identity: "bd_leader_admin",
recordType: "withdrawal",
salaryAssetType: "ADMIN_SALARY_USD",
sourceUser: {
displayUserId: "481479",
userId: "2002",
username: "Mao",
},
sourceUserId: "2002",
status: "pending",
updatedAtMs: 1780000001000,
usdMinorAmount: 5000,
withdrawAddress: "TRON9ADDRESS",
withdrawMethod: "USDT-TRC20",
};
}