diff --git a/src/studio-home/data/thunks.js b/src/studio-home/data/thunks.js index 12afbfc1b6..32b0a018e8 100644 --- a/src/studio-home/data/thunks.js +++ b/src/studio-home/data/thunks.js @@ -10,6 +10,7 @@ import { updateLoadingStatuses, updateSavingStatuses, fetchCourseDataSuccessV2, + updateStudioHomeCoursesCustomParams, } from './slice'; /** @@ -43,6 +44,9 @@ function fetchStudioHomeData( try { const coursesData = await getStudioHomeCoursesV2(search || '', requestParams); dispatch(fetchCourseDataSuccessV2(coursesData)); + const searchPage = search ? parseInt(new URLSearchParams(search).get('page'), 10) : NaN; + const fetchedPage = requestParams.page || (!Number.isNaN(searchPage) && searchPage > 0 ? searchPage : 1); + dispatch(updateStudioHomeCoursesCustomParams({ currentPage: fetchedPage })); dispatch(updateLoadingStatuses({ courseLoadingStatus: RequestStatus.SUCCESSFUL })); } catch { dispatch(updateLoadingStatuses({ courseLoadingStatus: RequestStatus.FAILED })); diff --git a/src/studio-home/data/thunks.test.js b/src/studio-home/data/thunks.test.js new file mode 100644 index 0000000000..2030be2d8b --- /dev/null +++ b/src/studio-home/data/thunks.test.js @@ -0,0 +1,78 @@ +import MockAdapter from 'axios-mock-adapter'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { fetchStudioHomeData } from './thunks'; +import { getApiBaseUrl, getStudioHomeApiUrl } from './api'; +import { + generateGetStudioCoursesApiResponseV2, + generateGetStudioHomeDataApiResponse, +} from '../factories/mockApiResponses'; + +let axiosMock; +let dispatch; + +describe('fetchStudioHomeData thunk', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + dispatch = jest.fn(); + + axiosMock.onGet(getStudioHomeApiUrl()).reply(200, generateGetStudioHomeDataApiResponse()); + axiosMock.onGet(new RegExp(`${getApiBaseUrl()}/api/contentstore/v2/home/courses.*`)) + .reply(200, generateGetStudioCoursesApiResponseV2()); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should sync currentPage from requestParams.page after fetching courses', async () => { + const requestParams = { page: 3 }; + await fetchStudioHomeData('', false, requestParams)(dispatch); + + const updateParamsCall = dispatch.mock.calls.find( + ([action]) => action.type === 'studioHome/updateStudioHomeCoursesCustomParams', + ); + expect(updateParamsCall).toBeDefined(); + expect(updateParamsCall[0].payload).toEqual({ currentPage: 3 }); + }); + + it('should sync currentPage from search query string when page is not in requestParams', async () => { + await fetchStudioHomeData('?page=2', false, {})(dispatch); + + const updateParamsCall = dispatch.mock.calls.find( + ([action]) => action.type === 'studioHome/updateStudioHomeCoursesCustomParams', + ); + expect(updateParamsCall).toBeDefined(); + expect(updateParamsCall[0].payload).toEqual({ currentPage: 2 }); + }); + + it('should default currentPage to 1 when page is not specified anywhere', async () => { + await fetchStudioHomeData('', false, {})(dispatch); + + const updateParamsCall = dispatch.mock.calls.find( + ([action]) => action.type === 'studioHome/updateStudioHomeCoursesCustomParams', + ); + expect(updateParamsCall).toBeDefined(); + expect(updateParamsCall[0].payload).toEqual({ currentPage: 1 }); + }); + + it('should prefer requestParams.page over search query string page', async () => { + const requestParams = { page: 5 }; + await fetchStudioHomeData('?page=2', false, requestParams)(dispatch); + + const updateParamsCall = dispatch.mock.calls.find( + ([action]) => action.type === 'studioHome/updateStudioHomeCoursesCustomParams', + ); + expect(updateParamsCall).toBeDefined(); + expect(updateParamsCall[0].payload).toEqual({ currentPage: 5 }); + }); +});