// @requirements REQ-EU-ORDER-ACTION // @requirements REQ-EU-GUARANTEE-LABEL // @requirements REQ-EU-GUARANTEE-NOTICE REQ-PRODUCT-GUARANTEE-NOTICE // @requirements REQ-NZ-INDIRECT REQ-PRODUCT-INDIRECT-NOTICE // @requirements REQ-PRODUCT-SERVICE-CATALOG // @requirements REQ-PRODUCT-FORM-PERMISSIONS REQ-PRODUCT-COLLECTION-NOTICE // @requirements REQ-PRODUCT-ASTRO REQ-PRODUCT-PACKAGE import {test} from 'node:test'; import assert from 'node:assert/strict'; import {mkdtemp,writeFile,readFile,mkdir,rm,symlink} from 'node:fs/promises'; import {existsSync} from 'node:fs'; import {tmpdir} from 'node:os'; import {join} from 'node:path'; import {fileURLToPath} from 'node:url'; import {spawnSync} from 'node:child_process'; import {compileLegalDocuments,createCollectionNotice,createIndirectCollectionNotice} from 'notabenda/content'; import {fixture} from './helpers.mjs'; import {paidOrderFiles} from '../../../examples/orders/build.mjs'; import {buildDurabilityGuaranteeLabel} from 'notabenda-authoring/guarantees'; import {buildLegalGuaranteeNotice} from 'notabenda/guarantees/content'; test('packed Astro components compile in an isolated consumer, escape supplied content and enforce explicit draft preview',async()=>{ const cwd=await mkdtemp(join(tmpdir(),'notabenda-astro-package-'));const root=fileURLToPath(new URL('../../..',import.meta.url)); const env={...process.env,...(existsSync(join(root,'.local/npm-cache'))?{npm_config_cache:join(root,'.local/npm-cache')}:{ }),ASTRO_TELEMETRY_DISABLED:'1'}; try { const packed=spawnSync('npm',['pack','--workspace','notabenda','--json','--ignore-scripts','--pack-destination',cwd],{cwd:root,encoding:'utf8',env});assert.equal(packed.status,0,packed.stderr);const manifest=JSON.parse(packed.stdout)[0]; for(const path of ['dist/astro/ServiceDirectory.astro','dist/astro/FormPermissionField.astro','dist/astro/CollectionNotice.astro','dist/astro/LegalDocument.astro','dist/astro/LegalLinks.astro','dist/astro/ConsentControls.astro','dist/astro/PreferencesButton.astro','dist/astro-client.d.ts'])assert.ok(manifest.files.some(f=>f.path===path),path); await writeFile(join(cwd,'package.json'),'{"private":true,"type":"module"}'); const installed=spawnSync('npm',['install','--offline','--ignore-scripts','--no-audit','--no-fund',join(cwd,manifest.filename)],{cwd,encoding:'utf8',env});assert.equal(installed.status,0,installed.stderr); await assert.rejects(readFile(join(cwd,'node_modules/react/package.json')),error=>error.code==='ENOENT'); await assert.rejects(readFile(join(cwd,'node_modules/astro/package.json')),error=>error.code==='ENOENT'); // Reuse the pinned framework toolchain, as consumer type tests reuse TypeScript. Core comes only from the tarball. await symlink(join(root,'node_modules/astro'),join(cwd,'node_modules/astro'),'dir'); await mkdir(join(cwd,'src/pages'),{recursive:true}); const config=await fixture({reviewed:true});config.documents.terms.sections[0].paragraphs=['Literal content.']; await writeFile(join(cwd,'src/site.json'),JSON.stringify(config)); const notice=createCollectionNotice(compileLegalDocuments(config).artifact,{scopeId:'contact',purposeIds:['enquiries'],reviewStatus:'reviewed',wording:{title:'About your enquiry',intro:'A fictional form context.'}});await writeFile(join(cwd,'src/notice.json'),JSON.stringify(notice)); const indirectConfig=structuredClone(config);indirectConfig.purposes[0].collection.source='indirect'; const indirect=createIndirectCollectionNotice(compileLegalDocuments(indirectConfig).artifact,{profile:'nz-ipp3a',scopeId:'referral',phase:'advance',reviewStatus:'reviewed',wording:{title:'Partner referral',intro:'Before a partner refers an enquiry.'},collections:[{purposeId:'enquiries',dataCategories:[indirectConfig.purposes[0].dataCategories[0]],sourceDescription:'A partner studio.',authority:{kind:'not-relied-on'}}],recipientStatement:'Our enquiries team.',accessCorrection:{statement:'You can request access or correction.',url:'mailto:privacy@example.test'}});await writeFile(join(cwd,'src/indirect.json'),JSON.stringify(indirect)); const guarantee=await buildLegalGuaranteeNotice({language:'en',reviewStatus:'reviewed'});await writeFile(join(cwd,'src/guarantee.json'),JSON.stringify(guarantee.notice)); const label=buildDurabilityGuaranteeLabel({product:{id:'one',name:'Literal '},producer:{brand:'Example brand',model:'One'},durationYears:5,qualification:{offeredByProducer:true,noAdditionalCost:true,coversEntireGood:true,informationProvidedToTrader:true},reviewStatus:'reviewed',locale:'en'},Buffer.from('')).label;await writeFile(join(cwd,'src/label.json'),JSON.stringify(label)); const orderFiles=await paidOrderFiles(),orderTemplate=JSON.parse(orderFiles['orders/conditional/template.json']),{createPaidOrderReview}=await import('notabenda-authoring/orders');const orderReview=createPaidOrderReview(orderTemplate.definition,{quoteId:'packed',revision:'1',contextRef:'a'.repeat(64),definitionId:orderTemplate.definition.definitionId,issuedAt:'2026-10-19T00:00:00.000Z',expiresAt:'2026-10-19T00:15:00.000Z',lines:orderTemplate.lines,pricing:orderTemplate.pricing},{},{allowPreview:true});await writeFile(join(cwd,'src/order.json'),JSON.stringify(orderReview)); const page=`---\nimport PaidOrderReview from 'notabenda/astro/PaidOrderReview.astro';\nimport orderReview from '../order.json';\nimport FormPermissionField from 'notabenda/astro/FormPermissionField.astro';\nimport CollectionNotice from 'notabenda/astro/CollectionNotice.astro';\nimport IndirectCollectionNotice from 'notabenda/astro/IndirectCollectionNotice.astro';\nimport indirect from '../indirect.json';\nimport LegalGuaranteeNotice from 'notabenda/astro/LegalGuaranteeNotice.astro';\nimport guarantee from '../guarantee.json';\nimport DurabilityGuaranteeLabel from 'notabenda/astro/DurabilityGuaranteeLabel.astro';\nimport label from '../label.json';\nimport notice from '../notice.json';\nimport LegalDocument from 'notabenda/astro/LegalDocument.astro';\nimport LegalLinks from 'notabenda/astro/LegalLinks.astro';\nimport ServiceDirectory from 'notabenda/astro/ServiceDirectory.astro';\nimport ConsentControls from 'notabenda/astro/ConsentControls.astro';\nimport PreferencesButton from 'notabenda/astro/PreferencesButton.astro';\nimport config from '../site.json';\n---\n

Contact our privacy team for help.

`; await writeFile(join(cwd,'src/pages/index.astro'),page); const build=()=>spawnSync(process.execPath,[join(cwd,'node_modules/astro/bin/astro.mjs'),'build','--root',cwd],{cwd,encoding:'utf8',env}); const first=build();assert.equal(first.status,0,first.stdout+first.stderr); const html=await readFile(join(cwd,'dist/index.html'),'utf8');assert.match(html,/<script>/);assert.doesNotMatch(html,/