From 711d65b5390f84f843c9057f147582de3c2187e7 Mon Sep 17 00:00:00 2001 From: cibelius Date: Fri, 21 Nov 2025 13:37:06 +0200 Subject: [PATCH 1/7] upgrade toolkit, add temporary conditional to approve action --- package.json | 2 +- src/form/v2/birth/index.ts | 23 ++++++++++++++++------- yarn.lock | 8 ++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index d9fcea32e1..7925e6e1cd 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@hapi/boom": "^9.1.1", "@hapi/hapi": "^20.0.1", "@hapi/inert": "^6.0.3", - "@opencrvs/toolkit": "1.9.0-rc.8476ac9", + "@opencrvs/toolkit": "1.9.0-rc.ee64af5", "@types/chalk": "^2.2.0", "@types/csv2json": "^1.4.0", "@types/fhir": "^0.0.30", diff --git a/src/form/v2/birth/index.ts b/src/form/v2/birth/index.ts index 8c04d1339b..632c6d857f 100644 --- a/src/form/v2/birth/index.ts +++ b/src/form/v2/birth/index.ts @@ -228,21 +228,30 @@ export const birthEvent = defineConfig({ 'This is shown as the action name anywhere the user can trigger the action from', id: 'event.birth.action.approve.label' }, - supportingCopy: { - defaultMessage: - 'This birth has been registered late. You are now approving it for further validation and registration.', - description: 'This is the confirmation text for the approve action', - id: 'event.birth.action.approve.confirmationText' - }, - form: [], flags: [ { id: 'approval-required-for-late-registration', operation: 'remove' } ], + form: [], + conditionals: [ + // @TODO: this is a placeholder conditional for testing purposes, which should be replace with a conditional like: + // flags('approval-required-for-late-registration') + // when that flags() is supported! + { + type: ConditionalType.ENABLE, + conditional: field('child.gender').isEqualTo('female') + } + ], auditHistoryLabel: { defaultMessage: 'Approved', description: 'The label to show in audit history for the approve action', id: 'event.birth.action.approve.audit-history-label' + }, + supportingCopy: { + defaultMessage: + 'This birth has been registered late. You are now approving it for further validation and registration.', + description: 'This is the confirmation text for the approve action', + id: 'event.birth.action.approve.confirmationText' } }, { diff --git a/yarn.lock b/yarn.lock index b60325ce32..dedef06ca5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -834,10 +834,10 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opencrvs/toolkit@1.9.0-rc.8476ac9": - version "1.9.0-rc.8476ac9" - resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.8476ac9.tgz#6794f0e137dc7dd2bd61f42478a79fddfe963902" - integrity sha512-Aqj5E+p+5iMhBjtH007JG7osgd5zCv60GZ2ltcGirAv7C89PWXFeTRumOUpXGMNCdhN2prfIRq32P3ZpXQxXHg== +"@opencrvs/toolkit@1.9.0-rc.ee64af5": + version "1.9.0-rc.ee64af5" + resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.ee64af5.tgz#9d6bdafa5dd15f8d48ac7b54668e1155dc59e22b" + integrity sha512-XVFYpV8dZDEFuTIWSXFvBo1lHn6vajfPaIEAXTGSaRqKavZ8sIU9ckOc35R97IZiXVb3i+htYS8D/IBOkuH32A== dependencies: "@trpc/client" "11.4.3" "@trpc/server" "11.4.3" From 4c5215170399c27d1aad6cbab30c9617c8accc0d Mon Sep 17 00:00:00 2001 From: cibelius Date: Mon, 24 Nov 2025 12:03:09 +0200 Subject: [PATCH 2/7] switch to conditionaltype show --- src/form/v2/birth/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/form/v2/birth/index.ts b/src/form/v2/birth/index.ts index 632c6d857f..e2c68cf2e7 100644 --- a/src/form/v2/birth/index.ts +++ b/src/form/v2/birth/index.ts @@ -237,7 +237,7 @@ export const birthEvent = defineConfig({ // flags('approval-required-for-late-registration') // when that flags() is supported! { - type: ConditionalType.ENABLE, + type: ConditionalType.SHOW, conditional: field('child.gender').isEqualTo('female') } ], From 6da237e86a7bf7e0940c4f26fc6b045a08eb9154 Mon Sep 17 00:00:00 2001 From: cibelius Date: Mon, 24 Nov 2025 14:13:55 +0200 Subject: [PATCH 3/7] skip test for now --- .../approval-of-late-birth-registration.spec.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts index e74e07d67d..ad3447bb3e 100644 --- a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts +++ b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts @@ -5,6 +5,7 @@ import { formatName, goToSection, login, + logout, switchEventTab } from '../../helpers' import { faker } from '@faker-js/faker' @@ -14,8 +15,8 @@ import { ensureAssigned, ensureOutboxIsEmpty, selectAction } from '../../utils' test.describe.serial('Approval of late birth registration', () => { let page: Page const childName = { - firstNames: faker.person.firstName('male'), - familyName: faker.person.lastName('male') + firstNames: faker.person.firstName('female'), + familyName: faker.person.lastName('female') } const childNameFormatted = formatName(childName) @@ -41,7 +42,7 @@ test.describe.serial('Approval of late birth registration', () => { await page.locator('#firstname').fill(childName.firstNames) await page.locator('#surname').fill(childName.familyName) await page.locator('#child____gender').click() - await page.getByText('Male', { exact: true }).click() + await page.getByText('Female', { exact: true }).click() await page.getByPlaceholder('dd').fill('12') await page.getByPlaceholder('mm').fill('05') @@ -137,7 +138,6 @@ test.describe.serial('Approval of late birth registration', () => { ).toBeVisible() }) - // @TODO: This test should be added after action conditionals are implemented test.skip('RA should not have the option to Approve', async () => { await page.getByRole('button', { name: 'Action', exact: true }).click() await expect(page.getByText('Approve', { exact: true })).not.toBeVisible() @@ -151,6 +151,11 @@ test.describe.serial('Approval of late birth registration', () => { await page.getByRole('button', { name: childNameFormatted }).click() }) + test('Unassign', async () => { + await page.getByRole('button', { name: 'Action', exact: true }).click() + await page.getByText('Unassign', { exact: true }).click() + }) + test('Approve action should be disabled before assignment', async () => { await page.getByRole('button', { name: 'Action', exact: true }).click() const approveButton = page.getByText('Approve', { exact: true }) From 47b2b5900e0b482864141f1f52782e2a8df9e92a Mon Sep 17 00:00:00 2001 From: cibelius Date: Mon, 24 Nov 2025 14:38:50 +0200 Subject: [PATCH 4/7] fix test --- .../approval-of-late-birth-registration.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts index ad3447bb3e..2d6fef6d6c 100644 --- a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts +++ b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts @@ -154,6 +154,10 @@ test.describe.serial('Approval of late birth registration', () => { test('Unassign', async () => { await page.getByRole('button', { name: 'Action', exact: true }).click() await page.getByText('Unassign', { exact: true }).click() + await page.getByRole('button', { name: 'Unassign', exact: true }).click() + await expect( + page.getByText('Not assigned', { exact: true }) + ).toBeVisible() }) test('Approve action should be disabled before assignment', async () => { From 7ffae13d2a0298a83d4e86458fe554f5aff2988f Mon Sep 17 00:00:00 2001 From: cibelius Date: Tue, 25 Nov 2025 13:17:14 +0200 Subject: [PATCH 5/7] upgrade toolkit --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d2c9636525..b21d203cf6 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@hapi/boom": "^9.1.1", "@hapi/hapi": "^20.0.1", "@hapi/inert": "^6.0.3", - "@opencrvs/toolkit": "1.9.0-rc.1e14161", + "@opencrvs/toolkit": "1.9.0-rc.1562cbf", "@types/chalk": "^2.2.0", "@types/csv2json": "^1.4.0", "@types/fhir": "^0.0.30", diff --git a/yarn.lock b/yarn.lock index 0bd15e48e2..da6edc88d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -834,10 +834,10 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opencrvs/toolkit@1.9.0-rc.1e14161": - version "1.9.0-rc.1e14161" - resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.1e14161.tgz#f533cba93a9038d678245b08596aace48147ba59" - integrity sha512-ozsfkIEvVdJ7ZdRiDdvG8u8Yq9gCVz3QRlwYnVUATt2l1s7DzJGragNCoCPghH6VKanSQyzKm6/s9DvrUNvpcA== +"@opencrvs/toolkit@1.9.0-rc.1562cbf": + version "1.9.0-rc.1562cbf" + resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.1562cbf.tgz#100c1a88f613825fb5699d111f83a86c8bb0e7ad" + integrity sha512-Y70Hf1cUnyik/805jSO4R7/s7TqHo+McaENmt1u2dWUDPVN6MuP7npr+8g0ccKuG908Rg4RMkMzirFvnGXpdNw== dependencies: "@trpc/client" "11.4.3" "@trpc/server" "11.4.3" From 90c0e799bb407c4a6ede3d2dafa1a6431fa5e5a1 Mon Sep 17 00:00:00 2001 From: cibelius Date: Wed, 26 Nov 2025 09:40:20 +0200 Subject: [PATCH 6/7] fix flag --- package.json | 2 +- src/form/v2/birth/index.ts | 6 ++---- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index d569c873c5..c9c64f771c 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@hapi/boom": "^9.1.1", "@hapi/hapi": "^20.0.1", "@hapi/inert": "^6.0.3", - "@opencrvs/toolkit": "1.9.0-rc.8bc97a5", + "@opencrvs/toolkit": "1.9.0-rc.8a42cc8", "@types/chalk": "^2.2.0", "@types/csv2json": "^1.4.0", "@types/fhir": "^0.0.30", diff --git a/src/form/v2/birth/index.ts b/src/form/v2/birth/index.ts index 8d8588f17f..5c073a5123 100644 --- a/src/form/v2/birth/index.ts +++ b/src/form/v2/birth/index.ts @@ -14,6 +14,7 @@ import { ConditionalType, defineConfig, field, + flag, not } from '@opencrvs/toolkit/events' import { @@ -244,12 +245,9 @@ export const birthEvent = defineConfig({ { id: 'approval-required-for-late-registration', operation: 'remove' } ], conditionals: [ - // @TODO: this is a placeholder conditional for testing purposes, which should be replace with a conditional like: - // flag('approval-required-for-late-registration') - // when that flag() is supported! { type: ConditionalType.SHOW, - conditional: field('child.gender').isEqualTo('female') + conditional: flag('approval-required-for-late-registration') } ], auditHistoryLabel: { diff --git a/yarn.lock b/yarn.lock index ad5255d391..d8af21da82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -834,10 +834,10 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opencrvs/toolkit@1.9.0-rc.8bc97a5": - version "1.9.0-rc.8bc97a5" - resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.8bc97a5.tgz#aa9efc84945fca9c1b8e0ac5c8e5d20ec1ce6577" - integrity sha512-o9tiQ5sDjlZDcHA8GNLjdr0ummC0Zm0SnOhDV67vplVtKv0hEM8SdIQWP0gahoKdg7ymFxGE5nmK74pY/AMonA== +"@opencrvs/toolkit@1.9.0-rc.8a42cc8": + version "1.9.0-rc.8a42cc8" + resolved "https://registry.yarnpkg.com/@opencrvs/toolkit/-/toolkit-1.9.0-rc.8a42cc8.tgz#29d8299ce1feed7b2d71f6eec1c89d5fb7a0c6dc" + integrity sha512-GCVX2eIHcZdc8GlmQT+RISlJjt0eU0ftld5Nd3lLwsso7lkVNQa7sY/LdbvMZ6dcgx9sdYUr32pgeEwL8iUMYw== dependencies: "@trpc/client" "11.4.3" "@trpc/server" "11.4.3" From 7f9b9c74551d81a77bb02cfec2e83a95331c25a0 Mon Sep 17 00:00:00 2001 From: cibelius Date: Wed, 26 Nov 2025 09:58:39 +0200 Subject: [PATCH 7/7] fix test cases --- .../action-menu/action-menu-options.spec.ts | 22 +-- ...pproval-of-late-birth-registration.spec.ts | 133 +++++++++++++++++- 2 files changed, 136 insertions(+), 19 deletions(-) diff --git a/e2e/testcases/action-menu/action-menu-options.spec.ts b/e2e/testcases/action-menu/action-menu-options.spec.ts index 0f502c350b..8902c4ca11 100644 --- a/e2e/testcases/action-menu/action-menu-options.spec.ts +++ b/e2e/testcases/action-menu/action-menu-options.spec.ts @@ -16,9 +16,7 @@ async function getActionMenuOptions(page: Page, declaration: Declaration) { return textContents } -// @TODO: these tests are disabled for now, as our work in custom actions temporarily affects these in a manner which is not intended -// These will be brought back in to use after the custom actions are hidden on the action menu correctly. -test.describe.skip('Action menu options', () => { +test.describe('Action menu options', () => { let page: Page test.beforeEach(async ({ browser }) => { @@ -53,13 +51,7 @@ test.describe.skip('Action menu options', () => { await login(page, CREDENTIALS.LOCAL_REGISTRAR) await page.getByRole('button', { name: 'Ready for review' }).click() const options = await getActionMenuOptions(page, declaration) - expect(options).toStrictEqual([ - 'Assign', - 'Register', - 'Archive', - 'Reject', - 'Approve' - ]) + expect(options).toStrictEqual(['Assign', 'Register', 'Archive', 'Reject']) }) }) @@ -83,8 +75,7 @@ test.describe.skip('Action menu options', () => { 'Unassign', 'Register', 'Archive', - 'Reject', - 'Approve' + 'Reject' ]) }) }) @@ -105,12 +96,7 @@ test.describe.skip('Action menu options', () => { await login(page, CREDENTIALS.LOCAL_REGISTRAR) await page.getByRole('button', { name: 'Ready to print' }).click() const options = await getActionMenuOptions(page, declaration) - expect(options).toStrictEqual([ - 'Assign', - 'Print', - 'Correct record', - 'Approve' - ]) + expect(options).toStrictEqual(['Assign', 'Print', 'Correct record']) }) }) }) diff --git a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts index 0b870d7cae..d8e2261e20 100644 --- a/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts +++ b/e2e/testcases/custom-actions-and-flags/approval-of-late-birth-registration.spec.ts @@ -5,7 +5,6 @@ import { formatName, goToSection, login, - logout, switchEventTab } from '../../helpers' import { faker } from '@faker-js/faker' @@ -212,6 +211,11 @@ test.describe.serial('Approval of late birth registration', () => { ).not.toBeVisible() }) + test("Validate that the 'Approve' action is no longer available", async () => { + await page.getByRole('button', { name: 'Action', exact: true }).click() + await expect(page.getByText('Approve', { exact: true })).not.toBeVisible() + }) + test('Validate that action and form field value appearing in audit trail', async () => { await switchEventTab(page, 'Audit') await page.getByRole('button', { name: 'Approved', exact: true }).click() @@ -221,3 +225,130 @@ test.describe.serial('Approval of late birth registration', () => { }) }) }) + +test.describe('Birth with non-late registration will not have flag or Approve-action available', () => { + let page: Page + const childName = { + firstNames: faker.person.firstName('female'), + familyName: faker.person.lastName('female') + } + + const childNameFormatted = formatName(childName) + + test.beforeAll(async ({ browser }) => { + page = await browser.newPage() + }) + + test.afterAll(async () => { + await page.close() + }) + + test.describe.serial('Declaration started by FA', async () => { + test.beforeAll(async () => { + await login(page, CREDENTIALS.FIELD_AGENT) + await page.click('#header-new-event') + await page.getByLabel('Birth').click() + await page.getByRole('button', { name: 'Continue' }).click() + await page.getByRole('button', { name: 'Continue' }).click() + }) + + test('Fill child details with birth date from over a year ago', async () => { + await page.locator('#firstname').fill(childName.firstNames) + await page.locator('#surname').fill(childName.familyName) + await page.locator('#child____gender').click() + await page.getByText('Female', { exact: true }).click() + + await page.getByPlaceholder('dd').fill('12') + await page.getByPlaceholder('mm').fill('05') + await page.getByPlaceholder('yyyy').fill('2019') + await page.locator('#child____reason').fill('Late registration reason') + + await page.locator('#child____placeOfBirth').click() + await page.getByText('Health Institution', { exact: true }).click() + await page + .locator('#child____birthLocation') + .fill('Golden Valley Rural Health Centre'.slice(0, 3)) + await page.getByText('Golden Valley Rural Health Centre').click() + + await continueForm(page) + }) + + test('Fill informant details', async () => { + await page.locator('#informant____relation').click() + await page.getByText('Mother', { exact: true }).click() + + await page.locator('#informant____email').fill('test@example.com') + + await continueForm(page) + }) + + test("Fill mother's details", async () => { + await page.locator('#firstname').fill(faker.person.firstName('female')) + await page.locator('#surname').fill(faker.person.lastName('female')) + + await page.getByPlaceholder('dd').fill('25') + await page.getByPlaceholder('mm').fill('11') + await page.getByPlaceholder('yyyy').fill('2025') + + await page.locator('#mother____idType').click() + await page.getByText('None', { exact: true }).click() + + await continueForm(page) + }) + + test("Fill father's details", async () => { + await page.locator('#firstname').fill(faker.person.firstName('male')) + await page.locator('#surname').fill(faker.person.lastName('male')) + + await page.getByPlaceholder('dd').fill('12') + await page.getByPlaceholder('mm').fill('05') + await page.getByPlaceholder('yyyy').fill('1985') + + await page.locator('#father____idType').click() + await page.getByText('None', { exact: true }).click() + + await page.locator('#father____nationality').click() + await page.getByText('Gabon', { exact: true }).click() + + await page.locator('#father____addressSameAs_YES').click() + + await page.getByRole('button', { name: 'Continue' }).click() + }) + + test('Go to review', async () => { + await goToSection(page, 'review') + }) + + test('Fill up informant comment & signature', async () => { + await page.locator('#review____comment').fill(faker.lorem.sentence()) + await page.getByRole('button', { name: 'Sign', exact: true }).click() + await drawSignature(page, 'review____signature_canvas_element', false) + await page + .locator('#review____signature_modal') + .getByRole('button', { name: 'Apply' }) + .click() + }) + + test('Send for review', async () => { + await page.getByRole('button', { name: 'Send for review' }).click() + await page.getByRole('button', { name: 'Confirm' }).click() + await ensureOutboxIsEmpty(page) + }) + + test('Navigate to the record', async () => { + await page.getByText('Sent for review').click() + await page.getByRole('button', { name: childNameFormatted }).click() + }) + + test("Record should not have the 'Approval required for late registration' -flag", async () => { + await expect( + page.getByText('Approval required for late registration') + ).not.toBeVisible() + }) + + test('Record should not have the "Approve"-action available', async () => { + await page.getByRole('button', { name: 'Action', exact: true }).click() + await expect(page.getByText('Approve', { exact: true })).not.toBeVisible() + }) + }) +})