1
1
import { Reducer } from 'redux'
2
+ import { Console } from 'console'
3
+ import { Writable } from 'stream'
2
4
import { configureStore } from './configureStore'
3
5
4
6
import {
@@ -79,8 +81,33 @@ describe('findNonSerializableValue', () => {
79
81
} )
80
82
81
83
describe ( 'serializableStateInvariantMiddleware' , ( ) => {
84
+ let log = ''
85
+ const originalConsole = window . console
86
+
82
87
beforeEach ( ( ) => {
83
- console . error = jest . fn ( )
88
+ log = ''
89
+
90
+ const writable = new Writable ( {
91
+ write ( chunk , encoding , callback ) {
92
+ log += chunk
93
+ callback ( )
94
+ }
95
+ } )
96
+
97
+ const mockConsole = new Console ( {
98
+ stdout : writable ,
99
+ stderr : writable
100
+ } )
101
+
102
+ Object . defineProperty ( window , 'console' , {
103
+ value : mockConsole
104
+ } )
105
+ } )
106
+
107
+ afterEach ( ( ) => {
108
+ Object . defineProperty ( window , 'console' , {
109
+ value : originalConsole
110
+ } )
84
111
} )
85
112
86
113
it ( 'Should log an error when a non-serializable action is dispatched' , ( ) => {
@@ -98,19 +125,12 @@ describe('serializableStateInvariantMiddleware', () => {
98
125
99
126
store . dispatch ( dispatchedAction )
100
127
101
- expect ( console . error ) . toHaveBeenCalled ( )
102
-
103
- const [
104
- message ,
105
- keyPath ,
106
- value ,
107
- action
108
- ] = ( console . error as jest . Mock ) . mock . calls [ 0 ]
109
-
110
- expect ( message ) . toContain ( 'detected in an action, in the path: `%s`' )
111
- expect ( keyPath ) . toBe ( 'type' )
112
- expect ( value ) . toBe ( type )
113
- expect ( action ) . toBe ( dispatchedAction )
128
+ expect ( log ) . toMatchInlineSnapshot ( `
129
+ "A non-serializable value was detected in an action, in the path: \`type\`. Value: Symbol(SOME_CONSTANT)
130
+ Take a look at the logic that dispatched this action: { type: Symbol(SOME_CONSTANT) }
131
+ (See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
132
+ "
133
+ ` )
114
134
} )
115
135
116
136
it ( 'Should log an error when a non-serializable value is in state' , ( ) => {
@@ -145,19 +165,12 @@ describe('serializableStateInvariantMiddleware', () => {
145
165
146
166
store . dispatch ( { type : ACTION_TYPE } )
147
167
148
- expect ( console . error ) . toHaveBeenCalled ( )
149
-
150
- const [
151
- message ,
152
- keyPath ,
153
- value ,
154
- actionType
155
- ] = ( console . error as jest . Mock ) . mock . calls [ 0 ]
156
-
157
- expect ( message ) . toContain ( 'detected in the state, in the path: `%s`' )
158
- expect ( keyPath ) . toBe ( 'testSlice.a' )
159
- expect ( value ) . toBe ( badValue )
160
- expect ( actionType ) . toBe ( ACTION_TYPE )
168
+ expect ( log ) . toMatchInlineSnapshot ( `
169
+ "A non-serializable value was detected in the state, in the path: \`testSlice.a\`. Value: Map {}
170
+ Take a look at the reducer(s) handling this action type: TEST_ACTION.
171
+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)
172
+ "
173
+ ` )
161
174
} )
162
175
163
176
describe ( 'consumer tolerated structures' , ( ) => {
@@ -212,20 +225,13 @@ describe('serializableStateInvariantMiddleware', () => {
212
225
213
226
store . dispatch ( { type : ACTION_TYPE } )
214
227
215
- expect ( console . error ) . toHaveBeenCalled ( )
216
-
217
- const [
218
- message ,
219
- keyPath ,
220
- value ,
221
- actionType
222
- ] = ( console . error as jest . Mock ) . mock . calls [ 0 ]
223
-
224
228
// since default options are used, the `entries` function in `serializableObject` will cause the error
225
- expect ( message ) . toContain ( 'detected in the state, in the path: `%s`' )
226
- expect ( keyPath ) . toBe ( 'testSlice.a.entries' )
227
- expect ( value ) . toBe ( serializableObject . entries )
228
- expect ( actionType ) . toBe ( ACTION_TYPE )
229
+ expect ( log ) . toMatchInlineSnapshot ( `
230
+ "A non-serializable value was detected in the state, in the path: \`testSlice.a.entries\`. Value: [Function: entries]
231
+ Take a look at the reducer(s) handling this action type: TEST_ACTION.
232
+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)
233
+ "
234
+ ` )
229
235
} )
230
236
231
237
it ( 'Should use consumer supplied isSerializable and getEntries options to tolerate certain structures' , ( ) => {
@@ -265,20 +271,13 @@ describe('serializableStateInvariantMiddleware', () => {
265
271
266
272
store . dispatch ( { type : ACTION_TYPE } )
267
273
268
- expect ( console . error ) . toHaveBeenCalled ( )
269
-
270
- const [
271
- message ,
272
- keyPath ,
273
- value ,
274
- actionType
275
- ] = ( console . error as jest . Mock ) . mock . calls [ 0 ]
276
-
277
274
// error reported is from a nested class instance, rather than the `entries` function `serializableObject`
278
- expect ( message ) . toContain ( 'detected in the state, in the path: `%s`' )
279
- expect ( keyPath ) . toBe ( 'testSlice.a.third.bad-map-instance' )
280
- expect ( value ) . toBe ( nonSerializableValue )
281
- expect ( actionType ) . toBe ( ACTION_TYPE )
275
+ expect ( log ) . toMatchInlineSnapshot ( `
276
+ "A non-serializable value was detected in the state, in the path: \`testSlice.a.third.bad-map-instance\`. Value: Map {}
277
+ Take a look at the reducer(s) handling this action type: TEST_ACTION.
278
+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)
279
+ "
280
+ ` )
282
281
} )
283
282
} )
284
283
@@ -320,7 +319,7 @@ describe('serializableStateInvariantMiddleware', () => {
320
319
321
320
// Supplied 'isSerializable' considers all values serializable, hence
322
321
// no error logging is expected:
323
- expect ( console . error ) . not . toHaveBeenCalled ( )
322
+ expect ( log ) . toBe ( '' )
324
323
} )
325
324
326
325
it ( 'should not check serializability for ignored action types' , ( ) => {
0 commit comments