-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: added update and upsert to zoho api
- Loading branch information
Showing
8 changed files
with
557 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,26 +4,35 @@ import { Test, TestingModule } from '@nestjs/testing'; | |
import { ZohoRecruitApi } from './recruit.api'; | ||
import { fileZohoAccountsAccessTokenCacheService, ZohoAccountsAccessTokenCacheService } from '../accounts/accounts.service'; | ||
import { expectFail, itShouldFail, jestExpectFailAssertErrorType } from '@dereekb/util/test'; | ||
import { ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, ZohoNewRecruitRecord, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordNoContentError } from '@dereekb/zoho'; | ||
import { randomNumber } from '@dereekb/util'; | ||
import { ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, NewZohoRecruitRecordData, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordNoContentError, ZohoRecruitRecord, ZohoRecruitRecordCrudNoMatchingRecordError, ZOHO_INVALID_DATA_ERROR_CODE, ZohoRecruitSearchRecordsCriteriaEntry, ZohoRecruitSearchRecordsCriteriaEntryArray, ZohoInvalidQueryError } from '@dereekb/zoho'; | ||
import { Getter, cachedGetter, randomNumber } from '@dereekb/util'; | ||
|
||
// NOTE: Should have test canidates available on the Zoho Sandbox that is being used. Use test_candidates.csv to generate if needed. | ||
|
||
const cacheService = fileZohoAccountsAccessTokenCacheService(); | ||
|
||
const NON_EXISTENT_CANDIDATE_ID = '01'; | ||
const NON_EXISTENT_CANDIDATE_ID = '576777777777777712'; | ||
|
||
/** | ||
* For the tests, atleast one account should have this email domain/suffix. | ||
*/ | ||
const TEST_ACCOUNT_EXPORT_SUFFIX = 'components.dereekb.com'; | ||
const TEST_ACCOUNT_INSERT_EXPORT_SUFFIX = `insert.${TEST_ACCOUNT_EXPORT_SUFFIX}`; | ||
const TEST_ACCOUNT_UPSERT_EXPORT_SUFFIX = `upsert.${TEST_ACCOUNT_EXPORT_SUFFIX}`; | ||
|
||
/** | ||
* This candidate is only avaialble within the specific testing sandbox used for tests. | ||
*/ | ||
const TEST_CANDIDATE_ID = '576214000000574340'; | ||
const TEST_CANDIDATE_EMAIL_ADDRESS = '[email protected]'; | ||
const UPSERT_TEST_FIRST_NAME_PREFIX = `Upsert`; | ||
const UPSERT_TEST_LAST_NAME = `Upsert`; | ||
|
||
interface TestCandidate { | ||
Email: string; | ||
First_Name: string; | ||
Last_Name: string; | ||
} | ||
|
||
describe('recruit.api', () => { | ||
let nest: TestingModule; | ||
|
@@ -53,6 +62,31 @@ describe('recruit.api', () => { | |
describe('ZohoRecruitApi', () => { | ||
let api: ZohoRecruitApi; | ||
|
||
const GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS = 2; | ||
|
||
/** | ||
* Cached getter across all test runs. These records should always exist and can be used for updating. | ||
*/ | ||
const loadTestRecords: Getter<Promise<ZohoRecruitRecord[]>> = cachedGetter(async () => { | ||
const upsertResult = await api.upsertRecord({ | ||
module: 'Candidates', | ||
data: [ | ||
{ | ||
First_Name: `${UPSERT_TEST_FIRST_NAME_PREFIX}_1`, | ||
Last_Name: UPSERT_TEST_LAST_NAME, | ||
Email: `upsert+1@${TEST_ACCOUNT_UPSERT_EXPORT_SUFFIX}` | ||
}, | ||
{ | ||
First_Name: `${UPSERT_TEST_FIRST_NAME_PREFIX}_2`, | ||
Last_Name: UPSERT_TEST_LAST_NAME, | ||
Email: `upsert+2@${TEST_ACCOUNT_UPSERT_EXPORT_SUFFIX}` | ||
} | ||
] | ||
}); | ||
|
||
return upsertResult.successItems.map((item) => item.result.details); | ||
}); | ||
|
||
beforeEach(() => { | ||
api = nest.get(ZohoRecruitApi); | ||
}); | ||
|
@@ -136,7 +170,7 @@ describe('recruit.api', () => { | |
it('should return error items for records that could not be created', async () => { | ||
const createNumber = randomNumber({ min: 1000000000000, max: 10000000000000 }); | ||
|
||
const data: ZohoNewRecruitRecord[] = [ | ||
const data: NewZohoRecruitRecordData[] = [ | ||
{ | ||
First_Name: `Create_${createNumber}`, | ||
lastNameFieldMissing: 'Candidate', // field missing | ||
|
@@ -162,6 +196,207 @@ describe('recruit.api', () => { | |
}); | ||
}); | ||
}); | ||
|
||
describe('updateRecord()', () => { | ||
describe('single record', () => { | ||
it('should update a record and return the updated record details', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const number = randomNumber({ min: 1000000000000, max: 10000000000000 }); | ||
const First_Name = `Updated For Test ${number}`; | ||
|
||
const updateResult = await api.updateRecord({ | ||
module: 'Candidates', | ||
data: { | ||
id: recordToUpdate.id, | ||
First_Name | ||
} | ||
}); | ||
|
||
expect(updateResult.id).toBe(recordToUpdate.id); | ||
|
||
const updatedRecord = await api.getRecordById({ module: 'Candidates', id: recordToUpdate.id }); | ||
expect(updatedRecord.First_Name).toBe(First_Name); | ||
}); | ||
|
||
itShouldFail('if attempting to update a value that does not exist', async () => { | ||
await expectFail( | ||
() => | ||
api.updateRecord({ | ||
module: 'Candidates', | ||
data: { | ||
id: NON_EXISTENT_CANDIDATE_ID, | ||
First_Name: 'Failure' | ||
} | ||
}), | ||
jestExpectFailAssertErrorType(ZohoRecruitRecordCrudNoMatchingRecordError) | ||
); | ||
}); | ||
|
||
itShouldFail('if attempting to update a unique value to an existing value', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
await expectFail( | ||
() => | ||
api.updateRecord({ | ||
module: 'Candidates', | ||
data: { | ||
id: recordToUpdate.id, | ||
Email: TEST_CANDIDATE_EMAIL_ADDRESS | ||
} | ||
}), | ||
jestExpectFailAssertErrorType(ZohoRecruitRecordCrudDuplicateDataError) | ||
); | ||
}); | ||
}); | ||
|
||
describe('multiple record', () => { | ||
it('should update multiple records and return the results in an array', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const number = randomNumber({ min: 1000000000000, max: 10000000000000 }); | ||
const First_Name = `Updated For Test ${number}`; | ||
|
||
const updateResult = await api.updateRecord({ | ||
module: 'Candidates', | ||
data: [ | ||
{ | ||
id: recordToUpdate.id, | ||
First_Name | ||
} | ||
] | ||
}); | ||
|
||
expect(updateResult.successItems).toHaveLength(1); | ||
expect(updateResult.successItems[0].result.details.id).toBe(recordToUpdate.id); | ||
|
||
const updatedRecord = await api.getRecordById({ module: 'Candidates', id: recordToUpdate.id }); | ||
expect(updatedRecord.First_Name).toBe(First_Name); | ||
}); | ||
|
||
it('should return error items for the items that failed updating', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const data = [ | ||
{ | ||
id: NON_EXISTENT_CANDIDATE_ID, // invalid data issue | ||
First_Name: 'Failure' | ||
}, | ||
{ | ||
id: recordToUpdate.id, | ||
Email: TEST_CANDIDATE_EMAIL_ADDRESS // duplicate issue | ||
} | ||
]; | ||
|
||
const result = await api.updateRecord({ | ||
module: 'Candidates', | ||
data | ||
}); | ||
|
||
expect(result.errorItems).toHaveLength(2); | ||
expect(result.errorItems[0].input).toBe(data[0]); | ||
expect(result.errorItems[1].input).toBe(data[1]); | ||
expect(result.errorItems[0].result.code).toBe(ZOHO_INVALID_DATA_ERROR_CODE); | ||
expect(result.errorItems[1].result.code).toBe(ZOHO_DUPLICATE_DATA_ERROR_CODE); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('upsertRecord()', () => { | ||
describe('single record', () => { | ||
it('should update a record and return the updated record details', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const number = randomNumber({ min: 1000000000000, max: 10000000000000 }); | ||
const First_Name = `Updated For Test ${number}`; | ||
|
||
const updateResult = await api.upsertRecord({ | ||
module: 'Candidates', | ||
data: { | ||
id: recordToUpdate.id, | ||
First_Name | ||
} | ||
}); | ||
|
||
expect(updateResult.id).toBe(recordToUpdate.id); | ||
|
||
const updatedRecord = await api.getRecordById({ module: 'Candidates', id: recordToUpdate.id }); | ||
expect(updatedRecord.First_Name).toBe(First_Name); | ||
}); | ||
|
||
itShouldFail('if attempting to update a value that does not exist', async () => { | ||
await expectFail( | ||
() => | ||
api.updateRecord({ | ||
module: 'Candidates', | ||
data: { | ||
id: NON_EXISTENT_CANDIDATE_ID, | ||
First_Name: 'Failure' | ||
} | ||
}), | ||
jestExpectFailAssertErrorType(ZohoRecruitRecordCrudNoMatchingRecordError) | ||
); | ||
}); | ||
}); | ||
|
||
describe('multiple record', () => { | ||
it('should update multiple records and return the results in an array', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const number = randomNumber({ min: 1000000000000, max: 10000000000000 }); | ||
const First_Name = `Updated For Test ${number}`; | ||
|
||
const updateResult = await api.upsertRecord({ | ||
module: 'Candidates', | ||
data: [ | ||
{ | ||
id: recordToUpdate.id, | ||
First_Name | ||
} | ||
] | ||
}); | ||
|
||
expect(updateResult.successItems).toHaveLength(1); | ||
expect(updateResult.successItems[0].result.details.id).toBe(recordToUpdate.id); | ||
|
||
const updatedRecord = await api.getRecordById({ module: 'Candidates', id: recordToUpdate.id }); | ||
expect(updatedRecord.First_Name).toBe(First_Name); | ||
}); | ||
|
||
it('should return error items for the items that failed updating', async () => { | ||
const testRecords = await loadTestRecords(); | ||
const recordToUpdate = testRecords[0]; | ||
|
||
const data = [ | ||
{ | ||
id: NON_EXISTENT_CANDIDATE_ID, // invalid data issue | ||
First_Name: 'Failure' | ||
}, | ||
{ | ||
id: recordToUpdate.id, | ||
Email: TEST_CANDIDATE_EMAIL_ADDRESS // duplicate issue | ||
} | ||
]; | ||
|
||
const result = await api.upsertRecord({ | ||
module: 'Candidates', | ||
data | ||
}); | ||
|
||
expect(result.errorItems).toHaveLength(2); | ||
expect(result.errorItems[0].input).toBe(data[0]); | ||
expect(result.errorItems[1].input).toBe(data[1]); | ||
expect(result.errorItems[0].result.code).toBe(ZOHO_INVALID_DATA_ERROR_CODE); | ||
expect(result.errorItems[1].result.code).toBe(ZOHO_DUPLICATE_DATA_ERROR_CODE); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('read', () => { | ||
|
@@ -202,7 +437,7 @@ describe('recruit.api', () => { | |
}); | ||
|
||
describe('searchRecords()', () => { | ||
it('should return a page of search results', async () => { | ||
it('should search results by email', async () => { | ||
const limit = 3; | ||
const result = await api.searchRecords({ | ||
module: 'Candidates', | ||
|
@@ -213,6 +448,62 @@ describe('recruit.api', () => { | |
expect(result).toBeDefined(); | ||
expect(result.data.length).toBeLessThanOrEqual(limit); | ||
}); | ||
|
||
it('should search results by a specific field', async () => { | ||
const limit = GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS; | ||
|
||
const result = await api.searchRecords<TestCandidate>({ | ||
module: 'Candidates', | ||
criteria: [{ field: 'Last_Name', filter: 'starts_with', value: UPSERT_TEST_LAST_NAME }], | ||
per_page: limit | ||
}); | ||
|
||
expect(result).toBeDefined(); | ||
expect(result.data).toHaveLength(GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS); | ||
|
||
expect(result.data[0].Last_Name).toBe(UPSERT_TEST_LAST_NAME); | ||
expect(result.data[1].Last_Name).toBe(UPSERT_TEST_LAST_NAME); | ||
}); | ||
|
||
it('should search results by a specific field', async () => { | ||
const limit = GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS; | ||
|
||
const result = await api.searchRecords<TestCandidate>({ | ||
module: 'Candidates', | ||
criteria: [{ field: 'Last_Name', filter: 'starts_with', value: UPSERT_TEST_LAST_NAME }], | ||
per_page: limit | ||
}); | ||
|
||
expect(result).toBeDefined(); | ||
expect(result.data).toHaveLength(GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS); | ||
|
||
expect(result.data[0].Last_Name).toBe(UPSERT_TEST_LAST_NAME); | ||
expect(result.data[1].Last_Name).toBe(UPSERT_TEST_LAST_NAME); | ||
}); | ||
|
||
it('should return no values if there are no results', async () => { | ||
const limit = GURANTEED_NUMBER_OF_UPSERT_TEST_RECORDS; | ||
|
||
const result = await api.searchRecords<TestCandidate>({ | ||
module: 'Candidates', | ||
criteria: [{ field: 'Last_Name', filter: 'starts_with', value: 'Should Not Return Any Results' }], | ||
per_page: limit | ||
}); | ||
|
||
expect(result).toBeDefined(); | ||
expect(result.data).toHaveLength(0); | ||
}); | ||
|
||
itShouldFail('if the criteria is invalid', async () => { | ||
await expectFail( | ||
() => | ||
api.searchRecords<TestCandidate>({ | ||
module: 'Candidates', | ||
criteria: [{ field: 'Last_Name', filter: 'STARTS_WITH_WRONG' as any, value: 'Should Not Return Any Results' }] | ||
}), | ||
jestExpectFailAssertErrorType(ZohoInvalidQueryError) | ||
); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.