feat(investments): warn and offer retry after exhausted read retries (WealthLedger/frontend#55) (#136)
This commit was merged in pull request #136.
This commit is contained in:
@@ -60,6 +60,10 @@ function configureTestAuth() {
|
||||
});
|
||||
}
|
||||
|
||||
// Automatic read retries wait 1s + 2s before the failure is final.
|
||||
const RETRIES_EXHAUSTED_MS = 6000;
|
||||
const TEST_MS = 10_000;
|
||||
|
||||
function renderAccountRoute(queryClient: QueryClient, accountId = "account-1") {
|
||||
configureTestAuth();
|
||||
|
||||
@@ -1255,6 +1259,110 @@ describe("AccountPage states", () => {
|
||||
expect(screen.getByText("Вторая")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it(
|
||||
"keeps cached totals, then warns and retries the same portfolio GET",
|
||||
{ timeout: TEST_MS },
|
||||
async () => {
|
||||
let isFailing = false;
|
||||
let requests = 0;
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/:accountId/portfolio", () => {
|
||||
requests += 1;
|
||||
if (isFailing)
|
||||
return HttpResponse.json(
|
||||
{ code: "TBANK_UNAVAILABLE" },
|
||||
{ status: 503 },
|
||||
);
|
||||
|
||||
return HttpResponse.json(resource(
|
||||
requests === 1
|
||||
? portfolio
|
||||
: { ...portfolio, totalsByCurrency: [{ currency: "RUB", value: "999" }] },
|
||||
{ resourceKey: "portfolio" },
|
||||
));
|
||||
}),
|
||||
);
|
||||
const queryClient = createTestQueryClient();
|
||||
renderAccountRoute(queryClient);
|
||||
await screen.findByText("Вторая");
|
||||
expect(screen.queryByRole("button", { name: "Повторить" }))
|
||||
.not.toBeInTheDocument();
|
||||
|
||||
isFailing = true;
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: portfolioQueryOptions("account-1").queryKey,
|
||||
});
|
||||
|
||||
const retry = await screen.findByRole(
|
||||
"button",
|
||||
{ name: "Повторить" },
|
||||
{ timeout: RETRIES_EXHAUSTED_MS },
|
||||
);
|
||||
|
||||
expect(screen.getByText("Не удалось обновить данные")).toBeInTheDocument();
|
||||
expect(screen.getByText("Вторая")).toBeInTheDocument();
|
||||
expect(screen.getByText("1 234,5 ₽")).toBeInTheDocument();
|
||||
// One cached read plus the three automatic attempts.
|
||||
expect(requests).toBe(4);
|
||||
|
||||
isFailing = false;
|
||||
fireEvent.click(retry);
|
||||
|
||||
expect(await screen.findByText("999 ₽")).toBeInTheDocument();
|
||||
expect(requests).toBe(5);
|
||||
expect(screen.queryByText("Не удалось обновить данные"))
|
||||
.not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("button", { name: "Повторить" }))
|
||||
.not.toBeInTheDocument();
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
"offers retry after an initial temporary failure and recovers in place",
|
||||
{ timeout: TEST_MS },
|
||||
async () => {
|
||||
let isFailing = true;
|
||||
let requests = 0;
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/:accountId/portfolio", () => {
|
||||
requests += 1;
|
||||
|
||||
return isFailing
|
||||
? HttpResponse.json({ code: "TBANK_UNAVAILABLE" }, { status: 503 })
|
||||
: HttpResponse.json(resource(portfolio, { resourceKey: "portfolio" }));
|
||||
}),
|
||||
);
|
||||
renderAccountRoute(createTestQueryClient());
|
||||
|
||||
const retry = await screen.findByRole(
|
||||
"button",
|
||||
{ name: "Повторить" },
|
||||
{ timeout: RETRIES_EXHAUSTED_MS },
|
||||
);
|
||||
|
||||
expect(requests).toBe(3);
|
||||
isFailing = false;
|
||||
fireEvent.click(retry);
|
||||
|
||||
expect(await screen.findByText("Вторая")).toBeInTheDocument();
|
||||
expect(requests).toBe(4);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(["NOT_FOUND", "UNAUTHORIZED"])(
|
||||
"does not offer a plain retry for %s after a cached portfolio",
|
||||
async (code) => {
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/:accountId/portfolio", () =>
|
||||
HttpResponse.json({ code }, { status: code === "NOT_FOUND" ? 404 : 401 })),
|
||||
);
|
||||
renderAccountRoute(createTestQueryClient());
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByRole("heading", { name: "Загрузка" })).not.toBeInTheDocument());
|
||||
expect(screen.queryByRole("button", { name: "Повторить" })).not.toBeInTheDocument();
|
||||
},
|
||||
);
|
||||
|
||||
it.each([503])(
|
||||
"preserves totals quietly through refresh error %i and success",
|
||||
async (status) => {
|
||||
|
||||
Reference in New Issue
Block a user