test(hq): golden fidelity — preview HTML byte-identical to the PDF's HTML
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>feat/client-detail-redesign
parent
268a7469d3
commit
1ac44ae7de
@ -0,0 +1,42 @@
|
|||||||
|
// apps/hq/test/preview-fidelity.test.ts
|
||||||
|
import { describe, it, expect, afterAll } from 'vitest'
|
||||||
|
import express from 'express'
|
||||||
|
import { openDb } from '../src/db'
|
||||||
|
import { seedIfEmpty } from '../src/seed'
|
||||||
|
import { createStaff } from '../src/auth'
|
||||||
|
import { createClient, getClient } from '../src/repos-clients'
|
||||||
|
import { createModule, setPrice } from '../src/repos-modules'
|
||||||
|
import { createDraft } from '../src/repos-documents'
|
||||||
|
import { documentHtml } from '../src/templates'
|
||||||
|
import { apiRouter } from '../src/api'
|
||||||
|
|
||||||
|
function companyMap(db: any): Record<string, string> {
|
||||||
|
const rows = db.prepare(`SELECT key, value FROM setting WHERE key LIKE 'company.%'`).all() as { key: string; value: string }[]
|
||||||
|
return Object.fromEntries(rows.map((r) => [r.key, r.value]))
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('preview fidelity (string identity with the PDF path)', () => {
|
||||||
|
const db = openDb(':memory:'); seedIfEmpty(db)
|
||||||
|
createStaff(db, { email: 'owner@test.in', displayName: 'Owner', role: 'owner', password: 'owner-password' })
|
||||||
|
const c = createClient(db, 'u1', { name: 'Acme', code: 'ACME', stateCode: '32', address: 'Kochi', gstin: '32ABCDE1234F1Z9' })
|
||||||
|
const m = createModule(db, 'u1', { code: 'POS', name: 'POS Billing', quoteContent: ['Cloud POS', 'GST filing'] })
|
||||||
|
setPrice(db, 'u1', { moduleId: m.id, kind: 'yearly', pricePaise: 10_000_00, effectiveFrom: '2026-04-01' })
|
||||||
|
const app = express(); app.use(express.json()); app.locals['db'] = db; app.use('/api', apiRouter(db))
|
||||||
|
const server = app.listen(0)
|
||||||
|
const base = `http://localhost:${(server.address() as { port: number }).port}/api`
|
||||||
|
afterAll(() => server.close())
|
||||||
|
|
||||||
|
it('preview.html === documentHtml the /pdf route would feed renderPdf', async () => {
|
||||||
|
const input = { docType: 'INVOICE', clientId: c.id, terms: 'Net 15',
|
||||||
|
lines: [{ moduleId: m.id, qty: 2, kind: 'yearly' }] }
|
||||||
|
// The fixture draft: exactly what /documents/:id/pdf renders (un-issued draft, docNo=null).
|
||||||
|
const fixture = createDraft(db, 'u1', input)
|
||||||
|
const expected = documentHtml(fixture, getClient(db, c.id)!, companyMap(db))
|
||||||
|
|
||||||
|
const token = (await (await fetch(`${base}/auth/login`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email: 'owner@test.in', password: 'owner-password' }) })).json() as any).token
|
||||||
|
const res = await fetch(`${base}/documents/preview`, { method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` }, body: JSON.stringify(input) })
|
||||||
|
const out = await res.json() as any
|
||||||
|
|
||||||
|
expect(out.html).toBe(expected) // one renderer — no drift possible
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue