From 9762d3b8818d42a5b11f11d75a7b78c586d85298 Mon Sep 17 00:00:00 2001 From: Brayan Ceron Date: Wed, 26 Feb 2025 10:07:55 -0500 Subject: [PATCH] test: improve coverage --- src/account-settings/AccountSettingsPage.jsx | 2 +- src/account-settings/data/sagas.test.js | 211 +++++++++++++++++++ src/tests/utils.test.js | 32 ++- 3 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/account-settings/data/sagas.test.js diff --git a/src/account-settings/AccountSettingsPage.jsx b/src/account-settings/AccountSettingsPage.jsx index 9d32b617e..9e53f3ad8 100644 --- a/src/account-settings/AccountSettingsPage.jsx +++ b/src/account-settings/AccountSettingsPage.jsx @@ -701,7 +701,7 @@ class AccountSettingsPage extends React.Component { /> {this.props.extendedProfileFields .sort(moveCheckboxFieldsToEnd).map((fieldDescription) => { - const fieldValue = this.props.formValues.extended_profile.find( + const fieldValue = this.props.formValues.extended_profile?.find( (field) => field.field_name === fieldDescription.name, ); diff --git a/src/account-settings/data/sagas.test.js b/src/account-settings/data/sagas.test.js new file mode 100644 index 000000000..47699587e --- /dev/null +++ b/src/account-settings/data/sagas.test.js @@ -0,0 +1,211 @@ +import { runSaga } from 'redux-saga'; +import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import { + fetchSettingsBegin, + fetchSettingsSuccess, + fetchSettingsFailure, + saveSettingsBegin, + saveSettingsSuccess, + fetchTimeZonesSuccess, + getExtendedProfileFieldsBegin, + getExtendedProfileFieldsSuccess, + getExtendedProfileFieldsFailure, +} from './actions'; +import { + getSettings, + patchSettings, + getTimeZones, + getExtendedProfileFields, +} from './service'; +import { + handleFetchSettings, + handleSaveSettings, + handleFetchTimeZones, + fetchThirdPartyAuthContext, +} from './sagas'; + +jest.mock('@edx/frontend-platform/auth', () => ({ + getAuthenticatedUser: jest.fn(), // Mock de la función +})); + +jest.mock('./service', () => ({ + getSettings: jest.fn(), + patchSettings: jest.fn(), + getTimeZones: jest.fn(), + getVerifiedNameHistory: jest.fn(), + getExtendedProfileFields: jest.fn(), // Asegurar que está incluido aquí +})); + +describe('Saga Tests', () => { + test('handleFetchSettings success', async () => { + const dispatched = []; + const mockUser = { username: 'testuser', userId: 1, roles: [] }; + const mockSettings = { + values: {}, + thirdPartyAuthProviders: {}, + profileDataManager: {}, + timeZones: {}, + verifiedNameHistory: undefined, + }; + getAuthenticatedUser.mockReturnValue(mockUser); + getSettings.mockResolvedValue(mockSettings); + + await runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + handleFetchSettings, + ).toPromise(); + + expect(dispatched).toContainEqual(fetchSettingsBegin()); + expect(dispatched).toContainEqual(fetchSettingsSuccess({ + // due to sagas.js and its ...values, we have to add the ...rest in values to pass test + ...mockSettings, + values: { + values: mockSettings.values, + verifiedNameHistory: undefined, + }, + })); + }); + + test('handleFetchSettings failure', async () => { + const dispatched = []; + const errorMessage = 'Failed to fetch'; + + getAuthenticatedUser.mockReturnValue({ username: 'testuser', userId: 1, roles: [] }); + getSettings.mockRejectedValue(new Error(errorMessage)); + + await expect(runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + handleFetchSettings, + ).toPromise()).rejects.toThrow(errorMessage); + + expect(dispatched).toContainEqual(fetchSettingsBegin()); + expect(dispatched).toContainEqual(fetchSettingsFailure(errorMessage)); + }); + + test('handleSaveSettings success', async () => { + const dispatched = []; + const mockUser = { username: 'testuser', userId: 1 }; + const mockAction = { + payload: { + commitValues: { exampleKey: 'exampleValue' }, + formId: 'someForm', + extendedProfile: {}, // Asegura que no sea undefined + }, + }; + const mockSavedValues = {}; + + getAuthenticatedUser.mockReturnValue(mockUser); + patchSettings.mockResolvedValue(mockSavedValues); + + await runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + handleSaveSettings, + mockAction, + ).toPromise(); + + expect(dispatched).toContainEqual(saveSettingsBegin()); + expect(dispatched).toContainEqual(saveSettingsSuccess( + mockSavedValues, + { [mockAction.payload.formId]: mockAction.payload.commitValues }, + )); + }); + + test('handleFetchTimeZones success', async () => { + const dispatched = []; + const mockedAction = { payload: { country: 'US' } }; + const mockResponse = ['EST', 'PST']; + + getTimeZones.mockResolvedValue(mockResponse); + + await runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + handleFetchTimeZones, + mockedAction, + ).toPromise(); + + expect(dispatched).toContainEqual(fetchTimeZonesSuccess(mockResponse, 'US')); + }); + + test('fetchThirdPartyAuthContext success', async () => { + const dispatched = []; + const mockedAction = { payload: { urlParams: {} } }; + const mockFields = { field1: 'value1' }; + + getExtendedProfileFields.mockResolvedValue({ fields: mockFields }); + + await runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + fetchThirdPartyAuthContext, + mockedAction, + ).toPromise(); + + expect(dispatched).toContainEqual(getExtendedProfileFieldsBegin()); + expect(dispatched).toContainEqual(getExtendedProfileFieldsSuccess(mockFields)); + }); + + test('fetchThirdPartyAuthContext failure', async () => { + const dispatched = []; + const mockedAction = { payload: { urlParams: {} } }; + + getExtendedProfileFields.mockRejectedValue(new Error('API error')); + + await expect(runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + fetchThirdPartyAuthContext, + mockedAction, + ).toPromise()).rejects.toThrow('API error'); + + expect(dispatched).toContainEqual(getExtendedProfileFieldsBegin()); + expect(dispatched).toContainEqual(getExtendedProfileFieldsFailure()); + }); + + test('getExtendedProfileFields success', async () => { + const dispatched = []; + const mockUrlParams = { param1: 'value1' }; + const mockFields = [{ name: 'field1', value: 'value1' }]; + + getExtendedProfileFields.mockResolvedValue({ fields: mockFields }); + + await runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + fetchThirdPartyAuthContext, + { payload: { urlParams: mockUrlParams } }, + ).toPromise(); + + expect(dispatched).toContainEqual(getExtendedProfileFieldsBegin()); + expect(dispatched).toContainEqual(getExtendedProfileFieldsSuccess(mockFields)); + }); + + test('getExtendedProfileFields failure', async () => { + const dispatched = []; + const mockUrlParams = { param1: 'value1' }; + const errorMessage = 'API error'; + + getExtendedProfileFields.mockRejectedValue(new Error(errorMessage)); + + await expect(runSaga( + { + dispatch: (action) => dispatched.push(action), + }, + fetchThirdPartyAuthContext, + { payload: { urlParams: mockUrlParams } }, + ).toPromise()).rejects.toThrow(errorMessage); + + expect(dispatched).toContainEqual(getExtendedProfileFieldsBegin()); + expect(dispatched).toContainEqual(getExtendedProfileFieldsFailure()); + }); +}); diff --git a/src/tests/utils.test.js b/src/tests/utils.test.js index 9287208ab..a6c7b4257 100644 --- a/src/tests/utils.test.js +++ b/src/tests/utils.test.js @@ -1,4 +1,4 @@ -import { compareVerifiedNamesByCreatedDate, getMostRecentApprovedOrPendingVerifiedName } from '../utils'; +import { compareVerifiedNamesByCreatedDate, getMostRecentApprovedOrPendingVerifiedName, moveCheckboxFieldsToEnd } from '../utils'; describe('getMostRecentApprovedOrPendingVerifiedName', () => { it('returns correct verified name if one exists', () => { @@ -80,4 +80,34 @@ describe('compareVerifiedNamesByCreatedDate', () => { expect(compareVerifiedNamesByCreatedDate(a, b)).toBeGreaterThan(0); }); + + describe('moveCheckboxFieldsToEnd', () => { + it('returns 1 when first field is checkbox and second field is not', () => { + const a = { type: 'checkbox' }; + const b = { type: 'text' }; + + expect(moveCheckboxFieldsToEnd(a, b)).toEqual(1); + }); + + it('returns -1 when first field is not checkbox and second field is', () => { + const a = { type: 'text' }; + const b = { type: 'checkbox' }; + + expect(moveCheckboxFieldsToEnd(a, b)).toEqual(-1); + }); + + it('returns 0 when both fields are checkboxes', () => { + const a = { type: 'checkbox' }; + const b = { type: 'checkbox' }; + + expect(moveCheckboxFieldsToEnd(a, b)).toEqual(0); + }); + + it('returns 0 when neither field is a checkbox', () => { + const a = { type: 'text' }; + const b = { type: 'text' }; + + expect(moveCheckboxFieldsToEnd(a, b)).toEqual(0); + }); + }); });