diff --git a/package.json b/package.json index bb25470..8cce7e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qas-cli", - "version": "0.3.3", + "version": "0.3.4", "description": "QAS CLI is a command line tool for submitting your automation test results to QA Sphere at https://qasphere.com/", "type": "module", "main": "./build/bin/qasphere.js", diff --git a/src/tests/fixtures/junit-xml/jest-failure-type-missing.xml b/src/tests/fixtures/junit-xml/jest-failure-type-missing.xml new file mode 100644 index 0000000..bb98059 --- /dev/null +++ b/src/tests/fixtures/junit-xml/jest-failure-type-missing.xml @@ -0,0 +1,28 @@ + + + + + + + Error: expect(received).toBe(expected) // Object.is equality + +Expected: 2 +Received: 3 + at Object.toBe (/Users/a/tmp/jest-test/src/math.test.js:10:28) + at Promise.then.completed (/Users/a/tmp/jest-test/node_modules/jest-circus/build/utils.js:298:28) + at new Promise (<anonymous>) + at callAsyncCircusFn (/Users/a/tmp/jest-test/node_modules/jest-circus/build/utils.js:231:10) + at _callCircusTest (/Users/a/tmp/jest-test/node_modules/jest-circus/build/run.js:316:40) + at _runTest (/Users/a/tmp/jest-test/node_modules/jest-circus/build/run.js:252:3) + at _runTestsForDescribeBlock (/Users/a/tmp/jest-test/node_modules/jest-circus/build/run.js:126:9) + at _runTestsForDescribeBlock (/Users/a/tmp/jest-test/node_modules/jest-circus/build/run.js:121:9) + at run (/Users/a/tmp/jest-test/node_modules/jest-circus/build/run.js:71:3) + at runAndTransformResultsToJestFormat (/Users/a/tmp/jest-test/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21) + at jestAdapter (/Users/a/tmp/jest-test/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19) + at runTestInternal (/Users/a/tmp/jest-test/node_modules/jest-runner/build/runTest.js:367:16) + at runTest (/Users/a/tmp/jest-test/node_modules/jest-runner/build/runTest.js:444:34) + + + + + \ No newline at end of file diff --git a/src/tests/junit-xml-parsing.spec.ts b/src/tests/junit-xml-parsing.spec.ts index e6dd520..dd6dc8d 100644 --- a/src/tests/junit-xml-parsing.spec.ts +++ b/src/tests/junit-xml-parsing.spec.ts @@ -83,4 +83,27 @@ describe('Junit XML parsing', () => { // Message should include system-out content but not fail on empty system-err expect(result.testcases[0].message).toContain('ViewManager initialized') }) + + test('Should handle Jest failure without type attribute', async () => { + const xmlPath = `${xmlBasePath}/jest-failure-type-missing.xml` + const xmlContent = await readFile(xmlPath, 'utf8') + + const result = await parseJUnitXml(xmlContent, xmlBasePath) + expect(result.testcases).toHaveLength(3) + + // Verify test result types + const typeCounts = result.testcases.reduce((acc, tc) => { + acc[tc.type] = (acc[tc.type] || 0) + 1 + return acc + }, {} as Record) + + expect(typeCounts.success).toBe(2) + expect(typeCounts.failure).toBe(1) + + // Find the failure test case + const failedTest = result.testcases.find(tc => tc.type === 'failure') + expect(failedTest).toBeDefined() + expect(failedTest?.name).toContain('subtracts two numbers correctly') + expect(failedTest?.message).toContain('expect(received).toBe(expected)') + }) }) diff --git a/src/utils/junit/junitXmlParser.ts b/src/utils/junit/junitXmlParser.ts index 881365b..a40a856 100644 --- a/src/utils/junit/junitXmlParser.ts +++ b/src/utils/junit/junitXmlParser.ts @@ -4,6 +4,13 @@ import { readFile } from 'fs/promises' import xml from 'xml2js' import z from 'zod' +// Note about junit xml schema: +// there are multiple schemas on the internet, and apparently some are more strict than others +// we have to use LESS strict schema (see one from Jest, based on Jenkins JUnit schema) +// see https://github.com/jest-community/jest-junit/blob/master/__tests__/lib/junit.xsd#L42 + + + const stringContent = z.object({ _: z.string().optional(), }) @@ -11,8 +18,8 @@ const stringContent = z.object({ const failureErrorSchema = stringContent.extend({ $: z.object({ message: z.string().optional(), - type: z.string(), // type attribute is required for failure and error - }), + type: z.string().optional(), // type attribute is optional (some test runners like Jest don't include it) + }).optional(), }) // As per https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd, only message attribute