From 777de0ab68534072006e276c6140c4edc8ff9dfe Mon Sep 17 00:00:00 2001 From: Tushar Verma Date: Wed, 5 Nov 2025 15:00:08 +0530 Subject: [PATCH 1/9] Refactor catalogList tests to use Testing Library and improve mock implementations --- .../Channel/__tests__/catalogList.spec.js | 373 +++++++++++------- 1 file changed, 220 insertions(+), 153 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index 32c9de6843..0d851a44ae 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -1,200 +1,267 @@ -import { mount } from '@vue/test-utils'; -import { factory } from '../../../store'; -import router from '../../../router'; -import { RouteNames } from '../../../constants'; + import { render, screen, waitFor } from '@testing-library/vue'; +import userEvent from '@testing-library/user-event'; +import { createLocalVue } from '@vue/test-utils'; +import Vuex, { Store } from 'vuex'; +import VueRouter from 'vue-router'; import CatalogList from '../CatalogList'; +import { RouteNames } from '../../../constants'; -const store = factory(); - -router.push({ name: RouteNames.CATALOG_ITEMS }); +const localVue = createLocalVue(); +localVue.use(Vuex); +localVue.use(VueRouter); + +const mockChannels = [ + { + id: 'channel-1', + name: 'Channel 1', + description: 'Test channel 1', + language: 'en', + }, + { + id: 'channel-2', + name: 'Channel 2', + description: 'Test channel 2', + language: 'en', + }, +]; const results = ['channel-1', 'channel-2']; -function makeWrapper(computed = {}) { - const loadCatalog = jest.spyOn(CatalogList.methods, 'loadCatalog'); - loadCatalog.mockImplementation(() => Promise.resolve()); +function makeWrapper() { + const mockSearchCatalog = jest.fn(() => Promise.resolve()); + + const store = new Store({ + state: { + connection: { + online: true, + }, + }, + actions: { + showSnackbar: jest.fn(), + }, + modules: { + channel: { + namespaced: true, + state: { + channelsMap: { + 'channel-1': mockChannels[0], + 'channel-2': mockChannels[1], + }, + }, + getters: { + getChannels: state => ids => { + return ids.map(id => state.channelsMap[id]).filter(Boolean); + }, + }, + actions: { + getChannelListDetails: jest.fn(() => Promise.resolve(mockChannels)), + }, + }, + channelList: { + namespaced: true, + state: { + page: { + count: results.length, + results, + page_number: 1, + total_pages: 1, + next: null, + previous: null, + }, + }, + actions: { + searchCatalog: mockSearchCatalog, + }, + }, + }, + }); + + const router = new VueRouter({ + routes: [ + { + name: RouteNames.CATALOG_ITEMS, + path: '/catalog', + }, + { + name: RouteNames.CATALOG_DETAILS, + path: '/catalog/:channelId', + }, + ], + }); - const downloadCSV = jest.spyOn(CatalogList.methods, 'downloadCSV'); - const downloadPDF = jest.spyOn(CatalogList.methods, 'downloadPDF'); + router.push({ name: RouteNames.CATALOG_ITEMS }).catch(() => {}); - const wrapper = mount(CatalogList, { - router, + const renderResult = render(CatalogList, { + localVue, store, - computed: { - page() { - return { - count: results.length, - results, - }; - }, - ...computed, - }, + router, stubs: { CatalogFilters: true, + ChannelItem: { + props: ['channelId'], + template: '
Channel Item
', + }, + LoadingText: { template: '
Loading...
' }, + Pagination: { template: '
Pagination
' }, + BottomBar: { template: '
' }, + Checkbox: { + props: ['value', 'label', 'indeterminate'], + template: ` + + `, + }, + ToolBar: { template: '
' }, + OfflineText: { template: '
Offline
' }, + }, + mocks: { + $tr: (key, params) => { + const translations = { + resultsText: params ? `${params.count} result${params.count !== 1 ? 's' : ''} found` : '', + selectChannels: 'Download a summary of selected channels', + selectAll: 'Select all', + cancelButton: 'Cancel', + downloadButton: 'Download', + downloadPDF: 'Download PDF', + downloadCSV: 'Download CSV', + downloadingMessage: 'Download started', + channelSelectionCount: params ? `${params.count} channel${params.count !== 1 ? 's' : ''} selected` : '', + }; + return translations[key] || key; + }, }, }); - return [wrapper, { loadCatalog, downloadCSV, downloadPDF }]; -} -describe('catalogFilterBar', () => { - let wrapper, mocks; + return { ...renderResult, store, router, mockSearchCatalog }; +} - beforeEach(async () => { - [wrapper, mocks] = makeWrapper(); - await wrapper.setData({ loading: false }); +describe('catalogList', () => { + beforeEach(() => { + jest.clearAllMocks(); }); - it('should call loadCatalog on mount', () => { - [wrapper, mocks] = makeWrapper(); - expect(mocks.loadCatalog).toHaveBeenCalled(); + it('should call loadCatalog on mount', async () => { + const { mockSearchCatalog } = makeWrapper(); + await waitFor(() => { + expect(mockSearchCatalog).toHaveBeenCalled(); + }); }); describe('on query change', () => { - const searchCatalogMock = jest.fn(); - - beforeEach(() => { - router.replace({ query: {} }).catch(() => {}); - searchCatalogMock.mockReset(); - [wrapper, mocks] = makeWrapper({ - debouncedSearch() { - return searchCatalogMock; - }, + it('should call searchCatalog when query changes', async () => { + const { router, mockSearchCatalog } = makeWrapper(); + + await waitFor(() => screen.getByText('2 results found')); + + const initialCalls = mockSearchCatalog.mock.calls.length; + + await router.push({ + name: RouteNames.CATALOG_ITEMS, + query: { keywords: 'search catalog test' } }); - }); - it('should call debouncedSearch', async () => { - const keywords = 'search catalog test'; - router.push({ query: { keywords } }).catch(() => {}); - await wrapper.vm.$nextTick(); - expect(searchCatalogMock).toHaveBeenCalled(); - }); - - it('should reset excluded if a filter changed', async () => { - const keywords = 'search reset test'; - await wrapper.setData({ excluded: ['item 1'] }); - router.push({ query: { keywords } }).catch(() => {}); - await wrapper.vm.$nextTick(); - expect(wrapper.vm.excluded).toEqual([]); - }); - - it('should keep excluded if page number changed', async () => { - await wrapper.setData({ excluded: ['item 1'] }); - router - .push({ - query: { - ...wrapper.vm.$route.query, - page: 2, - }, - }) - .catch(() => {}); - await wrapper.vm.$nextTick(); - expect(wrapper.vm.excluded).toEqual(['item 1']); + await waitFor(() => { + expect(mockSearchCatalog.mock.calls.length).toBeGreaterThan(initialCalls); + }); }); }); describe('download workflow', () => { describe('toggling selection mode', () => { - it('checkboxes and toolbar should be hidden if selecting is false', () => { - expect(wrapper.findComponent('[data-test="checkbox"]').exists()).toBe(false); - expect(wrapper.findComponent('[data-test="toolbar"]').exists()).toBe(false); + it('checkboxes and toolbar should be hidden if selecting is false', async () => { + makeWrapper(); + await waitFor(() => screen.getByText('2 results found')); + + expect(screen.queryByTestId('checkbox')).not.toBeInTheDocument(); + expect(screen.queryByTestId('toolbar')).not.toBeInTheDocument(); }); it('should activate when select button is clicked', async () => { - await wrapper.findComponent('[data-test="select"]').trigger('click'); - expect(wrapper.vm.selecting).toBe(true); + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => { + expect(screen.getByText('Select all')).toBeInTheDocument(); + }); }); it('clicking cancel should exit selection mode', async () => { - await wrapper.setData({ selecting: true }); - await wrapper.findComponent('[data-test="cancel"]').trigger('click'); - expect(wrapper.vm.selecting).toBe(false); - }); - - it('excluded should reset when selection mode is exited', async () => { - await wrapper.setData({ selecting: true, excluded: ['item-1', 'item-2'] }); - wrapper.vm.setSelection(false); - expect(wrapper.vm.excluded).toHaveLength(0); + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => screen.getByText('Cancel')); + await user.click(screen.getByText('Cancel')); + + await waitFor(() => { + expect(screen.queryByTestId('toolbar')).not.toBeInTheDocument(); + }); }); }); describe('selecting channels', () => { - const excluded = ['item-1']; - - beforeEach(async () => { - await wrapper.setData({ - selecting: true, - excluded, + it('should show all channels selected by default when entering selection mode', async () => { + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => { + expect(screen.getByText('2 channels selected')).toBeInTheDocument(); }); }); - it('selecting all should select all items on the page', async () => { - await wrapper.setData({ excluded: excluded.concat(results) }); - wrapper.vm.selectAll = true; - expect(wrapper.vm.excluded).toEqual(excluded); - expect(wrapper.vm.selected).toEqual(results); - }); - - it('deselecting all should select all items on the page', () => { - wrapper.vm.selectAll = false; - expect(wrapper.vm.excluded).toEqual(excluded.concat(results)); - expect(wrapper.vm.selected).toEqual([]); - }); - - it('selecting a channel should remove it from excluded', async () => { - await wrapper.setData({ excluded: excluded.concat(results) }); - wrapper.vm.selected = [results[0]]; - expect(wrapper.vm.excluded).toEqual(excluded.concat([results[1]])); - expect(wrapper.vm.selected).toEqual([results[0]]); - }); - - it('deselecting a channel should add it to excluded', () => { - wrapper.vm.selected = [results[0]]; - expect(wrapper.vm.excluded).toEqual(excluded.concat([results[1]])); - expect(wrapper.vm.selected).toEqual([results[0]]); + it('should show select all checkbox', async () => { + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => { + const selectAllCheckbox = screen.getByText('Select all'); + expect(selectAllCheckbox).toBeInTheDocument(); + }); }); }); - describe('download csv', () => { - let downloadChannelsCSV; - const excluded = ['item-1', 'item-2']; - - beforeEach(async () => { - await wrapper.setData({ selecting: true, excluded }); - downloadChannelsCSV = jest.spyOn(wrapper.vm, 'downloadChannelsCSV'); - downloadChannelsCSV.mockImplementation(() => Promise.resolve()); - }); - - it('clicking download CSV should call downloadCSV', async () => { - mocks.downloadCSV.mockImplementationOnce(() => Promise.resolve()); - await wrapper.findComponent('[data-test="download-button"]').trigger('click'); - const menuOptions = wrapper.findAll('.ui-menu-option-content'); - await menuOptions.at(1).trigger('click'); - expect(mocks.downloadCSV).toHaveBeenCalled(); - }); - - it('clicking download PDF should call downloadPDF', async () => { - mocks.downloadPDF.mockImplementationOnce(() => Promise.resolve()); - await wrapper.findComponent('[data-test="download-button"]').trigger('click'); - const menuOptions = wrapper.findAll('.ui-menu-option-content'); - await menuOptions.at(0).trigger('click'); - expect(mocks.downloadPDF).toHaveBeenCalled(); - }); - - it('downloadCSV should call downloadChannelsCSV with current parameters', async () => { - const keywords = 'Download csv keywords test'; - router.replace({ query: { keywords } }); - await wrapper.vm.downloadCSV(); - expect(downloadChannelsCSV.mock.calls[0][0].keywords).toBe(keywords); - }); - - it('downloadCSV should call downloadChannelsCSV with list of excluded items', async () => { - await wrapper.vm.downloadCSV(); - expect(downloadChannelsCSV.mock.calls[0][0].excluded).toEqual(excluded); + describe('download csv and pdf', () => { + it('clicking download button should show Download text', async () => { + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => { + expect(screen.getByText('Download')).toBeInTheDocument(); + }); }); - it('downloadCSV should exit selection mode', async () => { - await wrapper.vm.downloadCSV(); - expect(wrapper.vm.selecting).toBe(false); + it('should show both download options (CSV and PDF) available', async () => { + const user = userEvent.setup(); + makeWrapper(); + + await waitFor(() => screen.getByText('Download a summary of selected channels')); + await user.click(screen.getByText('Download a summary of selected channels')); + + await waitFor(() => { + expect(screen.getByText('Download')).toBeInTheDocument(); + // The dropdown menu contains both PDF and CSV options when clicked + }); }); }); }); From 84d1b9b37d02aed402a4cb304c6f4380c29a7165 Mon Sep 17 00:00:00 2001 From: Tushar Verma Date: Wed, 5 Nov 2025 15:48:02 +0530 Subject: [PATCH 2/9] Enhance catalogList tests: clarify checkbox test description and improve formatting --- .../channelList/views/Channel/__tests__/catalogList.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index 0d851a44ae..8898db5b5f 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -224,7 +224,7 @@ describe('catalogList', () => { }); }); - it('should show select all checkbox', async () => { + it('should show select all checkbox when in selection mode', async () => { const user = userEvent.setup(); makeWrapper(); From 54c181a8191077173470f61efaa3f63a995d1d23 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:31:51 +0000 Subject: [PATCH 3/9] [pre-commit.ci lite] apply automatic fixes --- .../Channel/__tests__/catalogList.spec.js | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index 8898db5b5f..07e0801904 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -1,4 +1,4 @@ - import { render, screen, waitFor } from '@testing-library/vue'; +import { render, screen, waitFor } from '@testing-library/vue'; import userEvent from '@testing-library/user-event'; import { createLocalVue } from '@vue/test-utils'; import Vuex, { Store } from 'vuex'; @@ -9,7 +9,7 @@ import { RouteNames } from '../../../constants'; const localVue = createLocalVue(); localVue.use(Vuex); localVue.use(VueRouter); - + const mockChannels = [ { id: 'channel-1', @@ -29,7 +29,7 @@ const results = ['channel-1', 'channel-2']; function makeWrapper() { const mockSearchCatalog = jest.fn(() => Promise.resolve()); - + const store = new Store({ state: { connection: { @@ -108,8 +108,8 @@ function makeWrapper() { props: ['value', 'label', 'indeterminate'], template: ` `, }, - KButton: { - props: ['text', 'dataTest', 'primary'], - template: - '', - }, - KDropdownMenu: { - props: ['options'], - template: ` -
- -
- `, - }, - ToolBar: { template: '
' }, - OfflineText: { template: '
Offline
' }, - VLayout: { template: '
' }, - VFlex: { template: '
' }, - VContainer: { template: '
' }, - VSlideYTransition: { template: '
' }, - VSpacer: { template: '
' }, }, mocks: { $tr: (key, params) => { @@ -222,7 +193,6 @@ describe('CatalogList', () => { makeWrapper(); await waitFor(() => screen.getByText('2 results found')); - // Checkboxes exist but are hidden, toolbar should not be in DOM const checkboxes = screen.queryAllByTestId('checkbox'); if (checkboxes.length > 0) { checkboxes.forEach(checkbox => { @@ -266,10 +236,8 @@ describe('CatalogList', () => { await user.click(screen.getByText('Download a summary of selected channels')); await waitFor(() => screen.getByTestId('toolbar')); - // Click cancel await user.click(screen.getByText('Cancel')); - // Verify toolbar is gone await waitFor(() => { expect(screen.queryByTestId('toolbar')).not.toBeInTheDocument(); }); @@ -281,11 +249,9 @@ describe('CatalogList', () => { const user = userEvent.setup(); makeWrapper(); - // Enter selection mode await waitFor(() => screen.getByText('Download a summary of selected channels')); await user.click(screen.getByText('Download a summary of selected channels')); - // Wait for toolbar with selection count to appear await waitFor(() => { expect(screen.getByTestId('toolbar')).toBeInTheDocument(); }); @@ -295,11 +261,9 @@ describe('CatalogList', () => { const user = userEvent.setup(); makeWrapper(); - // Enter selection mode await waitFor(() => screen.getByText('Download a summary of selected channels')); await user.click(screen.getByText('Download a summary of selected channels')); - // Verify select-all checkbox appears await waitFor(() => { expect(screen.getByTestId('select-all-checkbox')).toBeInTheDocument(); }); @@ -314,7 +278,6 @@ describe('CatalogList', () => { const initialCalls = mockSearchCatalog.mock.calls.length; - // Change search query await router.push({ name: RouteNames.CATALOG_ITEMS, query: { keywords: 'search test' }, @@ -330,13 +293,11 @@ describe('CatalogList', () => { await waitFor(() => screen.getByText('2 results found')); - // Change search query await router.push({ name: RouteNames.CATALOG_ITEMS, query: { keywords: 'test search' }, }); - // Results should still be visible await waitFor(() => { expect(screen.getByText('2 results found')).toBeInTheDocument(); }); @@ -359,29 +320,9 @@ describe('CatalogList', () => { await waitFor(() => screen.getByText('Download a summary of selected channels')); await user.click(screen.getByText('Download a summary of selected channels')); - // Toolbar should appear when in selection mode await waitFor(() => { expect(screen.getByTestId('toolbar')).toBeInTheDocument(); }); }); }); - - describe('offline state', () => { - it('should display offline message when connection is offline', async () => { - makeWrapper({ offline: true }); - - await waitFor(() => { - expect(screen.getByText('Offline')).toBeInTheDocument(); - }); - }); - }); - - describe('loading state', () => { - it('should show loading message when loading is true', async () => { - makeWrapper(); - - // Verify loading text appears initially - expect(screen.getByText('Loading...')).toBeInTheDocument(); - }); - }); }); From de8e0fc02358d8c81555ce99dbb7f13682c97f2f Mon Sep 17 00:00:00 2001 From: Tushar Verma Date: Tue, 25 Nov 2025 09:28:41 +0530 Subject: [PATCH 7/9] Refactor catalogList tests: enhance makeWrapper function --- .../Channel/__tests__/catalogList.spec.js | 58 +++++-------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index bde7953f00..e996b78dc0 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -38,6 +38,9 @@ function makeWrapper(overrides = {}) { online: overrides.offline ? false : true, }, }, + getters: { + loggedIn: () => true, + }, actions: { showSnackbar: jest.fn(), }, @@ -54,6 +57,7 @@ function makeWrapper(overrides = {}) { getChannels: state => ids => { return ids.map(id => state.channelsMap[id]).filter(Boolean); }, + getChannel: state => id => state.channelsMap[id], }, actions: { getChannelListDetails: jest.fn(() => Promise.resolve(mockChannels)), @@ -100,35 +104,6 @@ function makeWrapper(overrides = {}) { router, stubs: { CatalogFilters: true, - ChannelItem: { - props: ['channelId'], - template: '
Channel Item
', - }, - BottomBar: { template: '
' }, - Checkbox: { - props: ['value', 'label', 'indeterminate'], - data() { - return { - isChecked: this.value, - }; - }, - watch: { - value(newVal) { - this.isChecked = newVal; - }, - }, - template: ` - - `, - }, }, mocks: { $tr: (key, params) => { @@ -193,13 +168,9 @@ describe('CatalogList', () => { makeWrapper(); await waitFor(() => screen.getByText('2 results found')); - const checkboxes = screen.queryAllByTestId('checkbox'); - if (checkboxes.length > 0) { - checkboxes.forEach(checkbox => { - expect(checkbox.closest('label')).toHaveStyle('display: none'); - }); - } - expect(screen.queryByTestId('toolbar')).not.toBeInTheDocument(); + // Toolbar should not be visible initially (appears only in selection mode) + expect(screen.queryByText('Select all')).not.toBeInTheDocument(); + expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); }); it('should enter selection mode when user clicks select button', async () => { @@ -211,7 +182,7 @@ describe('CatalogList', () => { await waitFor(() => { expect(screen.getByText('Select all')).toBeInTheDocument(); - expect(screen.getByTestId('toolbar')).toBeInTheDocument(); + expect(screen.getByText('Cancel')).toBeInTheDocument(); }); }); @@ -234,12 +205,13 @@ describe('CatalogList', () => { // Enter selection mode await waitFor(() => screen.getByText('Download a summary of selected channels')); await user.click(screen.getByText('Download a summary of selected channels')); - await waitFor(() => screen.getByTestId('toolbar')); + await waitFor(() => screen.getByText('Cancel')); await user.click(screen.getByText('Cancel')); await waitFor(() => { - expect(screen.queryByTestId('toolbar')).not.toBeInTheDocument(); + expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); + expect(screen.queryByText('Select all')).not.toBeInTheDocument(); }); }); }); @@ -253,7 +225,8 @@ describe('CatalogList', () => { await user.click(screen.getByText('Download a summary of selected channels')); await waitFor(() => { - expect(screen.getByTestId('toolbar')).toBeInTheDocument(); + expect(screen.getByText('Select all')).toBeInTheDocument(); + expect(screen.getByText('2 channels selected')).toBeInTheDocument(); }); }); @@ -265,7 +238,7 @@ describe('CatalogList', () => { await user.click(screen.getByText('Download a summary of selected channels')); await waitFor(() => { - expect(screen.getByTestId('select-all-checkbox')).toBeInTheDocument(); + expect(screen.getByText('Select all')).toBeInTheDocument(); }); }); }); @@ -321,7 +294,8 @@ describe('CatalogList', () => { await user.click(screen.getByText('Download a summary of selected channels')); await waitFor(() => { - expect(screen.getByTestId('toolbar')).toBeInTheDocument(); + expect(screen.getByText('Select all')).toBeInTheDocument(); + expect(screen.getByText('Cancel')).toBeInTheDocument(); }); }); }); From 59ac00f52200b5ffafa5e8f0bcf1bbd1a772452e Mon Sep 17 00:00:00 2001 From: Tushar Verma Date: Mon, 1 Dec 2025 11:40:54 +0530 Subject: [PATCH 8/9] removed unused test to focus on user interactions --- .../Channel/__tests__/catalogList.spec.js | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index e996b78dc0..75a8489665 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -29,8 +29,6 @@ const results = ['channel-1', 'channel-2']; function makeWrapper(overrides = {}) { const mockSearchCatalog = jest.fn(() => Promise.resolve()); - const mockDownloadChannelsCSV = jest.fn(() => Promise.resolve()); - const mockDownloadChannelsPDF = jest.fn(() => Promise.resolve()); const store = new Store({ state: { @@ -130,8 +128,6 @@ function makeWrapper(overrides = {}) { store, router, mockSearchCatalog, - mockDownloadChannelsCSV, - mockDownloadChannelsPDF, }; } @@ -173,7 +169,7 @@ describe('CatalogList', () => { expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); }); - it('should enter selection mode when user clicks select button', async () => { + it('should enter selection mode and show toolbar with selection count when user clicks select button', async () => { const user = userEvent.setup(); makeWrapper(); @@ -183,17 +179,6 @@ describe('CatalogList', () => { await waitFor(() => { expect(screen.getByText('Select all')).toBeInTheDocument(); expect(screen.getByText('Cancel')).toBeInTheDocument(); - }); - }); - - it('should show all channels selected by default in selection mode', async () => { - const user = userEvent.setup(); - makeWrapper(); - - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); - - await waitFor(() => { expect(screen.getByText('2 channels selected')).toBeInTheDocument(); }); }); @@ -217,7 +202,7 @@ describe('CatalogList', () => { }); describe('channel selection', () => { - it('should show selection count in toolbar when in selection mode', async () => { + it('should display select-all checkbox and selection count in selection mode', async () => { const user = userEvent.setup(); makeWrapper(); @@ -229,18 +214,6 @@ describe('CatalogList', () => { expect(screen.getByText('2 channels selected')).toBeInTheDocument(); }); }); - - it('should display select-all checkbox in selection mode', async () => { - const user = userEvent.setup(); - makeWrapper(); - - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); - - await waitFor(() => { - expect(screen.getByText('Select all')).toBeInTheDocument(); - }); - }); }); describe('search and filtering', () => { @@ -285,18 +258,5 @@ describe('CatalogList', () => { expect(screen.getByText('Download a summary of selected channels')).toBeInTheDocument(); }); }); - - it('should display toolbar when entering selection mode', async () => { - const user = userEvent.setup(); - makeWrapper(); - - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); - - await waitFor(() => { - expect(screen.getByText('Select all')).toBeInTheDocument(); - expect(screen.getByText('Cancel')).toBeInTheDocument(); - }); - }); }); }); From b3c1b9cfeddef7bfc34bd77df6888db19d52d2fb Mon Sep 17 00:00:00 2001 From: Tushar Verma Date: Fri, 19 Dec 2025 13:21:01 +0530 Subject: [PATCH 9/9] Refactor catalogList tests: replace hardcoded strings with regex for improved flexibility --- .../Channel/__tests__/catalogList.spec.js | 74 ++++++++----------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js index 75a8489665..a5118f3ad4 100644 --- a/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js +++ b/contentcuration/contentcuration/frontend/channelList/views/Channel/__tests__/catalogList.spec.js @@ -103,24 +103,6 @@ function makeWrapper(overrides = {}) { stubs: { CatalogFilters: true, }, - mocks: { - $tr: (key, params) => { - const translations = { - resultsText: params ? `${params.count} result${params.count !== 1 ? 's' : ''} found` : '', - selectChannels: 'Download a summary of selected channels', - selectAll: 'Select all', - cancelButton: 'Cancel', - downloadButton: 'Download', - downloadPDF: 'Download PDF', - downloadCSV: 'Download CSV', - downloadingMessage: 'Download started', - channelSelectionCount: params - ? `${params.count} channel${params.count !== 1 ? 's' : ''} selected` - : '', - }; - return translations[key] || key; - }, - }, }); return { @@ -140,7 +122,8 @@ describe('CatalogList', () => { it('should render catalog results on mount', async () => { makeWrapper(); await waitFor(() => { - expect(screen.getByText('2 results found')).toBeInTheDocument(); + // Component renders actual translation - use regex for flexibility + expect(screen.getByText(/results found/i)).toBeInTheDocument(); }); }); @@ -154,7 +137,8 @@ describe('CatalogList', () => { it('should display download button when results are available', async () => { makeWrapper(); await waitFor(() => { - expect(screen.getByText('Download a summary of selected channels')).toBeInTheDocument(); + // Use actual button text rendered by component + expect(screen.getByText(/download a summary/i)).toBeInTheDocument(); }); }); }); @@ -162,24 +146,24 @@ describe('CatalogList', () => { describe('selection mode workflow', () => { it('should hide checkboxes and toolbar initially', async () => { makeWrapper(); - await waitFor(() => screen.getByText('2 results found')); + await waitFor(() => screen.getByText(/download a summary/i)); // Toolbar should not be visible initially (appears only in selection mode) - expect(screen.queryByText('Select all')).not.toBeInTheDocument(); - expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); + expect(screen.queryByText(/select all/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/cancel/i)).not.toBeInTheDocument(); }); - it('should enter selection mode and show toolbar with selection count when user clicks select button', async () => { + it('should enter selection mode and show toolbar when user clicks select button', async () => { const user = userEvent.setup(); makeWrapper(); - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); + await waitFor(() => screen.getByText(/download a summary/i)); + await user.click(screen.getByText(/download a summary/i)); await waitFor(() => { - expect(screen.getByText('Select all')).toBeInTheDocument(); - expect(screen.getByText('Cancel')).toBeInTheDocument(); - expect(screen.getByText('2 channels selected')).toBeInTheDocument(); + expect(screen.getByText(/select all/i)).toBeInTheDocument(); + expect(screen.getByText(/cancel/i)).toBeInTheDocument(); + expect(screen.getByText(/channels selected/i)).toBeInTheDocument(); }); }); @@ -188,30 +172,30 @@ describe('CatalogList', () => { makeWrapper(); // Enter selection mode - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); - await waitFor(() => screen.getByText('Cancel')); + await waitFor(() => screen.getByText(/download a summary/i)); + await user.click(screen.getByText(/download a summary/i)); + await waitFor(() => screen.getByText(/cancel/i)); - await user.click(screen.getByText('Cancel')); + await user.click(screen.getByText(/cancel/i)); await waitFor(() => { - expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); - expect(screen.queryByText('Select all')).not.toBeInTheDocument(); + expect(screen.queryByText(/cancel/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/select all/i)).not.toBeInTheDocument(); }); }); }); describe('channel selection', () => { - it('should display select-all checkbox and selection count in selection mode', async () => { + it('should display select-all checkbox in selection mode', async () => { const user = userEvent.setup(); makeWrapper(); - await waitFor(() => screen.getByText('Download a summary of selected channels')); - await user.click(screen.getByText('Download a summary of selected channels')); + await waitFor(() => screen.getByText(/download a summary/i)); + await user.click(screen.getByText(/download a summary/i)); await waitFor(() => { - expect(screen.getByText('Select all')).toBeInTheDocument(); - expect(screen.getByText('2 channels selected')).toBeInTheDocument(); + expect(screen.getByText(/select all/i)).toBeInTheDocument(); + expect(screen.getByText(/channels selected/i)).toBeInTheDocument(); }); }); }); @@ -220,7 +204,7 @@ describe('CatalogList', () => { it('should call searchCatalog when query parameters change', async () => { const { router, mockSearchCatalog } = makeWrapper(); - await waitFor(() => screen.getByText('2 results found')); + await waitFor(() => screen.getByText(/results found/i)); const initialCalls = mockSearchCatalog.mock.calls.length; @@ -234,10 +218,10 @@ describe('CatalogList', () => { }); }); - it('should show results after filtering', async () => { + it('should maintain results display after filtering', async () => { const { router } = makeWrapper(); - await waitFor(() => screen.getByText('2 results found')); + await waitFor(() => screen.getByText(/results found/i)); await router.push({ name: RouteNames.CATALOG_ITEMS, @@ -245,7 +229,7 @@ describe('CatalogList', () => { }); await waitFor(() => { - expect(screen.getByText('2 results found')).toBeInTheDocument(); + expect(screen.getByText(/results found/i)).toBeInTheDocument(); }); }); }); @@ -255,7 +239,7 @@ describe('CatalogList', () => { makeWrapper(); await waitFor(() => { - expect(screen.getByText('Download a summary of selected channels')).toBeInTheDocument(); + expect(screen.getByText(/download a summary/i)).toBeInTheDocument(); }); }); });