Skip to content

Commit

Permalink
Add tests and fix things 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
msutkowski committed Jan 25, 2022
1 parent a9e0561 commit e4c6be8
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/toolkit/src/query/core/buildInitiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Features like automatic cache collection, automatic refetching etc. will not be
subscribe = true,
forceRefetch,
subscriptionOptions,
structuralSharing = true,
structuralSharing,
} = {}
) =>
(dispatch, getState) => {
Expand Down
10 changes: 8 additions & 2 deletions packages/toolkit/src/query/core/buildSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function buildSlice({
apiUid,
extractRehydrationInfo,
hasRehydrationInfo,
structuralSharing,
structuralSharing: globalStructuralSharing,
},
assertTagType,
config,
Expand Down Expand Up @@ -156,10 +156,16 @@ export function buildSlice({
draft,
meta.arg.queryCacheKey,
(substate) => {
const endpointStructuralSharing =
definitions[meta.arg.endpointName].structuralSharing
const argStructuralSharing = meta.arg.structuralSharing

if (substate.requestId !== meta.requestId) return
substate.status = QueryStatus.fulfilled
substate.data =
structuralSharing && meta.arg.structuralSharing
argStructuralSharing ??
endpointStructuralSharing ??
globalStructuralSharing
? copyWithStructuralSharing(substate.data, payload)
: payload
delete substate.error
Expand Down
12 changes: 12 additions & 0 deletions packages/toolkit/src/query/react/buildHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ interface UseQuerySubscriptionOptions extends SubscriptionOptions {
* If you specify this option alongside `skip: true`, this **will not be evaluated** until `skip` is false.
*/
refetchOnMountOrArgChange?: boolean | number
/**
* Defaults to `true`.
*
* Most apps should leave this setting on. The only time it can be a performance issue
* is if an API returns extremely large amounts of data (e.g. 10,000 rows per request) and
* you're unable to paginate it.
*
* @see https://redux-toolkit.js.org/api/other-exports#copywithstructuralsharing
*/
structuralSharing?: boolean
}

/**
Expand Down Expand Up @@ -611,6 +621,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
refetchOnMountOrArgChange,
skip = false,
pollingInterval = 0,
structuralSharing,
} = {}
) => {
const { initiate } = api.endpoints[name] as ApiEndpointQuery<
Expand Down Expand Up @@ -668,6 +679,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
initiate(stableArg, {
subscriptionOptions: stableSubscriptionOptions,
forceRefetch: refetchOnMountOrArgChange,
structuralSharing,
})
)
promiseRef.current = promise
Expand Down
60 changes: 60 additions & 0 deletions packages/toolkit/src/query/tests/createApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from './helpers'
import { server } from './mocks/server'
import { rest } from 'msw'
import * as utils from '../utils'

const originalEnv = process.env.NODE_ENV
beforeAll(() => void ((process.env as any).NODE_ENV = 'development'))
Expand Down Expand Up @@ -763,3 +764,62 @@ test('providesTags and invalidatesTags can use baseQueryMeta', async () => {

expect('request' in _meta! && 'response' in _meta!).toBe(true)
})

describe('strucutralSharing flag behaviors', () => {
const mockCopyFn = jest.spyOn(utils, 'copyWithStructuralSharing')

beforeEach(() => {
mockCopyFn.mockClear()
})

type SuccessResponse = { value: 'success' }

const apiSuccessResponse: SuccessResponse = { value: 'success' }

const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }),
tagTypes: ['success'],
endpoints: (build) => ({
enabled: build.query<SuccessResponse, void>({
query: () => '/success',
}),
disabled: build.query<SuccessResponse, void>({
query: () => ({ url: '/success' }),
structuralSharing: false,
}),
}),
})

const storeRef = setupApiStore(api)

it('enables structural sharing for query endpoints by default', async () => {
const result = await storeRef.store.dispatch(
api.endpoints.enabled.initiate()
)
expect(mockCopyFn).toHaveBeenCalledTimes(1)
expect(result.data).toMatchObject(apiSuccessResponse)
})
it('allows a query endpoint to opt-out of structural sharing', async () => {
const result = await storeRef.store.dispatch(
api.endpoints.disabled.initiate()
)
expect(mockCopyFn).toHaveBeenCalledTimes(0)
expect(result.data).toMatchObject(apiSuccessResponse)
})
it('allows initiate to override endpoint and global settings and disable at the call site level', async () => {
// global flag is enabled, endpoint is also enabled by default
const result = await storeRef.store.dispatch(
api.endpoints.enabled.initiate(undefined, { structuralSharing: false })
)
expect(mockCopyFn).toHaveBeenCalledTimes(0)
expect(result.data).toMatchObject(apiSuccessResponse)
})
it('allows initiate to override the endpoint flag and enable sharing at the call site', async () => {
// global flag is enabled, endpoint is disabled
const result = await storeRef.store.dispatch(
api.endpoints.disabled.initiate(undefined, { structuralSharing: true })
)
expect(mockCopyFn).toHaveBeenCalledTimes(1)
expect(result.data).toMatchObject(apiSuccessResponse)
})
})

0 comments on commit e4c6be8

Please sign in to comment.