1- import {
2- mockConsole ,
3- createConsole ,
4- getLog ,
5- } from 'console-testing-library/pure'
1+ import { noop } from '@internal/listenerMiddleware/utils'
2+ import { isNestedFrozen } from '@internal/serializableStateInvariantMiddleware'
63import type { Reducer } from '@reduxjs/toolkit'
74import {
8- createNextState ,
95 configureStore ,
6+ createNextState ,
107 createSerializableStateInvariantMiddleware ,
118 findNonSerializableValue ,
129 isPlain ,
1310 Tuple ,
1411} from '@reduxjs/toolkit'
15- import { isNestedFrozen } from '@internal/serializableStateInvariantMiddleware'
1612
1713// Mocking console
18- let restore = ( ) => { }
19- beforeEach ( ( ) => {
20- restore = mockConsole ( createConsole ( ) )
14+ const consoleErrorSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( noop )
15+
16+ const consoleWarnSpy = vi . spyOn ( console , 'warn' ) . mockImplementation ( noop )
17+
18+ afterEach ( ( ) => {
19+ consoleErrorSpy . mockClear ( )
20+
21+ consoleWarnSpy . mockClear ( )
22+ } )
23+
24+ afterAll ( ( ) => {
25+ consoleErrorSpy . mockRestore ( )
26+
27+ consoleWarnSpy . mockRestore ( )
2128} )
22- afterEach ( ( ) => restore ( ) )
2329
2430describe ( 'findNonSerializableValue' , ( ) => {
2531 it ( 'Should return false if no matching values are found' , ( ) => {
@@ -109,15 +115,16 @@ describe('serializableStateInvariantMiddleware', () => {
109115
110116 store . dispatch ( dispatchedAction )
111117
112- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
113- "A non-serializable value was detected in an action, in the path: \`payload\`. Value: Symbol(SOME_CONSTANT)
114- Take a look at the logic that dispatched this action: Object {
115- "payload": Symbol(SOME_CONSTANT),
116- "type": "an-action",
117- }
118- (See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
119- (To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)"
120- ` )
118+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
119+
120+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
121+ `A non-serializable value was detected in an action, in the path: \`payload\`. Value:` ,
122+ symbol ,
123+ `\nTake a look at the logic that dispatched this action: ` ,
124+ dispatchedAction ,
125+ `\n(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)` ,
126+ `\n(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)` ,
127+ )
121128 } )
122129
123130 it ( 'Should log an error when a non-serializable value is in state' , ( ) => {
@@ -153,11 +160,14 @@ describe('serializableStateInvariantMiddleware', () => {
153160
154161 store . dispatch ( { type : ACTION_TYPE } )
155162
156- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
157- "A non-serializable value was detected in the state, in the path: \`testSlice.a\`. Value: Map {}
158- Take a look at the reducer(s) handling this action type: TEST_ACTION.
159- (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)"
160- ` )
163+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
164+
165+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
166+ `A non-serializable value was detected in the state, in the path: \`testSlice.a\`. Value:` ,
167+ badValue ,
168+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
169+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
170+ )
161171 } )
162172
163173 describe ( 'consumer tolerated structures' , ( ) => {
@@ -213,12 +223,15 @@ describe('serializableStateInvariantMiddleware', () => {
213223
214224 store . dispatch ( { type : ACTION_TYPE } )
215225
226+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
227+
216228 // since default options are used, the `entries` function in `serializableObject` will cause the error
217- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
218- "A non-serializable value was detected in the state, in the path: \`testSlice.a.entries\`. Value: [Function entries]
219- Take a look at the reducer(s) handling this action type: TEST_ACTION.
220- (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)"
221- ` )
229+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
230+ `A non-serializable value was detected in the state, in the path: \`testSlice.a.entries\`. Value:` ,
231+ serializableObject . entries ,
232+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
233+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
234+ )
222235 } )
223236
224237 it ( 'Should use consumer supplied isSerializable and getEntries options to tolerate certain structures' , ( ) => {
@@ -260,12 +273,15 @@ describe('serializableStateInvariantMiddleware', () => {
260273
261274 store . dispatch ( { type : ACTION_TYPE } )
262275
276+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
277+
263278 // error reported is from a nested class instance, rather than the `entries` function `serializableObject`
264- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
265- "A non-serializable value was detected in the state, in the path: \`testSlice.a.third.bad-map-instance\`. Value: Map {}
266- Take a look at the reducer(s) handling this action type: TEST_ACTION.
267- (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)"
268- ` )
279+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
280+ `A non-serializable value was detected in the state, in the path: \`testSlice.a.third.bad-map-instance\`. Value:` ,
281+ nonSerializableValue ,
282+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
283+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
284+ )
269285 } )
270286 } )
271287
@@ -306,7 +322,7 @@ describe('serializableStateInvariantMiddleware', () => {
306322
307323 // Supplied 'isSerializable' considers all values serializable, hence
308324 // no error logging is expected:
309- expect ( getLog ( ) . log ) . toBe ( '' )
325+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
310326 } )
311327
312328 it ( 'should not check serializability for ignored action types' , ( ) => {
@@ -352,7 +368,7 @@ describe('serializableStateInvariantMiddleware', () => {
352368 new Tuple ( createSerializableStateInvariantMiddleware ( ) ) ,
353369 } ) . dispatch ( { type : 'test' , meta : { arg : nonSerializableValue } } )
354370
355- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
371+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
356372 } )
357373
358374 it ( 'default value can be overridden' , ( ) => {
@@ -366,17 +382,16 @@ describe('serializableStateInvariantMiddleware', () => {
366382 ) ,
367383 } ) . dispatch ( { type : 'test' , meta : { arg : nonSerializableValue } } )
368384
369- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
370- "A non-serializable value was detected in an action, in the path: \`meta.arg\`. Value: Map {}
371- Take a look at the logic that dispatched this action: Object {
372- "meta": Object {
373- "arg": Map {},
374- },
375- "type": "test",
376- }
377- (See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
378- (To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)"
379- ` )
385+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
386+
387+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
388+ `A non-serializable value was detected in an action, in the path: \`meta.arg\`. Value:` ,
389+ nonSerializableValue ,
390+ `\nTake a look at the logic that dispatched this action: ` ,
391+ { type : 'test' , meta : { arg : nonSerializableValue } } ,
392+ `\n(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)` ,
393+ `\n(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)` ,
394+ )
380395 } )
381396
382397 it ( 'can specify (multiple) different values' , ( ) => {
@@ -394,7 +409,7 @@ describe('serializableStateInvariantMiddleware', () => {
394409 meta : { arg : nonSerializableValue } ,
395410 } )
396411
397- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
412+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
398413 } )
399414
400415 it ( 'can specify regexp' , ( ) => {
@@ -411,7 +426,7 @@ describe('serializableStateInvariantMiddleware', () => {
411426 payload : { arg : nonSerializableValue } ,
412427 } )
413428
414- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
429+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
415430 } )
416431 } )
417432
@@ -497,12 +512,15 @@ describe('serializableStateInvariantMiddleware', () => {
497512
498513 store . dispatch ( { type : ACTION_TYPE } )
499514
515+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
516+
500517 // testSlice.b.d was not covered in ignoredPaths, so will still log the error
501- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `
502- "A non-serializable value was detected in the state, in the path: \`testSlice.b.d\`. Value: Map {}
503- Take a look at the reducer(s) handling this action type: TEST_ACTION.
504- (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)"
505- ` )
518+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
519+ `A non-serializable value was detected in the state, in the path: \`testSlice.b.d\`. Value:` ,
520+ badValue ,
521+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
522+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
523+ )
506524 } )
507525
508526 it ( 'allows ignoring state entirely' , ( ) => {
@@ -527,7 +545,7 @@ describe('serializableStateInvariantMiddleware', () => {
527545
528546 store . dispatch ( { type : 'test' } )
529547
530- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
548+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
531549
532550 // Should be called twice for the action - there is an initial check for early returns, then a second and potentially 3rd for nested properties
533551 expect ( numTimesCalled ) . toBe ( 2 )
@@ -577,10 +595,15 @@ describe('serializableStateInvariantMiddleware', () => {
577595
578596 store . dispatch ( {
579597 type : 'SOME_ACTION' ,
580- payload : new Array ( 10000 ) . fill ( { value : 'more' } ) ,
598+ payload : new Array ( 10_000 ) . fill ( { value : 'more' } ) ,
581599 } )
582- expect ( getLog ( ) . log ) . toMatch (
583- / ^ S e r i a l i z a b l e S t a t e I n v a r i a n t M i d d l e w a r e t o o k \d * m s , w h i c h i s m o r e t h a n t h e w a r n i n g t h r e s h o l d o f 4 m s ./ ,
600+
601+ expect ( consoleWarnSpy ) . toHaveBeenCalledOnce ( )
602+
603+ expect ( consoleWarnSpy ) . toHaveBeenLastCalledWith (
604+ expect . stringMatching (
605+ / ^ S e r i a l i z a b l e S t a t e I n v a r i a n t M i d d l e w a r e t o o k \d * m s , w h i c h i s m o r e t h a n t h e w a r n i n g t h r e s h o l d o f 4 m s ./ ,
606+ ) ,
584607 )
585608 } )
586609
@@ -602,7 +625,8 @@ describe('serializableStateInvariantMiddleware', () => {
602625 } )
603626
604627 store . dispatch ( { type : 'SOME_ACTION' } )
605- expect ( getLog ( ) . log ) . toMatch ( '' )
628+
629+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
606630 } )
607631
608632 it ( 'Should cache its results' , ( ) => {
0 commit comments