Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds & updates service user profile related tests for covering exceptions calling external apis #478

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/partner-access/partner-access.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { sub } from 'date-fns';
import * as crispApi from 'src/api/crisp/crisp-api';
import * as mailchimpApi from 'src/api/mailchimp/mailchimp-api';
import { PartnerEntity } from 'src/entities/partner.entity';
import { GetUserDto } from 'src/user/dtos/get-user.dto';
import * as profileData from 'src/utils/serviceUserProfiles';
Expand Down Expand Up @@ -46,11 +47,12 @@ jest.mock('src/api/crisp/crisp-api', () => ({
getCrispProfileData: jest.fn(),
updateCrispProfileBase: jest.fn(),
updateCrispProfile: jest.fn(),
updateServiceUserProfilesPartnerAccess: jest.fn(),
}));

jest.mock('src/utils/serviceUserProfiles', () => ({
updateServiceUserProfilesPartnerAccess: jest.fn(),
jest.mock('src/api/mailchimp/mailchimp-api', () => ({
createMailchimpMergeField: jest.fn(),
createMailchimpProfile: jest.fn(),
updateMailchimpProfile: jest.fn(),
}));

describe('PartnerAccessService', () => {
Expand Down Expand Up @@ -143,6 +145,8 @@ describe('PartnerAccessService', () => {
});
// Mocks that the accesscode already exists
jest.spyOn(repo, 'findOne').mockResolvedValueOnce(mockPartnerAccessEntity);
// Observer on the service user profiles method
jest.spyOn(profileData, 'updateServiceUserProfilesPartnerAccess');

const partnerAccess = await service.assignPartnerAccess(mockUserEntity, '123456');

Expand Down Expand Up @@ -175,6 +179,23 @@ describe('PartnerAccessService', () => {
});
});

it('should assign partner access even if mailchimp profile api fails', async () => {
// Mocks that the accesscode already exists
jest.spyOn(repo, 'findOne').mockResolvedValueOnce(mockPartnerAccessEntity);

jest.spyOn(mailchimpApi, 'updateMailchimpProfile').mockImplementationOnce(async () => {
throw new Error('Test throw');
});

const partnerAccess = await service.assignPartnerAccess(mockUserEntity, '123456');

expect(partnerAccess).toEqual({
...mockPartnerAccessEntity,
userId: mockUserEntity.id,
activatedAt: partnerAccess.activatedAt,
});
});

it('should return an error when partner access code has already been used by another user account', async () => {
jest.spyOn(repo, 'findOne').mockResolvedValueOnce({
...mockPartnerAccessEntity,
Expand Down
2 changes: 1 addition & 1 deletion src/partner-access/partner-access.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export class PartnerAccessService {
},
relations: { partner: true },
});
updateServiceUserProfilesPartnerAccess(partnerAccesses, user.email);
await updateServiceUserProfilesPartnerAccess(partnerAccesses, user.email);
} catch (error) {
this.logger.error(
`Error: Unable to update crisp profile for ${user.email}. Error: ${error.message} `,
Expand Down
51 changes: 51 additions & 0 deletions src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HttpException, HttpStatus } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { createCrispProfile, updateCrispProfile } from 'src/api/crisp/crisp-api';
import { createMailchimpProfile, updateMailchimpProfile } from 'src/api/mailchimp/mailchimp-api';
import { PartnerAccessEntity } from 'src/entities/partner-access.entity';
import { PartnerEntity } from 'src/entities/partner.entity';
import { SubscriptionUserService } from 'src/subscription-user/subscription-user.service';
Expand Down Expand Up @@ -226,6 +227,30 @@ describe('UserService', () => {
{ ...partnerAccessData, therapySessions: [mockTherapySessionDto] },
]);
});

it('should not fail on crisp api call errors', async () => {
const mocked = jest.mocked(createCrispProfile);
mocked.mockRejectedValue(new Error('Crisp API call failed'));

const user = await service.createUser(createUserDto);

expect(mocked).toHaveBeenCalled();
expect(user.user.email).toBe('[email protected]');

mocked.mockReset();
});

it('should not fail on mailchimp api call errors', async () => {
const mocked = jest.mocked(createMailchimpProfile);
mocked.mockRejectedValue(new Error('Mailchimp API call failed'));

const user = await service.createUser(createUserDto);

expect(mocked).toHaveBeenCalled();
expect(user.user.email).toBe('[email protected]');

mocked.mockReset();
});
});

describe('getUser', () => {
Expand Down Expand Up @@ -264,6 +289,32 @@ describe('UserService', () => {
expect(repoSaveSpy).toHaveBeenCalledWith({ ...mockUserEntity, ...updateUserDto });
expect(repoSaveSpy).toHaveBeenCalled();
});

it('should not fail on crisp api call errors', async () => {
const mocked = jest.mocked(updateCrispProfile);
mocked.mockRejectedValue(new Error('Crisp API call failed'));

const user = await service.updateUser(updateUserDto, { user: mockUserEntity });

expect(mocked).toHaveBeenCalled();
expect(user.name).toBe('new name');
expect(user.email).toBe('[email protected]');

mocked.mockReset();
});

it('should not fail on mailchimp api call errors', async () => {
const mocked = jest.mocked(updateMailchimpProfile);
mocked.mockRejectedValue(new Error('Mailchimp API call failed'));

const user = await service.updateUser(updateUserDto, { user: mockUserEntity });

expect(mocked).toHaveBeenCalled();
expect(user.name).toBe('new name');
expect(user.email).toBe('[email protected]');

mocked.mockReset();
});
});

describe('deleteUserById', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class UserService {
this.logger.log(`Create user: created public user in db. User: ${email}`);
}

createServiceUserProfiles(user, partner, partnerAccess);
await createServiceUserProfiles(user, partner, partnerAccess);

const userDto = formatUserObject({
...user,
Expand Down Expand Up @@ -205,7 +205,7 @@ export class UserService {

const isNameOrLanguageUpdated =
user.signUpLanguage !== updateUserDto.signUpLanguage && user.name !== updateUserDto.name;
updateServiceUserProfilesUser(user, isNameOrLanguageUpdated, user.email);
await updateServiceUserProfilesUser(user, isNameOrLanguageUpdated, user.email);
annarhughes marked this conversation as resolved.
Show resolved Hide resolved

return updatedUser;
}
Expand Down
47 changes: 47 additions & 0 deletions src/utils/serviceUserProfiles.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,15 @@ describe('Service user profiles', () => {
},
});
});

it('should not propagate external api call errors', async () => {
const mocked = jest.mocked(createCrispProfile);
mocked.mockRejectedValue(new Error('Crisp API call failed'));
await expect(createServiceUserProfiles(mockUserEntity)).resolves.not.toThrow();
mocked.mockReset();
});
});

