From 01337ef4806a544ad24786a6863b1263c30df0dc Mon Sep 17 00:00:00 2001 From: gilles Date: Mon, 21 Sep 2026 17:55:34 +0200 Subject: [PATCH] test(repo): mock de Collection sans any et export CardDocument --- .../mongo-card-repository.test.ts | 58 +++++++++++-------- src/repositories/mongo-card-repository.ts | 4 +- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/repositories/mongo-card-repository.test.ts b/src/repositories/mongo-card-repository.test.ts index 86f940d..4f709f1 100644 --- a/src/repositories/mongo-card-repository.test.ts +++ b/src/repositories/mongo-card-repository.test.ts @@ -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 + findOne: ReturnType + insertOne: ReturnType + updateOne: ReturnType + deleteOne: ReturnType + aggregate: ReturnType + distinct: ReturnType +} + 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 - const repo = new MongoCardRepository(collection) + } + const repo = new MongoCardRepository(collection as unknown as Collection) 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 + 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 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() }) @@ -129,4 +141,4 @@ describe('MongoCardRepository', () => { collection.distinct.mockResolvedValueOnce(['react', 'docker']) await expect(repo.findThemes()).resolves.toEqual(['docker', 'react']) }) -}) \ No newline at end of file +}) diff --git a/src/repositories/mongo-card-repository.ts b/src/repositories/mongo-card-repository.ts index 143fb95..0952f95 100644 --- a/src/repositories/mongo-card-repository.ts +++ b/src/repositories/mongo-card-repository.ts @@ -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 @@ -123,4 +123,4 @@ export class MongoCardRepository implements CardRepository { const themes: string[] = await this.collection.distinct('theme') return themes.sort() } -} \ No newline at end of file +}