// Mock in-memory Firestore for jest tests. // Reset via resetMockDb() in setupTests.js beforeEach. const state = { docs: new Map(), // path -> data subscribers: new Map(), // path -> Set counter: 0, calls: [], // recorded SDK calls }; export const MOCK_DB = { get(path) { return state.docs.has(path) ? clone(state.docs.get(path)) : null; }, set(path, data) { state.docs.set(path, clone(data)); this._notify(path); }, merge(path, patch) { const cur = state.docs.has(path) ? state.docs.get(path) : {}; const next = { ...cur, ...clone(patch) }; state.docs.set(path, next); this._notify(path); }, delete(path) { state.docs.delete(path); this._notify(path); }, collection(collPath) { const out = []; for (const [p, data] of state.docs) { const parent = p.split('/').slice(0, -1).join('/'); if (parent === collPath) out.push({ id: p.split('/').pop(), data: clone(data) }); } return out; }, subscribe(path, cb) { if (!state.subscribers.has(path)) state.subscribers.set(path, new Set()); state.subscribers.get(path).add(cb); return () => state.subscribers.get(path)?.delete(cb); }, _notify(path) { // notify exact doc path subscribers if (state.subscribers.has(path)) state.subscribers.get(path).forEach(cb => cb()); // notify parent collection subscribers const parent = path.split('/').slice(0, -1).join('/'); if (parent && state.subscribers.has(parent)) state.subscribers.get(parent).forEach(cb => cb()); }, nextId() { state.counter += 1; return String(state.counter).padStart(3, '0'); }, _state: state, }; export function recordCall(entry) { state.calls.push({ ...entry, ts: Date.now() }); } export function resetMockDb() { state.docs.clear(); state.subscribers.clear(); state.calls.length = 0; state.counter = 0; } export function getCalls() { return [...state.calls]; } function clone(v) { if (v === null || v === undefined) return v; return JSON.parse(JSON.stringify(v)); }