describe('updateServiceUserProfilesUser', () => {
it('should update crisp and mailchimp profile user data', async () => {
await updateServiceUserProfilesUser(mockUserEntity, false, mockUserEntity.email);
Expand Down Expand Up @@ -209,6 +217,15 @@ describe('Service user profiles', () => {
mockUserEntity.email,
);
});

it('should not propagate external api call errors', async () => {
const mocked = jest.mocked(updateMailchimpProfile);
mocked.mockRejectedValue(new Error('Mailchimp API call failed'));
await expect(
updateServiceUserProfilesUser(mockUserEntity, false, mockUserEntity.email),
).resolves.not.toThrow();
mocked.mockReset();
});
});

describe('updateServiceUserProfilesPartnerAccess', () => {
Expand Down Expand Up @@ -286,6 +303,15 @@ describe('Service user profiles', () => {
mockUserEntity.email,
);
});

it('should not propagate external api call errors', async () => {
const mocked = jest.mocked(updateCrispProfile);
mocked.mockRejectedValue(new Error('Crisp API call failed'));
await expect(
updateServiceUserProfilesPartnerAccess([mockPartnerAccessEntity], mockUserEntity.email),
).resolves.not.toThrow();
mocked.mockReset();
});
});

describe('updateServiceUserProfilesTherapy', () => {
Expand Down Expand Up @@ -441,6 +467,18 @@ describe('Service user profiles', () => {
mockUserEntity.email,
);
});

it('should not propagate external api call errors', async () => {
const mocked = jest.mocked(updateMailchimpProfile);
mocked.mockRejectedValue(new Error('Mailchimp API call failed'));
await expect(
updateServiceUserProfilesTherapy(
[mockPartnerAccessEntity, mockAltPartnerAccessEntity],
mockUserEntity.email,
),
).resolves.not.toThrow();
mocked.mockReset();
});
});

describe('updateServiceUserProfilesCourse', () => {
Expand All @@ -465,6 +503,15 @@ describe('Service user profiles', () => {
mockUserEntity.email,
);
});

it('should not propagate external api call errors', async () => {
const mocked = jest.mocked(updateCrispProfile);
mocked.mockRejectedValue(new Error('Crisp API call failed'));
await expect(
updateServiceUserProfilesCourse(mockCourseUserEntity, mockUserEntity.email),
).resolves.not.toThrow();
mocked.mockReset();
});
});

describe('createMailchimpCourseMergeField', () => {
Expand Down
Loading