Add tests
This commit is contained in:
parent
15f536e949
commit
6b297c3a7e
4 changed files with 115 additions and 46 deletions
|
@ -2,8 +2,7 @@ import userEvent from '@testing-library/user-event';
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { __stub } from '../../../api';
|
import { mock, render, screen, waitFor } from '../../../jest/test-helpers';
|
||||||
import { render, screen, waitFor } from '../../../jest/test-helpers';
|
|
||||||
import FeedCarousel from '../feed-carousel';
|
import FeedCarousel from '../feed-carousel';
|
||||||
|
|
||||||
jest.mock('../../../hooks/useDimensions', () => ({
|
jest.mock('../../../hooks/useDimensions', () => ({
|
||||||
|
@ -55,55 +54,8 @@ describe('<FeedCarousel />', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the Carousel', () => {
|
describe('with avatars', () => {
|
||||||
store.carousels = {
|
|
||||||
avatars: [
|
|
||||||
{ account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
render(<FeedCarousel />, undefined, store);
|
|
||||||
|
|
||||||
expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with 0 avatars', () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
store.carousels = {
|
|
||||||
avatars: [],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the error message', () => {
|
|
||||||
render(<FeedCarousel />, undefined, store);
|
|
||||||
|
|
||||||
expect(screen.queryAllByTestId('feed-carousel-error')).toHaveLength(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with a failed request to the API', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
store.carousels = {
|
|
||||||
avatars: [],
|
|
||||||
error: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the error message', () => {
|
|
||||||
render(<FeedCarousel />, undefined, store);
|
|
||||||
|
|
||||||
expect(screen.getByTestId('feed-carousel-error')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with multiple pages of avatars', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
store.carousels = {
|
|
||||||
error: false,
|
|
||||||
avatars: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
__stub(mock => {
|
|
||||||
mock.onGet('/api/v1/truth/carousels/avatars')
|
mock.onGet('/api/v1/truth/carousels/avatars')
|
||||||
.reply(200, [
|
.reply(200, [
|
||||||
{ account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
|
{ account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
@ -113,6 +65,53 @@ describe('<FeedCarousel />', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render the Carousel', async() => {
|
||||||
|
render(<FeedCarousel />, undefined, store);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with 0 avatars', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.onGet('/api/v1/truth/carousels/avatars').reply(200, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders nothing', async() => {
|
||||||
|
render(<FeedCarousel />, undefined, store);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a failed request to the API', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.onGet('/api/v1/truth/carousels/avatars').networkError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the error message', async() => {
|
||||||
|
render(<FeedCarousel />, undefined, store);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('feed-carousel-error')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with multiple pages of avatars', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.onGet('/api/v1/truth/carousels/avatars')
|
||||||
|
.reply(200, [
|
||||||
|
{ account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '2', acct: 'b', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '3', acct: 'c', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '4', acct: 'd', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
]);
|
||||||
|
|
||||||
Element.prototype.getBoundingClientRect = jest.fn(() => {
|
Element.prototype.getBoundingClientRect = jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
width: 200,
|
width: 200,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { configureMockStore } from '@jedmao/redux-mock-store';
|
import { configureMockStore } from '@jedmao/redux-mock-store';
|
||||||
import { QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { render, RenderOptions } from '@testing-library/react';
|
import { render, RenderOptions } from '@testing-library/react';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
import { merge } from 'immutable';
|
import { merge } from 'immutable';
|
||||||
import React, { FC, ReactElement } from 'react';
|
import React, { FC, ReactElement } from 'react';
|
||||||
import { IntlProvider } from 'react-intl';
|
import { IntlProvider } from 'react-intl';
|
||||||
|
@ -10,7 +11,7 @@ import { Action, applyMiddleware, createStore } from 'redux';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
|
|
||||||
import { queryClient } from 'soapbox/queries/client';
|
import API from 'soapbox/queries/client';
|
||||||
|
|
||||||
import NotificationsContainer from '../features/ui/containers/notifications_container';
|
import NotificationsContainer from '../features/ui/containers/notifications_container';
|
||||||
import { default as rootReducer } from '../reducers';
|
import { default as rootReducer } from '../reducers';
|
||||||
|
@ -28,8 +29,26 @@ const applyActions = (state: any, actions: any, reducer: any) => {
|
||||||
return actions.reduce((state: any, action: any) => reducer(state, action), state);
|
return actions.reduce((state: any, action: any) => reducer(state, action), state);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createTestStore = (initialState: any) => createStore(rootReducer, initialState, applyMiddleware(thunk));
|
const mock = new MockAdapter(API, { onNoMatch: 'throwException' });
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
logger: {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
log: console.log,
|
||||||
|
warn: console.warn,
|
||||||
|
error: () => { },
|
||||||
|
},
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTestStore = (initialState: any) => createStore(rootReducer, initialState, applyMiddleware(thunk));
|
||||||
const TestApp: FC<any> = ({ children, storeProps, routerProps = {} }) => {
|
const TestApp: FC<any> = ({ children, storeProps, routerProps = {} }) => {
|
||||||
let store: ReturnType<typeof createTestStore>;
|
let store: ReturnType<typeof createTestStore>;
|
||||||
let appState = rootState;
|
let appState = rootState;
|
||||||
|
@ -71,6 +90,12 @@ const customRender = (
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const queryWrapper: React.FC = ({ children }) => (
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
{children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
);
|
||||||
|
|
||||||
const mockWindowProperty = (property: any, value: any) => {
|
const mockWindowProperty = (property: any, value: any) => {
|
||||||
const { [property]: originalProperty } = window;
|
const { [property]: originalProperty } = window;
|
||||||
delete window[property];
|
delete window[property];
|
||||||
|
@ -97,4 +122,6 @@ export {
|
||||||
rootReducer,
|
rootReducer,
|
||||||
mockWindowProperty,
|
mockWindowProperty,
|
||||||
createTestStore,
|
createTestStore,
|
||||||
|
mock,
|
||||||
|
queryWrapper,
|
||||||
};
|
};
|
||||||
|
|
45
app/soapbox/queries/__tests__/carousels.test.ts
Normal file
45
app/soapbox/queries/__tests__/carousels.test.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { renderHook } from '@testing-library/react-hooks';
|
||||||
|
|
||||||
|
import { mock, queryWrapper, waitFor } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import useCarouselAvatars from '../carousels';
|
||||||
|
|
||||||
|
describe('useCarouselAvatars', () => {
|
||||||
|
describe('with a successul query', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.onGet('/api/v1/truth/carousels/avatars')
|
||||||
|
.reply(200, [
|
||||||
|
{ account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '2', acct: 'b', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '3', acct: 'c', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
{ account_id: '4', acct: 'd', account_avatar: 'https://example.com/some.jpg' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is successful', async() => {
|
||||||
|
const { result } = renderHook(() => useCarouselAvatars(), {
|
||||||
|
wrapper: queryWrapper,
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => expect(result.current.isFetching).toBe(false));
|
||||||
|
|
||||||
|
expect(result.current.data?.length).toBe(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessul query', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mock.onGet('/api/v1/truth/carousels/avatars').networkError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is successful', async() => {
|
||||||
|
const { result } = renderHook(() => useCarouselAvatars(), {
|
||||||
|
wrapper: queryWrapper,
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => expect(result.current.isFetching).toBe(false));
|
||||||
|
|
||||||
|
expect(result.current.error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import API from './client';
|
import API from 'soapbox/queries/client';
|
||||||
|
|
||||||
type Avatar = {
|
type Avatar = {
|
||||||
account_id: string
|
account_id: string
|
||||||
|
@ -13,17 +13,15 @@ const getCarouselAvatars = async() => {
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function useCarouselAvatars(): { data: Avatar[], isFetching: boolean, isError: boolean, isSuccess: boolean } {
|
export default function useCarouselAvatars() {
|
||||||
const { data, isFetching, isError, isSuccess } = useQuery<Avatar[]>(['carouselAvatars'], getCarouselAvatars, {
|
const result = useQuery<Avatar[]>(['carouselAvatars'], getCarouselAvatars, {
|
||||||
placeholderData: [],
|
placeholderData: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const avatars = data as Avatar[];
|
const avatars = result.data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: avatars,
|
...result,
|
||||||
isFetching,
|
data: avatars || [],
|
||||||
isError,
|
|
||||||
isSuccess,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue