⚠️ Version préliminaire de la documentation. Peut contenir des coquilles et des imprécisions.
EN | DE | FR | FR | ES

Commentaire : git diff origin/develop -- reducers/authentication.test.js

Date : 2026-05-08

Commits comparés :

Réducteur (ancien et nouveau — identique) : reducers/authentication.js (40 lignes) — n'a pas changé entre les commits (créé le 2019-02-28).

Remarque : Les liens vers le nouveau code (SHA e67067aa7) pointent vers le fork MaurerAnton/projectforge (branche draft43npm). Les liens vers l'ancien code (SHA 9ed5fbe0f) pointent vers le dépôt principal micromata/projectforge (develop).

Section 1 : État initial (lignes 1–10)

@@ -1,10 +1,10 @@
1 import reducer from './authentication';
2
3 const exampleError = 'Uncool error message.';
4
5 Object.freeze(exampleError);
6+
7+const initialState = {
8+ loading: true,
9+ error: null,
10+ user: null,
11+};
6
7 describe('reducer', () => {
8 it('initial state', () => {
9 expect(reducer(undefined, {}))
10- .toEqual({
11- loading: false,
12- error: null,
13- loggedIn: false,
14- });
+ .toEqual(initialState);

1. initialState extrait dans une constante.

Ancienne version : objet codé en dur dans le test it('initial state') sous la forme { loading: false, error: null, loggedIn: false }.

Nouvelle version : constante initialState, qui en plus correspond exactement à initialState défini dans le réducteur [reducers/authentication.js:3].

2. loading: falseloading: true.

Ancien init : loading: false — l'utilisateur n'est pas connecté, le spinner ne tourne pas.

Nouvel init : loading: true — au chargement de l'application, loadUserStatus() est appelé immédiatement pour vérifier la session. L'état initial devient « recherche de l'utilisateur ». Cette modification vient du réducteur commit 8b3b44be7 (2020-03-18).

3. loggedIn: falseuser: null. CHANGEMENT MAJEUR DE LA STRUCTURE DE L'ÉTAT (STATE SHAPE).

{/* Ancienne forme */}
{ loading: boolean, error: string|null, loggedIn: boolean }
{/* Nouvelle forme */}
{ loading: boolean, error: string|null, user: object|null }

Section 2 : Action inconnue (lignes 11–21)

@@ -12,19 +12,14 @@
17- it('unknown action', () => {
13+ it('unknown action returns current state', () => {
18 const state = {
19- loading: true,
20- error: null,
21- loggedIn: false,
+ loading: false,
+ error: null,
+ user: { name: 'test' },
22 };
23
24 Object.freeze(state);
25
26- expect(reducer(state, {
27- type: 'UNKNOWN_ACTION',
28- }))
+ expect(reducer(state, { type: 'UNKNOWN_ACTION' }))
29 .toEqual(state);
30 });
31 });

unknown actionunknown action returns current state. Description explicite : « le réducteur ne connaît pas cette action → il retourne l'état actuel sans modification ». L'ancien test ne précisait pas ce qu'il vérifiait.

Modification de l'état d'entrée : l'ancien test vérifiait { loading: true, loggedIn: false }, le nouveau vérifie { loading: false, user: { name: 'test' } }. Un état d'utilisateur connecté a été choisi pour s'assurer que user n'est pas réinitialisé lors d'une action inconnue — ce qui garantit la pureté de la fonction [Redux reducers].

Formatage : l'ancien appel était sur 3 lignes, le nouveau tient sur une seule ligne. Uniquement du style.

Object.freeze(state) [MDN] — protection contre la mutation : si le réducteur modifiait l'état transmis (violant le principe de pureté), le test échouerait avec une erreur.

Section 3 : USER_LOGIN_BEGIN — 2 tests supprimés, 1 modifié (lignes 22–62)

@@ -33,57 +28,40 @@
33-describe('handles USER_LOGIN_BEGIN', () => {
34- it('fresh state', () => {
35- const state = {
36- loading: false,
37- error: null,
38- loggedIn: false,
39- };
40-
41- Object.freeze(state);
42-
43- expect(reducer(state, {
44- type: 'USER_LOGIN_BEGIN',
45- }))
46- .toEqual({
47- loading: true,
48- error: null,
49- loggedIn: false,
50- });
51- });
52-
53- it('error state', () => {
54- const state = {
55- loading: false,
56- error: exampleError,
57- loggedIn: false,
58- };
59-
60- Object.freeze(state);
61-
62- expect(reducer(state, {
63- type: 'USER_LOGIN_BEGIN',
64- }))
65- .toEqual({
66- loading: true,
67- error: null,
68- loggedIn: false,
69- });
70- });
71-
72- it('loggedIn state', () => {
73- const state = {
74- loading: false,
75- error: null,
76- loggedIn: false,
77- };
78-
79- Object.freeze(state);
80-
81- expect(reducer(state, {
82- type: 'USER_LOGIN_BEGIN',
83- }))
84- .toEqual({
85- loading: true,
86- error: null,
87- loggedIn: false,
88- });
89- });
90-});

describe('handles USER_LOGIN_BEGIN')describe('USER_LOGIN_BEGIN'). Le mot handles a été retiré — dans le nouveau style, chaque describe nomme l'action littéralement. [nouveau fichier]

2 des 3 tests supprimés.

« fresh state » — vérifiait la transition de { loading: false, error: null, ... } vers { loading: true, error: null, ... }. [ligne 34]

« error state » — vérifiait la transition de { loading: false, error: exampleError, ... } vers { loading: true, error: null, ... }. [ligne 53]

Les deux tests vérifiaient la même chose : error est réinitialisé à null, loading passe à true. La différence résidait dans l'error initial (null vs chaîne). C'était redondant — un seul test couvre les deux cas.

« loggedIn state » — entrée : { loading: false, error: null, loggedIn: false } — identique à « fresh state ». Probablement une coquille (il aurait dû y avoir loggedIn: true). [ligne 72]

Un seul nouveau test : 'resets to loading with null user' [nouveau fichier]

Section 4 : USER_LOGIN_SUCCESS — 1 test supprimé, 1 modifié (lignes 63–109)

@@ -91,29 +61,18 @@
92-describe('handles USER_LOGIN_SUCCESS', () => {
93- it('loading state', () => {
+describe('USER_LOGIN_SUCCESS', () => {
+ it('sets user and clears loading/error', () => {
94 const state = {
95 loading: true,
96 error: null,
97- loggedIn: false,
+ user: null,
98 };
99
100 Object.freeze(state);
101
102 expect(reducer(state, {
103 type: 'USER_LOGIN_SUCCESS',
+ payload,
106 }))
107
108- .toEqual({
109- loading: false,
110- error: null,
111- loggedIn: true,
112- });
113- });
114-
115- it('weird state', () => {
116- const state = {
117- loading: false,
118- error: exampleError,
119- loggedIn: true,
120- };
121-
122- Object.freeze(state);
123-
124- expect(reducer(state, {
125- type: 'USER_LOGIN_SUCCESS',
126- }))
127- .toEqual({
128- loading: false,
129- error: null,
130- loggedIn: true,
131- });
132- });
133-});

Ancien test « loading state » — SANS PAYLOAD.

Appelait { type: 'USER_LOGIN_SUCCESS' } sans troisième argument (payload). L'ancien réducteur supposément ne faisait que définir loggedIn: true et loading: false — les données utilisateur n'étaient pas conservées.

Suppression du test « weird state » : { loading: false, error: exampleError, loggedIn: true } — combinaison absurde : une erreur existe alors que l'utilisateur est connecté. [ligne 115]

Nouveau test — avec un payload réel :

const payload = {
  user: { name: 'testuser' },
  version: '1.0',
  buildTimestamp: '2024-01-01',
  alertMessage: 'Welcome',
};

Pourquoi exactement ces champs : le réducteur dans authentication.js:18-27 attend un payload avec quatre champs — chacun est écrit directement dans l'état :

Champ du payload→ Champ de l'étatLigneUtilité
payload.userstate.userL23objet utilisateur (nom, admin ?)
payload.versionstate.versionL24version de la build
payload.buildTimestampstate.buildTimestampL25date de compilation
payload.alertMessagestate.alertMessageL26message système (MOTD)

L'ancien test ne transmettait aucun payload — il ne vérifiait donc aucun de ces champs. Le nouveau test valide la correspondance complète.

loggedIn: trueuser: { name: 'testuser' }. Les composants vérifient state.user !== null au lieu de state.loggedIn === true — dans le cadre de la migration vers les react-redux hooks.

Section 5 : USER_LOGIN_FAILURE — 1 test supprimé, 1 modifié (lignes 110–148)

@@ -133,47 +94,30 @@
133-describe('handles USER_LOGIN_FAILURE', () => {
134- it('loading state', () => {
+describe('USER_LOGIN_FAILURE', () => {
+ it('sets error and clears user/loading', () => {
135 const state = {
136 loading: true,
137 error: null,
138- loggedIn: false,
+ user: { name: 'old' },
139 };
140
141 Object.freeze(state);
142
143 expect(reducer(state, {
144 type: 'USER_LOGIN_FAILURE',
145- payload: {
146- error: exampleError,
147- },
+ payload: { error: exampleError },
148 }))
149 .toEqual({
150 loading: false,
151 error: exampleError,
152- loggedIn: false,
+ user: null,
153 });
154- });
155-
156- it('weird state', () => {
157- const state = {
158- loading: false,
159- error: exampleError,
160- loggedIn: true,
161- };
162-
163- Object.freeze(state);
164-
165- expect(reducer(state, {
166- type: 'USER_LOGIN_FAILURE',
167- payload: {
168- error: exampleError,
169- },
170- }))
171- .toEqual({
172- loading: false,
173- error: exampleError,
174- loggedIn: false,
175- });
176- });
177-});

Changements analogues : handles USER_LOGIN_FAILUREUSER_LOGIN_FAILURE, suppression de « weird state », un seul test au lieu de deux.

Nouvelle description : 'sets error and clears user/loading' — explicite sur le comportement : l'erreur est conservée, l'utilisateur est réinitialisé, le spinner est retiré.

loggedIn: falseuser: null. Le champ user passe à null en cas d'erreur. C'est plus strict que loggedIn: false : l'ancienne approche conservait les données utilisateur dans l'état (elle indiquait simplement qu'il n'était plus connecté), la nouvelle les supprime complètement. Correspond à case USER_LOGIN_FAILURE: user: null.

Formatage du payload : { error: exampleError } sur une seule ligne au lieu de trois. Uniquement du style.

Section 6 : Suppression de describe('handles USER_LOGOUT') (lignes 178–216)

@@ -178,39 +120,12 @@
178-describe('handles USER_LOGOUT', () => {
179- const expectedState = {
180- loading: false,
181- error: null,
182- loggedIn: false,
183- };
184-
185- Object.freeze(expectedState);
186-
187- it('logged in state', () => {
188- const state = {
189- loading: false,
190- error: null,
191- loggedIn: true,
192- };
193-
194- Object.freeze(state);
195-
196- expect(reducer(state, {
197- type: 'USER_LOGOUT',
198- }))
199- .toEqual(expectedState);
200- });
201-
202- it('weird state', () => {
203- const state = {
204- loading: true,
205- error: exampleError,
206- loggedIn: false,
207- };
208-
209- Object.freeze(state);
210-
211- expect(reducer(state, {
212- type: 'USER_LOGOUT',
213- }))
214- .toEqual(expectedState);
215- });
216-});

Supprimé en entier (2 tests, ~40 lignes).

Il vérifiait que USER_LOGOUT réinitialisait { loggedIn: true } en { loggedIn: false } et effaçait l'erreur.

Raisons de la suppression :

  1. L'action USER_LOGOUT n'existe plus — elle n'est plus exportée depuis authentication.js (seuls USER_LOGIN_BEGIN, USER_LOGIN_FAILURE, USER_LOGIN_SUCCESS sont importés).
  2. USER_LOGOUT est absent du switch du réducteur [seulement 3 cases].
  3. La fonctionnalité de déconnexion est couverte par USER_LOGIN_BEGIN — les deux réinitialisent l'état.
  4. Le test importait USER_LOGOUT depuis une exportation inexistante — le test était cassé.

Historique : USER_LOGOUT a été supprimé des sources dans le commit 7c60c2fbb (2019-07-13, « implemented logout check ») — des actions/authentication.js et du réducteur. Mais le test n'a pas été mis à jour — il a continué à importer et tester USER_LOGOUT pendant encore 7 ans. Dans le nouveau réducteur, la déconnexion n'est plus qu'un simple USER_LOGIN_BEGIN (réinitialisation vers l'état de chargement).

Glossaire

Réducteur Redux
Fonction pure : (state, action) → nouvel état. Aucun effet de bord, aucune mutation. Object.freeze(state) dans le test garantit ce principe : si le réducteur modifie accidentellement l'état transmis, le test échouera. [Documentation Redux]
Structure de l'état (State Shape) : loggedIn → user
Ancien état : { loading, error, loggedIn }. Nouveau : { loading, error, user }. loggedIn: boolean indiquait simplement « oui/non ». user: object|null fournit l'objet utilisateur complet (id, nom, locale, ...) — les composants via useSelector(state => state.authentication.user) récupèrent directement toutes les données.
Object.freeze
Rend l'objet immuable. Dans les tests de réducteur : Object.freeze(state); reducer(state, action); — si le réducteur tente de modifier l'état (au lieu d'en créer un nouveau), JavaScript lèvera une erreur en mode strict. C'est une vérification de la pureté de la fonction. [MDN]

Résumé des modifications

AspectAncien fichier (216 lignes)Nouveau fichier (98 lignes)
Structure de l'état { loading, error, loggedIn } { loading, error, user }
État initial Codé en dur dans le test, loading: false Constante, identique au réducteur, loading: true
Nombre de describe 5 (avec le préfixe handles) 3 (sans préfixe)
Nombre de tests 9 4
USER_LOGIN_BEGIN 3 tests (fresh, error, loggedIn — redondants) 1 test (resets to loading)
USER_LOGIN_SUCCESS 2 tests — sans payload 1 test — avec payload (user, version, etc.)
USER_LOGIN_FAILURE 2 tests (loading, weird) 1 test (sets error)
USER_LOGOUT 2 tests Supprimé en entier — l'action n'existe plus
Description de l'action inconnue 'unknown action' — peu clair 'unknown action returns current state' — explicite

Pourquoi 9 tests → 4 ?

  1. Trois describe avec 1 test chacun — chaque action est testée une seule fois avec des données d'entrée représentatives. Inutile de tester « état vierge », « avec erreur » et « connecté » pour chaque action.
  2. USER_LOGOUT supprimé — sa fonctionnalité est couverte par USER_LOGIN_BEGIN (les deux réinitialisent l'état). L'action n'existe plus dans le réducteur.
  3. USER_LOGIN_SUCCESS teste le payload — l'ancien test ne vérifiait pas les données utilisateur (user, version, buildTimestamp, alertMessage), le nouveau valide tous les champs.
  4. Structure de l'état modifiéeloggedIn: boolean a été remplacé par user: object|null dans le cadre de la migration connect()useSelector [react-redux hooks].

— lien vers le code dans la branche draft43npm sur le fork, qui n'a pas été fusionnée dans develop. Le code peut ne pas être accessible sur GitHub tant que la PR n'est pas fusionnée.