102 lines
4.2 KiB
JavaScript
102 lines
4.2 KiB
JavaScript
// @ts-check
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
|
|
// Stub the firebase SDK at the adapter boundary so no real app/network is touched.
|
|
const fb = vi.hoisted(() => ({
|
|
initializeApp: vi.fn(() => ({ __app: true })),
|
|
getFirestore: vi.fn(() => ({ __internalStore: true })),
|
|
connectFirestoreEmulator: vi.fn(),
|
|
doc: vi.fn((...args) => ({ __ref: args })),
|
|
getDoc: vi.fn(async () => ({ data: () => ({ passingStatus: 'ok' }) })),
|
|
getDocs: vi.fn(async () => ({ docs: [] })),
|
|
setDoc: vi.fn(async () => {}),
|
|
collection: vi.fn((...args) => ({ __col: args })),
|
|
query: vi.fn((...args) => ({ __q: args })),
|
|
where: vi.fn((...args) => ({ __where: args })),
|
|
orderBy: vi.fn((...args) => ({ __order: args })),
|
|
limit: vi.fn((...args) => ({ __limit: args }))
|
|
}))
|
|
|
|
vi.mock('firebase/app', () => ({ initializeApp: fb.initializeApp }))
|
|
vi.mock('firebase/firestore/lite', () => ({
|
|
getFirestore: fb.getFirestore,
|
|
connectFirestoreEmulator: fb.connectFirestoreEmulator,
|
|
doc: fb.doc,
|
|
getDoc: fb.getDoc,
|
|
getDocs: fb.getDocs,
|
|
setDoc: fb.setDoc,
|
|
collection: fb.collection,
|
|
query: fb.query,
|
|
where: fb.where,
|
|
orderBy: fb.orderBy,
|
|
limit: fb.limit
|
|
}))
|
|
|
|
import { FirebaseAdapter } from '../adapters/firebase.js'
|
|
|
|
beforeEach(() => vi.clearAllMocks())
|
|
|
|
describe('FirebaseAdapter — consumer-supplied (injected) store', () => {
|
|
it('uses an injected store as-is and initializes nothing', () => {
|
|
// Stand-in for a privileged / server-side Firestore instance.
|
|
const store = { __adminStore: true }
|
|
const adapter = new FirebaseAdapter({ store, namespace: 'mw' })
|
|
expect(adapter.store).toBe(store)
|
|
expect(fb.initializeApp).not.toHaveBeenCalled()
|
|
expect(fb.getFirestore).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('performs a write through the injected store', async () => {
|
|
const store = { __adminStore: true }
|
|
const adapter = new FirebaseAdapter({ store, namespace: 'mw' })
|
|
const entry = { name: 'A', score: 42, category: 'beginner', time_stamp: 123 }
|
|
|
|
await adapter.addScore('beginner', entry)
|
|
|
|
// The collection was built from OUR store, and the entry was written.
|
|
expect(fb.collection).toHaveBeenCalledWith(store, 'mw-scores', 'beginner', 'games')
|
|
expect(fb.setDoc).toHaveBeenCalledTimes(1)
|
|
expect(fb.setDoc.mock.calls[0][1]).toEqual(entry)
|
|
})
|
|
|
|
it('archives through the injected store', async () => {
|
|
const store = { __adminStore: true }
|
|
const adapter = new FirebaseAdapter({ store, namespace: 'mw' })
|
|
await adapter.archive({ playerId: 'p1', score: 9, category: 'beginner', time_stamp: 5 })
|
|
expect(fb.doc).toHaveBeenCalledWith(store, 'mw-all', 'p1', 'games', expect.any(String))
|
|
expect(fb.setDoc).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('does not auto-connect the emulator for an injected store (consumer owns it)', () => {
|
|
new FirebaseAdapter({ store: { __s: 1 }, namespace: 'mw', emulator: { host: 'x', port: 1 } })
|
|
expect(fb.connectFirestoreEmulator).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('prefers the injected store when both store and firebaseConfig are given', () => {
|
|
const store = { __adminStore: true }
|
|
const adapter = new FirebaseAdapter({ store, firebaseConfig: { projectId: 'p' } })
|
|
expect(adapter.store).toBe(store)
|
|
expect(fb.initializeApp).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('FirebaseAdapter — internal init (existing path, unbroken)', () => {
|
|
it('still initializes its own store from firebaseConfig and writes', async () => {
|
|
const adapter = new FirebaseAdapter({ firebaseConfig: { projectId: 'p' }, namespace: 'mw' })
|
|
expect(fb.initializeApp).toHaveBeenCalledWith({ projectId: 'p' })
|
|
expect(fb.getFirestore).toHaveBeenCalledTimes(1)
|
|
expect(adapter.store).toEqual({ __internalStore: true })
|
|
|
|
await adapter.addScore('beginner', { score: 1 })
|
|
expect(fb.setDoc).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('still connects the emulator when configured', () => {
|
|
new FirebaseAdapter({ firebaseConfig: {}, emulator: { host: '127.0.0.1', port: 8080 } })
|
|
expect(fb.connectFirestoreEmulator).toHaveBeenCalledWith({ __internalStore: true }, '127.0.0.1', 8080)
|
|
})
|
|
|
|
it('throws a clear error when neither store nor firebaseConfig is given', () => {
|
|
expect(() => new FirebaseAdapter({})).toThrow(TypeError)
|
|
})
|
|
})
|