cjkPassphrase.test.ts

2.3 KB · raw

1import { describe, expect, it, vi } from "vitest";23import {4  MIN_PASSPHRASE_LENGTH,5  checkPassphraseBreached,6  generateDicewarePassphrase,7  validateForExport,8} from "./cjkPassphrase";910describe("crypto cjkPassphrase", () => {11  it("generateDicewarePassphrase returns words from the EFF wordlist", () => {12    const phrase = generateDicewarePassphrase();13    const words = phrase.split(" ");1415    expect(words).toHaveLength(6);16    expect(words.every((word) => /^[a-z]+(?:-[a-z]+)?$/.test(word))).toBe(true);17  });1819  it("validateForExport fails when the passphrase is too short", () => {20    expect(21      validateForExport({22        passphrase: "too short",23        confirm: "too short",24      })25    ).toMatchObject({26      ok: false,27      error: "PASSPHRASE_TOO_SHORT",28    });29    expect(MIN_PASSPHRASE_LENGTH).toBe(16);30  });3132  it("validateForExport fails when zxcvbn rates the passphrase too weak", () => {33    expect(34      validateForExport({35        passphrase: "aaaaaaaaaaaaaaaa",36        confirm: "aaaaaaaaaaaaaaaa",37      })38    ).toMatchObject({39      ok: false,40      error: "PASSPHRASE_TOO_WEAK",41    });42  });4344  it("validateForExport accepts a strong long passphrase", () => {45    expect(46      validateForExport({47        passphrase: "correct horse battery staple drift waves",48        confirm: "correct horse battery staple drift waves",49      })50    ).toMatchObject({51      ok: true,52    });53  });5455  it("checkPassphraseBreached only sends the 5-char SHA-1 prefix", async () => {56    const fetchMock = vi.fn(async () => ({57      ok: true,58      text: async () => "",59    }));60    vi.stubGlobal("fetch", fetchMock);6162    await checkPassphraseBreached("correct horse battery staple drift waves");6364    expect(fetchMock).toHaveBeenCalledTimes(1);65    const [url] = fetchMock.mock.calls[0] as unknown as [string, RequestInit];66    expect(url).toMatch(/\/range\/[A-F0-9]{5}$/);67    expect(url).not.toContain("correct horse battery");68  });6970  it("checkPassphraseBreached handles network failure without throwing", async () => {71    vi.stubGlobal("fetch", vi.fn(async () => {72      throw new Error("network down");73    }));7475    await expect(76      checkPassphraseBreached("correct horse battery staple drift waves")77    ).resolves.toEqual({78      breached: false,79      apiReachable: false,80    });81  });82});