70 lines
2.0 KiB
JavaScript
70 lines
2.0 KiB
JavaScript
|
|
// 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<cb>
|
||
|
|
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));
|
||
|
|
}
|