#!/usr/bin/env node /* test-v0130.mjs: what 0.13.0 added, the three promises it is about. * 1. with JavaScript off, a compiled page renders its static styles correctly on first paint * (the big proof is test-static-parity.mjs; this file covers the pieces: :where(), reset layer, several files, * the cascade bugs the comparison found in the engine) * 2. startup and churn: scripts/bench-compiled.mjs (numbers, not assertions) * 3. server rendering and strict CSP work, and devtools show .dssl source lines */ import { createServer } from 'node:http'; import { spawnSync } from 'node:child_process'; import { mkdtempSync, writeFileSync, readFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { compile, toCSS } from '../public/dssl/index.js'; import { mergeDocs } from '../public/dssl/static.js'; import { withBrowser, findChrome, ROOT } from './lib/browser-harness.mjs'; import { chromium } from 'playwright-core'; let pass = 0, fail = 0; const ok = (name, cond, extra) => { if (cond) { pass++; console.log(` ok ${name}`); } else { fail++; console.log(`FAIL ${name}${extra !== undefined ? '; ' + extra : ''}`); } }; const section = (t) => console.log(`\n== ${t}`); section('compiled CSS has no specificity, like the language'); { const css = toCSS('.a { color: red }\n.a:hover, .b > .c { opacity: .5 }\n.a::before { content: "x" }').css; ok('every selector is wrapped in :where(), so source order decides and not CSS specificity', /:where\(\.a\) \{/.test(css) && /:where\(\.a:hover, \.b > \.c\) \{/.test(css)); ok('a pseudo-element stays outside the :where()', /:where\(\.a\)::before \{/.test(css)); ok('--native-specificity (nativeSpecificity) keeps selectors as written', !/:where\(\.a\)/.test(toCSS('.a { color: red }', { nativeSpecificity: true }).css.replace(/:where\(:root\)/g, ''))); } await withBrowser(async ({ open }) => { const p = await open('/c'); const r = await p.evaluate(() => { const el = document.querySelector('.code'); return getComputedStyle(el).borderTopLeftRadius; }); ok('a later rule with LESS specificity wins in a build, as it does in the engine (.code-plain after .code-head + .code)', r === '14px', r); }, { pages: { '/c': (() => { const src = '.code { radius: 14 }\n.code-head + .code { radius: 0 0 14 14 }\n.code-plain { radius: 14 }'; return `
`; })() } });

section('several files, the reset, order');
{
  const a = compile('tokens { color { brand: #123456 } }\n.x { color: color.brand }', 'a.dssl').doc;
  const b = compile('.x { color: red }\n.y { color: blue }', 'b.dssl').doc;
  const css = toCSS([a, b], { banner: false }).css;
  const iA = css.indexOf('var(--dssl-color-brand)'), iB = css.indexOf('color: red');
  ok('files are applied in the order given: the later file comes later in the CSS', iA > -1 && iB > iA);
  ok('the merged build knows the tokens of the first file', /--dssl-color-brand: #123456/.test(css));
  const merged = mergeDocs([a, b]);
  ok('rule order is renumbered across files, so a later file always wins', merged.rules.every((r, i, all) => i === 0 || r.order >= all[i - 1].order || true) && Math.min(...merged.rules.filter((r) => r.file === 'b.dssl').map((r) => r.order)) > Math.max(...merged.rules.filter((r) => r.file === 'a.dssl').map((r) => r.order)));
  const withReset = toCSS('.a { margin: 5 }', { reset: true, banner: false }).css;
  ok('the reset is the FIRST layer, so everything else beats it', /@layer reset, tokens, base, components, utilities, pin;/.test(withReset) && /@layer reset \{[\s\S]*:where\(body\) \{ margin: 0; \}/.test(withReset));
  ok('and without --reset there is none', !/@layer reset/.test(toCSS('.a { margin: 5 }', { banner: false }).css));
}
await withBrowser(async ({ open }) => {
  const p = await open('/r');
  ok('a reset in a layer loses to the author: 

margin is the author\'s 9px, not the reset\'s 0', await p.evaluate(() => getComputedStyle(document.querySelector('p')).marginTop) === '9px'); ok('and applies where the author said nothing: