vault-search.test.ts

3.4 KB · raw

1import { describe, expect, it } from "vitest";2import type { PasskeyData, VaultEntry } from "../../shared/types";3import { filterAndSortVaultEntries } from "./vault-search";45function basePasskey(overrides: Partial<PasskeyData> = {}): PasskeyData {6  return {7    rpId: "example.com",8    rpName: "Example",9    credentialId: "cred-1",10    publicKeyCose: "cose",11    userHandle: "handle",12    userName: "passkey-user",13    userDisplayName: "Passkey User",14    algorithm: -7,15    signCount: 0,16    aaguid: "",17    backupEligible: false,18    backupState: false,19    createdAt: 1,20    ...overrides,21  };22}2324function entry(overrides: Partial<VaultEntry> = {}): VaultEntry {25  return {26    id: "entry-1",27    title: "Example",28    type: "login",29    createdAt: 1,30    modifiedAt: 1,31    ...overrides,32  };33}3435describe("vault-search", () => {36  it("sorts recent entries by last-used timestamps", () => {37    const entries = [38      entry({ id: "created-only", title: "Created only", modifiedAt: 10 }),39      entry({ id: "login-used", title: "Login used", passkey: basePasskey({ lastUsedAt: 300 }), modifiedAt: 20 }),40      entry({ id: "passkey-used", title: "Passkey used", passkey: basePasskey({ lastUsedAt: 200 }) }),41    ];4243    const sorted = filterAndSortVaultEntries(entries, {44      notesOnly: false,45      selectedTags: new Set(),46      query: "",47      searchScope: "both",48      sortOrder: "recent",49    });5051    expect(sorted.map((candidate) => candidate.id)).toEqual([52      "login-used",53      "passkey-used",54      "created-only",55    ]);56  });5758  it("respects the email and username search scope toggle", () => {59    const sample = entry({60      id: "identity",61      title: "Mailbox",62      username: "june-user",63      email: "[email protected]",64      url: "https://mail.example.com",65    });6667    const emailsOnly = filterAndSortVaultEntries([sample], {68      notesOnly: false,69      selectedTags: new Set(),70      query: "june-user",71      searchScope: "emails",72      sortOrder: "recent",73    });74    const usernamesOnly = filterAndSortVaultEntries([sample], {75      notesOnly: false,76      selectedTags: new Set(),77      query: "june-user",78      searchScope: "usernames",79      sortOrder: "recent",80    });81    const both = filterAndSortVaultEntries([sample], {82      notesOnly: false,83      selectedTags: new Set(),84      query: "june-user",85      searchScope: "both",86      sortOrder: "recent",87    });8889    expect(emailsOnly).toHaveLength(0);90    expect(usernamesOnly).toHaveLength(1);91    expect(both).toHaveLength(1);92  });9394  it("uses recent usage as the tie-breaker for matching search results", () => {95    const entries = [96      entry({97        id: "older",98        title: "Alpha",99        username: "alpha-user",100        modifiedAt: 10,101        passkey: basePasskey({ lastUsedAt: 100 }),102      }),103      entry({104        id: "newer",105        title: "Alpha",106        username: "alpha-user",107        modifiedAt: 20,108        passkey: basePasskey({ lastUsedAt: 200 }),109      }),110      entry({111        id: "fallback",112        title: "Alpha",113        username: "alpha-user",114        modifiedAt: 30,115      }),116    ];117118    const sorted = filterAndSortVaultEntries(entries, {119      notesOnly: false,120      selectedTags: new Set(),121      query: "alpha",122      searchScope: "usernames",123      sortOrder: "recent",124    });125126    expect(sorted.map((candidate) => candidate.id)).toEqual([127      "newer",128      "older",129      "fallback",130    ]);131  });132});