diff --git a/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx
new file mode 100644
index 000000000..4744b1c52
--- /dev/null
+++ b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx
@@ -0,0 +1,131 @@
+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 FeedCarousel from '../feed-carousel';
+
+jest.mock('../../../hooks/useDimensions', () => ({
+ useDimensions: () => [null, { width: 200 }],
+}));
+
+(window as any).ResizeObserver = class ResizeObserver {
+
+ observe() { }
+ disconnect() { }
+
+};
+
+describe('', () => {
+ let store;
+
+ describe('with "feedUserFiltering" disabled', () => {
+ beforeEach(() => {
+ store = {
+ instance: {
+ version: '2.7.2 (compatible; Pleroma 2.4.52-1337-g4779199e.gleasonator+soapbox)',
+ pleroma: ImmutableMap({
+ metadata: ImmutableMap({
+ features: [],
+ }),
+ }),
+ },
+ };
+ });
+
+ it('should render nothing', () => {
+ render(, null, store);
+
+ expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(0);
+ });
+ });
+
+ describe('with "feedUserFiltering" enabled', () => {
+ beforeEach(() => {
+ store = {
+ instance: {
+ version: '3.4.1 (compatible; TruthSocial 1.0.0)',
+ pleroma: ImmutableMap({
+ metadata: ImmutableMap({
+ features: [],
+ }),
+ }),
+ },
+ };
+ });
+
+ it('should render the Carousel', () => {
+ render(, null, store);
+
+ expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1);
+ });
+
+ describe('with a failed request to the API', () => {
+ beforeEach(() => {
+ store.carousels = {
+ avatars: [],
+ error: true,
+ };
+ });
+
+ it('renders the error message', () => {
+ render(, null, 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')
+ .reply(200, [
+ { account_id: '1', username: 'a', account_avatar: 'https://example.com/some.jpg' },
+ { account_id: '2', username: 'b', account_avatar: 'https://example.com/some.jpg' },
+ { account_id: '3', username: 'c', account_avatar: 'https://example.com/some.jpg' },
+ { account_id: '4', username: 'd', account_avatar: 'https://example.com/some.jpg' },
+ ]);
+ });
+
+ Element.prototype.getBoundingClientRect = jest.fn(() => {
+ return {
+ width: 200,
+ height: 120,
+ x: 0,
+ y: 0,
+ toJSON: () => null,
+ top: 0,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ };
+ });
+ });
+
+ it('should render the correct prev/next buttons', async() => {
+ const user = userEvent.setup();
+ render(, null, store);
+
+ await waitFor(() => {
+ expect(screen.getByTestId('next-page')).toBeInTheDocument();
+ expect(screen.queryAllByTestId('prev-page')).toHaveLength(0);
+ });
+
+ await waitFor(() => {
+ user.click(screen.getByTestId('next-page'));
+ });
+
+ await waitFor(() => {
+ expect(screen.getByTestId('prev-page')).toBeInTheDocument();
+ expect(screen.queryAllByTestId('next-page')).toHaveLength(0);
+ });
+ });
+ });
+ });
+});
diff --git a/app/soapbox/features/feed-filtering/feed-carousel.tsx b/app/soapbox/features/feed-filtering/feed-carousel.tsx
index ca3904900..2ca9f34bc 100644
--- a/app/soapbox/features/feed-filtering/feed-carousel.tsx
+++ b/app/soapbox/features/feed-filtering/feed-carousel.tsx
@@ -85,7 +85,7 @@ const FeedCarousel = () => {
if (hasError) {
return (
-
+
@@ -94,12 +94,13 @@ const FeedCarousel = () => {
}
return (
-
+
{hasPrevPage && (