git diff origin/develop -- reducers/authentication.test.jse67067aa7) ведут на форк MaurerAnton/projectforge (ветка draft43npm). Ссылки на старый код (SHA 9ed5fbe0f) — на основной репозиторий micromata/projectforge (develop).
unknown action → unknown action returns current state. Описание явное: «редиректор не знает такой action → возвращает текущее состояние без изменений». Старый тест не говорил что именно проверяет.
Изменение входного state: старый тест проверял { loading: true, loggedIn: false }, новый — { loading: false, user: { name: 'test' } }. Выбран state залогиненного пользователя, чтобы проверить что user не зануляется при неизвестном action — гарантия чистой функции [Redux reducers].
Форматирование: старый вызов разбит на 3 строки, новый — одной строкой. Только стиль.
Object.freeze(state) [MDN] — защита от мутации: если reducer изменит переданный state (нарушит чистоту), тест упадёт с ошибкой.
describe('handles USER_LOGIN_BEGIN') → describe('USER_LOGIN_BEGIN'). Убрано слово handles — в новом стиле все describe называют action дословно. [новый файл]⚡
Удалено 2 из 3 тестов.
«fresh state» — проверял переход из { loading: false, error: null, ... } → { loading: true, error: null, ... }. [строка 34]
«error state» — проверял переход из { loading: false, error: exampleError, ... } → { loading: true, error: null, ... }. [строка 53]
Оба теста проверяют одно и то же: error зануляется, loading становится true. Разница — в исходном error (null vs строка). Избыточно — один тест покрывает оба случая.
«loggedIn state» — вход: { loading: false, error: null, loggedIn: false } — полностью совпадает с «fresh state». Возможно, опечатка (должно было быть loggedIn: true). [строка 72]
Один новый тест: 'resets to loading with null user' [новый файл]⚡
{ loading: false, error: 'some error', user: { name: 'old' } }{ loading: true, error: null, user: null }user зануляется (жёстче чем loggedIn: false — полная очистка)error зануляется, loading становится true — как и в старых тестахloggedIn: false на user: null — ключевое отличие state shapeСтарый тест «loading state» — БЕЗ PAYLOAD.
Вызывал { type: 'USER_LOGIN_SUCCESS' } без третьего аргумента (payload). Старый редьюсер якобы просто ставил loggedIn: true и loading: false — пользовательские данные не сохранялись.
Удалён «weird state»: { loading: false, error: exampleError, loggedIn: true } — бессмысленная комбинация: error есть при loggedIn = true. [строка 115]
Новый тест — с реальным payload:
Почему именно эти поля: редьюсер в authentication.js:18-27 ожидает payload с четырьмя полями — каждое пишется в state напрямую:
| Поле payload | → поле state | Строка | Зачем |
|---|---|---|---|
payload.user | → state.user | L23 | объект пользователя (имя, админ?) |
payload.version | → state.version | L24 | версия сборки |
payload.buildTimestamp | → state.buildTimestamp | L25 | когда собрано |
payload.alertMessage | → state.alertMessage | L26 | системное сообщение (MOTD) |
Старый тест не передавал payload вообще — а значит не проверял ни одного из этих полей. Новый тест проверяет полное соответствие.
loggedIn: true → user: { name: 'testuser' }. Компоненты проверяют state.user !== null вместо state.loggedIn === true — часть миграции на react-redux hooks.
Аналогичные изменения: handles USER_LOGIN_FAILURE → USER_LOGIN_FAILURE, удалён «weird state», один тест вместо двух.
Новое описание: 'sets error and clears user/loading' — явно говорит что происходит: ошибка сохраняется, пользователь сбрасывается, спиннер убирается.
loggedIn: false → user: null. Поле user становится null при ошибке. Это жёстче чем loggedIn: false — старый подход оставлял пользовательские данные в state (просто помечал что не залогинен), новый — полностью очищает. Соответствует case USER_LOGIN_FAILURE: user: null.
Форматирование payload: { error: exampleError } на одной строке вместо трёх. Только стиль.
Удалён целиком (2 теста, ~40 строк).
Проверял что USER_LOGOUT сбрасывает { loggedIn: true } в { loggedIn: false } и зануляет ошибку.
Почему удалён:
USER_LOGOUT больше не существует — не экспортится из authentication.js (импортит только USER_LOGIN_BEGIN, USER_LOGIN_FAILURE, USER_LOGIN_SUCCESS).USER_LOGOUT нет в switch редьюсера [только 3 case].USER_LOGIN_BEGIN — оба сбрасывают состояние.USER_LOGOUT из несуществующего экспорта — тест был сломан.Исторически: USER_LOGOUT был удалён из исходников commit 7c60c2fbb (2019-07-13, «implemented logout check») — из actions/authentication.js и из редьюсера. Но тест не обновили — он продолжал импортировать и тестировать USER_LOGOUT ещё 7 лет. В новом редьюсере логаут — это просто USER_LOGIN_BEGIN (сброс к loading).
(state, action) → new state. Никаких side effects, никаких мутаций. Object.freeze(state) в тесте гарантирует это: если редьюсер случайно мутирует переданный state, тест упадёт. [Redux docs]{ loading, error, loggedIn }. Новый: { loading, error, user }. loggedIn: boolean говорил только «да/нет». user: object|null даёт полный объект пользователя (id, name, locale, ...) — компоненты через useSelector(state => state.authentication.user) получают сразу все данные.Object.freeze(state); reducer(state, action); — если редьюсер попытается изменить state (вместо создания нового), JavaScript бросит ошибку в strict mode. Это проверка чистоты функции. [MDN]| Аспект | Старый файл (216 строк) | Новый файл (98 строк) |
|---|---|---|
| State shape | { loading, error, loggedIn } |
{ loading, error, user } |
| Initial state | Встроен в тест, loading: false |
Константа, совпадает с редьюсером, loading: true |
| Количество describe | 5 (с префиксом handles) |
3 (без префикса) |
| Количество тестов | 9 | 4 |
| USER_LOGIN_BEGIN | 3 теста (fresh, error, loggedIn — дубликаты) | 1 тест (resets to loading) |
| USER_LOGIN_SUCCESS | 2 теста — без payload | 1 тест — с payload (user, version и т.д.) |
| USER_LOGIN_FAILURE | 2 теста (loading, weird) | 1 тест (sets error) |
| USER_LOGOUT | 2 теста | Удалён полностью — action не существует |
| Описание unknown action | 'unknown action' — непонятно |
'unknown action returns current state' — понятно |
USER_LOGIN_BEGIN (оба сбрасывают состояние). Action не существует в редьюсере.user, version, buildTimestamp, alertMessage), новый проверяет все поля.loggedIn: boolean заменён на user: object|null как часть миграции connect() → useSelector [react-redux hooks].⚡ — ссылка на код в ветке draft43npm на форке, не слитой в develop. Код может быть не доступен на GitHub до слияния PR.
1.
initialStateвынесен в константу.Было: объект захардкожен в тесте
it('initial state')как{ loading: false, error: null, loggedIn: false }.Стало: константа
initialState, которая к тому же совпадает сinitialStateиз самого редьюсера [reducers/authentication.js:3].2.
loading: false→loading: true.Старый init:
loading: false— пользователь не логинился, спиннер не крутится.Новый init:
loading: true— при загрузке приложения сразу идётloadUserStatus(), который проверяет сессию. Стартовое состояние — «ищем пользователя». Это изменение редьюсера commit 8b3b44be7 (2020-03-18).3.
loggedIn: false→user: null. ГЛАВНОЕ ИЗМЕНЕНИЕ STATE SHAPE.{ loading: boolean, error: string|null, loggedIn: boolean }
{ loading: boolean, error: string|null, user: object|null }
loggedIn: trueпосле логина → теперьuser: { name: 'test', ... }loggedIn: falseдо логина → теперьuser: nulluser !== nullвместоloggedIn === trueconnect()→useSelector[react-redux hooks]