test(packet): verify the packet in ITS OWN language, not in English
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
The gate asserted a hardcoded English word list for the prayer rhythms — which tests the opposite of what i18n means. It passed a packet whose translation silently did nothing, and FAILED every correctly translated one: the Spanish packet reported "only 0/11 prayer rhythms present" while rendering all twelve correctly as ALABANZA / ESPERAR / CONFESAR. Expected words now come from the strings catalog for the packet's OWN language, resolved per key with English fallback — the same contract the renderer honours. So the gate asserts the PROPERTY (all rhythms present, in this language) rather than a vocabulary. The catalog path is derived from the packet's own location instead of a machine-specific constant, with PACKET_STRINGS to override. Adds the assertion the tick exposed: a non-English packet must ACTUALLY DIFFER from English. That failure is invisible to every other check, because an all-English packet is a perfectly valid packet — a mis-keyed block, a block under the wrong ISO code, or a renderer ignoring its lang argument all produce one. Confirmed to fire before being accepted: a packet relabelled lang="de" with no de block reports "lang=de but no string differs from English".
This commit is contained in:
parent
41847076a2
commit
cd5e5f5590
1 changed files with 44 additions and 4 deletions
|
|
@ -27,8 +27,8 @@
|
|||
// Default path is overridable with PACKET_HTML so this is not machine-specific.
|
||||
|
||||
import { chromium } from 'playwright'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { resolve, dirname } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
|
||||
const target = process.argv[2] || process.env.PACKET_HTML
|
||||
|
|
@ -50,11 +50,45 @@ const errs = []
|
|||
page.on('pageerror', (e) => errs.push(String(e).slice(0, 120)))
|
||||
await page.goto(pathToFileURL(file).href, { waitUntil: 'networkidle' })
|
||||
|
||||
// Resolve the rhythm words for THIS packet's language from the shared catalog.
|
||||
// Per-key fallback to English, the same contract the renderer honours.
|
||||
const lang = await page.evaluate(() => document.documentElement.lang || 'en')
|
||||
// The catalog sits beside the generator that produced this packet, so derive it
|
||||
// from the packet's own path rather than hardcoding a machine-specific location.
|
||||
const catalogPath = process.env.PACKET_STRINGS
|
||||
|| resolve(dirname(file), '..', '..', 'packet-strings.json')
|
||||
if (!existsSync(catalogPath)) {
|
||||
console.error(`PACKET-RENDER: FAIL — no strings catalog at ${catalogPath}`)
|
||||
console.error(' Set PACKET_STRINGS if the packet lives outside the generator tree.')
|
||||
process.exit(1)
|
||||
}
|
||||
const catalog = JSON.parse(readFileSync(catalogPath, 'utf8'))
|
||||
const enR = catalog.en.rhythms
|
||||
const langR = (catalog[lang] || {}).rhythms || {}
|
||||
const expected = [...new Set(Object.keys(enR).map((k) => langR[k] ?? enR[k]))]
|
||||
// ★ A NON-ENGLISH PACKET MUST ACTUALLY DIFFER FROM ENGLISH. The failure this
|
||||
// catches is a language block that exists but does nothing — a typo'd key, a
|
||||
// block under the wrong ISO code, or a renderer that ignored the lang argument.
|
||||
// Every assertion below would still pass in that case, because an all-English
|
||||
// packet is a perfectly valid packet; only the comparison reveals it.
|
||||
const translated = lang !== 'en'
|
||||
? Object.keys(catalog.en).filter((k) => typeof catalog.en[k] === 'string'
|
||||
&& (catalog[lang] || {})[k] && catalog[lang][k] !== catalog.en[k]).length
|
||||
: null
|
||||
await page.evaluate((words) => { window.__EXPECTED_RHYTHMS = words }, expected)
|
||||
|
||||
const r = await page.evaluate(() => {
|
||||
const body = document.body.innerText
|
||||
const imgs = [...document.querySelectorAll('.card img')]
|
||||
const RHYTHMS = ['PRAISE', 'WAIT', 'CONFESS', 'READ THE WORD', 'ASK', 'INTERCESSION',
|
||||
'PRAY THE WORD', 'THANK', 'SING', 'MEDITATE', 'LISTEN']
|
||||
// ⚠ The expected rhythm words come from the STRINGS CATALOG FOR THIS PACKET'S
|
||||
// LANGUAGE, never a hardcoded English list. A fixed list tests the opposite of
|
||||
// what i18n means: it passed a packet whose translation silently did nothing and
|
||||
// FAILED every correctly-translated one (measured — the Spanish packet reported
|
||||
// 0/11 rhythms while rendering all twelve correctly as ALABANZA/ESPERAR/...).
|
||||
// Read the packet's own <html lang> and resolve per-key, exactly as the renderer
|
||||
// does, so this asserts the PROPERTY (all rhythms present, in this language)
|
||||
// rather than a vocabulary.
|
||||
const RHYTHMS = window.__EXPECTED_RHYTHMS || []
|
||||
|
||||
// Whole-map property, NOT one sampled element — see header note 2.
|
||||
const mapFaults = (() => {
|
||||
|
|
@ -106,6 +140,10 @@ if (r.rhythms !== r.rhythmsTotal) fails.push(`only ${r.rhythms}/${r.rhythmsTotal
|
|||
if (!r.hasMark5) fails.push('Mark 5:1-20 is NOT printed in full (Driver requirement for point 4)')
|
||||
if (r.metacamp !== 2) fails.push(`${r.metacamp} metacamp.org attributions, expected exactly 2`)
|
||||
if (r.mapFaults.length) fails.push(`map: ${r.mapFaults.join('; ')}`)
|
||||
if (translated === 0) {
|
||||
fails.push(`lang="${lang}" but no string differs from English — `
|
||||
+ 'the language block is missing, mis-keyed, or the renderer ignored it')
|
||||
}
|
||||
if (errs.length) fails.push(`${errs.length} page error(s): ${errs[0]}`)
|
||||
if (landscape) fails.push(`${landscape} landscape page(s) — the packet must be portrait`)
|
||||
if (pages !== r.sheets) fails.push(`${pages} PDF pages for ${r.sheets} sheets — one sheet must be exactly one page`)
|
||||
|
|
@ -117,6 +155,8 @@ console.log(` Mark 5 in full : ${r.hasMark5}`)
|
|||
console.log(` metacamp.org : ${r.metacamp}`)
|
||||
console.log(` map : ${r.mapFaults.length ? r.mapFaults.join('; ') : 'palette resolves, not black'}`)
|
||||
console.log(` page size : ${boxes[0] ? boxes[0].join(' x ') : '?'} pt`)
|
||||
console.log(` language : ${lang} (${r.rhythms}/${r.rhythmsTotal} rhythms in ${lang}`
|
||||
+ `${translated === null ? '' : `, ${translated} strings translated`})`)
|
||||
|
||||
if (fails.length) {
|
||||
console.error(`\nPACKET-RENDER: FAIL — ${fails.length} problem(s)`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue