⚠️ Entwurf der Dokumentation. Kann Tippfehler und Ungenauigkeiten enthalten.
EN | DE | RU | FR | ES

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

Datum: 2026-05-08

Verglichene Commits:

Reducer (alt und neu — identisch): reducers/authentication.js (40 Zeilen) — zwischen den Commits unverändert (erstellt 2019-02-28).

Hinweis: Links auf neuen Code (SHA e67067aa7) zeigen auf den Fork MaurerAnton/projectforge (Branch draft43npm). Links auf alten Code (SHA 9ed5fbe0f) — auf das Haupt-Repository micromata/projectforge (develop).

Abschnitt 1: Initial State (Zeilen 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 als Konstante extrahiert.

Vorher: Objekt war im Test it('initial state') als { loading: false, error: null, loggedIn: false } hartcodiert.

Neu: Konstante initialState, die zudem mit initialState aus dem Reducer selbst übereinstimmt [reducers/authentication.js:3].

2. loading: falseloading: true.

Alter Init: loading: false — Benutzer nicht eingeloggt, kein Spinner.

Neuer Init: loading: true — beim App-Start wird sofort loadUserStatus() ausgeführt, das die Session prüft. Startzustand — »Benutzer wird gesucht«. Diese Änderung des Reducers in commit 8b3b44be7 (2020-03-18).

3. loggedIn: falseuser: null. HAUPTÄNDERUNG DES STATE SHAPE.

{/* Alte Form */}
{ loading: boolean, error: string|null, loggedIn: boolean }
{/* Neue Form */}
{ loading: boolean, error: string|null, user: object|null }

Abschnitt 2: Unknown Action (Zeilen 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. Explizite Beschreibung: »Reducer kennt diese Action nicht → gibt aktuellen State unverändert zurück«. Der alte Test sagte nicht, was genau geprüft wird.

Änderung des Eingabe-States: alter Test prüfte { loading: true, loggedIn: false }, neuer — { loading: false, user: { name: 'test' } }. Eingeloggter Benutzer-State gewählt, um zu prüfen, dass user bei unbekannter Action nicht genullt wird — Garantie der Pure Function [Redux reducers].

Formatierung: alter Aufruf auf 3 Zeilen verteilt, neuer — eine Zeile. Nur Stil.

Object.freeze(state) [MDN] — Mutationsschutz: falls der Reducer den übergebenen State verändert (verletzt Reinheit), der Test mit Fehler fehlschlägt.

Abschnitt 3: USER_LOGIN_BEGIN — 2 Tests gelöscht, 1 geändert (Zeilen 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'). Wort handles entfernt — im neuen Stil heißen alle describe wie die Action. [neue Datei]

2 von 3 Tests gelöscht.

«fresh state» — prüfte Übergang von { loading: false, error: null, ... }{ loading: true, error: null, ... }. [Zeile 34]

«error state» — prüfte Übergang von { loading: false, error: exampleError, ... }{ loading: true, error: null, ... }. [Zeile 53]

Beide Tests prüfen dasselbe: error wird genullt, loading wird true. Unterschied — der ursprüngliche error (null vs String). Redundant — ein Test deckt beide Fälle ab.

«loggedIn state» — Eingabe: { loading: false, error: null, loggedIn: false } — identisch mit »fresh state«. Möglicherweise ein Tippfehler (hätte loggedIn: true sein sollen). [Zeile 72]

Ein neuer Test: 'resets to loading with null user' [neue Datei]

Abschnitt 4: USER_LOGIN_SUCCESS — 1 Test gelöscht, 1 geändert (Zeilen 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-});

Alter Test «loading state» — OHNE PAYLOAD.

Rief { type: 'USER_LOGIN_SUCCESS' } ohne drittes Argument (Payload) auf. Der alte Reducer setzte angeblich nur loggedIn: true und loading: false — Benutzerdaten wurden nicht gespeichert.

»weird state« gelöscht: { loading: false, error: exampleError, loggedIn: true } — sinnlose Kombination: error vorhanden bei loggedIn = true. [Zeile 115]

Neuer Test — mit echtem Payload:

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

Warum genau diese Felder: der Reducer in authentication.js:18-27 erwartet vier Payload-Felder — jedes wird direkt in den State geschrieben:

Payload-Feld→ State-FeldZeileZweck
payload.userstate.userL23Benutzerobjekt (Name, Admin?)
payload.versionstate.versionL24Build-Version
payload.buildTimestampstate.buildTimestampL25Build-Zeitpunkt
payload.alertMessagestate.alertMessageL26Systemmeldung (MOTD)

Der alte Test übergab überhaupt keinen Payload — prüfte also keines dieser Felder. Der neue Test prüft vollständige Übereinstimmung.

loggedIn: trueuser: { name: 'testuser' }. Komponenten prüfen state.user !== null statt state.loggedIn === true — Teil der Migration auf react-redux hooks.

Abschnitt 5: USER_LOGIN_FAILURE — 1 Test gelöscht, 1 geändert (Zeilen 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-});

Ähnliche Änderungen: handles USER_LOGIN_FAILUREUSER_LOGIN_FAILURE, »weird state« gelöscht, ein Test statt zwei.

Neue Beschreibung: 'sets error and clears user/loading' — sagt explizit, was passiert: Fehler wird gespeichert, Benutzer wird zurückgesetzt, Spinner verschwindet.

loggedIn: falseuser: null. Feld user wird bei Fehler null. Das ist strenger als loggedIn: false — der alte Ansatz ließ Benutzerdaten im State (markierte nur als nicht eingeloggt), der neue löscht vollständig. Entspricht case USER_LOGIN_FAILURE: user: null.

Payload-Formatierung: { error: exampleError } in einer Zeile statt drei. Nur Stil.

Abschnitt 6: describe('handles USER_LOGOUT') gelöscht (Zeilen 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-});

