Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert "middleware not registered" warning into a full error #2792

Merged
merged 2 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/toolkit/src/query/core/buildInitiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@ export function buildInitiate({
;(middlewareWarning as any).triggered = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not need any tracking to trigger only once any more, it should throw every time.
It should also do so in production I guess?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding this code:

const registered =
        getState()[api.reducerPath]?.config?.middlewareRegistered

We can also do the check for registered better now by really dispatching an internal_probeSubscription action and seeing if the middleware picks it up. That middlewareRegistered field could also come from persistence being overactive.

}
if (registered === false) {
console.warn(
throw new Error(
`Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
Features like automatic cache collection, automatic refetching etc. will not be available.`
You must add the middleware for RTK-Query to function correctly!`
)
}
}
Expand Down
9 changes: 9 additions & 0 deletions packages/toolkit/src/query/react/buildHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,15 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
})
)

if (process.env.NODE_ENV !== 'production') {
if (typeof returnedValue !== 'boolean') {
throw new Error(
`Warning: Middleware for RTK-Query API at reducerPath "${api.reducerPath}" has not been added to the store.
You must add the middleware for RTK-Query to function correctly!`
)
}
}

currentRenderHasSubscription = !!returnedValue
}

Expand Down
40 changes: 39 additions & 1 deletion packages/toolkit/src/query/tests/buildHooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ import {
expectExactType,
expectType,
setupApiStore,
withProvider,
useRenderCounter,
waitMs,
} from './helpers'
import { server } from './mocks/server'
import type { AnyAction } from 'redux'
import type { SubscriptionOptions } from '@reduxjs/toolkit/dist/query/core/apiState'
import { createListenerMiddleware, SerializedError } from '@reduxjs/toolkit'
import {
createListenerMiddleware,
SerializedError,
configureStore,
} from '@reduxjs/toolkit'
import { renderHook } from '@testing-library/react'
import { delay } from '../../utils'

Expand Down Expand Up @@ -651,6 +656,39 @@ describe('hooks tests', () => {
const res = await resPromise
expect(res.data!.amount).toBeGreaterThan(originalAmount)
})

describe('Hook middleware requirements', () => {
let mock: jest.SpyInstance

beforeEach(() => {
mock = jest.spyOn(console, 'error').mockImplementation(() => {})
})

afterEach(() => {
mock.mockReset()
})

test('Throws error if middleware is not added to the store', async () => {
const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
},
})

const doRender = () => {
const { result } = renderHook(
() => api.endpoints.getIncrementedAmount.useQuery(),
{
wrapper: withProvider(store),
}
)
}

expect(doRender).toThrowError(
/Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store/
)
})
})
})

describe('useLazyQuery', () => {
Expand Down
46 changes: 27 additions & 19 deletions packages/toolkit/src/query/tests/devWarnings.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ beforeEach(() => {
;[api1, api1_2, api2] = createApis()
})

const reMatchMissingMiddlewareError =
/Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store/

describe('missing middleware', () => {
test.each([
['development', true],
Expand All @@ -61,13 +64,14 @@ describe('missing middleware', () => {
const store = configureStore({
reducer: { [api1.reducerPath]: api1.reducer },
})
store.dispatch(api1.endpoints.q1.initiate(undefined))
expect(getLog().log).toBe(
shouldWarn
? `Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store.
Features like automatic cache collection, automatic refetching etc. will not be available.`
: ''
)
const doDispatch = () => {
store.dispatch(api1.endpoints.q1.initiate(undefined))
}
if (shouldWarn) {
expect(doDispatch).toThrowError(reMatchMissingMiddlewareError)
} else {
expect(doDispatch).not.toThrowError()
}
})

test('does not warn if middleware is not missing', () => {
Expand All @@ -83,11 +87,12 @@ Features like automatic cache collection, automatic refetching etc. will not be
const store = configureStore({
reducer: { [api1.reducerPath]: api1.reducer },
})
store.dispatch(api1.endpoints.q1.initiate(undefined))
store.dispatch(api1.endpoints.q1.initiate(undefined))
expect(getLog().log)
.toBe(`Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store.
Features like automatic cache collection, automatic refetching etc. will not be available.`)
const doDispatch = () => {
store.dispatch(api1.endpoints.q1.initiate(undefined))
}

expect(doDispatch).toThrowError(reMatchMissingMiddlewareError)
expect(doDispatch).not.toThrowError()
})

test('warns multiple times for multiple apis', () => {
Expand All @@ -97,13 +102,16 @@ Features like automatic cache collection, automatic refetching etc. will not be
[api2.reducerPath]: api2.reducer,
},
})
store.dispatch(api1.endpoints.q1.initiate(undefined))
store.dispatch(api2.endpoints.q1.initiate(undefined))
expect(getLog().log)
.toBe(`Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store.
Features like automatic cache collection, automatic refetching etc. will not be available.
Warning: Middleware for RTK-Query API at reducerPath "api2" has not been added to the store.
Features like automatic cache collection, automatic refetching etc. will not be available.`)
const doDispatch1 = () => {
store.dispatch(api1.endpoints.q1.initiate(undefined))
}
const doDispatch2 = () => {
store.dispatch(api2.endpoints.q1.initiate(undefined))
}
expect(doDispatch1).toThrowError(reMatchMissingMiddlewareError)
expect(doDispatch2).toThrowError(
/Warning: Middleware for RTK-Query API at reducerPath "api2" has not been added to the store/
)
})
})

Expand Down