-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/55891 add ToE code and pupil source to ps report (#2484)
* Upgrade patch deps for tslib, and functions * Upgrade dotenv to v16.0.3 * upgrade uuid v9.0.0 * upgrade axios to v1.3.4 * axios integration test fix * upgrade ioredis to v5.3.1 * upgrade @azure/data-tables to v13.2.1 * upgrade various dev-deps * Upgrade dev deps * axios fix for jest * db - add ToECode to ps report * ws only * Upgrage @azure/functions to v3.5.0 * db - add migration for importedFromCensus flag * Add ToE code and ImportedToCensus to PS report * Update documentation * db - add isEdited col to pupil * Add pupil isEdited trigger * add integration tests * add fakerjs as dev dep * add integration tests * rm newline * Re-add faker-js a dev dep required for integration tests * Rm extra whitespace * whitespace change * fix trigger * Update post_check_window_steps.rb --------- Co-authored-by: Mohsen Qureshi <[email protected]>
- Loading branch information
1 parent
a01c9a5
commit 88924ef
Showing
42 changed files
with
1,982 additions
and
1,352 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 |
---|---|---|
@@ -0,0 +1,274 @@ | ||
'use strict' | ||
/* global expect describe test afterAll */ | ||
|
||
/** | ||
* @file Integration Tests for Pupil Edit Service | ||
*/ | ||
|
||
const pupilAddService = require('../services/pupil-add-service') | ||
const { faker } = require('@faker-js/faker') | ||
const upnService = require('../services/upn.service') | ||
const pupilTestService = require('./test-support/pupil-test.service') | ||
const moment = require('moment') | ||
const sqlService = require('../services/data-access/sql.service') | ||
const redisCacheService = require('../services/data-access/redis-cache.service') | ||
|
||
const currentUTCDate = moment.utc() | ||
const currentYear = currentUTCDate.year() | ||
const academicYear = currentUTCDate.isBetween(moment.utc(`${currentYear}-01-01`), moment.utc(`${currentYear}-08-31`), null, '[]') | ||
? currentYear - 1 | ||
: currentYear | ||
|
||
function createFakeUpn () { | ||
const base = '201' + faker.datatype.number({ min: 100000000, max: 900000000 }) | ||
const checkLetter = upnService.calculateCheckLetter(base) | ||
return checkLetter + base.toString() | ||
} | ||
|
||
function fakePupilData () { | ||
const gender = faker.helpers.arrayElement(['M', 'F']) | ||
const dob = moment(`${academicYear}-08-31`) | ||
.subtract(8, 'years') | ||
.subtract(faker.datatype.number({ min: 0, max: 364 }), 'days') // randomise dob | ||
|
||
return { | ||
school_id: 1, | ||
upn: createFakeUpn(), | ||
foreName: faker.name.firstName(gender === 'M' ? 'male' : 'female'), | ||
middleNames: faker.name.middleName(gender === 'M' ? 'male' : 'female'), | ||
lastName: faker.name.lastName(), | ||
foreNameAlias: '', | ||
lastNameAlias: '', | ||
gender, | ||
ageReason: '', | ||
'dob-year': dob.year().toString(), | ||
'dob-month': (dob.month() + 1).toString().padStart(2, '0'), // months are zero-indexed | ||
'dob-day': dob.date().toString().padStart(2, '0') | ||
} | ||
} | ||
|
||
describe('pupilEditService', () => { | ||
const schoolId = 1 | ||
const userId = 1 | ||
|
||
afterAll(async () => { | ||
await sqlService.drainPool() | ||
redisCacheService.disconnect() | ||
}) | ||
|
||
test('it sets the isEdited flag when the foreName changes', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateForename(dbPupilData.id, 'Testforename') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.foreName).toBe('Testforename') | ||
}) | ||
|
||
test('it sets the isEdited flag when the middlesNames change', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateMiddlenames(dbPupilData.id, 'New Middle Names') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.middleNames).toBe('New Middle Names') | ||
}) | ||
|
||
test('it sets the isEdited flag when the lastName changes', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateLastname(dbPupilData.id, 'NewLastName') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.lastName).toBe('NewLastName') | ||
}) | ||
|
||
test('it sets the isEdited flag when the gender changes', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateGender(dbPupilData.id, dbPupilData.gender === 'M' ? 'F' : 'M') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.gender).toBe(dbPupilData.gender === 'M' ? 'F' : 'M') | ||
}) | ||
|
||
test('it sets the isEdited flag when the UPN changes', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
const newUpn = createFakeUpn() | ||
await pupilTestService.updateUPN(dbPupilData.id, newUpn) | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(newUpn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.upn).toBe(newUpn) | ||
}) | ||
|
||
test('it sets the isEdited flag when the date of birth changes', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
const newDob = moment('2023-01-01') | ||
await pupilTestService.updateDob(dbPupilData.id, newDob) | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.dateOfBirth.format('YYYY-MM-DD')).toBe(newDob.format('YYYY-MM-DD')) | ||
}) | ||
|
||
test('it does not set the isEdited flag when the forename alias is changed', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateForenameAlias(dbPupilData.id, 'first alias') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.isEdited).toBe(false) // does NOT get set! | ||
expect(newPupilData.foreNameAlias).toBe('first alias') | ||
}) | ||
|
||
test('it does not set the isEdited flag when the lastname alias is changed', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test - confirm the isEdited flag state | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change, that will cause the functionality (in this case the pupil trigger for update) | ||
await pupilTestService.updateLastnameAlias(dbPupilData.id, 'last alias') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.isEdited).toBe(false) // does NOT get set! | ||
expect(newPupilData.lastNameAlias).toBe('last alias') | ||
}) | ||
|
||
test('it updates the updatedAt timestamp when edited ', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
const ts1 = dbPupilData.updatedAt | ||
|
||
// Apply any change | ||
await pupilTestService.updateLastnameAlias(dbPupilData.id, 'last alias') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.updatedAt.valueOf()).toBeGreaterThan(ts1.valueOf()) // compare in milliseconds from moment objects. | ||
expect(newPupilData.lastNameAlias).toBe('last alias') | ||
}) | ||
|
||
test('updating an already-edited pupil record keeps the isEdited field set to true', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply any change | ||
await pupilTestService.updateLastname(dbPupilData.id, 'Newman') | ||
|
||
// Check the isEdited flag is now applied. As it is a trigger it will run on changes from the admin app, and even DB Admin. | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.isEdited).toBe(true) | ||
expect(newPupilData.lastName).toBe('Newman') | ||
|
||
// update again | ||
await pupilTestService.updateForename(newPupilData.id, 'Zwei') | ||
const updatedPupilData = await pupilTestService.findPupilByUPN(newPupilData.upn) | ||
|
||
// final checks | ||
expect(updatedPupilData.isEdited).toBe(true) | ||
expect(updatedPupilData.foreName).toBe('Zwei') | ||
}) | ||
|
||
test('updating an already-edited pupil record keeps the isEdited field set to false (it was already false)e', async () => { | ||
// setup - add a fresh pupil | ||
const pupilData = fakePupilData() | ||
await pupilAddService.addPupil(pupilData, schoolId, userId) | ||
const dbPupilData = await pupilTestService.findPupilByUPN(pupilData.upn) | ||
|
||
// Pre-test | ||
expect(dbPupilData.isEdited).toBe(false) | ||
|
||
// Apply a change that does not set the isEdited flag to true | ||
await pupilTestService.updateForenameAlias(dbPupilData.id, 'first alias') | ||
|
||
// Review the results | ||
await pupilTestService.updateForenameAlias(dbPupilData.id, 'first alias') | ||
const newPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(newPupilData.isEdited).toBe(false) | ||
expect(newPupilData.foreNameAlias).toBe('first alias') | ||
|
||
// Re-apply a change (that does not set the isEdited flag to true | ||
await pupilTestService.updateForenameAlias(dbPupilData.id, 'updated alias') | ||
|
||
// review | ||
const updatedPupilData = await pupilTestService.findPupilByUPN(dbPupilData.upn) | ||
expect(updatedPupilData.isEdited).toBe(false) | ||
expect(updatedPupilData.foreNameAlias).toBe('updated alias') | ||
}) | ||
}) |
86 changes: 86 additions & 0 deletions
86
admin/tests-integration/test-support/pupil-test.service.js
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 |
---|---|---|
@@ -0,0 +1,86 @@ | ||
'use strict' | ||
const sqlService = require('../../services/data-access/sql.service') | ||
const { TYPES } = require('../../services/data-access/sql.service') | ||
|
||
const pupilTestService = { | ||
findPupilByUPN: async function (upn) { | ||
const sql = 'SELECT * from mtc_admin.pupil where upn = @upn' | ||
const params = [{ name: 'upn', value: upn, type: TYPES.Char(13) }] | ||
const data = await sqlService.query(sql, params) | ||
return data[0] | ||
}, | ||
|
||
updateForename: async function (id, foreName) { | ||
const sql = 'UPDATE mtc_admin.pupil set foreName = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: foreName, type: TYPES.NVarChar(128) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateMiddlenames: async function (id, foreName) { | ||
const sql = 'UPDATE mtc_admin.pupil set middleNames = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: foreName, type: TYPES.NVarChar(128) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateLastname: async function (id, lastname) { | ||
const sql = 'UPDATE mtc_admin.pupil set lastName = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: lastname, type: TYPES.NVarChar(128) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateGender: async function (id, gender) { | ||
const sql = 'UPDATE mtc_admin.pupil set gender = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: gender, type: TYPES.Char(1) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateUPN: async function (id, gender) { | ||
const sql = 'UPDATE mtc_admin.pupil set upn = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: gender, type: TYPES.Char(13) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateDob: async function (id, date) { | ||
const sql = 'UPDATE mtc_admin.pupil set dateOfBirth = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: date.toDate(), type: TYPES.DateTimeOffset }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateForenameAlias: async function (id, alias) { | ||
const sql = 'UPDATE mtc_admin.pupil set foreNameAlias = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: alias, type: TYPES.NVarChar(128) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
}, | ||
|
||
updateLastnameAlias: async function (id, alias) { | ||
const sql = 'UPDATE mtc_admin.pupil set lastNameAlias = @s1 where id = @id' | ||
const params = [ | ||
{ name: 's1', value: alias, type: TYPES.NVarChar(128) }, | ||
{ name: 'id', value: id, type: TYPES.Int } | ||
] | ||
await sqlService.modify(sql, params) | ||
} | ||
} | ||
|
||
module.exports = pupilTestService |
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 |
---|---|---|
|
@@ -1568,6 +1568,11 @@ | |
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" | ||
integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== | ||
|
||
"@faker-js/faker@^7.6.0": | ||
version "7.6.0" | ||
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-7.6.0.tgz#9ea331766084288634a9247fcd8b84f16ff4ba07" | ||
integrity sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw== | ||
|
||
"@fast-csv/[email protected]": | ||
version "4.3.5" | ||
resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" | ||
|
Oops, something went wrong.