Skip to content

Commit

Permalink
test: useFetch... hooks when has error or no data (#632)
Browse files Browse the repository at this point in the history
<!--
Filling out this template is required. Any PR that does not include
enough information to be reviewed may be closed at a maintainers'
discretion. All new code requires documentation and tests to ensure
against regressions.
-->

### Description of the Change
<!--
We must be able to understand the design of your change from this
description. The maintainer reviewing this PR may not have worked with
this code recently, so please provide as much detail as possible.

Where possible, please also include:
- verification steps to ensure your change has the desired effects and
has not introduced any regressions
- any benefits that will be realized
- any alternative implementations or possible drawbacks that you
considered
- screenshots or screencasts
-->

<!-- Enter any applicable Issue number(s) here that will be
closed/resolved by this PR. -->
Closes #

### How to test the Change
<!-- Please provide steps on how to test or validate that the change in
this PR works as described. -->
`npm run test`


### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you are unsure about any of these, please ask for
clarification. We are here to help! -->
- [x] I agree to follow this project's [**Code of
Conduct**](https://github.com/10up/.github/blob/trunk/CODE_OF_CONDUCT.md).
- [x] I have updated the documentation accordingly.
- [x] I have added tests to cover my change.
- [x] All new and existing tests pass.
  • Loading branch information
nicholasio authored Nov 20, 2023
2 parents f0f5c08 + 99c8198 commit 1a5fe38
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 3 deletions.
27 changes: 26 additions & 1 deletion packages/core/src/react/hooks/__tests__/useFetchAppSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { renderHook } from '@testing-library/react';
import { renderHook, waitFor } from '@testing-library/react';
import { expectTypeOf } from 'expect-type';
import { AppEntity, EndpointParams } from '../../../data';
import { useFetchAppSettings } from '../useFetchAppSettings';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchAppSettings types', () => {
it('allows overriding types', () => {
Expand All @@ -23,4 +25,27 @@ describe('useFetchAppSettings types', () => {
| undefined
>();
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchAppSettings({ includeCustomSettings: true }));

const expectedKeys = ['error', 'loading', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(1);
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(true);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.posts).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});
});
27 changes: 27 additions & 0 deletions packages/core/src/react/hooks/__tests__/useFetchPost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { DRAFT_POST_ID, VALID_AUTH_TOKEN } from '../../../../test/server';
import { PostEntity, PostParams } from '../../../data';
import { SettingsProvider } from '../../provider';
import { useFetchPost } from '../useFetchPost';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchPost', () => {
const wrapper = ({ children }) => {
Expand Down Expand Up @@ -43,6 +45,31 @@ describe('useFetchPost', () => {
);
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchPost({}), {
wrapper,
});

const expectedKeys = ['error', 'loading', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(1);
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(false);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.post.title).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});

