Ctrl K
ComunidadGuías…

__tests__/cardstore.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * cardstore — cards persisted beside the sessions. The properties worth pinning: it round-trips a
 * card, an unreadable/absent store degrades to empty (every intent walks the UI, not a crash), and
 * a write failure is never fatal (the whole mechanism is an optimisation on top of a working
 * browser). Real fs in a temp dir.
 */
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'fs';
import os from 'os';
import path from 'path';
import { makeCardStore } from '../src/cardstore.js';
import { distill, onVerified, planFor } from '../src/routecards.js';

let dir;
beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cards-')); });
afterEach(() => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* ignore */ } });

const aCard = () => onVerified(distill({
  intent: 'facebook.page.post', origin: 'https://www.facebook.com',
  requests: [{ method: 'POST', url: 'https://www.facebook.com/api/graphql/', headers: { 'x-fb-lsd': 'x' }, postData: '{"text":"hi"}' }],
  now: 1,
}).card, 2);

describe('cardstore round-trips', () => {
  it('put then get returns the card; a fresh reader sees it from disk', () => {
    const s = makeCardStore({ dir });
    s.put(aCard());
    expect(s.get('https://www.facebook.com', 'facebook.page.post').lastVerified).toBe(2);
    const reader = makeCardStore({ dir });   // separate instance, reads the file
    expect(reader.get('https://www.facebook.com', 'facebook.page.post')).toBeTruthy();
  });

  it('forget removes it from disk', () => {
    const s = makeCardStore({ dir });
    s.put(aCard());
    s.forget('https://www.facebook.com', 'facebook.page.post');
    expect(makeCardStore({ dir }).get('https://www.facebook.com', 'facebook.page.post')).toBeNull();
  });

  it('findByIntent locates a card whichever origin it was learned on, and prefers a healthy one', () => {
    const s = makeCardStore({ dir });
    s.put(aCard());   // origin www.facebook.com, intent facebook.page.post
    // a walk that thinks in a different subdomain still finds it by intent
    expect(s.findByIntent('facebook.page.post')).toBeTruthy();
    expect(s.findByIntent('facebook.page.post').origin).toBe('https://www.facebook.com');
    expect(s.findByIntent('nothing.here')).toBeNull();
  });

  it('findByIntent falls back to a quarantined card only when no healthy one exists', () => {
    const s = makeCardStore({ dir });
    const q = { ...aCard(), origin: 'https://m.facebook.com', quarantined: true };
    const good = { ...aCard(), origin: 'https://www.facebook.com', quarantined: false };
    s.put(q); s.put(good);
    expect(s.findByIntent('facebook.page.post').quarantined).toBe(false);   // the healthy one wins
    s.forget('https://www.facebook.com', 'facebook.page.post');
    expect(s.findByIntent('facebook.page.post').quarantined).toBe(true);    // now only the quarantined one is left
  });

  it('list is shapes only — safe to render, no token values', () => {
    const s = makeCardStore({ dir });
    s.put(aCard());
    expect(JSON.stringify(s.list())).not.toMatch(/x-fb-lsd.*:.*"x"/);   // the NAME may appear, the VALUE never
    expect(s.list()).toHaveLength(1);
  });
});

describe('a broken store degrades to empty, never crashes', () => {
  it('absent file → empty store, every intent walks the UI', () => {
    const s = makeCardStore({ dir: path.join(dir, 'does-not-exist-yet') });
    expect(s.list()).toEqual([]);
    expect(s.get('https://x', 'y')).toBeNull();
  });

  it('garbage file → empty store, not a throw', () => {
    fs.writeFileSync(path.join(dir, 'route-cards.json'), '{ not json');
    const s = makeCardStore({ dir });
    expect(s.list()).toEqual([]);
  });

  it('an unwritable dir makes put best-effort, never fatal', () => {
    const s = makeCardStore({ dir, file: path.join('no', 'such', 'nested', 'x.json') });
    expect(() => s.put(aCard())).not.toThrow();
  });
});

describe('durable capture acknowledgement',()=>{
 it('returns failure and disables replay when storage cannot commit the new card',()=>{
  const s=makeCardStore({dir,log:{warn(){}}});expect(s.put(aCard())).toBeTruthy();
  fs.mkdirSync(path.join(dir,'route-cards.json.tmp'));
  const card={...aCard(),intent:'new.capture'};
  expect(s.put(card)).toBeNull();expect(s.get(card.origin,card.intent)._persisted).toBe(false);
  expect(makeCardStore({dir}).get(card.origin,card.intent)).toBeNull();
  expect(planFor(s.get(card.origin,card.intent)).mode).toBe('ui');
  expect(JSON.stringify(s.list())).not.toContain('_persisted');
 });
});