132 lines
4.0 KiB
TypeScript
132 lines
4.0 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 header, exact total and separate card rows per account", () => {
|
|
renderGroup([
|
|
operation("1", { id: "broker", name: "Брокерский" }, "0.1"),
|
|
operation("2", { id: "iis", name: "ИИС" }, "0.2"),
|
|
]);
|
|
|
|
expect(screen.getByText("Купон · BOND")).toBeInTheDocument();
|
|
expect(screen.getByText("+0,3 ₽")).toBeInTheDocument();
|
|
|
|
const accounts = within(screen.getByRole("list", {
|
|
name: /Купон · BOND, Исполнено 14\.08\.2026.*, \+0,3 ₽/,
|
|
}));
|
|
|
|
expect(accounts.getByRole("listitem", { name: "Брокерский, +0,1 ₽" }))
|
|
.toHaveTextContent("Купон");
|
|
expect(accounts.getByRole("listitem", { name: "ИИС, +0,2 ₽" }))
|
|
.toHaveTextContent("Купон");
|
|
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();
|
|
});
|
|
|
|
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();
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|