Contract rewritten to match main prod truth:
- require id injection in all doc/collection results
- honor setDoc({merge:true}) (main L1624 + 4 activeDisplay sites)
- drop invented bare<->prefixed cross-lookup tests (main never does this)
- add setDoc{merge}, batch set-only/update-only contract coverage
Fix mismatches vs main:
- subscribeCollection hook now forwards queryConstraints (was dropped;
LOG_QUERY sort+limit honored again). Mock onSnapshot honors orderBy+limit.
2 new contract tests prove the chain.
- subscribeDoc/subscribeCollection adapters now forward errCb. App hooks +
DisplayView propagate subscribe errors to UI (match main onSnapshot 3rd arg).
- ws adapter signatures accept queryConstraints + errCb (interface match).
activeDisplay writes match main:
- 5 unguarded sites -> setDoc({merge:true}) (create-if-missing, not updateDoc)
- 3 guarded sites stay updateDoc
Delete memory adapter: third storage system added complexity, zero value.
firebase-mock covers fast tests, ws covers server path. Factory throws on
unknown mode now.
Delete phantom 'Phase A/B' comment in firebase.js header.
Tests updated to assert setDoc{merge} (not updateDoc) for activeDisplay writes.
83/83 green.
56 lines
2.2 KiB
JavaScript
56 lines
2.2 KiB
JavaScript
// Firebase adapter contract test.
|
|
// Runs the SAME storage contract as ws (src/storage/contract.js)
|
|
// against createFirebaseStorage. The SDK is mocked via src/__mocks__/firebase/*,
|
|
// so this proves the adapter translates contract calls -> SDK calls correctly
|
|
// (path handling, merge semantics, subscribe) without hitting network.
|
|
|
|
import { initFirebase, createFirebaseStorage } from '../storage/firebase';
|
|
import { runStorageContract } from '../storage/contract';
|
|
import { resetMockDb, MOCK_DB } from '../__mocks__/firebase/_mock-db';
|
|
import { orderBy, limit } from '../__mocks__/firebase/firestore';
|
|
|
|
// Firebase mock DB is shared global state. Reset before each factory so
|
|
// contract tests are isolated.
|
|
runStorageContract('firebase', () => {
|
|
resetMockDb();
|
|
const ok = initFirebase();
|
|
if (!ok) throw new Error('initFirebase failed under mocked env');
|
|
return createFirebaseStorage();
|
|
});
|
|
|
|
// Firebase-only: queryConstraints (orderBy + limit) must flow through
|
|
// subscribeCollection. main App passes LOG_QUERY = [orderBy('timestamp','desc'),
|
|
// limit(500)] for the combat log. Adapter forwards them to the SDK; this proves
|
|
// the whole chain sorts + caps, not just dumps raw.
|
|
describe('firebase adapter: queryConstraints', () => {
|
|
let storage;
|
|
beforeEach(() => {
|
|
resetMockDb();
|
|
initFirebase();
|
|
storage = createFirebaseStorage();
|
|
});
|
|
|
|
test('subscribeCollection honors orderBy desc', async () => {
|
|
MOCK_DB.set('logs/a', { message: 'A', timestamp: 100 });
|
|
MOCK_DB.set('logs/b', { message: 'B', timestamp: 300 });
|
|
MOCK_DB.set('logs/c', { message: 'C', timestamp: 200 });
|
|
|
|
const result = await new Promise((resolve) => {
|
|
storage.subscribeCollection('logs', resolve, [orderBy('timestamp', 'desc')]);
|
|
});
|
|
expect(result.map(d => d.message)).toEqual(['B', 'C', 'A']);
|
|
});
|
|
|
|
test('subscribeCollection honors limit', async () => {
|
|
for (let i = 0; i < 5; i++) {
|
|
MOCK_DB.set(`logs/l${i}`, { message: `L${i}`, timestamp: i });
|
|
}
|
|
|
|
const result = await new Promise((resolve) => {
|
|
storage.subscribeCollection('logs', resolve, [orderBy('timestamp', 'desc'), limit(3)]);
|
|
});
|
|
expect(result).toHaveLength(3);
|
|
expect(result.map(d => d.message)).toEqual(['L4', 'L3', 'L2']);
|
|
});
|
|
});
|