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+ vi . clearAllMocks ( )
20+ } )
21+
22+ afterAll ( ( ) => {
23+ vi . restoreAllMocks ( )
2124} )
22- afterEach ( ( ) => restore ( ) )
2325
2426describe ( 'findNonSerializableValue' , ( ) => {
2527 it ( 'Should return false if no matching values are found' , ( ) => {
@@ -109,15 +111,16 @@ describe('serializableStateInvariantMiddleware', () => {
109111
110112 store . dispatch ( dispatchedAction )
111113
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- ` )
114+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
115+
116+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
117+ `A non-serializable value was detected in an action, in the path: \`payload\`. Value:` ,
118+ symbol ,
119+ `\nTake a look at the logic that dispatched this action: ` ,
120+ dispatchedAction ,
121+ `\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)` ,
122+ `\n(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)` ,
123+ )
121124 } )
122125
123126 it ( 'Should log an error when a non-serializable value is in state' , ( ) => {
@@ -153,11 +156,14 @@ describe('serializableStateInvariantMiddleware', () => {
153156
154157 store . dispatch ( { type : ACTION_TYPE } )
155158
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- ` )
159+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
160+
161+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
162+ `A non-serializable value was detected in the state, in the path: \`testSlice.a\`. Value:` ,
163+ badValue ,
164+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
165+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
166+ )
161167 } )
162168
163169 describe ( 'consumer tolerated structures' , ( ) => {
@@ -213,12 +219,15 @@ describe('serializableStateInvariantMiddleware', () => {
213219
214220 store . dispatch ( { type : ACTION_TYPE } )
215221
222+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
223+
216224 // 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- ` )
225+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
226+ `A non-serializable value was detected in the state, in the path: \`testSlice.a.entries\`. Value:` ,
227+ serializableObject . entries ,
228+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
229+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
230+ )
222231 } )
223232
224233 it ( 'Should use consumer supplied isSerializable and getEntries options to tolerate certain structures' , ( ) => {
@@ -260,12 +269,15 @@ describe('serializableStateInvariantMiddleware', () => {
260269
261270 store . dispatch ( { type : ACTION_TYPE } )
262271
272+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
273+
263274 // 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- ` )
275+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
276+ `A non-serializable value was detected in the state, in the path: \`testSlice.a.third.bad-map-instance\`. Value:` ,
277+ nonSerializableValue ,
278+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
279+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
280+ )
269281 } )
270282 } )
271283
@@ -306,7 +318,7 @@ describe('serializableStateInvariantMiddleware', () => {
306318
307319 // Supplied 'isSerializable' considers all values serializable, hence
308320 // no error logging is expected:
309- expect ( getLog ( ) . log ) . toBe ( '' )
321+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
310322 } )
311323
312324 it ( 'should not check serializability for ignored action types' , ( ) => {
@@ -352,7 +364,7 @@ describe('serializableStateInvariantMiddleware', () => {
352364 new Tuple ( createSerializableStateInvariantMiddleware ( ) ) ,
353365 } ) . dispatch ( { type : 'test' , meta : { arg : nonSerializableValue } } )
354366
355- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
367+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
356368 } )
357369
358370 it ( 'default value can be overridden' , ( ) => {
@@ -366,17 +378,16 @@ describe('serializableStateInvariantMiddleware', () => {
366378 ) ,
367379 } ) . dispatch ( { type : 'test' , meta : { arg : nonSerializableValue } } )
368380
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- ` )
381+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
382+
383+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
384+ `A non-serializable value was detected in an action, in the path: \`meta.arg\`. Value:` ,
385+ nonSerializableValue ,
386+ `\nTake a look at the logic that dispatched this action: ` ,
387+ { type : 'test' , meta : { arg : nonSerializableValue } } ,
388+ `\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)` ,
389+ `\n(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)` ,
390+ )
380391 } )
381392
382393 it ( 'can specify (multiple) different values' , ( ) => {
@@ -394,7 +405,7 @@ describe('serializableStateInvariantMiddleware', () => {
394405 meta : { arg : nonSerializableValue } ,
395406 } )
396407
397- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
408+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
398409 } )
399410
400411 it ( 'can specify regexp' , ( ) => {
@@ -411,7 +422,7 @@ describe('serializableStateInvariantMiddleware', () => {
411422 payload : { arg : nonSerializableValue } ,
412423 } )
413424
414- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
425+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
415426 } )
416427 } )
417428
@@ -497,12 +508,15 @@ describe('serializableStateInvariantMiddleware', () => {
497508
498509 store . dispatch ( { type : ACTION_TYPE } )
499510
511+ expect ( consoleErrorSpy ) . toHaveBeenCalledOnce ( )
512+
500513 // 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- ` )
514+ expect ( consoleErrorSpy ) . toHaveBeenLastCalledWith (
515+ `A non-serializable value was detected in the state, in the path: \`testSlice.b.d\`. Value:` ,
516+ badValue ,
517+ `\nTake a look at the reducer(s) handling this action type: TEST_ACTION.
518+ (See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)` ,
519+ )
506520 } )
507521
508522 it ( 'allows ignoring state entirely' , ( ) => {
@@ -527,7 +541,7 @@ describe('serializableStateInvariantMiddleware', () => {
527541
528542 store . dispatch ( { type : 'test' } )
529543
530- expect ( getLog ( ) . log ) . toMatchInlineSnapshot ( `""` )
544+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
531545
532546 // Should be called twice for the action - there is an initial check for early returns, then a second and potentially 3rd for nested properties
533547 expect ( numTimesCalled ) . toBe ( 2 )
@@ -577,10 +591,15 @@ describe('serializableStateInvariantMiddleware', () => {
577591
578592 store . dispatch ( {
579593 type : 'SOME_ACTION' ,
580- payload : new Array ( 10000 ) . fill ( { value : 'more' } ) ,
594+ payload : new Array ( 10_000 ) . fill ( { value : 'more' } ) ,
581595 } )
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 ./ ,
596+
597+ expect ( consoleWarnSpy ) . toHaveBeenCalledOnce ( )
598+
599+ expect ( consoleWarnSpy ) . toHaveBeenLastCalledWith (
600+ expect . stringMatching (
601+ / ^ 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 ./ ,
602+ ) ,
584603 )
585604 } )
586605
@@ -602,7 +621,8 @@ describe('serializableStateInvariantMiddleware', () => {
602621 } )
603622
604623 store . dispatch ( { type : 'SOME_ACTION' } )
605- expect ( getLog ( ) . log ) . toMatch ( '' )
624+
625+ expect ( consoleErrorSpy ) . not . toHaveBeenCalled ( )
606626 } )
607627
608628 it ( 'Should cache its results' , ( ) => {
0 commit comments