Komplett gelöscht (2 Tests, ~40 Zeilen).

Prüfte, dass USER_LOGOUT setzt zurück { loggedIn: true } b { loggedIn: false } und nullt den Fehler.

Warum gelöscht:

  1. Action USER_LOGOUT existiert nicht mehr — wird nicht exportiert aus authentication.js (importiert nur USER_LOGIN_BEGIN, USER_LOGIN_FAILURE, USER_LOGIN_SUCCESS).
  2. USER_LOGOUT fehlt im Reducer-Switch [nur 3 case].
  3. Logout-Funktionalität wird von USER_LOGIN_BEGIN abgedeckt — beide setzen den State zurück.
  4. Der Test importierte USER_LOGOUT aus einem nicht existierenden Export — der Test war defekt.

Historisch: USER_LOGOUT wurde aus dem Quellcode entfernt commit 7c60c2fbb (2019-07-13, «implemented logout check») — aus actions/authentication.js und aus dem Reducer. Aber der Test wurde nicht aktualisiert — er importierte und testete USER_LOGOUT noch 7 Jahre lang. Im neuen Reducer ist Logout einfach USER_LOGIN_BEGIN (Reset auf loading).

Begriffe

Redux Reducer
Pure Funktion: (state, action) → new State. Keine Side Effects, keine Mutationen. Object.freeze(state) im Test garantiert dies: mutiert der Reducer versehentlich den übergebenen State, schlägt der Test fehl. [Redux docs]
State Shape: loggedIn → user
Alter State: { loading, error, loggedIn }. Neu: { loading, error, user }. loggedIn: boolean sagte nur »ja/nein«. user: object|null liefert das vollständige Benutzerobjekt (id, name, locale, ...) — Komponenten erhalten über useSelector(state => state.authentication.user) alle Daten auf einmal.
Object.freeze
Macht ein Objekt unveränderlich. Im Reducer-Test: Object.freeze(state); reducer(state, action); — versucht der Reducer den State zu mutieren (statt ein neues Objekt zu erstellen), wirft JavaScript im Strict Mode einen Fehler. Dies prüft die Reinheit der Funktion. [MDN]

Zusammenfassung der Änderungen

AspektAlte Datei (216 Zeilen)Neue Datei (98 Zeilen)
State Shape { loading, error, loggedIn } { loading, error, user }
Initial state Im Test eingebettet, loading: false Konstante, identisch mit Reducer, loading: true
Anzahl describe 5 (mit Präfix handles) 3 (ohne Präfix)
Anzahl Tests 9 4
USER_LOGIN_BEGIN 3 Tests (fresh, error, loggedIn — Duplikate) 1 Test (resets to loading)
USER_LOGIN_SUCCESS 2 Tests — ohne Payload 1 Test — mit Payload (user, version usw.)
USER_LOGIN_FAILURE 2 Tests (loading, weird) 1 Test (sets error)
USER_LOGOUT 2 Tests Komplett gelöscht — Action existiert nicht
Beschreibung von unknown action 'unknown action' — unklar 'unknown action returns current state' — klar

Warum 9 Tests → 4?

  1. Drei describe mit je 1 Test — jede Action wird einmal mit repräsentativen Eingabedaten geprüft. Keine Notwendigkeit, »fresh«, »error« und »loggedIn« für jede Action zu testen.
  2. USER_LOGOUT gelöscht — seine Funktionalität wird von USER_LOGIN_BEGIN abgedeckt (beide setzen den State zurück). Action existiert nicht im Reducer.
  3. USER_LOGIN_SUCCESS testet payload — der alte Test prüfte keine Benutzerdaten (user, version, buildTimestamp, alertMessage), der neue prüft alle Felder.
  4. State Shape geändertloggedIn: boolean ersetzt durch user: object|null als Teil der Migration connect()useSelector [react-redux hooks].

— Link auf Code im Branch draft43npm im Fork, nicht in develop gemergt. Code möglicherweise bis zum PR-Merge nicht auf GitHub verfügbar.