passwordless.test.ts49 lines · main
1import { describe, expect, test } from 'bun:test';
2
3import {
4 hashSecret,
5 matchPasswordlessSecret,
6 sixDigitCode,
7} from './passwordless.js';
8
9describe('passwordless pure helpers (Phase 3)', () => {
10 test('sixDigitCode is 6 digits', () => {
11 for (let i = 0; i < 20; i++) {
12 const c = sixDigitCode();
13 expect(c).toMatch(/^\d{6}$/);
14 expect(Number(c)).toBeGreaterThanOrEqual(100000);
15 expect(Number(c)).toBeLessThanOrEqual(999999);
16 }
17 });
18
19 test('match OTP-only hash', () => {
20 const otp = '123456';
21 const stored = hashSecret(otp);
22 expect(matchPasswordlessSecret(stored, { userInputCode: otp })).toBe(true);
23 expect(matchPasswordlessSecret(stored, { userInputCode: '000000' })).toBe(
24 false,
25 );
26 });
27
28 test('match link-only hash', () => {
29 const link = 'abcLinkCodeXYZ';
30 const stored = hashSecret(link);
31 expect(matchPasswordlessSecret(stored, { linkCode: link })).toBe(true);
32 expect(matchPasswordlessSecret(stored, { linkCode: 'nope' })).toBe(false);
33 });
34
35 test('match dual otp:link form', () => {
36 const otp = '654321';
37 const link = 'linkSecret99';
38 const stored = `${hashSecret(otp)}:${hashSecret(link)}`;
39 expect(matchPasswordlessSecret(stored, { userInputCode: otp })).toBe(true);
40 expect(matchPasswordlessSecret(stored, { linkCode: link })).toBe(true);
41 expect(
42 matchPasswordlessSecret(stored, { userInputCode: '111111', linkCode: 'x' }),
43 ).toBe(false);
44 });
45
46 test('empty input fails', () => {
47 expect(matchPasswordlessSecret(hashSecret('1'), {})).toBe(false);
48 });
49});