Files
probably-rendering-one-more…/apps/studio/tests/native-layout.test.mjs

32 lines
2.9 KiB
JavaScript

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs';
import {nativeLayout,defaultText,textSize,imageShape,designUrl,newElementId} from '../src/lib/native-layout.ts';
const layouts=JSON.parse(readFileSync(new URL('../src/content/templates/layouts.json',import.meta.url)));
test('all 27 native pages are independent of source images and supply actual text',()=>{
for(const original of layouts){const layout=nativeLayout(original),serialized=JSON.stringify(layout);assert.ok(!serialized.includes('data:image'));assert.ok(!serialized.includes('raster'));assert.ok(!serialized.includes('source'));assert.ok(serialized.length<7000);
for(const slot of layout.elements.filter(s=>s.kind==='text')){assert.ok(defaultText(layout,slot).length);for(const text of [defaultText(layout,slot),'','新的文字\n第二行','<script>plain text</script>']){const size=textSize(layout,slot,text);assert.ok(Number.isFinite(size)&&size>0)}}
}
});
test('geometric templates retain their distinct silhouettes without bitmap masks',()=>{
assert.equal(imageShape(layouts[4],layouts[4].elements.find(s=>s.id==='I03')).borderRadius,'50%');
assert.ok(imageShape(layouts[21],layouts[21].elements.find(s=>s.id==='I02')).clipPath.startsWith('polygon('));
assert.notEqual(imageShape(layouts[21],layouts[21].elements.find(s=>s.id==='I02')).clipPath,imageShape(layouts[26],layouts[26].elements.find(s=>s.id==='I02')).clipPath);
assert.equal(designUrl('ref-01','abc'),'/studio/template-layout?id=abc');
assert.equal(designUrl('standard-01','abc'),'/studio/template-layout?id=abc');
});
test('element IDs work on HTTP origins without secure-context randomUUID',()=>{const saved=Object.getOwnPropertyDescriptor(globalThis,'crypto');let calls=0;Object.defineProperty(globalThis,'crypto',{configurable:true,value:{getRandomValues(array){for(let i=0;i<array.length;i++)array[i]=++calls;return array}}});try{const first=newElementId(),second=newElementId();assert.match(first,/^user-[a-f0-9]{32}$/);assert.notEqual(first,second)}finally{Object.defineProperty(globalThis,'crypto',saved)}});
// Measured by ces-control Chromium/Noto in production run 660, at 860px art width.
// These glyph bounds exceed CSS line-height, including single-letter title slots.
test('default copy leaves room for production fallback glyph bounds',()=>{
const cases=[['ref-07','T02',97/73.7143],['ref-08','T01',112/85.2389],['ref-19','T01',287/217.055],['ref-19','T02',298/225.274],['ref-19','T03',313/237.451],['ref-19','T04',306/231.363],['ref-21','T01',195/160.307]];
for(const [id,slotId,glyphExtent] of cases){
const layout=layouts.find(l=>l.id===id),slot=layout.elements.find(s=>s.id===slotId);
const size=textSize(layout,slot,defaultText(layout,slot))*860/layout.width;
const crossAxis=slot.direction==='rotated'?slot.box[2]:slot.box[3];
assert.ok(Math.ceil(size*glyphExtent)<=crossAxis*860/layout.width+2,`${id}/${slotId}: fallback glyphs must fit`);
}
});