feat: enhance location handling and localization; improve fallback mechanisms and unify type definitions

This commit is contained in:
Nati
2026-08-18 14:44:24 +00:00
parent 03e2b2b8a4
commit 99eb55c366
18 changed files with 194 additions and 101 deletions

View File

@@ -184,9 +184,7 @@ test.describe('seafarer registration', () => {
deleteApplicant(applicant.email);
});
test('the wizard refuses to open until the profile it is built from is complete', async ({
page,
}) => {
test('selecting seafarer opens the registration wizard', async ({ page }) => {
const offset = await signUp(page, applicant);
await verifyOtpIfPrompted(page, offset);
await expect(page).toHaveURL(/\/onboarding\/operations/, { timeout: 30_000 });
@@ -195,17 +193,19 @@ test.describe('seafarer registration', () => {
.first()
.check();
await page.getByRole('button', { name: /save operations/i }).click();
await expect(page).toHaveURL(/\/profile/, { timeout: 30_000 });
// A new account holds none of the identity the registration is filled in
// from, so the gate collects it rather than opening an uncompletable form.
// Straight to the form they came for. The wizard collects the identity
// itself (Identity Details), so a brand-new account with an empty profile
// is a thing it fills rather than a reason to be sent to /profile first.
await expect(page).toHaveURL(/\/licensing\/SEAFARER_REGISTRATION\/apply/, {
timeout: 30_000,
});
// The short link lands in the same place.
await page.goto('/seafarer-registration');
await expect(page).toHaveURL(/\/profile/, { timeout: 30_000 });
// The shared wizard route is gated identically — otherwise the gate is
// decoration a deep link walks straight past.
await page.goto('/licensing/SEAFARER_REGISTRATION/apply');
await expect(page).toHaveURL(/\/profile/, { timeout: 30_000 });
await expect(page).toHaveURL(/\/licensing\/SEAFARER_REGISTRATION\/apply/, {
timeout: 30_000,
});
});
test('opening the wizard creates the draft up front', async ({ page }) => {
@@ -300,9 +300,10 @@ test.describe('seafarer registration', () => {
]);
expect(statusOf(number)).toBe('REJECTED');
// A rejection is terminal: nothing is numbered and no children open.
// A rejection is terminal: nothing is numbered, and the children submit
// opened stay drafts — never filed, never billed, nothing an officer sees.
expect(seafarerNumberOf(applicant.email)).toBeNull();
expect(childrenOf(number)).toHaveLength(0);
expect(childrenOf(number).every((r) => r[1] === 'DRAFT')).toBe(true);
});
test('approval numbers the profile and opens both child applications', async ({
@@ -328,13 +329,15 @@ test.describe('seafarer registration', () => {
expect(profile[0][1]).toBe('ACTIVE');
// The applicant is not made to apply twice more for the documents that
// prove what they have just been told.
// prove what they have just been told. Both were opened as drafts when the
// registration was submitted; approval is what puts them in flight — the
// BTC straight to payment, the Seaman Book into the queue for the TRB
// inspection it still owes.
const children = childrenOf(number);
expect(children.map((r) => r[0])).toEqual([
'BTC_BASIC_TRAINING',
'SEAMAN_BOOK',
expect(children.map((r) => [r[0], r[1]])).toEqual([
['BTC_BASIC_TRAINING', 'PAYMENT_PENDING'],
['SEAMAN_BOOK', 'SUBMITTED'],
]);
expect(children.every((r) => r[1] === 'SUBMITTED')).toBe(true);
expect(children.every((r) => r[2] === 'AUTO_SEAFARER_APPROVAL')).toBe(true);
});