Skip to content

Commit

Permalink
Clear the reports state from the store on logout
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxime Naulleau committed Jan 24, 2025
1 parent eb7d2f8 commit 40e3732
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 16 deletions.
2 changes: 1 addition & 1 deletion apps/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"types:check": "tsc --noEmit -p ./tsconfig.app.json",
"types:check:watch": "tsc --noEmit -p ./tsconfig.app.json --watch",
"preview": "vite preview",
"test": "DEBUG_PRINT_LIMIT=10000 vitest",
"test": "DEBUG_PRINT_LIMIT=1000 vitest",
"test:all": "vitest run",
"postinstall": "pnpm dsfr:build",
"dsfr:build": "react-dsfr update-icons",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { ReportBuilder } from "../../../../reports/core-logic/builders/Report.builder";
import { listReport } from "../../../../reports/core-logic/use-cases/report-listing/listReport.use-case";
import { retrieveReport } from "../../../../reports/core-logic/use-cases/report-retrieval/retrieveReport.use-case";
import { AppState } from "../../../../store/appState";
import { ReduxStore, initReduxStore } from "../../../../store/reduxStore";
import { ApiAuthenticationGateway } from "../../../adapters/secondary/gateways/ApiAuthentication.gateway";
Expand Down Expand Up @@ -33,20 +36,38 @@ describe("Logout", () => {

it("disconnects a user", async () => {
await store.dispatch(logout());
expect(store.getState()).toEqual<AppState>({
...initialState,
authentication: {
...initialState.authentication,
authenticated: false,
},
});
expectUnauthenticatedStore();
});

it("persists the disconnection", async () => {
authenticationStorageProvider._isAuthenticated = true;

store.dispatch(logout.fulfilled(undefined, "", undefined));

expect(await authenticationStorageProvider.isAuthenticated()).toBe(false);
});

it("clears the reports from the store on logout", async () => {
givenSomeReport();
await store.dispatch(logout());
expectUnauthenticatedStore();
});

const givenSomeReport = () => {
store.dispatch(listReport.fulfilled([aReportListSM], "", undefined));
store.dispatch(
retrieveReport.fulfilled(aReportRetrieveSM, "", aReportRetrieveSM.id),
);
};

const expectUnauthenticatedStore = () => {
expect(store.getState()).toEqual<AppState>({
...initialState,
authentication: {
...initialState.authentication,
authenticated: false,
},
});
};
});

const aReportListSM = new ReportBuilder().buildListSM();
const aReportRetrieveSM = new ReportBuilder().buildRetrieveSM();
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { AppState } from "../../../store/appState";
import { listReport } from "../use-cases/report-listing/listReport.use-case";
import { ReportListStateFilter } from "../../adapters/primary/labels/report-list-state-filter-labels.mapper";
import { logout } from "../../../authentication/core-logic/use-cases/logout/logout";

const initialState: AppState["reportList"] = { data: null, filters: {} };

Expand All @@ -18,6 +19,9 @@ const reportListSlice = createSlice({
builder.addCase(listReport.fulfilled, (state, action) => {
if (action.payload) state.data = action.payload;
});
builder.addCase(logout.fulfilled, (state) => {
state.data = null;
});
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { retrieveReport } from "../use-cases/report-retrieval/retrieveReport.use
import { updateReportRule } from "../use-cases/report-rule-update/updateReportRule.use-case";
import { updateReport } from "../use-cases/report-update/updateReport.use-case";
import { SummarySection } from "../../adapters/primary/labels/summary-labels";
import { logout } from "../../../authentication/core-logic/use-cases/logout/logout";

export const createReportOverviewSlice = (
summarySections: SummarySection[],
Expand Down Expand Up @@ -115,6 +116,10 @@ export const createReportOverviewSlice = (
);
}
});

