gabriel / musehub public
domain-viewers.test.ts typescript
90 lines 3.1 KB
Raw
sha256:34035d72cef530c1ab9d6a6f53be18d803dde705fc3157617d70352a96d0747b Merge branch 'fix/wire-push-external-parent-manifest' into dev Human 8 days ago
1 import { describe, it, expect } from 'vitest';
2 import {
3 renderSymbolGraphViewer,
4 renderPianoRollViewer,
5 renderGenericViewer,
6 renderDomainViewer,
7 } from './domain-viewers';
8
9 // Minimal HTMLElement shim — vitest runs in node, no real DOM/SVG needed
10 // since these functions only ever set innerHTML to a plain string.
11 function makeContainer(): HTMLElement {
12 return { innerHTML: '', clientWidth: 600 } as unknown as HTMLElement;
13 }
14
15 describe('renderSymbolGraphViewer', () => {
16 it('renders one labeled node per dimension', () => {
17 const el = makeContainer();
18 renderSymbolGraphViewer(el, [{ name: 'file' }, { name: 'symbol' }]);
19 expect(el.innerHTML).toContain('<svg');
20 expect(el.innerHTML).toContain('file');
21 expect(el.innerHTML).toContain('symbol');
22 });
23
24 it('renders a placeholder node when no dimensions are declared', () => {
25 const el = makeContainer();
26 renderSymbolGraphViewer(el, []);
27 expect(el.innerHTML).toContain('state');
28 });
29
30 it('escapes dimension names to prevent injection', () => {
31 const el = makeContainer();
32 renderSymbolGraphViewer(el, [{ name: '<script>alert(1)</script>' }]);
33 expect(el.innerHTML).not.toContain('<script>');
34 expect(el.innerHTML).toContain('&lt;script&gt;');
35 });
36 });
37
38 describe('renderPianoRollViewer', () => {
39 it('renders one track row per dimension', () => {
40 const el = makeContainer();
41 renderPianoRollViewer(el, [{ name: 'drums' }, { name: 'bass' }, { name: 'lead' }]);
42 expect(el.innerHTML).toContain('<svg');
43 expect(el.innerHTML).toContain('drums');
44 expect(el.innerHTML).toContain('bass');
45 expect(el.innerHTML).toContain('lead');
46 });
47
48 it('is deterministic for the same dimension name', () => {
49 const a = makeContainer();
50 const b = makeContainer();
51 renderPianoRollViewer(a, [{ name: 'drums' }]);
52 renderPianoRollViewer(b, [{ name: 'drums' }]);
53 expect(a.innerHTML).toBe(b.innerHTML);
54 });
55 });
56
57 describe('renderGenericViewer', () => {
58 it('lists declared dimensions with descriptions', () => {
59 const el = makeContainer();
60 renderGenericViewer(el, [{ name: 'notes', description: 'Note events' }]);
61 expect(el.innerHTML).toContain('notes');
62 expect(el.innerHTML).toContain('Note events');
63 });
64
65 it('shows an informative empty state, not a blank render', () => {
66 const el = makeContainer();
67 renderGenericViewer(el, []);
68 expect(el.innerHTML.toLowerCase()).toContain('no dimensions');
69 });
70 });
71
72 describe('renderDomainViewer dispatch', () => {
73 it('dispatches symbol_graph to the graph renderer', () => {
74 const el = makeContainer();
75 renderDomainViewer(el, 'symbol_graph', [{ name: 'file' }]);
76 expect(el.innerHTML).toContain('Symbol graph preview');
77 });
78
79 it('dispatches piano_roll to the track renderer', () => {
80 const el = makeContainer();
81 renderDomainViewer(el, 'piano_roll', [{ name: 'drums' }]);
82 expect(el.innerHTML).toContain('Track preview');
83 });
84
85 it('falls back to the generic renderer for anything else', () => {
86 const el = makeContainer();
87 renderDomainViewer(el, 'generic', [{ name: 'x' }]);
88 expect(el.innerHTML).toContain('domain-viewer-list');
89 });
90 });
File History 3 commits
sha256:34035d72cef530c1ab9d6a6f53be18d803dde705fc3157617d70352a96d0747b Merge branch 'fix/wire-push-external-parent-manifest' into dev Human 8 days ago
sha256:fc04e4cae9e1774d6a21b65c45daeed0e6787eb581d13aa1b03bfe9384a34226 Merge branch 'fix/two-column-scroll-layout' into dev Human 8 days ago
sha256:408916fc5973ba59c6e4eebaa80ebdcc801c0a63205651e25009d11548f79454 chore: bump version to 0.2.0.dev2 — nightly.2, matching muse Sonnet 4.6 patch 11 days ago