Skip to content

Commit

Permalink
fe/be tests for contact management
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjaytkbabu committed Jan 8, 2025
1 parent fd1adca commit 564c66e
Show file tree
Hide file tree
Showing 4 changed files with 347 additions and 0 deletions.
219 changes: 219 additions & 0 deletions app/tests/unit/controllers/contact.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { contactService } from '../../../src/services';
import contactController from '../../../src/controllers/contact';
import { Request, Response } from 'express';

// Mock config library - @see {@link https://stackoverflow.com/a/64819698}
jest.mock('config');

const mockResponse = () => {
const res: { status?: jest.Mock; json?: jest.Mock; end?: jest.Mock } = {};
res.status = jest.fn().mockReturnValue(res);
res.json = jest.fn().mockReturnValue(res);

return res;
};

let res = mockResponse();
beforeEach(() => {
res = mockResponse();
});

afterEach(() => {
jest.resetAllMocks();
});

const CURRENT_CONTEXT = { authType: 'BEARER', tokenPayload: null };

describe('contactController', () => {
const next = jest.fn();

describe('searchContacts', () => {
const searchContactsSpy = jest.spyOn(contactService, 'searchContacts');

it('should return 200 if all good', async () => {
const req = {
query: { userId: '5e3f0c19-8664-4a43-ac9e-210da336e923' },
currentContext: CURRENT_CONTEXT
} as unknown as Request;

const contacts = [
{
contactId: 'contact123',
userId: 'user123',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
email: '[email protected]',
contactPreference: 'email',
contactApplicantRelationship: 'applicant'
}
];

searchContactsSpy.mockResolvedValue(contacts);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.searchContacts(req as any, res as unknown as Response, next);

expect(searchContactsSpy).toHaveBeenCalledTimes(1);
expect(searchContactsSpy).toHaveBeenCalledWith({
userId: ['5e3f0c19-8664-4a43-ac9e-210da336e923'],
contactId: undefined,
email: undefined,
firstName: undefined,
lastName: undefined,
contactApplicantRelationship: undefined,
phoneNumber: undefined
});
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith(contacts);
});

it('adds dashes to user IDs', async () => {
const req = {
query: { userId: '5e3f0c1986644a43ac9e210da336e923,8b9dedd279d442c6b82f52844a8e2757' },
currentContext: CURRENT_CONTEXT
} as unknown as Request;

const contacts = [
{
contactId: 'contact123',
userId: 'user123',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
email: '[email protected]',
contactPreference: 'email',
contactApplicantRelationship: 'applicant'
}
];

searchContactsSpy.mockResolvedValue(contacts);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.searchContacts(req as any, res as unknown as Response, next);

expect(searchContactsSpy).toHaveBeenCalledTimes(1);
expect(searchContactsSpy).toHaveBeenCalledWith({
userId: ['5e3f0c19-8664-4a43-ac9e-210da336e923', '8b9dedd2-79d4-42c6-b82f-52844a8e2757'],
contactId: undefined,
email: undefined,
firstName: undefined,
lastName: undefined,
contactApplicantRelationship: undefined,
phoneNumber: undefined
});
});

it('adds dashes to contact IDs', async () => {
const req = {
query: { contactId: '5e3f0c1986644a43ac9e210da336e923,8b9dedd279d442c6b82f52844a8e2757' },
currentContext: CURRENT_CONTEXT
} as unknown as Request;

const contacts = [
{
contactId: 'contact123',
userId: 'user123',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
email: '[email protected]',
contactPreference: 'email',
contactApplicantRelationship: 'applicant'
}
];

searchContactsSpy.mockResolvedValue(contacts);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.searchContacts(req as any, res as unknown as Response, next);

expect(searchContactsSpy).toHaveBeenCalledTimes(1);
expect(searchContactsSpy).toHaveBeenCalledWith({
contactId: ['5e3f0c19-8664-4a43-ac9e-210da336e923', '8b9dedd2-79d4-42c6-b82f-52844a8e2757'],
userId: undefined,
email: undefined,
firstName: undefined,
lastName: undefined,
contactApplicantRelationship: undefined,
phoneNumber: undefined
});
});

it('calls next if the contact service fails to list contacts', async () => {
const req = {
query: { userId: '5e3f0c19-8664-4a43-ac9e-210da336e923' },
currentContext: CURRENT_CONTEXT
} as unknown as Request;

searchContactsSpy.mockImplementationOnce(() => {
throw new Error();
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.searchContacts(req as any, res as unknown as Response, next);

expect(searchContactsSpy).toHaveBeenCalledTimes(1);
expect(searchContactsSpy).toHaveBeenCalledWith({
userId: ['5e3f0c19-8664-4a43-ac9e-210da336e923'],
contactId: undefined,
email: undefined,
firstName: undefined,
lastName: undefined,
contactApplicantRelationship: undefined,
phoneNumber: undefined
});
expect(res.status).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledTimes(1);
});
});

describe('updateContact', () => {
const upsertContactsSpy = jest.spyOn(contactService, 'upsertContacts');

it('should return 200 if contact is updated successfully', async () => {
const req = {
body: {
userId: '5e3f0c19-8664-4a43-ac9e-210da336e923',
email: '[email protected]',
firstName: 'First',
lastName: 'Last'
},
currentContext: CURRENT_CONTEXT
} as unknown as Request;

upsertContactsSpy.mockResolvedValue();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.updateContact(req as any, res as unknown as Response, next);

expect(upsertContactsSpy).toHaveBeenCalledTimes(1);
expect(upsertContactsSpy).toHaveBeenCalledWith([req.body], req.currentContext);
expect(res.status).toHaveBeenCalledWith(200);
});

it('calls next if the contact service fails to update contact', async () => {
const req = {
body: {
userId: '5e3f0c19-8664-4a43-ac9e-210da336e923',
email: '[email protected]',
firstName: 'First',
lastName: 'Last'
},
currentContext: CURRENT_CONTEXT
} as unknown as Request;

upsertContactsSpy.mockImplementationOnce(() => {
throw new Error();
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
await contactController.updateContact(req as any, res as unknown as Response, next);

expect(upsertContactsSpy).toHaveBeenCalledTimes(1);
expect(upsertContactsSpy).toHaveBeenCalledWith([req.body], req.currentContext);
expect(res.status).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledTimes(1);
});
});
});
1 change: 1 addition & 0 deletions frontend/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as atsService } from './atsService';
export { default as AuthService } from './authService';
export { default as ConfigService } from './configService';
export { default as comsService } from './comsService';
export { default as contactService } from './contactService';
export { default as documentService } from './documentService';
export { default as enquiryService } from './enquiryService';
export { default as externalApiService } from './externalApiService';
Expand Down
69 changes: 69 additions & 0 deletions frontend/tests/unit/service/contactService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { contactService } from '@/services';
import { appAxios } from '@/services/interceptors';

import type { Contact, ContactSearchParameters } from '@/types';

vi.mock('vue-router', () => ({
useRouter: () => ({
push: vi.fn(),
replace: vi.fn()
})
}));

const sampleContact: Contact = {
contactId: 'contact123',
userId: 'user123',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
email: '[email protected]',
contactPreference: 'email',
contactApplicantRelationship: 'applicant',
createdBy: 'testCreatedBy',
createdAt: new Date().toISOString(),
updatedBy: 'testUpdatedAt',
updatedAt: new Date().toISOString()
};
const sampleContactSearchParameters: ContactSearchParameters = {
contactApplicantRelationship: 'applicant',
contactPreference: 'email',
contactId: ['contact123', 'contact456'],
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
userId: ['user123', 'user456']
};

const getSpy = vi.fn();
const deleteSpy = vi.fn();
const patchSpy = vi.fn();
const putSpy = vi.fn();

vi.mock('@/services/interceptors');
vi.mocked(appAxios).mockReturnValue({
get: getSpy,
delete: deleteSpy,
patch: patchSpy,
put: putSpy
} as any);

beforeEach(() => {
vi.clearAllMocks();
});

describe('contactService', () => {
it('calls searchContacts with correct data', () => {
contactService.searchContacts(sampleContactSearchParameters);

expect(getSpy).toHaveBeenCalledTimes(1);
expect(getSpy).toHaveBeenCalledWith('contact', { params: sampleContactSearchParameters });
});

it('calls updateContact with correct data', () => {
contactService.updateContact(sampleContact.contactId, sampleContact);

expect(putSpy).toHaveBeenCalledTimes(1);
expect(putSpy).toHaveBeenCalledWith(`contact/${sampleContact.contactId}`, sampleContact);
});
});
58 changes: 58 additions & 0 deletions frontend/tests/unit/views/contact/ContactProfileView.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { AxiosResponse } from 'axios';
import { shallowMount } from '@vue/test-utils';

import ContactProfileView from '@/views/contact/ContactProfileView.vue';
import { contactService } from '@/services';
import PrimeVue from 'primevue/config';
import ToastService from 'primevue/toastservice';

import type { Contact } from '@/types';

vi.mock('vue-i18n', () => ({
useI18n: () => ({
t: vi.fn()
})
}));

vi.mock('vue-router', () => ({
useRouter: () => ({
push: vi.fn()
})
}));

const testContact: Contact = {
contactId: 'contact123',
userId: 'user123',
firstName: 'John',
lastName: 'Doe',
phoneNumber: '123-456-7890',
email: '[email protected]',
contactPreference: 'email',
contactApplicantRelationship: 'applicant'
};

const useContactService = vi.spyOn(contactService, 'searchContacts');
useContactService.mockResolvedValue({ data: [testContact] } as AxiosResponse);

beforeEach(() => {
vi.clearAllMocks();
});

afterEach(() => {
sessionStorage.clear();
});

const wrapperSettings = () => ({
global: {
plugins: [() => PrimeVue, ToastService],
stubs: ['font-awesome-icon']
}
});

describe('ContactProfileView.vue', () => {
it('renders', () => {
const wrapper = shallowMount(ContactProfileView, wrapperSettings());

expect(wrapper).toBeTruthy();
});
});

0 comments on commit 564c66e

Please sign in to comment.