builder.addCase(logout.fulfilled, (state) => {
state.byIds = null;
});
},
});
};
25 changes: 22 additions & 3 deletions apps/webapp/src/router/AppRouter.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import userEvent from "@testing-library/user-event";
import { Provider } from "react-redux";
import { ApiAuthenticationGateway } from "../authentication/adapters/secondary/gateways/ApiAuthentication.gateway";
import { FakeAuthenticationApiClient } from "../authentication/adapters/secondary/gateways/FakeAuthentication.client";
import { FakeAuthenticationStorageProvider } from "../authentication/adapters/secondary/providers/fakeAuthenticationStorage.provider";
import { AuthenticatedUserSM } from "../authentication/core-logic/gateways/Authentication.gateway";
import {
authenticate,
AuthenticateParams,
Expand All @@ -22,7 +24,8 @@ import { AppRouter } from "./AppRouter";
import { redirectOnLogin } from "./core-logic/listeners/redirectOnLogin.listeners";
import { redirectOnLogout } from "./core-logic/listeners/redirectOnLogout.listeners";
import { redirectOnRouteChange } from "./core-logic/listeners/redirectOnRouteChange.listeners";
import { AuthenticatedUserSM } from "../authentication/core-logic/gateways/Authentication.gateway";
import { sleep } from "../shared-kernel/core-logic/sleep";
import { storeDisconnectionOnLogout } from "../authentication/core-logic/listeners/logout.listeners";

const routeToComponentMap: RouteToComponentMap = {
login: () => <div>a login</div>,
Expand All @@ -35,21 +38,28 @@ describe("App Router Component", () => {
let authenticationGateway: ApiAuthenticationGateway;
let routerProvider: TypeRouterProvider;
let apiClient: FakeAuthenticationApiClient;
let authenticationStorageProvider: FakeAuthenticationStorageProvider;

beforeEach(() => {
apiClient = new FakeAuthenticationApiClient();
authenticationGateway = new ApiAuthenticationGateway(apiClient);
routerProvider = new TypeRouterProvider();
authenticationStorageProvider = new FakeAuthenticationStorageProvider();

store = initReduxStore(
{ authenticationGateway },
{ routerProvider },
{ routerProvider, authenticationStorageProvider },
{
routeToComponentFactory: useRouteToComponentFactory,
routeChangedHandler: useRouteChanged,
},

{ redirectOnRouteChange, redirectOnLogin, redirectOnLogout },
{
redirectOnRouteChange,
redirectOnLogin,
redirectOnLogout,
storeDisconnectionOnLogout,
},
routeToComponentMap,
);
});
Expand Down Expand Up @@ -127,6 +137,8 @@ describe("App Router Component", () => {
store.dispatch(retrieveReport.fulfilled(aNominationRetrieved, "", ""));
});

await waitListenersCompletion();

act(() => {
routerProvider.gotToReportOverview(aNominationRetrieved.id);
});
Expand All @@ -152,18 +164,25 @@ describe("App Router Component", () => {
givenAnAuthenticatedUser();
routerProvider.goToReportList();
});

await screen.findByText("a list");

await userEvent.click(
screen.getAllByText("Se déconnecter")[elementIndex]!,
);

await waitListenersCompletion();

await screen.findByText("a login");
},
);
});

const waitListenersCompletion = () => sleep(50);

const givenAnAuthenticatedUser = () => {
authenticationStorageProvider._isAuthenticated = true;
authenticationStorageProvider._user = user;
store.dispatch(authenticate.fulfilled(user, "", userCredentials));
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,24 @@ export const redirectOnRouteChange: Listener = (startAppListening) =>
predicate: (action) =>
action.type === routeChanged.type ||
action.type === authenticationStateInitFromStore.type,
effect: (
effect: async (
action,
{
getState,
extra: {
providers: { routerProvider },
providers: { routerProvider, authenticationStorageProvider },
},
},
) => {
if (!routerProvider) throw new Error("routerProvider is not defined");
const state = getState();
const { authenticated } = state.authentication;

// We use the stored authentication state because it could
// have changed in another tab or window.
const authenticated = authenticationStorageProvider
? await authenticationStorageProvider.isAuthenticated()
: state.authentication.authenticated;

const { current: currentHref } = state.router.hrefs;

if (action.type === authenticationStateInitFromStore.type) {
Expand Down

0 comments on commit 40e3732

Please sign in to comment.