Skip to content

Commit 2abd08d

Browse files
committed
Fix issues related to console spies in serializableStateInvariantMiddleware.test.ts
1 parent ca397f3 commit 2abd08d

File tree

1 file changed

+84
-60
lines changed

1 file changed

+84
-60
lines changed

packages/toolkit/src/tests/serializableStateInvariantMiddleware.test.ts

Lines changed: 84 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
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'
63
import type { Reducer } from '@reduxjs/toolkit'
74
import {
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

2430
describe('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-
/^SerializableStateInvariantMiddleware took \d*ms, which is more than the warning threshold of 4ms./,
600+
601+
expect(consoleWarnSpy).toHaveBeenCalledOnce()
602+
603+
expect(consoleWarnSpy).toHaveBeenLastCalledWith(
604+
expect.stringMatching(
605+
/^SerializableStateInvariantMiddleware took \d*ms, which is more than the warning threshold of 4ms./,
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

Comments
 (0)