import { TextDocument } from 'vscode-languageserver-textdocument'; import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver/node'; import { validateTextDocument } from '../../server/src/providers/diagnostics'; function createDocument(content: string): TextDocument { return TextDocument.create('file:///test.html', 'html', 1, content); } // Mock connection that captures diagnostics function createMockConnection() { let lastDiagnostics: Diagnostic[] = []; return { sendDiagnostics: (params: { uri: string; diagnostics: Diagnostic[] }) => { lastDiagnostics = params.diagnostics; }, getDiagnostics: () => lastDiagnostics, }; } describe('DiagnosticsProvider', () => { describe('Required values', () => { it('reports error for directive missing required value', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const getError = diagnostics.find(d => d.message.includes('"get" requires a value')); expect(getError).toBeDefined(); expect(getError!.severity).toBe(DiagnosticSeverity.Error); }); it('does not report error for directive with value', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const getError = diagnostics.find(d => d.message.includes('"get" requires')); expect(getError).toBeUndefined(); }); it('does not report error for i18n-ns without value', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const nsError = diagnostics.find(d => d.message.includes('"i18n-ns" requires')); expect(nsError).toBeUndefined(); }); }); describe('Orphaned else/else-if', () => { it('reports error for else without preceding if', async () => { const content = '
Alt
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const elseError = diagnostics.find(d => d.message.includes('"else" must be preceded')); expect(elseError).toBeDefined(); }); it('does not report for else after if sibling', async () => { const content = '
VisibleHidden
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const elseError = diagnostics.find(d => d.message.includes('"else" must be preceded')); expect(elseError).toBeUndefined(); }); }); describe('Unknown filters', () => { it('warns about unknown filter names', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const filterWarn = diagnostics.find(d => d.message.includes('Unknown filter')); expect(filterWarn).toBeDefined(); }); it('does not warn about known filters', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const filterWarn = diagnostics.find(d => d.message.includes('Unknown filter')); expect(filterWarn).toBeUndefined(); }); }); describe('Invalid animations', () => { it('warns about unknown animation name', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const animWarn = diagnostics.find(d => d.message.includes('Unknown animation')); expect(animWarn).toBeDefined(); }); it('does not warn about valid animation', async () => { const content = '
'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const animWarn = diagnostics.find(d => d.message.includes('Unknown animation')); expect(animWarn).toBeUndefined(); }); }); describe('No false positives', () => { it('does not report diagnostics for plain HTML', async () => { const content = '

Hello World

'; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); expect(diagnostics.length).toBe(0); }); }); describe('foreach directive', () => { it('does not flag foreach without template as an error', async () => { const content = '
  • '; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const templateError = diagnostics.find(d => d.message.includes('template')); expect(templateError).toBeUndefined(); }); it('reports error for foreach without a value', async () => { const content = '
  • '; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const reqError = diagnostics.find(d => d.message.includes('"foreach" requires a value')); expect(reqError).toBeDefined(); }); }); describe('for directive', () => { it('does not flag valid for directive', async () => { const content = '
  • '; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const forError = diagnostics.find(d => d.message.includes('"for"')); expect(forError).toBeUndefined(); }); it('reports error for for directive without a value', async () => { const content = '
  • '; const doc = createDocument(content); const conn = createMockConnection(); await validateTextDocument(doc, conn as any); const diagnostics = conn.getDiagnostics(); const reqError = diagnostics.find(d => d.message.includes('"for" requires a value')); expect(reqError).toBeDefined(); }); }); });