From b5432ad8dea7681b51e1c4665e7b8399cd8d1893 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 11 Mar 2022 14:42:52 -0600 Subject: [PATCH] Refactor some reducers with Immutable.Record --- app/soapbox/reducers/__tests__/admin-test.js | 18 +-- app/soapbox/reducers/__tests__/alerts-test.js | 118 +++++++++--------- app/soapbox/reducers/__tests__/meta-test.js | 6 +- app/soapbox/reducers/admin.js | 5 +- app/soapbox/reducers/admin_log.js | 5 +- app/soapbox/reducers/alerts.js | 39 ++++-- app/soapbox/reducers/meta.js | 8 +- app/soapbox/reducers/notifications.js | 5 +- 8 files changed, 110 insertions(+), 94 deletions(-) diff --git a/app/soapbox/reducers/__tests__/admin-test.js b/app/soapbox/reducers/__tests__/admin-test.js index 807bdd02e..43018c880 100644 --- a/app/soapbox/reducers/__tests__/admin-test.js +++ b/app/soapbox/reducers/__tests__/admin-test.js @@ -1,21 +1,11 @@ -import { - Map as ImmutableMap, - List as ImmutableList, - OrderedSet as ImmutableOrderedSet, -} from 'immutable'; +import { Record as ImmutableRecord } from 'immutable'; import reducer from '../admin'; describe('admin reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap({ - reports: ImmutableMap(), - openReports: ImmutableOrderedSet(), - users: ImmutableMap(), - latestUsers: ImmutableOrderedSet(), - awaitingApproval: ImmutableOrderedSet(), - configs: ImmutableList(), - needsReboot: false, - })); + const result = reducer(undefined, {}); + expect(ImmutableRecord.isRecord(result)).toBe(true); + expect(result.needsReboot).toBe(false); }); }); diff --git a/app/soapbox/reducers/__tests__/alerts-test.js b/app/soapbox/reducers/__tests__/alerts-test.js index 7059c843f..907a0adb3 100644 --- a/app/soapbox/reducers/__tests__/alerts-test.js +++ b/app/soapbox/reducers/__tests__/alerts-test.js @@ -1,6 +1,11 @@ -import { List as ImmutableList } from 'immutable'; +import { Record as ImmutableRecord, List as ImmutableList } from 'immutable'; -import * as actions from 'soapbox/actions/alerts'; +import { + ALERT_SHOW, + ALERT_DISMISS, + ALERT_CLEAR, +} from 'soapbox/actions/alerts'; +import { applyActions } from 'soapbox/test_helpers'; import reducer from '../alerts'; @@ -9,66 +14,65 @@ describe('alerts reducer', () => { expect(reducer(undefined, {})).toEqual(ImmutableList()); }); - it('should handle ALERT_SHOW', () => { - const state = ImmutableList([]); - const action = { - type: actions.ALERT_SHOW, - title: 'alert_title', - message: 'this is an alert message', - }; - expect(reducer(state, action).toJS()).toMatchObject([ - { + describe('ALERT_SHOW', () => { + it('imports the alert', () => { + const action = { + type: ALERT_SHOW, + title: 'alert_title', + message: 'this is an alert message', + }; + + const expected = [{ key: 0, message: 'this is an alert message', title: 'alert_title', - }, - ]); - }); + }]; - // it('should handle ALERT_DISMISS', () => { - // const state = ImmutableList([ - // { - // key: 0, - // message: 'message_1', - // title: 'title_1', - // }, - // { - // key: 1, - // message: 'message_2', - // title: 'title_2', - // }, - // ]); - // const action = { - // type: actions.ALERT_DISMISS, - // alert: { key: 0 }, - // }; - // expect(reducer(state, action).toJS()).toMatchObject([ - // { - // key: 1, - // message: 'message_2', - // title: 'title_2', - // } - // ]); - // }); - - it('should handle ALERT_CLEAR', () => { - const state = ImmutableList([ - { - key: 0, - message: 'message_1', - title: 'title_1', - }, - { - key: 1, - message: 'message_2', - title: 'title_2', - }, - ]); - const action = { - type: actions.ALERT_CLEAR, - }; - expect(reducer(state, action).toJS()).toMatchObject({ + const result = reducer(undefined, action); + expect(ImmutableRecord.isRecord(result.get(0))).toBe(true); + expect(result.toJS()).toMatchObject(expected); }); }); + describe('ALERT_CLEAR', () => { + it('deletes the alerts', () => { + const actions = [{ + type: ALERT_SHOW, + title: 'Oops!', + message: 'Server is down', + }, { + type: ALERT_SHOW, + title: 'Uh-oh!', + message: 'Shit done fucked up', + }, { + type: ALERT_CLEAR, + }]; + + const result = applyActions(undefined, actions, reducer); + expect(result.isEmpty()).toBe(true); + }); + }); + + describe('ALERT_DISMISS', () => { + it('deletes an individual alert', () => { + const actions = [{ + type: ALERT_SHOW, + title: 'Oops!', + message: 'Server is down', + }, { + type: ALERT_SHOW, + title: 'Uh-oh!', + message: 'Shit done fucked up', + }, { + type: ALERT_DISMISS, + alert: { + key: 0, + }, + }]; + + const result = applyActions(undefined, actions, reducer); + expect(result.size).toEqual(1); + expect(result.get(0).key).toEqual(1); + }); + }); }); diff --git a/app/soapbox/reducers/__tests__/meta-test.js b/app/soapbox/reducers/__tests__/meta-test.js index cfdf882cb..92ee4e6ff 100644 --- a/app/soapbox/reducers/__tests__/meta-test.js +++ b/app/soapbox/reducers/__tests__/meta-test.js @@ -1,9 +1,11 @@ -import { Map as ImmutableMap } from 'immutable'; +import { Record as ImmutableRecord } from 'immutable'; import reducer from '../meta'; describe('meta reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap()); + const result = reducer(undefined, {}); + expect(ImmutableRecord.isRecord(result)).toBe(true); + expect(result.instance_fetch_failed).toBe(false); }); }); diff --git a/app/soapbox/reducers/admin.js b/app/soapbox/reducers/admin.js index 1da0ef7aa..6a75e2c5b 100644 --- a/app/soapbox/reducers/admin.js +++ b/app/soapbox/reducers/admin.js @@ -2,6 +2,7 @@ import { Map as ImmutableMap, List as ImmutableList, Set as ImmutableSet, + Record as ImmutableRecord, OrderedSet as ImmutableOrderedSet, fromJS, is, @@ -20,7 +21,7 @@ import { ADMIN_USERS_APPROVE_SUCCESS, } from '../actions/admin'; -const initialState = ImmutableMap({ +const ReducerRecord = ImmutableRecord({ reports: ImmutableMap(), openReports: ImmutableOrderedSet(), users: ImmutableMap(), @@ -126,7 +127,7 @@ function handleReportDiffs(state, reports) { }); } -export default function admin(state = initialState, action) { +export default function admin(state = ReducerRecord(), action) { switch(action.type) { case ADMIN_CONFIG_FETCH_SUCCESS: case ADMIN_CONFIG_UPDATE_SUCCESS: diff --git a/app/soapbox/reducers/admin_log.js b/app/soapbox/reducers/admin_log.js index 9008de52b..c194bbc04 100644 --- a/app/soapbox/reducers/admin_log.js +++ b/app/soapbox/reducers/admin_log.js @@ -1,12 +1,13 @@ import { Map as ImmutableMap, + Record as ImmutableRecord, OrderedSet as ImmutableOrderedSet, fromJS, } from 'immutable'; import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin'; -const initialState = ImmutableMap({ +const ReducerRecord = ImmutableRecord({ items: ImmutableMap(), index: ImmutableOrderedSet(), total: 0, @@ -34,7 +35,7 @@ const importItems = (state, items, total) => { }); }; -export default function admin_log(state = initialState, action) { +export default function admin_log(state = ReducerRecord(), action) { switch(action.type) { case ADMIN_LOG_FETCH_SUCCESS: return importItems(state, action.items, action.total); diff --git a/app/soapbox/reducers/alerts.js b/app/soapbox/reducers/alerts.js index 79fad30e6..31428d402 100644 --- a/app/soapbox/reducers/alerts.js +++ b/app/soapbox/reducers/alerts.js @@ -1,4 +1,4 @@ -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { Record as ImmutableRecord, List as ImmutableList } from 'immutable'; import { ALERT_SHOW, @@ -6,21 +6,38 @@ import { ALERT_CLEAR, } from '../actions/alerts'; -const initialState = ImmutableList([]); +const AlertRecord = ImmutableRecord({ + key: 0, + title: '', + message: '', + severity: 'info', + actionLabel: '', + actionLink: '', +}); + +const initialState = ImmutableList(); + +// Get next key based on last alert +const getNextKey = state => state.size > 0 ? state.last().get('key') + 1 : 0; + +// Import the alert +const importAlert = (state, alert) => { + const key = getNextKey(state); + const record = AlertRecord({ ...alert, key }); + return state.push(record); +}; + +// Delete an alert by its key +const deleteAlert = (state, alert) => { + return state.filterNot(item => item.key === alert.key); +}; export default function alerts(state = initialState, action) { switch(action.type) { case ALERT_SHOW: - return state.push(ImmutableMap({ - key: state.size > 0 ? state.last().get('key') + 1 : 0, - title: action.title, - message: action.message, - severity: action.severity || 'info', - actionLabel: action.actionLabel, - actionLink: action.actionLink, - })); + return importAlert(state, action); case ALERT_DISMISS: - return state.filterNot(item => item.get('key') === action.alert.key); + return deleteAlert(state, action.alert); case ALERT_CLEAR: return state.clear(); default: diff --git a/app/soapbox/reducers/meta.js b/app/soapbox/reducers/meta.js index 46f662ece..eb4f40486 100644 --- a/app/soapbox/reducers/meta.js +++ b/app/soapbox/reducers/meta.js @@ -1,12 +1,14 @@ 'use strict'; -import { Map as ImmutableMap } from 'immutable'; +import { Record as ImmutableRecord } from 'immutable'; import { INSTANCE_FETCH_FAIL } from 'soapbox/actions/instance'; -const initialState = ImmutableMap(); +const ReducerRecord = ImmutableRecord({ + instance_fetch_failed: false, +}); -export default function meta(state = initialState, action) { +export default function meta(state = ReducerRecord(), action) { switch(action.type) { case INSTANCE_FETCH_FAIL: return state.set('instance_fetch_failed', true); diff --git a/app/soapbox/reducers/notifications.js b/app/soapbox/reducers/notifications.js index 61600674b..02ffa58e9 100644 --- a/app/soapbox/reducers/notifications.js +++ b/app/soapbox/reducers/notifications.js @@ -32,8 +32,7 @@ import { } from '../actions/notifications'; import { TIMELINE_DELETE } from '../actions/timelines'; -// Record for the whole reducer -const NotificationsRecord = ImmutableRecord({ +const ReducerRecord = ImmutableRecord({ items: ImmutableOrderedMap(), hasMore: true, top: false, @@ -182,7 +181,7 @@ const importMarker = (state, marker) => { }); }; -export default function notifications(state = NotificationsRecord(), action) { +export default function notifications(state = ReducerRecord(), action) { switch(action.type) { case NOTIFICATIONS_EXPAND_REQUEST: return state.set('isLoading', true);