waybetter-for-x/apps/desktop/tests/themeV3Remap.test.ts

51 lines
3.9 KiB
TypeScript

// Theme engine v3, step 6: pair-aware remap. X fills that are no palette colour take a theme surface and
// everything inside reads in that surface's ink; X's tooltip is the tooltip surface.
import assert from 'node:assert/strict';
import test from 'node:test';
import { contrastRatio } from '../../../waybetter/packages/runtime/src/themeApi.ts';
import { X_COLOUR_KEYS, X_MEANING_KEYS, X_PALETTES, accentWash, buildThemeCss, foreignFillSurface, paletteSurfaces } from '../src/inject/theme.ts';
import { BUILTIN_THEMES } from '../src/inject/themeSpec.ts';
const rule = (selectorText: string, style: Record<string, string>) => ({ selectorText, style: { getPropertyValue: (name: string) => style[name] ?? '' } });
for (const theme of BUILTIN_THEMES.filter(t => t.colors)) {
test(`${theme.id}: Creator Studio's indigo pill (class or inline) gets a fill and an ink that read (was 1.19:1)`, () => {
const palette = { ...theme.colors! };
const css = buildThemeCss([rule('.bg-indigo-950', { 'background-color': 'rgb(30, 27, 75)' })], X_PALETTES.light, palette);
const surfaces = paletteSurfaces(palette)!;
const s = foreignFillSurface('30,27,75', X_PALETTES.light, surfaces);
assert.ok(contrastRatio(s.ink, s.fill) >= 4.5, `${s.ink} on ${s.fill}`);
assert.ok(css.includes(`.bg-indigo-950`) && css.includes(`background-color:${s.fill} !important`), 'class fill remapped');
assert.ok(css.includes('background-color: rgb(30, 27, 75)"]'), 'inline fill remapped');
assert.ok(css.includes(`--jf-text-color:${s.ink} !important`), 'jetfuel text token follows the fill');
// The tooltip: its label reads on its fill (the "More" HoverLabel was 2.7:1).
assert.ok(contrastRatio(surfaces.tooltip.ink, surfaces.tooltip.fill) >= 4.5);
assert.ok(css.includes('[data-testid="HoverLabel"]'));
});
}
test('meaning colours and X accent swatches stay X\'s; every palette key is listed for the leak check', () => {
const palette = { ...BUILTIN_THEMES.find(t => t.id === 'windows-98')!.colors! };
const css = buildThemeCss([rule('.swatch', { 'background-color': 'rgb(120, 86, 255)' }), rule('.like', { 'background-color': 'rgb(249, 24, 128)' })], X_PALETTES.light, palette);
assert.ok(!css.includes('.swatch{') && !css.includes(':is(.swatch'));
assert.ok(!css.includes(':is(.like'));
for (const key of ['120,86,255', '249,24,128']) assert.ok(X_MEANING_KEYS.includes(key), key);
for (const key of ['255,255,255', '15,20,25', '29,155,240', '0,0,0', '115,115,115']) assert.ok(X_COLOUR_KEYS.includes(key), key);
});
test('X\'s blue washes become the content surface\'s neutral hover and its selection (no lavender rows)', () => {
const palette = { ...BUILTIN_THEMES.find(t => t.id === 'windows-98')!.colors! };
const surfaces = paletteSurfaces(palette)!;
const css = buildThemeCss([rule('.r-hover', { 'background-color': 'rgba(29, 155, 240, 0.1)' }), rule('.r-sel', { 'background-color': 'rgba(29, 155, 240, 0.15)' })], X_PALETTES.light, palette);
assert.ok(css.includes(`.r-hover{background-color:${surfaces.content.hover} !important}`), css.split('\n').find(l => l.startsWith('.r-hover')));
assert.ok(css.includes(`.r-sel{background-color:${surfaces.content.selected} !important}`));
assert.equal(accentWash('rgba(29, 155, 240, 0.5)', X_PALETTES.light, surfaces), null, 'a strong tint is a fill, not a state');
});
test('the live rule of the "New" pill: a compound selector with jetfuel\'s variable alpha is a fill class too', () => {
const palette = { ...BUILTIN_THEMES.find(t => t.id === 'windows-98')!.colors! };
const sel = '[data-theme="dark"] .jetfuel-style-root .j-j6ij7u11';
const css = buildThemeCss([rule(sel, { 'background-color': 'rgba(30, 27, 75, var(--jbgo))' })], X_PALETTES.light, palette);
const s = foreignFillSurface('30,27,75', X_PALETTES.light, paletteSurfaces(palette)!);
assert.ok(css.includes(`:is(${sel}`) && css.includes(`--jf-text-color:${s.ink} !important`));
});