Skip to content

Commit fcc3445

Browse files
committed
Fix issues related to console spies in serializableStateInvariantMiddleware.test.ts
1 parent f76d63d commit fcc3445

File tree

1 file changed

+80
-60
lines changed

1 file changed

+80
-60
lines changed

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

Lines changed: 80 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
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+
vi.clearAllMocks()
20+
})
21+
22+
afterAll(() => {
23+
vi.restoreAllMocks()
2124
})
22-
afterEach(() => restore())
2325

2426
describe('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-
/^SerializableStateInvariantMiddleware took \d*ms, which is more than the warning threshold of 4ms./,
596+
597+
expect(consoleWarnSpy).toHaveBeenCalledOnce()
598+
599+
expect(consoleWarnSpy).toHaveBeenLastCalledWith(
600+
expect.stringMatching(
601+
/^SerializableStateInvariantMiddleware took \d*ms, which is more than the warning threshold of 4ms./,
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

Comments
 (0)