test(service): CardService et schémas de validation
This commit is contained in:
1 parent
12670b7134
commit
e4aa5f4b3b
2 files changed
+154
No files matched your search
@@ -0,0 +1,39 @@
|
||||
// @vitest-environment node
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createCardSchema, updateCardSchema } from './card-schemas'
|
||||
|
||||
describe('createCardSchema', () => {
|
||||
it('accepte une entrée valide et normalise les champs', () => {
|
||||
const result = createCardSchema.parse({
|
||||
question: ' Question ? ',
|
||||
response: 'Réponse',
|
||||
theme: ' javascript ',
|
||||
tags: ['scope'],
|
||||
})
|
||||
expect(result.question).toBe('Question ?')
|
||||
expect(result.theme).toBe('javascript')
|
||||
})
|
||||
|
||||
it('accepte une entrée sans tags', () => {
|
||||
expect(createCardSchema.parse({ question: 'Q', response: 'R', theme: 'git' }).tags).toBeUndefined()
|
||||
})
|
||||
|
||||
it('rejette une question vide', () => {
|
||||
expect(() => createCardSchema.parse({ question: ' ', response: 'R', theme: 'git' })).toThrow()
|
||||
})
|
||||
|
||||
it('rejette un thème manquant', () => {
|
||||
expect(() => createCardSchema.parse({ question: 'Q', response: 'R' })).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateCardSchema', () => {
|
||||
it('accepte une mise à jour partielle', () => {
|
||||
const result = updateCardSchema.parse({ response: 'Nouvelle réponse' })
|
||||
expect(result).toEqual({ response: 'Nouvelle réponse' })
|
||||
})
|
||||
|
||||
it('rejette un champ vide lors d une mise à jour', () => {
|
||||
expect(() => updateCardSchema.parse({ theme: '' })).toThrow()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,115 @@
|
||||
// @vitest-environment node
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { Card } from '@/domain/card'
|
||||
import type { CardRepository } from '@/domain/card-repository'
|
||||
import { NotFoundError } from '@/domain/errors'
|
||||
import { CardService } from './card-service'
|
||||
|
||||
const CARD: Card = {
|
||||
id: '10000000-0000-4000-8000-000000000001',
|
||||
question: 'Qu est-ce qu une closure ?',
|
||||
response: 'Une fonction qui conserve la portée de sa définition.',
|
||||
theme: 'javascript',
|
||||
tags: ['scope'],
|
||||
createdAt: new Date('2026-01-01T08:00:00Z'),
|
||||
updatedAt: new Date('2026-01-01T08:00:00Z'),
|
||||
}
|
||||
|
||||
type RepoMock = Record<keyof CardRepository, ReturnType<typeof vi.fn>>
|
||||
|
||||
function setup() {
|
||||
const repository: RepoMock = {
|
||||
findAll: vi.fn(),
|
||||
findById: vi.fn(),
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
findRandom: vi.fn(),
|
||||
findRandomByTheme: vi.fn(),
|
||||
findThemes: vi.fn(),
|
||||
}
|
||||
const service = new CardService(repository as unknown as CardRepository)
|
||||
return { service, repository }
|
||||
}
|
||||
|
||||
describe('CardService', () => {
|
||||
it('list délègue au repository et renvoie toutes les cartes', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findAll.mockResolvedValueOnce([CARD])
|
||||
await expect(service.list()).resolves.toEqual([CARD])
|
||||
})
|
||||
|
||||
it('get renvoie la carte quand elle existe', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findById.mockResolvedValueOnce(CARD)
|
||||
await expect(service.get(CARD.id)).resolves.toEqual(CARD)
|
||||
})
|
||||
|
||||
it('get lève NotFoundError si la carte est inconnue', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findById.mockResolvedValueOnce(null)
|
||||
await expect(service.get('inconnu')).rejects.toThrow(NotFoundError)
|
||||
})
|
||||
|
||||
it('create délègue l entrée au repository', async () => {
|
||||
const { service, repository } = setup()
|
||||
const input = { question: 'Q ?', response: 'R', theme: 'git' }
|
||||
repository.create.mockResolvedValueOnce(CARD)
|
||||
await expect(service.create(input)).resolves.toEqual(CARD)
|
||||
expect(repository.create).toHaveBeenCalledWith(input)
|
||||
})
|
||||
|
||||
it('update renvoie la carte mise à jour', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.update.mockResolvedValueOnce({ ...CARD, question: 'Nouvelle' })
|
||||
const card = await service.update(CARD.id, { question: 'Nouvelle' })
|
||||
expect(card.question).toBe('Nouvelle')
|
||||
})
|
||||
|
||||
it('update lève NotFoundError si la carte est inconnue', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.update.mockResolvedValueOnce(null)
|
||||
await expect(service.update('inconnu', { question: 'X' })).rejects.toThrow(NotFoundError)
|
||||
})
|
||||
|
||||
it('remove délègue la suppression', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.delete.mockResolvedValueOnce(true)
|
||||
await expect(service.remove(CARD.id)).resolves.toBeUndefined()
|
||||
expect(repository.delete).toHaveBeenCalledWith(CARD.id)
|
||||
})
|
||||
|
||||
it('remove lève NotFoundError si aucune carte ne correspond', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.delete.mockResolvedValueOnce(false)
|
||||
await expect(service.remove('inconnu')).rejects.toThrow(NotFoundError)
|
||||
})
|
||||
|
||||
it('random sans thème utilise findRandom', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findRandom.mockResolvedValueOnce(CARD)
|
||||
await expect(service.random()).resolves.toEqual(CARD)
|
||||
expect(repository.findRandomByTheme).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('random avec thème utilise findRandomByTheme', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findRandomByTheme.mockResolvedValueOnce(CARD)
|
||||
await expect(service.random('javascript')).resolves.toEqual(CARD)
|
||||
expect(repository.findRandomByTheme).toHaveBeenCalledWith('javascript')
|
||||
})
|
||||
|
||||
it('random lève NotFoundError si aucune carte', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findRandom.mockResolvedValueOnce(null)
|
||||
await expect(service.random()).rejects.toThrow(NotFoundError)
|
||||
repository.findRandomByTheme.mockResolvedValueOnce(null)
|
||||
await expect(service.random('react')).rejects.toThrow('Aucune carte pour le thème react')
|
||||
})
|
||||
|
||||
it('themes renvoie la liste des thèmes', async () => {
|
||||
const { service, repository } = setup()
|
||||
repository.findThemes.mockResolvedValueOnce(['docker', 'git'])
|
||||
await expect(service.themes()).resolves.toEqual(['docker', 'git'])
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user