test(repo): mock de Collection sans any et export CardDocument
This commit is contained in:
1 parent
9d743d898f
commit
01337ef480
2 files changed
+35
-23
No files matched your search
@@ -1,7 +1,7 @@
|
||||
// @vitest-environment node
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { Collection } from 'mongodb'
|
||||
import { MongoCardRepository } from './mongo-card-repository'
|
||||
import { MongoCardRepository, type CardDocument } from './mongo-card-repository'
|
||||
|
||||
const DOC = {
|
||||
c_id: '10000000-0000-4000-8000-000000000001',
|
||||
@@ -13,12 +13,22 @@ const DOC = {
|
||||
updatedAt: new Date('2026-01-02T09:00:00Z'),
|
||||
}
|
||||
|
||||
interface CollectionMock {
|
||||
find: ReturnType<typeof vi.fn>
|
||||
findOne: ReturnType<typeof vi.fn>
|
||||
insertOne: ReturnType<typeof vi.fn>
|
||||
updateOne: ReturnType<typeof vi.fn>
|
||||
deleteOne: ReturnType<typeof vi.fn>
|
||||
aggregate: ReturnType<typeof vi.fn>
|
||||
distinct: ReturnType<typeof vi.fn>
|
||||
}
|
||||
|
||||
function cursorOf(docs: unknown[]) {
|
||||
return { toArray: vi.fn().mockResolvedValue(docs) }
|
||||
}
|
||||
|
||||
function setup() {
|
||||
const collection = {
|
||||
const collection: CollectionMock = {
|
||||
find: vi.fn(),
|
||||
findOne: vi.fn(),
|
||||
insertOne: vi.fn(),
|
||||
@@ -26,15 +36,15 @@ function setup() {
|
||||
deleteOne: vi.fn(),
|
||||
aggregate: vi.fn(),
|
||||
distinct: vi.fn(),
|
||||
} as unknown as Collection<any>
|
||||
const repo = new MongoCardRepository(collection)
|
||||
}
|
||||
const repo = new MongoCardRepository(collection as unknown as Collection<CardDocument>)
|
||||
return { repo, collection }
|
||||
}
|
||||
|
||||
describe('MongoCardRepository', () => {
|
||||
it('findAll renvoie toutes les cartes mappées', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.find.mockReturnValue(cursorOf([DOC]) as any)
|
||||
collection.find.mockReturnValue(cursorOf([DOC]))
|
||||
const cards = await repo.findAll()
|
||||
expect(cards).toHaveLength(1)
|
||||
expect(cards[0].id).toBe(DOC.c_id)
|
||||
@@ -43,7 +53,7 @@ describe('MongoCardRepository', () => {
|
||||
|
||||
it('findAll renvoie un tableau vide si aucune carte', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.find.mockReturnValue(cursorOf([]) as any)
|
||||
collection.find.mockReturnValue(cursorOf([]))
|
||||
await expect(repo.findAll()).resolves.toEqual([])
|
||||
})
|
||||
|
||||
@@ -59,68 +69,70 @@ describe('MongoCardRepository', () => {
|
||||
|
||||
it('create insère un document avec c_id et renvoie l entité', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.insertOne.mockResolvedValueOnce({ insertedId: '' } as any)
|
||||
collection.insertOne.mockResolvedValueOnce({ insertedId: '' })
|
||||
const card = await repo.create({
|
||||
question: 'Que retourne typeof null ?',
|
||||
response: 'object',
|
||||
theme: 'javascript',
|
||||
})
|
||||
const [doc] = collection.insertOne.mock.calls[0]
|
||||
expect(doc.c_id).toBe(card.id)
|
||||
expect(doc.tags).toEqual([])
|
||||
const [doc] = collection.insertOne.mock.calls[0] as unknown[]
|
||||
const inserted = doc as Record<string, unknown>
|
||||
expect(inserted.c_id).toBe(card.id)
|
||||
expect(inserted.tags).toEqual([])
|
||||
expect(card.tags).toEqual([])
|
||||
expect(card.createdAt).toBeInstanceOf(Date)
|
||||
})
|
||||
|
||||
it('update modifie les champs fournis et renvoie la carte', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.updateOne.mockResolvedValueOnce({ matchedCount: 1 } as any)
|
||||
collection.updateOne.mockResolvedValueOnce({ matchedCount: 1 })
|
||||
collection.findOne.mockResolvedValueOnce({ ...DOC, response: 'Nouvelle' })
|
||||
const card = await repo.update(DOC.c_id, { response: 'Nouvelle' })
|
||||
expect(card?.response).toBe('Nouvelle')
|
||||
const [filter, set] = collection.updateOne.mock.calls[0]
|
||||
const [filter, set] = collection.updateOne.mock.calls[0] as unknown[]
|
||||
const setDoc = set as Record<string, { response?: string; updatedAt?: Date }>
|
||||
expect(filter).toEqual({ c_id: DOC.c_id })
|
||||
expect(set.$set.response).toBe('Nouvelle')
|
||||
expect(set.$set.updatedAt).toBeInstanceOf(Date)
|
||||
expect(setDoc.$set.response).toBe('Nouvelle')
|
||||
expect(setDoc.$set.updatedAt).toBeInstanceOf(Date)
|
||||
})
|
||||
|
||||
it('update renvoie null si aucune carte ne correspond', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.updateOne.mockResolvedValueOnce({ matchedCount: 0 } as any)
|
||||
collection.updateOne.mockResolvedValueOnce({ matchedCount: 0 })
|
||||
await expect(repo.update('inconnu', { question: 'X' })).resolves.toBeNull()
|
||||
})
|
||||
|
||||
it('delete renvoie true si un document est supprimé', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.deleteOne.mockResolvedValueOnce({ deletedCount: 1 } as any)
|
||||
collection.deleteOne.mockResolvedValueOnce({ deletedCount: 1 })
|
||||
await expect(repo.delete(DOC.c_id)).resolves.toBe(true)
|
||||
expect(collection.deleteOne).toHaveBeenCalledWith({ c_id: DOC.c_id })
|
||||
})
|
||||
|
||||
it('delete renvoie false si aucun document ne correspond', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.deleteOne.mockResolvedValueOnce({ deletedCount: 0 } as any)
|
||||
collection.deleteOne.mockResolvedValueOnce({ deletedCount: 0 })
|
||||
await expect(repo.delete('inconnu')).resolves.toBe(false)
|
||||
})
|
||||
|
||||
it('findRandom renvoie une carte au hasard ou null', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([DOC]) as any)
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([DOC]))
|
||||
const card = await repo.findRandom()
|
||||
expect(card?.id).toBe(DOC.c_id)
|
||||
expect(collection.aggregate.mock.calls[0][0]).toContainEqual({ $sample: { size: 1 } })
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([]) as any)
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([]))
|
||||
await expect(repo.findRandom()).resolves.toBeNull()
|
||||
})
|
||||
|
||||
it('findRandomByTheme filtre par thème', async () => {
|
||||
const { repo, collection } = setup()
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([DOC]) as any)
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([DOC]))
|
||||
const card = await repo.findRandomByTheme('javascript')
|
||||
expect(card?.id).toBe(DOC.c_id)
|
||||
const stages = collection.aggregate.mock.calls[0][0]
|
||||
const stages = collection.aggregate.mock.calls[0][0] as unknown[]
|
||||
expect(stages[0]).toEqual({ $match: { theme: 'javascript' } })
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([]) as any)
|
||||
collection.aggregate.mockReturnValueOnce(cursorOf([]))
|
||||
await expect(repo.findRandomByTheme('react')).resolves.toBeNull()
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { MongoClient, type Collection } from 'mongodb'
|
||||
import type { Card, CardInput } from '../domain/card'
|
||||
import type { CardRepository } from '../domain/card-repository'
|
||||
|
||||
interface CardDocument {
|
||||
export interface CardDocument {
|
||||
c_id: string
|
||||
question: string
|
||||
response: string
|
||||
|
||||
Reference in new issue
Block a user