176 lines
6.0 KiB
JavaScript
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",
|
|
};
|
|
}
|