Files
TREK/plugin-sdk/test/ui-kit.test.ts
T

73 lines
3.5 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { TREK_UI_CSS, TREK_THEME_JS, TREK_UI_MARKER, injectTrekUi } from '../src/index.js';
describe('design kit', () => {
it('ships a token-driven stylesheet with the signature TREK components', () => {
// Components an author leans on.
for (const cls of ['.trek-card', '.trek-glass', '.trek-btn', '.trek-input', '.trek-chip', '.trek-row']) {
expect(TREK_UI_CSS).toContain(cls);
}
// The glass recipe is baked (it can't be read over the bridge) and swaps for dark.
expect(TREK_UI_CSS).toContain('--glass-bg');
expect(TREK_UI_CSS).toContain('--glass-highlight');
expect(TREK_UI_CSS).toContain('[data-theme="dark"]');
// Honours the same accessibility choices as the host.
expect(TREK_UI_CSS).toContain('prefers-reduced-motion');
expect(TREK_UI_CSS).toContain('[data-no-transparency]');
});
it('ships a bootstrap that wires the frame and never breaks inline embedding', () => {
expect(TREK_THEME_JS).toContain("type: 'trek:ready'");
expect(TREK_THEME_JS).toContain('window.trek');
expect(TREK_THEME_JS).toContain("'trek:context'");
// Applies the host tokens + theme to the document.
expect(TREK_THEME_JS).toContain('setProperty');
expect(TREK_THEME_JS).toContain("setAttribute('data-theme'");
// Auto-sizing so a widget/page reports its own height.
expect(TREK_THEME_JS).toContain('trek:resize');
// Trusts only the real parent window (opaque frame has a 'null' origin).
expect(TREK_THEME_JS).toContain('ev.source !== window.parent');
// Host-managed tab state uses the same request/response channel.
expect(TREK_THEME_JS).toContain("trek:session:get");
expect(TREK_THEME_JS).toContain('session: session');
});
it('never contains a closing tag that would break <style>/<script> inlining', () => {
expect(TREK_UI_CSS.toLowerCase()).not.toContain('</style');
expect(TREK_UI_CSS.toLowerCase()).not.toContain('</script');
expect(TREK_THEME_JS.toLowerCase()).not.toContain('</script');
expect(TREK_THEME_JS.toLowerCase()).not.toContain('</style');
});
it('injectTrekUi expands the marker into an inline style + script block', () => {
const html = `<!doctype html><html><head></head><body>${TREK_UI_MARKER}</body></html>`;
const out = injectTrekUi(html);
expect(out).not.toContain(TREK_UI_MARKER);
expect(out).toContain('<style data-trek-ui>');
expect(out).toContain('<script data-trek-ui>');
expect(out).toContain('.trek-glass');
expect(out).toContain('window.trek');
});
it('auto-upgrades native <select> into a host-styled, opt-out-able listbox', () => {
// Styles for the enhanced control ship in the kit.
for (const cls of ['.trek-select-trigger', '.trek-select-menu', '.trek-select-option']) {
expect(TREK_UI_CSS).toContain(cls);
}
// The bootstrap enhances selects as a listbox, keeps a per-field opt-out, and
// re-emits real change events so form/plugin code still works.
expect(TREK_THEME_JS).toContain('enhanceSelect');
expect(TREK_THEME_JS).toContain('data-trek-native');
expect(TREK_THEME_JS).toContain("'listbox'");
expect(TREK_THEME_JS).toContain("dispatch(sel, 'change')");
});
it('injectTrekUi is a no-op without the marker and expands every occurrence', () => {
const plain = '<html><body><h1>hi</h1></body></html>';
expect(injectTrekUi(plain)).toBe(plain);
const twice = `${TREK_UI_MARKER}<hr>${TREK_UI_MARKER}`;
const out = injectTrekUi(twice);
expect(out.match(/<style data-trek-ui>/g)?.length).toBe(2);
});
});