UNPKG

vitest-sonar-reporter

Version:
90 lines (89 loc) 3.25 kB
import { escapeXML } from './xml-escape.js'; const NEWLINE = '\n'; /** * Generate XML. Reference: * * ```xml * <?xml version="1.0" encoding="UTF-8"?> * <testExecutions version="1"> * <file path="testx/ClassOneTest.xoo"> * <testCase name="test1" duration="5"/> * <testCase name="test2" duration="500"> * <skipped message="short message">other</skipped> * </testCase> * <testCase name="test3" duration="100"> * <failure message="short">stacktrace</failure> * </testCase> * <testCase name="test4" duration="500"> * <error message="short">stacktrace</error> * </testCase> * </file> * </testExecutions> * ``` */ export function generateXml(files) { return join('<?xml version="1.0" encoding="UTF-8"?>', NEWLINE, '<testExecutions version="1">', NEWLINE, files?.map(generateFileElement).join(NEWLINE), NEWLINE, '</testExecutions>'); } function generateFileElement(file) { return join(indent(1), `<file path="${escapeXML(file.name)}">`, NEWLINE, generateTestCases(file), NEWLINE, indent(1), `</file>`); } function generateTestCases(file) { const tests = file.tasks.map(getAllTests).flat(); return tests.map(generateTestCaseElement).join(NEWLINE); } function generateTestCaseElement(test) { const start = join(indent(2), '<testCase ', `name="${escapeXML(generateTestCaseName(test))}"`, getDurationAttribute(test)); if (test.result?.state === 'fail') { return parseErrors(test) ?.map((error) => { const element = error?.name === 'AssertionError' ? 'failure' : 'error'; return join(start, '>', NEWLINE, indent(3), `<${element} message="${escapeXML(error?.message)}">`, NEWLINE, indent(4), `<![CDATA[${escapeXML(error?.stack)}]]>`, NEWLINE, indent(3), `</${element}>`, NEWLINE, indent(2), '</testCase>'); }) .join(NEWLINE); } if (test.mode === 'skip' || test.mode === 'todo' || // These might work in future? test.result?.state === 'skip' || test.result?.state === 'todo') { return join(start, '>', NEWLINE, indent(3), `<skipped message="${escapeXML(test.name)}" />`, NEWLINE, indent(2), '</testCase>'); } return join(start, ' />'); } function getAllTests(task) { const tests = []; // @ts-expect-error -- Vitest v2 only if (task.type === 'custom') { return tests; } if (task.type === 'test') { return [...tests, task]; } return [...tests, ...task.tasks.map(getAllTests).flat()]; } function getDurationAttribute(test) { const duration = test.result?.duration; if (typeof duration !== 'number') { return ` duration="0"`; } return ` duration="${Math.round(duration)}"`; } function generateTestCaseName(task) { if (task.suite && task.suite.name) { return `${generateTestCaseName(task.suite)} - ${task.name}`; } return task.name; } function join(...lines) { return lines.filter(Boolean).join(''); } function indent(level) { return ' '.repeat(level); } function parseErrors(test) { // Vitest v1-beta-02 and 0.x if (test.result && 'error' in test.result) return [test.result.error]; // Vitest v1-beta-03 return test.result?.errors; }