teqo-backup/tests/unit/cardFaceDetection.unit.spec.ts
Francisco Solla cde96b26d0 feat(S18): cabeça do visitante proporcional à dos candidatos no card Time de você
- FaceDetector (blaze_face_full_range, Apache-2.0, lazy/on-device) mede o maior rosto no canvas do recorte; math pura frameCardPhotoOnFace escala a face à referência TEAM_CARD_FACE_REFERENCE_SIZE=103 (mediana das 5 caixas da arte-mestre).
- Piso do time CARD_TEAM_PHOTO_MIN_ZOOM=0.2 com clamp contain/cover por eixo (minZoom opcional preserva os 3 modelos S13/S14); fallback silencioso ao enquadramento S15 sem rosto/falha.
- Stub e2e estendido ('noface'); unit novo da math e da seleção do rosto; craft com retrato real 86-98px vs 103 (±20%); crítica Tier 1 certificada.

Closes #1197
2026-09-19 13:42:22 -03:00

28 lines
982 B
TypeScript

import type { Detection } from '@mediapipe/tasks-vision'
import { describe, expect, it } from 'vitest'
import { readLargestFaceBox } from '@/components/cards/cardCutout'
const detection = (originX: number, originY: number, width: number, height: number): Detection => ({
categories: [],
keypoints: [],
boundingBox: { originX, originY, width, height, angle: 0 },
})
describe('readLargestFaceBox (S18)', () => {
it('returns null when there is no usable box', () => {
expect(readLargestFaceBox([])).toBeNull()
expect(readLargestFaceBox([{ categories: [], keypoints: [] }])).toBeNull()
expect(readLargestFaceBox([detection(0, 0, 0, 40), detection(0, 0, 40, 0)])).toBeNull()
})
it('maps the largest detection to the CardFaceBox shape', () => {
expect(
readLargestFaceBox([
detection(10, 20, 30, 40),
detection(50, 60, 80, 90),
detection(0, 0, 70, 70),
]),
).toEqual({ x: 50, y: 60, width: 80, height: 90 })
})
})