- settings.json: deny patterns críticos (rm -rf root, force push, etc.) - settings.local.json en gitignore — cada dev configura sus allows Refs: methodology/PATTERNS.md B.4 (reglas no negociables en repo)
149 lines
6.2 KiB
TypeScript
149 lines
6.2 KiB
TypeScript
/**
|
|
* Tests del módulo compartido de header/footer PDF — Etapa 4 Sprint 1.5.
|
|
*/
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { PDF_COLORS, drawSharedHeader, drawSharedFooter, applyFootersToAllPages } from '@/lib/export/pdf-sections-shared'
|
|
|
|
// ─── Mock DocLike ─────────────────────────────────────────────────────────────
|
|
|
|
function makeMockDoc(pageW = 210, pageH = 297, totalPages = 2) {
|
|
return {
|
|
setFont: vi.fn(),
|
|
setFontSize: vi.fn(),
|
|
setTextColor: vi.fn(),
|
|
setFillColor: vi.fn(),
|
|
setDrawColor: vi.fn(),
|
|
setLineWidth: vi.fn(),
|
|
text: vi.fn(),
|
|
rect: vi.fn(),
|
|
roundedRect: vi.fn(),
|
|
line: vi.fn(),
|
|
addImage: vi.fn(),
|
|
addPage: vi.fn(),
|
|
setPage: vi.fn(),
|
|
splitTextToSize: vi.fn().mockImplementation((t: string) => [t]),
|
|
internal: {
|
|
getNumberOfPages: vi.fn().mockReturnValue(totalPages),
|
|
pageSize: {
|
|
getWidth: vi.fn().mockReturnValue(pageW),
|
|
getHeight: vi.fn().mockReturnValue(pageH),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
const BASE_OPTS = { processName: 'Proceso de prueba', simulatedAt: new Date('2026-05-17T10:00:00Z').getTime() }
|
|
|
|
// ─── PDF_COLORS ───────────────────────────────────────────────────────────────
|
|
|
|
describe('PDF_COLORS', () => {
|
|
it('expone inqOrange como array RGB válido [245, 152, 69]', () => {
|
|
expect(PDF_COLORS.inqOrange).toEqual([245, 152, 69])
|
|
})
|
|
|
|
it('NO incluye colores de CONCILIA (#572FA2 → [87, 47, 162])', () => {
|
|
const all = JSON.stringify(PDF_COLORS)
|
|
expect(all).not.toContain('87, 47, 162') // #572FA2 morado CONCILIA
|
|
expect(all).not.toContain('203, 24, 137') // #CB1889 magenta CONCILIA
|
|
})
|
|
|
|
it('tiene al menos 8 colores definidos', () => {
|
|
expect(Object.keys(PDF_COLORS).length).toBeGreaterThanOrEqual(8)
|
|
})
|
|
})
|
|
|
|
// ─── drawSharedHeader ─────────────────────────────────────────────────────────
|
|
|
|
describe('drawSharedHeader', () => {
|
|
let doc: ReturnType<typeof makeMockDoc>
|
|
|
|
beforeEach(() => { doc = makeMockDoc() })
|
|
|
|
it('retorna un número mayor que el margen (20mm) — espacio del header', () => {
|
|
const y = drawSharedHeader(doc, { ...BASE_OPTS, pageNumber: 1 })
|
|
expect(y).toBeGreaterThan(20)
|
|
})
|
|
|
|
it('dibuja border-bottom más grueso en página 1 que en páginas siguientes', () => {
|
|
drawSharedHeader(doc, { ...BASE_OPTS, pageNumber: 1 })
|
|
const page1LineWidths = doc.setLineWidth.mock.calls.map((c: number[]) => c[0])
|
|
|
|
doc.setLineWidth.mockClear()
|
|
drawSharedHeader(doc, { ...BASE_OPTS, pageNumber: 2 })
|
|
const page2LineWidths = doc.setLineWidth.mock.calls.map((c: number[]) => c[0])
|
|
|
|
// El grosor máximo de página 1 debe ser mayor que el de página 2
|
|
expect(Math.max(...page1LineWidths)).toBeGreaterThan(Math.max(...page2LineWidths))
|
|
})
|
|
|
|
it('dibuja el texto "InQ ROI" en la primera llamada a text()', () => {
|
|
drawSharedHeader(doc, { ...BASE_OPTS, pageNumber: 1 })
|
|
const firstTextCall = doc.text.mock.calls[0]
|
|
expect(firstTextCall[0]).toBe('InQ ROI')
|
|
})
|
|
|
|
it('usa inqOrange para el texto del logo', () => {
|
|
drawSharedHeader(doc, { ...BASE_OPTS, pageNumber: 1 })
|
|
// La primera llamada a setTextColor debe ser el naranja InQ
|
|
const firstColor = doc.setTextColor.mock.calls[0]
|
|
expect(firstColor).toEqual(PDF_COLORS.inqOrange)
|
|
})
|
|
|
|
it('usa doc.internal.pageSize.getWidth() — compatible con landscape', () => {
|
|
const landscapeDoc = makeMockDoc(297, 210)
|
|
const y = drawSharedHeader(landscapeDoc, { ...BASE_OPTS, pageNumber: 1 })
|
|
expect(landscapeDoc.internal.pageSize.getWidth).toHaveBeenCalled()
|
|
expect(y).toBeGreaterThan(20)
|
|
})
|
|
})
|
|
|
|
// ─── drawSharedFooter ─────────────────────────────────────────────────────────
|
|
|
|
describe('drawSharedFooter', () => {
|
|
let doc: ReturnType<typeof makeMockDoc>
|
|
|
|
beforeEach(() => { doc = makeMockDoc() })
|
|
|
|
it('incluye "InQ ROI" en el texto del footer', () => {
|
|
drawSharedFooter(doc, { ...BASE_OPTS, pageNumber: 1, totalPages: 3 })
|
|
const textCalls = doc.text.mock.calls.map((c: unknown[]) => c[0])
|
|
expect(textCalls.some((t: unknown) => typeof t === 'string' && t.includes('InQ ROI'))).toBe(true)
|
|
})
|
|
|
|
it('incluye "Powered by InQuality" en el texto del footer', () => {
|
|
drawSharedFooter(doc, { ...BASE_OPTS, pageNumber: 1, totalPages: 3 })
|
|
const textCalls = doc.text.mock.calls.map((c: unknown[]) => c[0])
|
|
expect(textCalls.some((t: unknown) => typeof t === 'string' && t.includes('Powered by InQuality'))).toBe(true)
|
|
})
|
|
|
|
it('muestra paginación correcta "Página X de Y"', () => {
|
|
drawSharedFooter(doc, { ...BASE_OPTS, pageNumber: 2, totalPages: 4 })
|
|
const textCalls = doc.text.mock.calls.map((c: unknown[]) => c[0])
|
|
expect(textCalls.some((t: unknown) => typeof t === 'string' && t === 'Página 2 de 4')).toBe(true)
|
|
})
|
|
|
|
it('NO incluye versión del producto (v0.1.0)', () => {
|
|
drawSharedFooter(doc, { ...BASE_OPTS, pageNumber: 1, totalPages: 3 })
|
|
const allText = doc.text.mock.calls.map((c: unknown[]) => c[0]).join(' ')
|
|
expect(allText).not.toContain('v0.')
|
|
expect(allText).not.toContain('v0.1')
|
|
})
|
|
|
|
it('usa doc.internal.pageSize.getHeight() para posición inferior', () => {
|
|
drawSharedFooter(doc, { ...BASE_OPTS, pageNumber: 1, totalPages: 3 })
|
|
expect(doc.internal.pageSize.getHeight).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
// ─── applyFootersToAllPages ───────────────────────────────────────────────────
|
|
|
|
describe('applyFootersToAllPages', () => {
|
|
it('llama setPage para cada página del documento', () => {
|
|
const doc = makeMockDoc(210, 297, 4)
|
|
applyFootersToAllPages(doc, BASE_OPTS)
|
|
expect(doc.setPage).toHaveBeenCalledTimes(4)
|
|
expect(doc.setPage).toHaveBeenNthCalledWith(1, 1)
|
|
expect(doc.setPage).toHaveBeenNthCalledWith(4, 4)
|
|
})
|
|
})
|