From 4e7feaa9b5ed3bc5edcc118ca5e1a930f7083351 Mon Sep 17 00:00:00 2001 From: Severin Beauvais Date: Mon, 9 Feb 2026 12:28:46 -0800 Subject: [PATCH 1/2] - added new package declaration - created validators folder - added index file - added initial package file - added ValidatePostalCode file --- lerna.json | 3 ++- src/validators/index.ts | 1 + src/validators/package.json | 12 ++++++++++++ src/validators/validate-postal-code.ts | 13 +++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/validators/index.ts create mode 100644 src/validators/package.json create mode 100644 src/validators/validate-postal-code.ts diff --git a/lerna.json b/lerna.json index 72425889..66d15516 100644 --- a/lerna.json +++ b/lerna.json @@ -7,8 +7,9 @@ "src/interfaces", "src/mixins", "src/modules/*", + "src/services", "src/types", - "src/services" + "src/validators" ], "command": { "publish": { diff --git a/src/validators/index.ts b/src/validators/index.ts new file mode 100644 index 00000000..cdcdae5d --- /dev/null +++ b/src/validators/index.ts @@ -0,0 +1 @@ +export * from './validate-postal-code' diff --git a/src/validators/package.json b/src/validators/package.json new file mode 100644 index 00000000..e982e8c5 --- /dev/null +++ b/src/validators/package.json @@ -0,0 +1,12 @@ +{ + "name": "@bcrs-shared-components/validators", + "version": "0.0.0", + "publishConfig": { + "access": "public" + }, + "dependencies": { + }, + "devDependencies": { + }, + "gitHead": "31c1b1c7fa82101f90ccd7842e436608bdfca752" +} diff --git a/src/validators/validate-postal-code.ts b/src/validators/validate-postal-code.ts new file mode 100644 index 00000000..e68fce0f --- /dev/null +++ b/src/validators/validate-postal-code.ts @@ -0,0 +1,13 @@ +/** + * Canadian postal code regex (eg, accepts A1A 1A1 or A1A1A1). + * Ref: https://en.wikipedia.org/wiki/Postal_codes_in_Canada + */ +const CanadaPostalCodeRegex = /^[ABCEGHJ-NPRSTVXY][0-9][ABCEGHJ-NPRSTV-Z][ ]?[0-9][ABCEGHJ-NPRSTV-Z][0-9]$/i + +/** Custom validator for postal codes. */ +export function validatePostalCode (value: string, parentVm: any): boolean { + // if Canada, validate postal code format + if (parentVm.addressCountry === 'CA') return CanadaPostalCodeRegex.test(value) + // otherwise, no validation + return true +} From 65eadbcebb0941898166f5c792d21612badfaa4e Mon Sep 17 00:00:00 2001 From: Severin Beauvais Date: Mon, 9 Feb 2026 12:53:13 -0800 Subject: [PATCH 2/2] - empty postal code is valid - added unit tests --- src/validators/validate-postal-code.ts | 3 +- tests/unit/validate-postal-code.spec.ts | 57 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/unit/validate-postal-code.spec.ts diff --git a/src/validators/validate-postal-code.ts b/src/validators/validate-postal-code.ts index e68fce0f..347a5754 100644 --- a/src/validators/validate-postal-code.ts +++ b/src/validators/validate-postal-code.ts @@ -7,7 +7,8 @@ const CanadaPostalCodeRegex = /^[ABCEGHJ-NPRSTVXY][0-9][ABCEGHJ-NPRSTV-Z][ ]?[0- /** Custom validator for postal codes. */ export function validatePostalCode (value: string, parentVm: any): boolean { // if Canada, validate postal code format - if (parentVm.addressCountry === 'CA') return CanadaPostalCodeRegex.test(value) + // empty value is considered valid -- "required" validation is handled separately + if (parentVm.addressCountry === 'CA') return !value || CanadaPostalCodeRegex.test(value) // otherwise, no validation return true } diff --git a/tests/unit/validate-postal-code.spec.ts b/tests/unit/validate-postal-code.spec.ts new file mode 100644 index 00000000..4d964186 --- /dev/null +++ b/tests/unit/validate-postal-code.spec.ts @@ -0,0 +1,57 @@ +import Vue from 'vue' +import { shallowMount } from '@vue/test-utils' +import { validatePostalCode } from '@/validators' + +const Dummy = Vue.component('DummyComponent', { template: '
' }) + +describe('Validate Postal Code', () => { + let vm: any + + beforeAll(async () => { + // mount the component and wait for everything to stabilize + // (this can be any component since we are not really using it) + const wrapper = shallowMount(Dummy) + vm = wrapper.vm + await Vue.nextTick() + }) + + it.each([ + '', // empty value is valid + 'A1A 1A1', + 'A1A1A1', + 'a1a 1a1', + 'a1a1a1' + ])('accepts valid postal code "%s" for Canada', (postalCode) => { + expect(validatePostalCode(postalCode, { addressCountry: 'CA' })).toBe(true) + }) + + it.each([ + '123456', + 'A1A-1A1', + 'AA1 1A1', + 'A11 1A1', + 'A1 A1A1', + 'A1A 1AA', + 'A1A 11A', + ' A1A 1A1', + 'A1A 1A1', + 'A1A 1A1 ', + 'D1D 1D1', // D is not allowed in Canadian postal codes + 'W1W 1W1', // W is not allowed in Canadian postal codes + 'Z1Z 1Z1' // Z is not allowed in Canadian postal codes + ])('rejects invalid postal code "%s" for Canada', (postalCode) => { + expect(validatePostalCode(postalCode, { addressCountry: 'CA' })).toBe(false) + }) + + it.each([ + '', + 'invalid', + 'A1A 1A1', + 'A1A-1A1', + 'D1D 1D1', + 'W1W 1W1', + 'Z1Z 1Z1' + ])('accepts any postal code "%s" for non-Canada', (postalCode) => { + expect(validatePostalCode(postalCode, { addressCountry: 'XX' })).toBe(true) + }) +})