diff --git a/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx
index 350cf385f..c17ea2c5a 100644
--- a/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx
+++ b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx
@@ -2,8 +2,7 @@ import userEvent from '@testing-library/user-event';
import { Map as ImmutableMap } from 'immutable';
import React from 'react';
-import { __stub } from '../../../api';
-import { render, screen, waitFor } from '../../../jest/test-helpers';
+import { mock, render, screen, waitFor } from '../../../jest/test-helpers';
import FeedCarousel from '../feed-carousel';
jest.mock('../../../hooks/useDimensions', () => ({
@@ -55,63 +54,63 @@ describe('', () => {
};
});
- it('should render the Carousel', () => {
- store.carousels = {
- avatars: [
- { account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' },
- ],
- };
+ describe('with 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' },
+ ]);
+ });
- render(, undefined, store);
+ it('should render the Carousel', async() => {
+ render(, undefined, store);
- expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1);
+ await waitFor(() => {
+ expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1);
+ });
+ });
});
describe('with 0 avatars', () => {
beforeEach(() => {
- store.carousels = {
- avatars: [],
- };
+ mock.onGet('/api/v1/truth/carousels/avatars').reply(200, []);
});
- it('renders the error message', () => {
+ it('renders nothing', async() => {
render(, undefined, store);
- expect(screen.queryAllByTestId('feed-carousel-error')).toHaveLength(0);
+ await waitFor(() => {
+ expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(0);
+ });
});
});
describe('with a failed request to the API', () => {
beforeEach(() => {
- store.carousels = {
- avatars: [],
- error: true,
- };
+ mock.onGet('/api/v1/truth/carousels/avatars').networkError();
});
- it('renders the error message', () => {
+ it('renders the error message', async() => {
render(, undefined, store);
- expect(screen.getByTestId('feed-carousel-error')).toBeInTheDocument();
+ await waitFor(() => {
+ 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')
- .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' },
- ]);
- });
+ 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(() => {
return {
diff --git a/app/soapbox/jest/test-helpers.tsx b/app/soapbox/jest/test-helpers.tsx
index b7223caca..f48bf09f3 100644
--- a/app/soapbox/jest/test-helpers.tsx
+++ b/app/soapbox/jest/test-helpers.tsx
@@ -1,6 +1,7 @@
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 MockAdapter from 'axios-mock-adapter';
import { merge } from 'immutable';
import React, { FC, ReactElement } from 'react';
import { IntlProvider } from 'react-intl';
@@ -10,7 +11,7 @@ import { Action, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
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 { 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);
};
-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 = ({ children, storeProps, routerProps = {} }) => {
let store: ReturnType;
let appState = rootState;
@@ -71,6 +90,12 @@ const customRender = (
...options,
});
+const queryWrapper: React.FC = ({ children }) => (
+
+ {children}
+
+);
+
const mockWindowProperty = (property: any, value: any) => {
const { [property]: originalProperty } = window;
delete window[property];
@@ -97,4 +122,6 @@ export {
rootReducer,
mockWindowProperty,
createTestStore,
+ mock,
+ queryWrapper,
};
diff --git a/app/soapbox/queries/__tests__/carousels.test.ts b/app/soapbox/queries/__tests__/carousels.test.ts
new file mode 100644
index 000000000..61edbce11
--- /dev/null
+++ b/app/soapbox/queries/__tests__/carousels.test.ts
@@ -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();
+ });
+ });
+});
diff --git a/app/soapbox/queries/carousels.ts b/app/soapbox/queries/carousels.ts
index 36652e3cb..2989f4a52 100644
--- a/app/soapbox/queries/carousels.ts
+++ b/app/soapbox/queries/carousels.ts
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
-import API from './client';
+import API from 'soapbox/queries/client';
type Avatar = {
account_id: string
@@ -13,17 +13,15 @@ const getCarouselAvatars = async() => {
return data;
};
-export default function useCarouselAvatars(): { data: Avatar[], isFetching: boolean, isError: boolean, isSuccess: boolean } {
- const { data, isFetching, isError, isSuccess } = useQuery(['carouselAvatars'], getCarouselAvatars, {
+export default function useCarouselAvatars() {
+ const result = useQuery(['carouselAvatars'], getCarouselAvatars, {
placeholderData: [],
});
- const avatars = data as Avatar[];
+ const avatars = result.data;
return {
- data: avatars,
- isFetching,
- isError,
- isSuccess,
+ ...result,
+ data: avatars || [],
};
}