From a424be5f6c9d9518ae0319ce904a12c3f2d031c0 Mon Sep 17 00:00:00 2001 From: estifanos Date: Thu, 20 Aug 2026 07:32:23 +0000 Subject: [PATCH] test files --- libs/auth/src/lib/utils/jwt.spec.ts | 39 +++++++++++++++++++++++++++++ libs/ui/src/lib/input/phone.spec.ts | 34 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 libs/auth/src/lib/utils/jwt.spec.ts create mode 100644 libs/ui/src/lib/input/phone.spec.ts diff --git a/libs/auth/src/lib/utils/jwt.spec.ts b/libs/auth/src/lib/utils/jwt.spec.ts new file mode 100644 index 000000000..17a2ad540 --- /dev/null +++ b/libs/auth/src/lib/utils/jwt.spec.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest'; +import { currentSessionId } from './jwt'; + +/** Builds a JWT-shaped string whose payload is `claims`, base64url encoded. */ +function token(claims: Record): string { + const payload = btoa(JSON.stringify(claims)) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + return `header.${payload}.signature`; +} + +describe('currentSessionId', () => { + it('reads the sessionId claim', () => { + expect(currentSessionId(token({ sessionId: 'abc' }))).toBe('abc'); + }); + + it('falls back to sid, then jti', () => { + expect(currentSessionId(token({ sid: 'from-sid' }))).toBe('from-sid'); + expect(currentSessionId(token({ jti: 'from-jti' }))).toBe('from-jti'); + }); + + it('decodes payloads containing base64url characters', () => { + // '>' and '?' are what force '+' and '/' in standard base64. + const id = 'a>b?c>d?e>f?'; + expect(currentSessionId(token({ sessionId: id }))).toBe(id); + }); + + it('returns undefined for a token with no session claim', () => { + expect(currentSessionId(token({ sub: 'user-1' }))).toBeUndefined(); + }); + + it('returns undefined rather than throwing on junk', () => { + expect(currentSessionId(undefined)).toBeUndefined(); + expect(currentSessionId('')).toBeUndefined(); + expect(currentSessionId('opaque-token')).toBeUndefined(); + expect(currentSessionId('header.not-base64!!.sig')).toBeUndefined(); + }); +}); diff --git a/libs/ui/src/lib/input/phone.spec.ts b/libs/ui/src/lib/input/phone.spec.ts new file mode 100644 index 000000000..b1b589102 --- /dev/null +++ b/libs/ui/src/lib/input/phone.spec.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from 'vitest'; +import { optionalPhoneNumber, phoneNumber } from './phone'; + +describe('phoneNumber', () => { + it('normalizes a legacy Ethiopian national number to E.164', () => { + expect(phoneNumber.parse('0911223344')).toBe('+251911223344'); + }); + + it('passes an Ethiopian E.164 number through unchanged', () => { + expect(phoneNumber.parse('+251911223344')).toBe('+251911223344'); + }); + + it('accepts a valid international number', () => { + expect(phoneNumber.parse('+14155552671')).toBe('+14155552671'); + }); + + it('rejects a too-short number', () => { + expect(() => phoneNumber.parse('+251911')).toThrow(); + }); + + it('rejects non-numeric input', () => { + expect(() => phoneNumber.parse('abc')).toThrow(); + }); +}); + +describe('optionalPhoneNumber', () => { + it('allows a blank value', () => { + expect(optionalPhoneNumber.parse('')).toBe(''); + }); + + it('still validates a non-blank value', () => { + expect(() => optionalPhoneNumber.parse('abc')).toThrow(); + }); +});