Skip to content

Commit fb60fd3

Browse files
added tests
1 parent 113ba89 commit fb60fd3

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

src/views/component-viewer/test/unit/component-viewer-webview-provider.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,89 @@ describe('ComponentViewerWebviewProvider', () => {
324324
expect(html).toContain('padding-left:20px');
325325
expect(html).toContain('padding-left:36px');
326326
});
327+
328+
it('re-renders when the data provider fires onDidChangeTreeData', () => {
329+
// Override onDidChangeTreeData to capture the listener
330+
let changeListener: (() => void) | undefined;
331+
Object.defineProperty(dataProvider, 'onDidChangeTreeData', {
332+
value: (listener: () => void) => {
333+
changeListener = listener;
334+
return { dispose: jest.fn() };
335+
},
336+
configurable: true,
337+
});
338+
339+
const { view, getHtml } = makeMockWebviewView();
340+
webviewProvider.resolveWebviewView(view, {} as never, {} as never);
341+
expect(getHtml()).toContain('No component data available');
342+
343+
// Mutate data and fire change event
344+
dataProvider.setRoots([makeGui({ getGuiName: () => 'Dynamic' })]);
345+
changeListener?.();
346+
347+
expect(getHtml()).toContain('Dynamic');
348+
});
349+
350+
it('skips rendering a node whose getGuiId returns undefined', () => {
351+
const good = makeGui({ getGuiName: () => 'Good', getGuiId: () => 'ok' });
352+
const bad = makeGui({ getGuiName: () => 'Bad', getGuiId: () => undefined });
353+
dataProvider.setRoots([good, bad]);
354+
355+
const { view, getHtml } = makeMockWebviewView();
356+
webviewProvider.resolveWebviewView(view, {} as never, {} as never);
357+
358+
const html = getHtml();
359+
expect(html).toContain('Good');
360+
expect(html).not.toContain('Bad');
361+
});
362+
363+
it('handles undefined name and value gracefully', () => {
364+
const nodeNameOnly = makeGui({
365+
getGuiName: () => 'OnlyName',
366+
getGuiValue: () => undefined,
367+
getGuiId: () => 'n1',
368+
});
369+
const nodeValueOnly = makeGui({
370+
getGuiName: () => undefined,
371+
getGuiValue: () => 'OnlyValue',
372+
getGuiId: () => 'v1',
373+
});
374+
const nodeNeither = makeGui({
375+
getGuiName: () => undefined,
376+
getGuiValue: () => undefined,
377+
getGuiId: () => 'e1',
378+
});
379+
dataProvider.setRoots([nodeNameOnly, nodeValueOnly, nodeNeither]);
380+
381+
const { view, getHtml } = makeMockWebviewView();
382+
webviewProvider.resolveWebviewView(view, {} as never, {} as never);
383+
384+
const html = getHtml();
385+
expect(html).toContain('OnlyName');
386+
expect(html).toContain('OnlyValue');
387+
// Node with neither name nor value should still render (with empty tooltip)
388+
expect(html).toContain('data-row-id="e1"');
389+
});
390+
391+
it('includes CSP meta tag in rendered HTML', () => {
392+
const { view, getHtml } = makeMockWebviewView();
393+
webviewProvider.resolveWebviewView(view, {} as never, {} as never);
394+
expect(getHtml()).toContain('Content-Security-Policy');
395+
});
396+
397+
it('escapes single quotes in HTML output', () => {
398+
const node = makeGui({
399+
getGuiName: () => 'it\'s',
400+
getGuiValue: () => 'it\'s',
401+
getGuiId: () => 'sq1',
402+
});
403+
dataProvider.setRoots([node]);
404+
405+
const { view, getHtml } = makeMockWebviewView();
406+
webviewProvider.resolveWebviewView(view, {} as never, {} as never);
407+
408+
const html = getHtml();
409+
expect(html).toContain('it's');
410+
expect(html).not.toContain('it\'s');
411+
});
327412
});

0 commit comments

Comments
 (0)