refactor: simplify frontend state and mutation boundaries
Frontend verify / commits (pull_request) Successful in 31s
Frontend verify / security (pull_request) Successful in 11s
Frontend verify / verify (pull_request) Successful in 9m1s
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 10s
Frontend verify / verify (push) Successful in 9m59s
Frontend verify / commits (pull_request) Successful in 31s
Frontend verify / security (pull_request) Successful in 11s
Frontend verify / verify (pull_request) Successful in 9m1s
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 10s
Frontend verify / verify (push) Successful in 9m59s
This commit was merged in pull request #44.
This commit is contained in:
@@ -102,6 +102,24 @@ const portfolio: Portfolio
|
||||
totalsByCurrency: [{ currency: "RUB", value: "1234.5" }],
|
||||
};
|
||||
|
||||
function position(
|
||||
overrides: Partial<Portfolio["positions"][number]>,
|
||||
): Portfolio["positions"][number] {
|
||||
return {
|
||||
absoluteReturn: null,
|
||||
averagePurchasePrice: null,
|
||||
currentValue: null,
|
||||
displayName: "Инструмент",
|
||||
figi: null,
|
||||
isin: null,
|
||||
logoName: null,
|
||||
quantity: "1",
|
||||
ticker: null,
|
||||
type: "STOCK",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const emptyRecentOperations: AccountPageRecentOperations = {
|
||||
state: "empty",
|
||||
to: "/accounts/account-1/operations",
|
||||
@@ -474,242 +492,106 @@ describe("AccountPage states", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("renders stock cards with logo fallback and signed unlabeled return", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
it.each(["STOCK", "BOND"] as const)(
|
||||
"renders %s logos, fallbacks and signed returns including zero",
|
||||
(type) => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps({
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
position({
|
||||
absoluteReturn: { currency: "RUB", value: "3" },
|
||||
averagePurchasePrice: null,
|
||||
currentValue: { currency: "RUB", value: "5" },
|
||||
displayName: "Абра",
|
||||
figi: "FIGI-A",
|
||||
isin: null,
|
||||
logoName: null,
|
||||
quantity: "1",
|
||||
ticker: null,
|
||||
type: "STOCK",
|
||||
},
|
||||
{
|
||||
displayName: "С логотипом",
|
||||
logoName: "dolg.png",
|
||||
type,
|
||||
}),
|
||||
position({
|
||||
absoluteReturn: { currency: "RUB", value: "2" },
|
||||
displayName: "Без логотипа",
|
||||
type,
|
||||
}),
|
||||
position({
|
||||
absoluteReturn: { currency: "RUB", value: "0" },
|
||||
averagePurchasePrice: null,
|
||||
currentValue: { currency: "RUB", value: "7" },
|
||||
displayName: "Кадабра",
|
||||
figi: "FIGI-B",
|
||||
isin: null,
|
||||
logoName: null,
|
||||
quantity: "1",
|
||||
ticker: null,
|
||||
type: "STOCK",
|
||||
},
|
||||
displayName: "Нулевой доход",
|
||||
type,
|
||||
}),
|
||||
],
|
||||
},
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("А")).toBeInTheDocument();
|
||||
expect(screen.getByText("+3 ₽")).toBeInTheDocument();
|
||||
expect(screen.getByText("0 ₽")).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Доход:/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("img", { name: "Абра" })).not.toBeInTheDocument();
|
||||
});
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("img", { name: "С логотипом" })).toHaveAttribute(
|
||||
"src", "https://invest-brands.cdn-tinkoff.ru/dolgx160.png",
|
||||
);
|
||||
expect(screen.getByText("Б")).toBeInTheDocument();
|
||||
expect(screen.getByText("Н")).toBeInTheDocument();
|
||||
expect(screen.getAllByRole("img")).toHaveLength(1);
|
||||
for (const value of ["+3 ₽", "+2 ₽", "0 ₽"])
|
||||
expect(screen.getByText(value)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Доход:/)).not.toBeInTheDocument();
|
||||
},
|
||||
);
|
||||
|
||||
it("groups stock supporting metrics into quiet single lines", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
it.each(["STOCK", "BOND"] as const)(
|
||||
"groups %s supporting metrics into quiet single lines",
|
||||
(type) => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps({
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
absoluteReturn: { currency: "RUB", value: "3" },
|
||||
averagePurchasePrice: { currency: "RUB", value: "11" },
|
||||
currentValue: { currency: "RUB", value: "10" },
|
||||
displayName: "Тихая акция",
|
||||
figi: "FIGI-QUIET",
|
||||
isin: "RU000QUIET1",
|
||||
logoName: null,
|
||||
quantity: "2",
|
||||
ticker: null,
|
||||
type: "STOCK",
|
||||
},
|
||||
],
|
||||
},
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Количество: 2 · RU000QUIET1")).not.toHaveAttribute(
|
||||
"data-line-clamp",
|
||||
);
|
||||
expect(
|
||||
screen.getByText("Средняя цена: 11 ₽ · Доля: 100 %"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
positions: [position({
|
||||
averagePurchasePrice: { currency: "RUB", value: "11" },
|
||||
currentValue: { currency: "RUB", value: "10" },
|
||||
isin: "RU000QUIET1",
|
||||
quantity: "2",
|
||||
type,
|
||||
})],
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("Количество: 2 · RU000QUIET1"))
|
||||
.not.toHaveAttribute("data-line-clamp");
|
||||
expect(screen.getByText("Средняя цена: 11 ₽ · Доля: 100 %"))
|
||||
.toBeInTheDocument();
|
||||
},
|
||||
);
|
||||
|
||||
it("uses the ticker only for stock cards and otherwise keeps the ISIN", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
absoluteReturn: null,
|
||||
averagePurchasePrice: null,
|
||||
currentValue: null,
|
||||
displayName: "Акция с тикером",
|
||||
figi: "FIGI-STOCK",
|
||||
isin: "STOCK-ISIN",
|
||||
logoName: null,
|
||||
quantity: "1",
|
||||
ticker: "SBER",
|
||||
type: "STOCK",
|
||||
},
|
||||
{
|
||||
absoluteReturn: null,
|
||||
averagePurchasePrice: null,
|
||||
currentValue: null,
|
||||
displayName: "Акция без тикера",
|
||||
figi: "FIGI-FALLBACK",
|
||||
isin: "FALLBACK-ISIN",
|
||||
logoName: null,
|
||||
quantity: "2",
|
||||
ticker: null,
|
||||
type: "STOCK",
|
||||
},
|
||||
{
|
||||
absoluteReturn: null,
|
||||
averagePurchasePrice: null,
|
||||
currentValue: null,
|
||||
displayName: "Облигация",
|
||||
figi: "FIGI-BOND",
|
||||
isin: "BOND-ISIN",
|
||||
logoName: null,
|
||||
quantity: "3",
|
||||
ticker: "OFZ",
|
||||
type: "BOND",
|
||||
},
|
||||
],
|
||||
},
|
||||
)}
|
||||
{...loadedProps({
|
||||
...portfolio,
|
||||
positions: [
|
||||
position({ isin: "STOCK-ISIN", ticker: "SBER" }),
|
||||
position({ isin: "FALLBACK-ISIN", quantity: "2" }),
|
||||
position({
|
||||
isin: "BOND-ISIN", quantity: "3", ticker: "OFZ", type: "BOND",
|
||||
}),
|
||||
],
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Количество: 1 · SBER")).toBeInTheDocument();
|
||||
expect(screen.queryByText("STOCK-ISIN")).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("Количество: 2 · FALLBACK-ISIN"),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("Количество: 3 · BOND-ISIN")).toBeInTheDocument();
|
||||
expect(screen.getByText("Количество: 2 · FALLBACK-ISIN"))
|
||||
.toBeInTheDocument();
|
||||
expect(screen.getByText("Количество: 3 · BOND-ISIN"))
|
||||
.toBeInTheDocument();
|
||||
expect(screen.queryByText("OFZ")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders bond cards with logo, fallback, and signed unlabeled return like stocks", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
absoluteReturn: { currency: "RUB", value: "2" },
|
||||
averagePurchasePrice: null,
|
||||
currentValue: { currency: "RUB", value: "50" },
|
||||
displayName: "Долг",
|
||||
figi: "FIGI-C",
|
||||
isin: "RU000C0XY1Z3",
|
||||
logoName: "dolg.png",
|
||||
quantity: "5",
|
||||
ticker: null,
|
||||
type: "BOND",
|
||||
},
|
||||
{
|
||||
absoluteReturn: { currency: "RUB", value: "0" },
|
||||
averagePurchasePrice: null,
|
||||
currentValue: null,
|
||||
displayName: "Купон",
|
||||
figi: "FIGI-D",
|
||||
isin: null,
|
||||
logoName: null,
|
||||
quantity: "1",
|
||||
ticker: null,
|
||||
type: "BOND",
|
||||
},
|
||||
],
|
||||
},
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("img", { name: "Долг" })).toHaveAttribute(
|
||||
"src",
|
||||
"https://invest-brands.cdn-tinkoff.ru/dolgx160.png",
|
||||
);
|
||||
expect(screen.getByText("К")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole("img", { name: "Купон" }),
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.getByText("+2 ₽")).toBeInTheDocument();
|
||||
expect(screen.getByText("0 ₽")).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Доход:/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders bond cards in expanded layout with bond-specific classes", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
absoluteReturn: { currency: "RUB", value: "50" },
|
||||
averagePurchasePrice: { currency: "RUB", value: "950" },
|
||||
currentValue: { currency: "RUB", value: "1000" },
|
||||
displayName: "Облигация 2030",
|
||||
figi: "FIGI-BOND",
|
||||
isin: "RU000B0ND123",
|
||||
logoName: null,
|
||||
quantity: "10",
|
||||
ticker: null,
|
||||
type: "BOND",
|
||||
},
|
||||
],
|
||||
},
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("О")).toBeInTheDocument();
|
||||
expect(screen.getByText("+50 ₽")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("Средняя цена: 950 ₽ · Доля: 100 %"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps other-position cards compact with labeled return and no logo", () => {
|
||||
renderPage(
|
||||
<AccountPageLoaded
|
||||
{...loadedProps(
|
||||
{
|
||||
...portfolio,
|
||||
positions: [
|
||||
{
|
||||
absoluteReturn: { currency: "RUB", value: "-5" },
|
||||
averagePurchasePrice: null,
|
||||
currentValue: { currency: "RUB", value: "30" },
|
||||
displayName: "Фонд",
|
||||
figi: "FIGI-E",
|
||||
isin: null,
|
||||
logoName: "fond.png",
|
||||
quantity: "3",
|
||||
ticker: null,
|
||||
type: "FUND",
|
||||
},
|
||||
],
|
||||
},
|
||||
)}
|
||||
{...loadedProps({
|
||||
...portfolio,
|
||||
positions: [position({
|
||||
absoluteReturn: { currency: "RUB", value: "-5" },
|
||||
displayName: "Фонд",
|
||||
logoName: "fond.png",
|
||||
type: "FUND",
|
||||
})],
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("Доход: -5 ₽")).toBeInTheDocument();
|
||||
|
||||
Reference in New Issue
Block a user