fix(ux): preserve localized save errors and current language retries
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import React from "react";
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
|
||||
|
||||
import { api } from "./api";
|
||||
import { I18nProvider, useI18n } from "./i18n/I18nProvider";
|
||||
import { ToastProvider } from "./toast";
|
||||
|
||||
function Probe() {
|
||||
const { language, setLanguage, hydrateLanguage, t } = useI18n();
|
||||
@@ -44,3 +45,52 @@ test("hydrates an authenticated server preference without writing it back", () =
|
||||
expect(window.localStorage.getItem("uiLanguage")).toBe("nb");
|
||||
expect(api.put).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test.each([
|
||||
["Norsk", "nb", "nb-NO", "Språket er endret på denne enheten, men kunne ikke lagres på kontoen din.", "Prøv igjen"],
|
||||
["English", "en", "en", "The language changed on this device, but your account preference could not be saved.", "Retry"],
|
||||
])("a failed account language save keeps the local choice and offers a localized retry: %s", async (button, local, remote, message, retry) => {
|
||||
(api.put as jest.Mock).mockRejectedValueOnce({ response: { status: 500, data: "Internal database detail" } });
|
||||
render(<ToastProvider><I18nProvider><Probe /></I18nProvider></ToastProvider>);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: button }));
|
||||
expect(screen.getByLabelText("language")).toHaveTextContent(local);
|
||||
expect(window.localStorage.getItem("uiLanguage")).toBe(local);
|
||||
expect(document.documentElement.lang).toBe(remote);
|
||||
const alert = await screen.findByRole("alert");
|
||||
expect(alert).toHaveTextContent(message);
|
||||
expect(alert).not.toHaveTextContent("Internal database detail");
|
||||
expect(api.put).toHaveBeenCalledTimes(1);
|
||||
expect(api.put).toHaveBeenLastCalledWith("/auth/preferences/language", { language: remote });
|
||||
|
||||
fireEvent.click(within(alert).getByRole("button", { name: retry }));
|
||||
await waitFor(() => expect(api.put).toHaveBeenCalledTimes(2));
|
||||
expect(api.put).toHaveBeenLastCalledWith("/auth/preferences/language", { language: remote });
|
||||
await waitFor(() => expect(screen.queryByRole("alert")).not.toBeInTheDocument());
|
||||
expect(screen.getByLabelText("language")).toHaveTextContent(local);
|
||||
});
|
||||
|
||||
test("a delayed language-save failure cannot offer a retry for a newer successful choice", async () => {
|
||||
let rejectOld!: (error: Error) => void;
|
||||
(api.put as jest.Mock).mockImplementationOnce(() => new Promise((_, reject) => { rejectOld = reject; }));
|
||||
render(<ToastProvider><I18nProvider><Probe /></I18nProvider></ToastProvider>);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Norsk" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "English" }));
|
||||
await act(async () => { rejectOld(new Error("offline")); });
|
||||
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
|
||||
expect(screen.getByLabelText("language")).toHaveTextContent("en");
|
||||
expect(api.put).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test("a previously delivered language retry cannot reverse a newer choice", async () => {
|
||||
(api.put as jest.Mock).mockRejectedValueOnce(new Error("offline"));
|
||||
render(<ToastProvider><I18nProvider><Probe /></I18nProvider></ToastProvider>);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Norsk" }));
|
||||
const alert = await screen.findByRole("alert");
|
||||
const retry = within(alert).getByRole("button", { name: "Prøv igjen" });
|
||||
fireEvent.click(screen.getByRole("button", { name: "English" }));
|
||||
fireEvent.click(retry);
|
||||
expect(screen.getByLabelText("language")).toHaveTextContent("en");
|
||||
expect(window.localStorage.getItem("uiLanguage")).toBe("en");
|
||||
expect(api.put).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user