fix(i18n): localise session-change feedback outside private providers
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# Session-change message localisation — 2 November 2026
|
||||
|
||||
Implemented in the existing App invalidation branch. Reuses the existing `sessionChangedCleared` English/Bokmål catalogue message. The canonical document language (`nb-NO`, set by I18nProvider) selects Bokmål; other values safely select English. Reading it occurs only in the invalidated client branch. No provider, hook, storage access, request, dialog or private callback is retained to obtain the message.
|
||||
|
||||
Callers: root App renders Application only while valid; invalidation replaces it with a main alert and preserves the existing passive redirect to /login?sessionChanged=1. I18nProvider already publishes the current UI language to the document; generated-content language is unrelated. All routes, auth/CSRF/context tokens, abort logic and provider teardown remain unchanged. No new translation key or dependency.
|
||||
|
||||
RED: two new root-render tests failed against the previous literal English alert. PASSED after patch: 17 tests in session-boundary-message.test.tsx and session-boundary.test.ts, zero failures/pending, exit 0. New cases verify EN/NB feedback outside the private provider tree and zero API requests. Existing cases exercise cross-tab/cookie invalidation, abort/stale callbacks and session-context handling. These are local Jest/DOM tests; jsdom navigation is not browser redirect qualification.
|
||||
|
||||
PASSED: full TypeScript typecheck; scoped ESLint of App.tsx and the new test, zero warnings. Local ignored native Jest result: job-tracker-ui/.artifacts/session-boundary-message.json. No fresh full build/browser or complete security acceptance claimed. Rollback: revert the two source/test files in this package; no data changes. The attachment-label fix remains independently preserved.
|
||||
|
||||
The original literal-inventory App.tsx entry is now implemented; the inventory remains a historical snapshot. Final integrated security regression must run after relevant application changes are complete.
|
||||
@@ -29,6 +29,7 @@ import JobTable from "./components/JobTable";
|
||||
import NotificationsPopover from "./components/NotificationsPopover";
|
||||
import type { JobTableColumns } from "./components/JobTable";
|
||||
import { I18nProvider, useI18n } from "./i18n/I18nProvider";
|
||||
import { translations } from "./i18n/translations";
|
||||
import LoginPage from "./views/LoginPage";
|
||||
import LandingPage from "./views/LandingPage";
|
||||
import ForgotPasswordPage from "./views/ForgotPasswordPage";
|
||||
@@ -485,7 +486,7 @@ export default function App() {
|
||||
}, [invalidated]);
|
||||
// Unmount providers as well as routes: confirmations/toasts can retain private text and
|
||||
// callbacks. Passive effect navigation runs after the old forms' unload guards are removed.
|
||||
return invalidated ? <main role="alert">Session changed. Clearing this page…</main> : <Application />;
|
||||
return invalidated ? <main role="alert">{translations[document.documentElement.lang === "nb-NO" ? "nb" : "en"].sessionChangedCleared}</main> : <Application />;
|
||||
}
|
||||
|
||||
function Application() {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import App from "./App";
|
||||
import { I18nProvider } from "./i18n/I18nProvider";
|
||||
import { api } from "./api";
|
||||
|
||||
jest.mock("./sessionBoundary", () => ({
|
||||
isSessionInvalidated: () => true,
|
||||
SESSION_INVALIDATED_EVENT: "session-invalidated",
|
||||
}));
|
||||
jest.mock("./i18n/I18nProvider", () => ({
|
||||
...jest.requireActual("./i18n/I18nProvider"),
|
||||
I18nProvider: jest.fn(() => { throw new Error("Invalidated sessions must not mount providers"); }),
|
||||
}));
|
||||
|
||||
test.each([
|
||||
["en", "Your session changed. Private data and unsaved edits were cleared from this page. Sign in again to continue."],
|
||||
["nb-NO", "Økten din ble endret. Private data og ulagrede endringer ble fjernet fra denne siden. Logg inn igjen for å fortsette."],
|
||||
])("invalidated session shows %s feedback outside the private provider tree", (language, message) => {
|
||||
const previousLanguage = document.documentElement.lang;
|
||||
document.documentElement.lang = language;
|
||||
try {
|
||||
render(<App />);
|
||||
expect(screen.getByRole("alert")).toHaveTextContent(message);
|
||||
expect(I18nProvider).not.toHaveBeenCalled();
|
||||
expect(api.get).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
document.documentElement.lang = previousLanguage;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user