From 2f94676678f9da7519ee1e51539d3a3794e99ba0 Mon Sep 17 00:00:00 2001 From: Nazareno Bucciarelli Date: Fri, 10 Apr 2026 17:42:09 -0300 Subject: [PATCH 1/6] fix custom sounds pagination --- .../admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx index e200a994d174b..549a644825c93 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx @@ -88,7 +88,7 @@ const CustomSoundsTable = ({ reload, onClick }: CustomSoundsTableProps) => { divider current={current} itemsPerPage={itemsPerPage} - count={data.sounds.length || 0} + count={data?.total || 0} onSetItemsPerPage={onSetItemsPerPage} onSetCurrent={onSetCurrent} {...paginationProps} From f87d50d0bb79ecb03bdc4d032970bef48117844a Mon Sep 17 00:00:00 2001 From: Nazareno Bucciarelli Date: Fri, 10 Apr 2026 17:54:07 -0300 Subject: [PATCH 2/6] add changeset --- .changeset/tall-flowers-return.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tall-flowers-return.md diff --git a/.changeset/tall-flowers-return.md b/.changeset/tall-flowers-return.md new file mode 100644 index 0000000000000..10638011ac066 --- /dev/null +++ b/.changeset/tall-flowers-return.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes inability to use custom sounds pagination action buttons when the amount exceeds the specified limit From ed36571687f3a917cfcce95b62a4d968c44c181b Mon Sep 17 00:00:00 2001 From: Nazareno Bucciarelli Date: Mon, 13 Apr 2026 14:20:35 -0300 Subject: [PATCH 3/6] add snapshot testing --- .../CustomSoundsTable.spec.tsx | 42 ++ .../CustomSoundsTable.stories.tsx | 27 + .../CustomSoundsTable.spec.tsx.snap | 468 ++++++++++++++++++ 3 files changed, 537 insertions(+) create mode 100644 apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx create mode 100644 apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx create mode 100644 apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx new file mode 100644 index 0000000000000..19d3af73db685 --- /dev/null +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx @@ -0,0 +1,42 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { composeStories } from '@storybook/react'; +import { render, screen } from '@testing-library/react'; + +import * as stories from './CustomSoundsTable.stories'; + +const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]); + +const mockSounds = Array.from({ length: 50 }, (_, i) => ({ + _id: `sound-${i}`, + name: `Custom Sound ${i + 1}`, + extension: 'mp3', +})); + +const getMockedAppRoot = () => + mockAppRoot().withEndpoint('GET', '/v1/custom-sounds.list', () => ({ + sounds: mockSounds.slice(0, 25), + total: 50, + count: 25, + offset: 0, + })); + +test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => { + const { baseElement } = render(, { wrapper: getMockedAppRoot().build() }); + expect(baseElement).toMatchSnapshot(); +}); + +test('should enable pagination when data.total exceeds itemsPerPage', async () => { + const { Default } = composeStories(stories); + const { container } = render(, { wrapper: getMockedAppRoot().build() }); + + const firstSound = await screen.findByText('Custom Sound 1'); + expect(firstSound).toBeInTheDocument(); + + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const forwardButton = container.querySelector('.rcx-pagination__forward'); + expect(forwardButton).toBeInTheDocument(); + expect(forwardButton).not.toBeDisabled(); + + const pageTwoButton = screen.getByRole('button', { name: '2' }); + expect(pageTwoButton).toBeInTheDocument(); +}); diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx new file mode 100644 index 0000000000000..e2ed32dba4b34 --- /dev/null +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx @@ -0,0 +1,27 @@ +import { Margins } from '@rocket.chat/fuselage'; +import { PageContent } from '@rocket.chat/ui-client'; +import type { Meta, StoryFn } from '@storybook/react'; +import { useRef } from 'react'; + +import CustomSoundsTable from './CustomSoundsTable'; + +export default { + component: CustomSoundsTable, + decorators: [ + (fn) => ( + + {fn()} + + ), + ], +} satisfies Meta; + +const Template: StoryFn = (args) => { + const reloadRef = useRef(() => undefined); + return ; +}; + +export const Default = Template.bind({}); +Default.args = { + onClick: (soundId: string) => () => console.log('Clicked sound', soundId), +}; diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap new file mode 100644 index 0000000000000..0c7070fc6c617 --- /dev/null +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap @@ -0,0 +1,468 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`renders Default without crashing 1`] = ` + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Name + + + + +
+
+
+
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +`; From fcf38ae0606da062e073ed827a0616240ce21fe6 Mon Sep 17 00:00:00 2001 From: Nazareno Bucciarelli Date: Mon, 13 Apr 2026 14:27:19 -0300 Subject: [PATCH 4/6] decrease amount of mocked sounds to improve efficiency --- .../customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx index 19d3af73db685..57ac8539791a2 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.spec.tsx @@ -6,7 +6,7 @@ import * as stories from './CustomSoundsTable.stories'; const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]); -const mockSounds = Array.from({ length: 50 }, (_, i) => ({ +const mockSounds = Array.from({ length: 25 }, (_, i) => ({ _id: `sound-${i}`, name: `Custom Sound ${i + 1}`, extension: 'mp3', @@ -14,7 +14,7 @@ const mockSounds = Array.from({ length: 50 }, (_, i) => ({ const getMockedAppRoot = () => mockAppRoot().withEndpoint('GET', '/v1/custom-sounds.list', () => ({ - sounds: mockSounds.slice(0, 25), + sounds: mockSounds, total: 50, count: 25, offset: 0, From 1964d37e2c3cb368891d31cf9b1187f322a483f4 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 15 Apr 2026 16:41:31 -0300 Subject: [PATCH 5/6] test: add stories variations with mock data and error handling --- .../CustomSoundsTable.stories.tsx | 53 +++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx index e2ed32dba4b34..02f98def2d70f 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.stories.tsx @@ -1,19 +1,46 @@ import { Margins } from '@rocket.chat/fuselage'; +import { mockAppRoot } from '@rocket.chat/mock-providers'; import { PageContent } from '@rocket.chat/ui-client'; -import type { Meta, StoryFn } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import type { Decorator, Meta, StoryFn } from '@storybook/react'; import { useRef } from 'react'; import CustomSoundsTable from './CustomSoundsTable'; +const mockSounds = Array.from({ length: 25 }, (_, i) => ({ + _id: `sound-${i}`, + name: `Custom Sound ${i + 1}`, + extension: 'mp3', +})); + +type CustomSoundsListResponse = { + sounds: typeof mockSounds; + total: number; + count: number; + offset: number; +}; + +const withCustomSoundsEndpoint = (response: () => CustomSoundsListResponse | Promise): Decorator => + mockAppRoot().withEndpoint('GET', '/v1/custom-sounds.list', response).buildStoryDecorator(); + export default { component: CustomSoundsTable, decorators: [ + withCustomSoundsEndpoint(() => ({ + sounds: mockSounds, + total: 50, + count: 25, + offset: 0, + })), (fn) => ( {fn()} ), ], + args: { + onClick: () => action('click'), + }, } satisfies Meta; const Template: StoryFn = (args) => { @@ -22,6 +49,24 @@ const Template: StoryFn = (args) => { }; export const Default = Template.bind({}); -Default.args = { - onClick: (soundId: string) => () => console.log('Clicked sound', soundId), -}; + +export const Empty = Template.bind({}); +Empty.decorators = [ + withCustomSoundsEndpoint(() => ({ + sounds: [], + total: 0, + count: 0, + offset: 0, + })), +]; + +export const Loading = Template.bind({}); +Loading.decorators = [withCustomSoundsEndpoint(() => new Promise(() => undefined))]; + +export const Errored = Template.bind({}); +Errored.storyName = 'Error'; +Errored.decorators = [ + withCustomSoundsEndpoint(() => { + throw new Error('Failed to load custom sounds'); + }), +]; From eb09e502d15fa4a4b57250217b20156e80989894 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 15 Apr 2026 16:41:44 -0300 Subject: [PATCH 6/6] chore: update snapshot --- .../CustomSoundsTable.spec.tsx.snap | 1401 +++++++++++++++++ 1 file changed, 1401 insertions(+) diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap index 0c7070fc6c617..3d015fb601f13 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/__snapshots__/CustomSoundsTable.spec.tsx.snap @@ -466,3 +466,1404 @@ exports[`renders Default without crashing 1`] = `
`; + +exports[`renders Empty without crashing 1`] = ` + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Name + + + + +
+
+
+
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +`; + +exports[`renders Errored without crashing 1`] = ` + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Name + + + + +
+
+
+
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +`; + +exports[`renders Loading without crashing 1`] = ` + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Name + + + + +
+
+
+
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +`;