"chore(claude-code): configurar permisos compartidos del proyecto
- 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)
This commit is contained in:
148
tests/lib/export/pdf-sections-shared.test.ts
Normal file
148
tests/lib/export/pdf-sections-shared.test.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user