it('fetch by id', async () => {
const { result } = renderHook(() => useFetchPost({ id: 64 }), {
wrapper,
Expand Down
29 changes: 29 additions & 0 deletions packages/core/src/react/hooks/__tests__/useFetchPostOrPosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useFetchPostOrPosts } from '../useFetchPostOrPosts';
import { PostEntity, PostOrPostsParams } from '../../../data';
import { useFetchPost } from '../useFetchPost';
import { useFetchPosts } from '../useFetchPosts';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchPostOrPosts', () => {
const wrapper = ({ children }) => {
Expand Down Expand Up @@ -75,6 +77,33 @@ describe('useFetchPostOrPosts', () => {
});
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchPostOrPosts({}), {
wrapper,
});
const expectedKeys = ['error', 'loading', 'isArchive', 'isSingle', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(3); // #1 useFetch, #2 useFetchPost, #3 useFetchPosts
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(false);
expect(result.current.isArchive).toBe(false);
expect(result.current.isSingle).toBe(false);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.post!.title).toThrow();
expect(() => result.current.data?.posts![0].title).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});

it('populates internal swr cache (single)', async () => {
const p: PostOrPostsParams = {
archive: { taxonomy: 'category' },
Expand Down
29 changes: 29 additions & 0 deletions packages/core/src/react/hooks/__tests__/useFetchPosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { PostEntity, PostsArchiveParams } from '../../../data';
import { SettingsProvider } from '../../provider';
import { useFetchPosts } from '../useFetchPosts';
import { setHeadlessConfig } from '../../../utils';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchPosts', () => {
const wrapper = ({ children }) => {
Expand Down Expand Up @@ -40,6 +42,33 @@ describe('useFetchPosts', () => {
});
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchPosts({}), {
wrapper,
});

const expectedKeys = ['error', 'loading', 'pageType', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(1);
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(true);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.posts[0].title).toThrow();
expect(() => result.current.data?.pageInfo[0].title).toThrow();
expect(() => result.current.data?.queriedObject[0].title).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});

it('returns queried object for category archives', async () => {
const { result } = renderHook(
() =>
Expand Down
31 changes: 30 additions & 1 deletion packages/core/src/react/hooks/__tests__/useFetchSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { PostEntity, PostsArchiveParams } from '../../../data';
import { SettingsProvider } from '../../provider';
import { useFetchSearch } from '../useFetchSearch';
import { setHeadlessConfig } from '../../../utils';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchPosts', () => {
describe('useFetchSearch', () => {
const wrapper = ({ children }) => {
return <SettingsProvider settings={{ sourceUrl: '' }}>{children}</SettingsProvider>;
};
Expand All @@ -29,6 +31,33 @@ describe('useFetchPosts', () => {
});
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchSearch({}), {
wrapper,
});

const expectedKeys = ['error', 'loading', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(1);
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(true);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.posts[0].title).toThrow();
expect(() => result.current.data?.pageInfo[0].title).toThrow();
expect(() => result.current.data?.queriedObject[0].title).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});

it('fetches data properly', async () => {
const { result } = renderHook(() => useFetchSearch({ per_page: 2 }, {}, '/ipsum'), {
wrapper,
Expand Down
28 changes: 27 additions & 1 deletion packages/core/src/react/hooks/__tests__/useFetchTerms.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { renderHook } from '@testing-library/react';
import { renderHook, waitFor } from '@testing-library/react';
import { expectTypeOf } from 'expect-type';
import { TaxonomyArchiveParams, TermEntity } from '../../../data';
import { useFetchTerms } from '../useFetchTerms';
import * as useFetchModule from '../useFetch';
import { mockUseFetchErrorResponse } from '../mocks';

describe('useFetchTerms types', () => {
it('allows overriding types', () => {
Expand All @@ -22,4 +24,28 @@ describe('useFetchTerms types', () => {
| undefined
>();
});

it('handles response if has error or there is no data', async () => {
const spyUseFetch = jest
.spyOn(useFetchModule, 'useFetch')
.mockReturnValueOnce(mockUseFetchErrorResponse);
const { result } = renderHook(() => useFetchTerms({ includeCustomSettings: true }));

const expectedKeys = ['error', 'loading', 'data', 'isMainQuery'];
const returnedKeys = Object.keys(result.current);
const missingKeys = returnedKeys.filter((key) => !expectedKeys.includes(key));

await waitFor(() => {
expect(missingKeys).toHaveLength(0);
expect(spyUseFetch).toHaveBeenCalledTimes(1);
expect(result.current.error).toBe('Not found');
expect(result.current.loading).toBe(true);
expect(() => result.current.data).not.toThrow();
expect(() => result.current.data?.terms[0].title).toThrow();
expect(() => result.current.data?.pageInfo[0].title).toThrow();
expect(result.current.isMainQuery).toBe(true);
});

spyUseFetch.mockRestore();
});
});
9 changes: 9 additions & 0 deletions packages/core/src/react/hooks/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const mockUseFetchErrorResponse = {
error: 'Not found',
params: {},
data: undefined,
isMainQuery: true,
mutate: jest.fn(),
isLoading: false,
isValidating: false,
};

1 comment on commit 1a5fe38

@vercel
Copy link

@vercel vercel bot commented on 1a5fe38 Nov 20, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.