From 63f101c8396dec936b6ef6a418181cc54e0299f6 Mon Sep 17 00:00:00 2001 From: Matt Sutkowski Date: Wed, 17 Mar 2021 21:23:52 -0700 Subject: [PATCH] Basic WIP of useLazyQuery --- .../react/src/features/posts/PostsManager.tsx | 14 +- examples/react/src/mocks/handlers.ts | 2 +- package.json | 1 + src/react-hooks/buildHooks.ts | 23 + src/react-hooks/module.ts | 4 +- test/buildHooks.test.tsx | 1085 +++++++++-------- yarn.lock | 21 + 7 files changed, 624 insertions(+), 526 deletions(-) diff --git a/examples/react/src/features/posts/PostsManager.tsx b/examples/react/src/features/posts/PostsManager.tsx index 4fb5d2b8..9151624e 100644 --- a/examples/react/src/features/posts/PostsManager.tsx +++ b/examples/react/src/features/posts/PostsManager.tsx @@ -56,7 +56,9 @@ const PostListItem = ({ data: { name, id }, onSelect }: { data: Post; onSelect: }; const PostList = () => { - const { data: posts, isLoading } = useGetPostsQuery(); + // const { data: posts, isLoading } = useGetPostsQuery(); + const [getPosts, { data: posts, isLoading, isFetching }] = postApi.endpoints['getPosts'].useLazyQuery(); + const { push } = useHistory(); if (isLoading) { @@ -64,11 +66,19 @@ const PostList = () => { } if (!posts) { - return
No posts :(
; + return ( +
+ No posts :({' '} + +
+ ); } return (
+ {posts.map((post) => ( push(`/posts/${id}`)} /> ))} diff --git a/examples/react/src/mocks/handlers.ts b/examples/react/src/mocks/handlers.ts index 3bdab6c5..419cc750 100644 --- a/examples/react/src/mocks/handlers.ts +++ b/examples/react/src/mocks/handlers.ts @@ -58,7 +58,7 @@ export const handlers = [ }), rest.get('/posts', (req, res, ctx) => { - return res(ctx.json(Object.values(state.entities))); + return res(ctx.delay(300), ctx.json(Object.values(state.entities))); }), rest.post('/posts', (req, res, ctx) => { diff --git a/package.json b/package.json index b5a66a6e..f397c0a5 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "rollup-plugin-terser": "^7.0.2", "shelljs": "^0.8.4", "size-limit": "^4.6.0", + "ts-jest": "^26.5.4", "ts-node": "^9.0.0", "ts-unused-exports": "^7.0.0", "tsdx": "^0.14.1", diff --git a/src/react-hooks/buildHooks.ts b/src/react-hooks/buildHooks.ts index cefa1c69..3459f216 100644 --- a/src/react-hooks/buildHooks.ts +++ b/src/react-hooks/buildHooks.ts @@ -27,6 +27,7 @@ import { useShallowStableValue } from './useShallowStableValue'; export interface QueryHooks> { useQuery: UseQuery; + useLazyQuery: UseLazyQuery; useQuerySubscription: UseQuerySubscription; useQueryState: UseQueryState; } @@ -40,6 +41,11 @@ export type UseQuery> = ) => UseQueryStateResult & ReturnType>; +export type UseLazyQuery> = >( + arg: QueryArgFrom, + options?: UseQuerySubscriptionOptions & UseQueryStateOptions +) => [() => void, UseQueryStateResult & ReturnType>]; + interface UseQuerySubscriptionOptions extends SubscriptionOptions { skip?: boolean; refetchOnMountOrArgChange?: boolean | number; @@ -262,6 +268,23 @@ export function buildHooks({ return { useQueryState, useQuerySubscription, + useLazyQuery(arg, options) { + const queryStateResults = useQueryState(arg, options); + const [isTriggered, setTriggered] = useState((queryStateResults as any).isSuccess); + const { refetch, ...querySubscriptionResults } = useQuerySubscription(arg, { + ...options, + ...(isTriggered ? {} : { skip: !isTriggered }), + }); + + const triggerQuery = useCallback(() => (!isTriggered ? setTriggered(true) : refetch()), [refetch, isTriggered]); + + return useMemo(() => [triggerQuery, { refetch, ...queryStateResults, ...querySubscriptionResults }], [ + queryStateResults, + querySubscriptionResults, + refetch, + triggerQuery, + ]); + }, useQuery(arg, options) { const querySubscriptionResults = useQuerySubscription(arg, options); const queryStateResults = useQueryState(arg, options); diff --git a/src/react-hooks/module.ts b/src/react-hooks/module.ts index acadf833..49db538c 100644 --- a/src/react-hooks/module.ts +++ b/src/react-hooks/module.ts @@ -70,13 +70,15 @@ export const reactHooksModule = ({ injectEndpoint(endpointName, definition) { const anyApi = (api as any) as Api, string, string, ReactHooksModule>; if (isQueryDefinition(definition)) { - const { useQuery, useQueryState, useQuerySubscription } = buildQueryHooks(endpointName); + const { useQuery, useLazyQuery, useQueryState, useQuerySubscription } = buildQueryHooks(endpointName); safeAssign(anyApi.endpoints[endpointName], { useQuery, + useLazyQuery, useQueryState, useQuerySubscription, }); (api as any)[`use${capitalize(endpointName)}Query`] = useQuery; + (api as any)[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery; } else if (isMutationDefinition(definition)) { const useMutation = buildMutationHook(endpointName); safeAssign(anyApi.endpoints[endpointName], { diff --git a/test/buildHooks.test.tsx b/test/buildHooks.test.tsx index 072c4413..2a06be67 100644 --- a/test/buildHooks.test.tsx +++ b/test/buildHooks.test.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import { createApi, fetchBaseQuery, QueryStatus } from '@rtk-incubator/rtk-query/react'; -import { act, fireEvent, render, waitFor } from '@testing-library/react'; +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { rest } from 'msw'; import { setupApiStore, waitMs } from './helpers'; import { server } from './mocks/server'; -import { rest } from 'msw'; // Just setup a temporary in-memory counter for tests that `getIncrementedAmount`. // This can be used to test how many renders happen due to data changes or @@ -47,589 +47,630 @@ afterEach(() => { }); describe('hooks tests', () => { - test('useQuery hook sets isFetching=true whenever a request is in flight', async () => { - function User() { - const [value, setValue] = React.useState(0); + describe('useQuery', () => { + test('useQuery hook sets isFetching=true whenever a request is in flight', async () => { + function User() { + const [value, setValue] = React.useState(0); - const { isFetching } = api.endpoints.getUser.useQuery(1, { skip: value < 1 }); + const { isFetching } = api.endpoints.getUser.useQuery(1, { skip: value < 1 }); - return ( -
-
{String(isFetching)}
- -
- ); - } - - const { getByText, getByTestId } = render(, { wrapper: storeRef.wrapper }); + return ( +
+
{String(isFetching)}
+ +
+ ); + } - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - fireEvent.click(getByText('Increment value')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - fireEvent.click(getByText('Increment value')); - // Being that nothing has changed in the args, this should never fire. - expect(getByTestId('isFetching').textContent).toBe('false'); - }); + render(, { wrapper: storeRef.wrapper }); - test('useQuery hook sets isLoading=true only on initial request', async () => { - let refetch: any, isLoading: boolean; - function User() { - const [value, setValue] = React.useState(0); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + fireEvent.click(screen.getByText('Increment value')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + fireEvent.click(screen.getByText('Increment value')); + // Being that nothing has changed in the args, this should never fire. + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); - ({ isLoading, refetch } = api.endpoints.getUser.useQuery(2, { skip: value < 1 })); - return ( -
-
{String(isLoading)}
- -
- ); - } + test('useQuery hook sets isLoading=true only on initial request', async () => { + let refetch: any, isLoading: boolean; + function User() { + const [value, setValue] = React.useState(0); - const { getByText, getByTestId } = render(, { wrapper: storeRef.wrapper }); - - // Being that we skipped the initial request on mount, this should be false - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); - fireEvent.click(getByText('Increment value')); - // Condition is met, should load - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); // Make sure the original loading has completed. - fireEvent.click(getByText('Increment value')); - // Being that we already have data, isLoading should be false - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); - // We call a refetch, should set to true - act(() => refetch()); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); - }); + ({ isLoading, refetch } = api.endpoints.getUser.useQuery(2, { skip: value < 1 })); + return ( +
+
{String(isLoading)}
+ +
+ ); + } - test('useQuery hook sets isLoading and isFetching to the correct states', async () => { - let refetchMe: () => void = () => {}; - function User() { - const [value, setValue] = React.useState(0); + render(, { wrapper: storeRef.wrapper }); + + // Being that we skipped the initial request on mount, this should be false + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); + fireEvent.click(screen.getByText('Increment value')); + // Condition is met, should load + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); // Make sure the original loading has completed. + fireEvent.click(screen.getByText('Increment value')); + // Being that we already have data, isLoading should be false + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); + // We call a refetch, should set to true + act(() => refetch()); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); + }); - const { isLoading, isFetching, refetch } = api.endpoints.getUser.useQuery(22, { skip: value < 1 }); - refetchMe = refetch; - return ( -
-
{String(isFetching)}
-
{String(isLoading)}
- -
- ); - } + test('useQuery hook sets isLoading and isFetching to the correct states', async () => { + let refetchMe: () => void = () => {}; + function User() { + const [value, setValue] = React.useState(0); - const { getByText, getByTestId } = render(, { wrapper: storeRef.wrapper }); + const { isLoading, isFetching, refetch } = api.endpoints.getUser.useQuery(22, { skip: value < 1 }); + refetchMe = refetch; + return ( +
+
{String(isFetching)}
+
{String(isLoading)}
+ +
+ ); + } - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('isFetching').textContent).toBe('false'); - }); - fireEvent.click(getByText('Increment value')); - // Condition is met, should load - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('true'); - expect(getByTestId('isFetching').textContent).toBe('true'); - }); - // Make sure the request is done for sure. - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('isFetching').textContent).toBe('false'); - }); - fireEvent.click(getByText('Increment value')); - // Being that we already have data, isLoading should be false - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('isFetching').textContent).toBe('false'); - }); - // Make sure the request is done for sure. - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('isFetching').textContent).toBe('false'); - }); - // We call a refetch, should set both to true, then false when complete/errored - act(() => refetchMe()); - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('true'); - expect(getByTestId('isFetching').textContent).toBe('true'); - }); - await waitFor(() => { - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('isFetching').textContent).toBe('false'); + render(, { wrapper: storeRef.wrapper }); + + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); + fireEvent.click(screen.getByText('Increment value')); + // Condition is met, should load + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('true'); + expect(screen.getByTestId('isFetching').textContent).toBe('true'); + }); + // Make sure the request is done for sure. + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); + fireEvent.click(screen.getByText('Increment value')); + // Being that we already have data, isLoading should be false + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); + // Make sure the request is done for sure. + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); + // We call a refetch, should set both to true, then false when complete/errored + act(() => refetchMe()); + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('true'); + expect(screen.getByTestId('isFetching').textContent).toBe('true'); + }); + await waitFor(() => { + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + }); }); - }); - test('useQuery hook respects refetchOnMountOrArgChange: true', async () => { - let data, isLoading, isFetching; - function User() { - ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { - refetchOnMountOrArgChange: true, - })); - return ( -
-
{String(isLoading)}
-
{String(isFetching)}
-
{String(data?.amount)}
-
- ); - } + test('useQuery hook respects refetchOnMountOrArgChange: true', async () => { + let data, isLoading, isFetching; + function User() { + ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { + refetchOnMountOrArgChange: true, + })); + return ( +
+
{String(isLoading)}
+
{String(isFetching)}
+
{String(data?.amount)}
+
+ ); + } - let { getByTestId, unmount } = render(, { wrapper: storeRef.wrapper }); + const { unmount } = render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); - unmount(); + unmount(); - ({ getByTestId } = render(, { wrapper: storeRef.wrapper })); - // Let's make sure we actually fetch, and we increment - expect(getByTestId('isLoading').textContent).toBe('false'); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + render(, { wrapper: storeRef.wrapper }); + // Let's make sure we actually fetch, and we increment + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('2')); - }); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('2')); + }); - test('useQuery does not refetch when refetchOnMountOrArgChange: NUMBER condition is not met', async () => { - let data, isLoading, isFetching; - function User() { - ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { - refetchOnMountOrArgChange: 10, - })); - return ( -
-
{String(isLoading)}
-
{String(isFetching)}
-
{String(data?.amount)}
-
- ); - } + test('useQuery does not refetch when refetchOnMountOrArgChange: NUMBER condition is not met', async () => { + let data, isLoading, isFetching; + function User() { + ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { + refetchOnMountOrArgChange: 10, + })); + return ( +
+
{String(isLoading)}
+
{String(isFetching)}
+
{String(data?.amount)}
+
+ ); + } - let { getByTestId, unmount } = render(, { wrapper: storeRef.wrapper }); + const { unmount } = render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); - unmount(); + unmount(); - ({ getByTestId } = render(, { wrapper: storeRef.wrapper })); - // Let's make sure we actually fetch, and we increment. Should be false because we do this immediately - // and the condition is set to 10 seconds - expect(getByTestId('isFetching').textContent).toBe('false'); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); - }); + render(, { wrapper: storeRef.wrapper }); + // Let's make sure we actually fetch, and we increment. Should be false because we do this immediately + // and the condition is set to 10 seconds + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); + }); - test('useQuery refetches when refetchOnMountOrArgChange: NUMBER condition is met', async () => { - let data, isLoading, isFetching; - function User() { - ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { - refetchOnMountOrArgChange: 0.5, - })); - return ( -
-
{String(isLoading)}
-
{String(isFetching)}
-
{String(data?.amount)}
-
- ); - } + test('useQuery refetches when refetchOnMountOrArgChange: NUMBER condition is met', async () => { + let data, isLoading, isFetching; + function User() { + ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { + refetchOnMountOrArgChange: 0.5, + })); + return ( +
+
{String(isLoading)}
+
{String(isFetching)}
+
{String(data?.amount)}
+
+ ); + } - let { getByTestId, unmount } = render(, { wrapper: storeRef.wrapper }); + const { unmount } = render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); - unmount(); + unmount(); - // Wait to make sure we've passed the `refetchOnMountOrArgChange` value - await waitMs(510); + // Wait to make sure we've passed the `refetchOnMountOrArgChange` value + await waitMs(510); - ({ getByTestId } = render(, { wrapper: storeRef.wrapper })); - // Let's make sure we actually fetch, and we increment - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + render(, { wrapper: storeRef.wrapper }); + // Let's make sure we actually fetch, and we increment + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('2')); - }); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('2')); + }); - test('refetchOnMountOrArgChange works as expected when changing skip from false->true', async () => { - let data, isLoading, isFetching; - function User() { - const [skip, setSkip] = React.useState(true); - ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { - refetchOnMountOrArgChange: 0.5, - skip, - })); + test('refetchOnMountOrArgChange works as expected when changing skip from false->true', async () => { + let data, isLoading, isFetching; + function User() { + const [skip, setSkip] = React.useState(true); + ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { + refetchOnMountOrArgChange: 0.5, + skip, + })); - return ( -
-
{String(isLoading)}
-
{String(isFetching)}
-
{String(data?.amount)}
- ; -
- ); - } + return ( +
+
{String(isLoading)}
+
{String(isFetching)}
+
{String(data?.amount)}
+ ; +
+ ); + } - let { getByTestId, getByText } = render(, { wrapper: storeRef.wrapper }); + render(, { wrapper: storeRef.wrapper }); - expect(getByTestId('isLoading').textContent).toBe('false'); - expect(getByTestId('amount').textContent).toBe('undefined'); + expect(screen.getByTestId('isLoading').textContent).toBe('false'); + expect(screen.getByTestId('amount').textContent).toBe('undefined'); - fireEvent.click(getByText('change skip')); + fireEvent.click(screen.getByText('change skip')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); - }); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); + }); - test('refetchOnMountOrArgChange works as expected when changing skip from false->true with a cached query', async () => { - // 1. we need to mount a skipped query, then toggle skip to generate a cached result - // 2. we need to mount a skipped component after that, then toggle skip as well. should pull from the cache. - // 3. we need to mount another skipped component, then toggle skip after the specified duration and expect the time condition to be satisfied + test('refetchOnMountOrArgChange works as expected when changing skip from false->true with a cached query', async () => { + // 1. we need to mount a skipped query, then toggle skip to generate a cached result + // 2. we need to mount a skipped component after that, then toggle skip as well. should pull from the cache. + // 3. we need to mount another skipped component, then toggle skip after the specified duration and expect the time condition to be satisfied - let data, isLoading, isFetching; - function User() { - const [skip, setSkip] = React.useState(true); - ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { - skip, - refetchOnMountOrArgChange: 0.5, - })); + let data, isLoading, isFetching; + function User() { + const [skip, setSkip] = React.useState(true); + ({ data, isLoading, isFetching } = api.endpoints.getIncrementedAmount.useQuery(undefined, { + skip, + refetchOnMountOrArgChange: 0.5, + })); - return ( -
-
{String(isLoading)}
-
{String(isFetching)}
-
{String(data?.amount)}
- ; -
- ); - } + return ( +
+
{String(isLoading)}
+
{String(isFetching)}
+
{String(data?.amount)}
+ ; +
+ ); + } - let { getByTestId, getByText, unmount } = render(, { wrapper: storeRef.wrapper }); + let { unmount } = render(, { wrapper: storeRef.wrapper }); - // skipped queries do nothing by default, so we need to toggle that to get a cached result - fireEvent.click(getByText('change skip')); + // skipped queries do nothing by default, so we need to toggle that to get a cached result + fireEvent.click(screen.getByText('change skip')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); - unmount(); + unmount(); - await waitMs(100); + await waitMs(100); - // This will pull from the cache as the time criteria is not met. - ({ getByTestId, getByText, unmount } = render(, { - wrapper: storeRef.wrapper, - })); + // This will pull from the cache as the time criteria is not met. + ({ unmount } = render(, { + wrapper: storeRef.wrapper, + })); - // skipped queries return nothing - expect(getByTestId('isFetching').textContent).toBe('false'); - expect(getByTestId('amount').textContent).toBe('undefined'); + // skipped queries return nothing + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + expect(screen.getByTestId('amount').textContent).toBe('undefined'); - // toggle skip -> true... won't refetch as the time critera is not met, and just loads the cached values - fireEvent.click(getByText('change skip')); - expect(getByTestId('isFetching').textContent).toBe('false'); - expect(getByTestId('amount').textContent).toBe('1'); + // toggle skip -> true... won't refetch as the time critera is not met, and just loads the cached values + fireEvent.click(screen.getByText('change skip')); + expect(screen.getByTestId('isFetching').textContent).toBe('false'); + expect(screen.getByTestId('amount').textContent).toBe('1'); - unmount(); + unmount(); - await waitMs(500); + await waitMs(500); - ({ getByTestId, getByText, unmount } = render(, { - wrapper: storeRef.wrapper, - })); + ({ unmount } = render(, { + wrapper: storeRef.wrapper, + })); - // toggle skip -> true... will cause a refetch as the time criteria is now satisfied - fireEvent.click(getByText('change skip')); + // toggle skip -> true... will cause a refetch as the time criteria is now satisfied + fireEvent.click(screen.getByText('change skip')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('2')); + }); }); - test('useMutation hook sets and unsets the `isLoading` flag when running', async () => { - function User() { - const [updateUser, { isLoading }] = api.endpoints.updateUser.useMutation(); - - return ( -
-
{String(isLoading)}
- -
- ); - } + describe('useLazyQuery', () => { + test('useLazyQuery does not automatically fetch when mounted', async () => { + function User() { + const [fetchUser, { isFetching, isUninitialized }] = api.endpoints.getUser.useLazyQuery(1); - const { getByText, getByTestId } = render(, { wrapper: storeRef.wrapper }); + return ( +
+
{String(isUninitialized)}
+
{String(isFetching)}
- await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); - fireEvent.click(getByText('Update User')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); - }); + +
+ ); + } - test('useMutation hook sets data to the resolved response on success', async () => { - const result = { name: 'Banana' }; + render(, { wrapper: storeRef.wrapper }); - function User() { - const [updateUser, { data }] = api.endpoints.updateUser.useMutation(); + await waitFor(() => expect(screen.getByTestId('isUninitialized').textContent).toBe('true')); - return ( -
-
{JSON.stringify(data)}
- -
- ); - } + fireEvent.click(screen.getByTestId('fetchButton')); - const { getByText, getByTestId } = render(, { wrapper: storeRef.wrapper }); + await waitFor(() => { + expect(screen.getByTestId('isUninitialized').textContent).toBe('false'); + expect(screen.getByTestId('isFetching').textContent).toBe('true'); + }); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + }); - fireEvent.click(getByText('Update User')); - await waitFor(() => expect(getByTestId('result').textContent).toBe(JSON.stringify(result))); + test.todo('shows existing data for a query if available'); + test.todo('handles arg changes and basic useQuery opts'); + test.todo('deals with any skip oddities assuming we keep partial skip functionality?'); }); - test('usePrefetch respects force arg', async () => { - const { usePrefetch } = api; - const USER_ID = 4; - function User() { - const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); - const prefetchUser = usePrefetch('getUser', { force: true }); + describe('useMutation', () => { + test('useMutation hook sets and unsets the `isLoading` flag when running', async () => { + function User() { + const [updateUser, { isLoading }] = api.endpoints.updateUser.useMutation(); - return ( -
-
{String(isFetching)}
- -
- ); - } + return ( +
+
{String(isLoading)}
+ +
+ ); + } - const { getByTestId } = render(, { wrapper: storeRef.wrapper }); - - // Resolve initial query - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - - userEvent.hover(getByTestId('highPriority')); - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - error: undefined, - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: true, - isSuccess: false, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.pending, - }); + render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: false, - isSuccess: true, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.fulfilled, + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); + fireEvent.click(screen.getByText('Update User')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); }); - }); - test('usePrefetch does not make an additional request if already in the cache and force=false', async () => { - const { usePrefetch } = api; - const USER_ID = 2; + test('useMutation hook sets data to the resolved response on success', async () => { + const result = { name: 'Banana' }; - function User() { - // Load the initial query - const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); - const prefetchUser = usePrefetch('getUser', { force: false }); + function User() { + const [updateUser, { data }] = api.endpoints.updateUser.useMutation(); - return ( -
-
{String(isFetching)}
- -
- ); - } + return ( +
+
{JSON.stringify(data)}
+ +
+ ); + } - const { getByTestId } = render(, { wrapper: storeRef.wrapper }); - - // Let the initial query resolve - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - // Try to prefetch what we just loaded - userEvent.hover(getByTestId('lowPriority')); - - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: false, - isSuccess: true, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.fulfilled, + render(, { wrapper: storeRef.wrapper }); + + fireEvent.click(screen.getByText('Update User')); + await waitFor(() => expect(screen.getByTestId('result').textContent).toBe(JSON.stringify(result))); }); + }); - await waitMs(); + describe('usePrefetch', () => { + test('usePrefetch respects force arg', async () => { + const { usePrefetch } = api; + const USER_ID = 4; + function User() { + const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); + const prefetchUser = usePrefetch('getUser', { force: true }); - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: false, - isSuccess: true, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.fulfilled, + return ( +
+
{String(isFetching)}
+ +
+ ); + } + + render(, { wrapper: storeRef.wrapper }); + + // Resolve initial query + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + + userEvent.hover(screen.getByTestId('highPriority')); + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + error: undefined, + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: true, + isSuccess: false, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.pending, + }); + + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: false, + isSuccess: true, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.fulfilled, + }); }); - }); - test('usePrefetch respects `ifOlderThan` when it evaluates to `true`', async () => { - const { usePrefetch } = api; - const USER_ID = 47; + test('usePrefetch does not make an additional request if already in the cache and force=false', async () => { + const { usePrefetch } = api; + const USER_ID = 2; - function User() { - // Load the initial query - const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); - const prefetchUser = usePrefetch('getUser', { ifOlderThan: 0.2 }); + function User() { + // Load the initial query + const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); + const prefetchUser = usePrefetch('getUser', { force: false }); - return ( -
-
{String(isFetching)}
- -
- ); - } + return ( +
+
{String(isFetching)}
+ +
+ ); + } - const { getByTestId } = render(, { wrapper: storeRef.wrapper }); - - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - - // Wait 400ms, making it respect ifOlderThan - await waitMs(400); - - // This should run the query being that we're past the threshold - userEvent.hover(getByTestId('lowPriority')); - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: true, - isSuccess: false, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.pending, - }); + render(, { wrapper: storeRef.wrapper }); + + // Let the initial query resolve + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + // Try to prefetch what we just loaded + userEvent.hover(screen.getByTestId('lowPriority')); + + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: false, + isSuccess: true, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.fulfilled, + }); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - data: undefined, - endpointName: 'getUser', - fulfilledTimeStamp: expect.any(Number), - isError: false, - isLoading: false, - isSuccess: true, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: QueryStatus.fulfilled, + await waitMs(); + + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: false, + isSuccess: true, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.fulfilled, + }); }); - }); - test('usePrefetch returns the last success result when `ifOlderThan` evalutes to `false`', async () => { - const { usePrefetch } = api; - const USER_ID = 2; + test('usePrefetch respects `ifOlderThan` when it evaluates to `true`', async () => { + const { usePrefetch } = api; + const USER_ID = 47; - function User() { - // Load the initial query - const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); - const prefetchUser = usePrefetch('getUser', { ifOlderThan: 10 }); + function User() { + // Load the initial query + const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); + const prefetchUser = usePrefetch('getUser', { ifOlderThan: 0.2 }); - return ( -
-
{String(isFetching)}
- -
- ); - } + return ( +
+
{String(isFetching)}
+ +
+ ); + } - const { getByTestId } = render(, { wrapper: storeRef.wrapper }); + render(, { wrapper: storeRef.wrapper }); + + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + + // Wait 400ms, making it respect ifOlderThan + await waitMs(400); + + // This should run the query being that we're past the threshold + userEvent.hover(screen.getByTestId('lowPriority')); + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: true, + isSuccess: false, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.pending, + }); + + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + data: undefined, + endpointName: 'getUser', + fulfilledTimeStamp: expect.any(Number), + isError: false, + isLoading: false, + isSuccess: true, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: QueryStatus.fulfilled, + }); + }); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); - await waitMs(); + test('usePrefetch returns the last success result when `ifOlderThan` evalutes to `false`', async () => { + const { usePrefetch } = api; + const USER_ID = 2; - // Get a snapshot of the last result - const latestQueryData = api.endpoints.getUser.select(USER_ID)(storeRef.store.getState()); + function User() { + // Load the initial query + const { isFetching } = api.endpoints.getUser.useQuery(USER_ID); + const prefetchUser = usePrefetch('getUser', { ifOlderThan: 10 }); - userEvent.hover(getByTestId('lowPriority')); - // Serve up the result from the cache being that the condition wasn't met - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual(latestQueryData); - }); + return ( +
+
{String(isFetching)}
+ +
+ ); + } - test('usePrefetch executes a query even if conditions fail when the cache is empty', async () => { - const { usePrefetch } = api; - const USER_ID = 2; + render(, { wrapper: storeRef.wrapper }); - function User() { - const prefetchUser = usePrefetch('getUser', { ifOlderThan: 10 }); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + await waitMs(); - return ( -
- -
- ); - } + // Get a snapshot of the last result + const latestQueryData = api.endpoints.getUser.select(USER_ID)(storeRef.store.getState()); + + userEvent.hover(screen.getByTestId('lowPriority')); + // Serve up the result from the cache being that the condition wasn't met + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual(latestQueryData); + }); + + test('usePrefetch executes a query even if conditions fail when the cache is empty', async () => { + const { usePrefetch } = api; + const USER_ID = 2; - const { getByTestId } = render(, { wrapper: storeRef.wrapper }); + function User() { + const prefetchUser = usePrefetch('getUser', { ifOlderThan: 10 }); - userEvent.hover(getByTestId('lowPriority')); + return ( +
+ +
+ ); + } - expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ - endpointName: 'getUser', - isError: false, - isLoading: true, - isSuccess: false, - isUninitialized: false, - originalArgs: USER_ID, - requestId: expect.any(String), - startedTimeStamp: expect.any(Number), - status: 'pending', + render(, { wrapper: storeRef.wrapper }); + + userEvent.hover(screen.getByTestId('lowPriority')); + + expect(api.endpoints.getUser.select(USER_ID)(storeRef.store.getState())).toEqual({ + endpointName: 'getUser', + isError: false, + isLoading: true, + isSuccess: false, + isUninitialized: false, + originalArgs: USER_ID, + requestId: expect.any(String), + startedTimeStamp: expect.any(Number), + status: 'pending', + }); }); }); }); @@ -670,12 +711,12 @@ describe('hooks with createApi defaults set', () => { ); } - let { getByTestId, unmount } = render(, { wrapper: storeRef.wrapper }); + const { unmount } = render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); unmount(); @@ -691,12 +732,12 @@ describe('hooks with createApi defaults set', () => { ); } - ({ getByTestId } = render(, { wrapper: storeRef.wrapper })); + render(, { wrapper: storeRef.wrapper }); // Let's make sure we actually fetch, and we increment - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('2')); }); test('useQuery hook overrides default refetchOnMountOrArgChange: false that was set by createApi', async () => { @@ -712,12 +753,12 @@ describe('hooks with createApi defaults set', () => { ); } - let { getByTestId, unmount } = render(, { wrapper: storeRef.wrapper }); + let { unmount } = render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('true')); - await waitFor(() => expect(getByTestId('isLoading').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('true')); + await waitFor(() => expect(screen.getByTestId('isLoading').textContent).toBe('false')); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); unmount(); @@ -733,10 +774,10 @@ describe('hooks with createApi defaults set', () => { ); } - ({ getByTestId } = render(, { wrapper: storeRef.wrapper })); - await waitFor(() => expect(getByTestId('isFetching').textContent).toBe('false')); + render(, { wrapper: storeRef.wrapper }); - await waitFor(() => expect(getByTestId('amount').textContent).toBe('1')); + await waitFor(() => expect(screen.getByTestId('isFetching').textContent).toBe('false')); + await waitFor(() => expect(screen.getByTestId('amount').textContent).toBe('1')); }); describe('selectFromResult behaviors', () => { @@ -856,25 +897,25 @@ describe('hooks with createApi defaults set', () => { return
{String(renderCount)}
; } - const { getByTestId } = render( + render(
, { wrapper: storeRef.wrapper } ); - expect(getByTestId('renderCount').textContent).toBe('1'); + expect(screen.getByTestId('renderCount').textContent).toBe('1'); - const addBtn = getByTestId('addPost'); + const addBtn = screen.getByTestId('addPost'); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); // We fire off a few requests that would typically cause a rerender as JSON.parse() on a request would always be a new object. fireEvent.click(addBtn); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); // Being that it didn't rerender, we can be assured that the behavior is correct }); @@ -907,24 +948,24 @@ describe('hooks with createApi defaults set', () => { return
{String(renderCount)}
; } - const { getByTestId } = render( + render(
, { wrapper: storeRef.wrapper } ); - expect(getByTestId('renderCount').textContent).toBe('1'); + expect(screen.getByTestId('renderCount').textContent).toBe('1'); - const addBtn = getByTestId('addPost'); + const addBtn = screen.getByTestId('addPost'); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); fireEvent.click(addBtn); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); }); test('useQuery with selectFromResult option serves a deeply memoized value, then ONLY updates when the underlying data changes', async () => { @@ -968,30 +1009,30 @@ describe('hooks with createApi defaults set', () => { ); } - const { getByTestId } = render( + render(
, { wrapper: storeRef.wrapper } ); - expect(getByTestId('renderCount').textContent).toBe('1'); + expect(screen.getByTestId('renderCount').textContent).toBe('1'); - const addBtn = getByTestId('addPost'); - const updateBtn = getByTestId('updatePost'); + const addBtn = screen.getByTestId('addPost'); + const updateBtn = screen.getByTestId('updatePost'); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); fireEvent.click(addBtn); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('2')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('2')); fireEvent.click(updateBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('3')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('3')); expect(expectablePost?.name).toBe('supercoooll!'); fireEvent.click(addBtn); - await waitFor(() => expect(getByTestId('renderCount').textContent).toBe('3')); + await waitFor(() => expect(screen.getByTestId('renderCount').textContent).toBe('3')); }); }); }); diff --git a/yarn.lock b/yarn.lock index d51240a8..5141ecca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5919,6 +5919,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash@4.x: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" @@ -8819,6 +8824,22 @@ ts-jest@^25.3.1, ts-jest@^26.4.4: semver "7.x" yargs-parser "20.x" +ts-jest@^26.5.4: + version "26.5.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.4.tgz#207f4c114812a9c6d5746dd4d1cdf899eafc9686" + integrity sha512-I5Qsddo+VTm94SukBJ4cPimOoFZsYTeElR2xy6H2TOVs+NsvgYglW8KuQgKoApOKuaU/Ix/vrF9ebFZlb5D2Pg== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "^26.1.0" + json5 "2.x" + lodash "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "20.x" + ts-node@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.0.0.tgz#e7699d2a110cc8c0d3b831715e417688683460b3"