139 lines
4.6 KiB
TypeScript
139 lines
4.6 KiB
TypeScript
import { MantineProvider } from "@mantine/core";
|
||
import { render, screen, within } from "@testing-library/react";
|
||
import { MemoryRouter } from "react-router";
|
||
import { describe, expect, it } from "vitest";
|
||
|
||
import type { BrokerageOperation } from "../api/useBrokerageOperations";
|
||
|
||
import { OperationGroup } from "./OperationGroup";
|
||
|
||
function operation(
|
||
id: string,
|
||
account: { id: string; name: string },
|
||
value: null | string,
|
||
currency = "RUB",
|
||
): BrokerageOperation {
|
||
return {
|
||
account,
|
||
accruedInterest: null,
|
||
category: "income",
|
||
commission: null,
|
||
description: "Купон",
|
||
figi: "FIGI",
|
||
id,
|
||
instrumentType: "bond",
|
||
instrumentUid: "UID",
|
||
logoName: null,
|
||
occurredAt: "2026-08-14T10:00:00Z",
|
||
payment: value === null ? null : { currency, value },
|
||
price: null,
|
||
quantity: null,
|
||
ticker: "BOND",
|
||
type: "OPERATION_TYPE_COUPON",
|
||
};
|
||
}
|
||
|
||
function renderGroup(
|
||
operations: BrokerageOperation[],
|
||
isTotalVisible = true,
|
||
) {
|
||
return render(
|
||
<MantineProvider>
|
||
<MemoryRouter>
|
||
<ul>
|
||
<OperationGroup
|
||
entries={operations.map((operation, index) => ({
|
||
key: `${operation.id}-${index}`,
|
||
operation,
|
||
}))}
|
||
totalVisible={isTotalVisible}
|
||
/>
|
||
</ul>
|
||
</MemoryRouter>
|
||
</MantineProvider>,
|
||
);
|
||
}
|
||
|
||
describe("OperationGroup", () => {
|
||
it("shows the received coupon and positive totals in flat account rows", () => {
|
||
renderGroup([
|
||
{ ...operation("1", { id: "broker", name: "Брокерский" }, "0.1"), description: "Выплата купонов СФО ВТБ РКС Эталон 04" },
|
||
operation("2", { id: "iis", name: "ИИС" }, "0.2"),
|
||
]);
|
||
|
||
expect(screen.getByText("Выплата купонов СФО ВТБ РКС Эталон 04")).toBeInTheDocument();
|
||
expect(screen.getByText("+0,3 ₽")).toBeInTheDocument();
|
||
|
||
const accounts = within(screen.getByRole("list", {
|
||
name: /Выплата купонов СФО ВТБ РКС Эталон 04, Исполнено 14\.08\.2026.*, \+0,3 ₽/,
|
||
}));
|
||
|
||
expect(accounts.getByRole("listitem", { name: "Брокерский, +0,1 ₽" }))
|
||
.toHaveTextContent("Купон");
|
||
expect(accounts.getByText("+0,1 ₽")).toHaveClass(/positive/);
|
||
expect(accounts.getByRole("listitem", { name: "ИИС, +0,2 ₽" }))
|
||
.toHaveTextContent("Купон");
|
||
expect(accounts.getByText("+0,2 ₽")).toHaveClass(/positive/);
|
||
expect(accounts.getByRole("listitem", { name: "ИИС, +0,2 ₽" }))
|
||
.not.toHaveClass("EntryGroup_accountCardRow");
|
||
expect(accounts.queryByText(/Исполнено/)).not.toBeInTheDocument();
|
||
expect(accounts.queryByRole("link")).not.toBeInTheDocument();
|
||
});
|
||
|
||
it("announces the hidden total as unavailable", () => {
|
||
renderGroup([
|
||
operation("1", { id: "broker", name: "Брокерский" }, "100"),
|
||
operation("2", { id: "iis", name: "ИИС" }, null),
|
||
]);
|
||
|
||
expect(screen.getByRole("list", {
|
||
name: /Выплата купонов BOND, Исполнено .*Итог недоступен/,
|
||
})).toBeInTheDocument();
|
||
expect(screen.getByText("Итог недоступен")).toBeInTheDocument();
|
||
expect(screen.getByText("—")).not.toHaveClass(/positive/);
|
||
});
|
||
|
||
it.each(["0", "0.000"])(
|
||
"hides the whole total for a zero source amount (%s)",
|
||
(value) => {
|
||
renderGroup([
|
||
operation("1", { id: "broker", name: "Брокерский" }, value),
|
||
operation("2", { id: "iis", name: "ИИС" }, "100"),
|
||
]);
|
||
|
||
expect(screen.getAllByText("+100 ₽")).toHaveLength(1);
|
||
expect(screen.getByText("Итог недоступен")).toBeInTheDocument();
|
||
},
|
||
);
|
||
|
||
it("hides the total for incomplete data but keeps compensated zero", () => {
|
||
const { unmount } = renderGroup([
|
||
operation("1", { id: "broker", name: "Брокерский" }, "100"),
|
||
operation("2", { id: "iis", name: "ИИС" }, "100"),
|
||
], false);
|
||
|
||
expect(screen.queryByText("+200 ₽")).not.toBeInTheDocument();
|
||
unmount();
|
||
|
||
renderGroup([
|
||
operation("1", { id: "broker", name: "Брокерский" }, "100"),
|
||
operation("2", { id: "iis", name: "ИИС" }, "-100"),
|
||
]);
|
||
expect(screen.getByText("0 ₽")).toBeInTheDocument();
|
||
expect(screen.getByText("−100 ₽")).toHaveClass(/negative/);
|
||
});
|
||
|
||
it("renders repeated ids inside one group as separate rows", () => {
|
||
renderGroup([
|
||
operation("same", { id: "broker", name: "Брокерский" }, "10"),
|
||
operation("same", { id: "iis", name: "ИИС" }, "20"),
|
||
]);
|
||
|
||
expect(screen.getByText("+30 ₽")).toBeInTheDocument();
|
||
const accounts = within(screen.getByRole("list", { name: /Выплата купонов/ }));
|
||
expect(accounts.getAllByText("Брокерский")).toHaveLength(1);
|
||
expect(accounts.getAllByText("ИИС")).toHaveLength(1);
|
||
expect(accounts.getAllByRole("listitem")).toHaveLength(2);
|
||
});
|
||
});
|