jest-allure2-reporter
Version:
Idiomatic Jest reporter for Allure Framework
105 lines (98 loc) • 3.66 kB
text/typescript
import type { TestCaseResult } from '@jest/reporters';
import type {
Label,
Stage,
Status,
TestCaseCustomizer,
TestCaseExtractorContext,
} from 'jest-allure2-reporter';
import { compose2 } from '../common';
import * as custom from '../custom';
import { getStatusDetails } from '../../utils';
export const testCase: TestCaseCustomizer<TestCaseExtractorContext> = {
ignored: () => false,
historyId: ({ testCaseMetadata, result }) => testCaseMetadata.historyId ?? result.fullName,
displayName: ({ testCase, testCaseMetadata }) => testCaseMetadata.displayName ?? testCase.title,
fullName: ({ testCase, testCaseMetadata }) => testCaseMetadata.fullName ?? testCase.fullName,
description: ({ testCaseMetadata }) => testCaseMetadata.description?.join('\n\n') ?? '',
descriptionHtml: ({ testCaseMetadata }) => testCaseMetadata.descriptionHtml?.join('\n') ?? '',
start: ({ testCase, testCaseMetadata }) =>
testCaseMetadata.start ?? (testCaseMetadata.stop ?? Date.now()) - (testCase.duration ?? 0),
stop: ({ testCaseMetadata }) => testCaseMetadata.stop ?? Date.now(),
stage: ({ testCase, testCaseMetadata }) => testCaseMetadata.stage ?? getTestCaseStage(testCase),
status: ({ testCase, testCaseMetadata }) =>
testCaseMetadata.status ?? getTestCaseStatus(testCase),
statusDetails: ({ $, testCase, testCaseMetadata }) =>
$.stripAnsi(
testCaseMetadata.statusDetails ??
getStatusDetails((testCase.failureMessages ?? []).join('\n')),
),
attachments: ({ testCaseMetadata }) => testCaseMetadata.attachments ?? [],
parameters: ({ testCaseMetadata }) => testCaseMetadata.parameters ?? [],
labels: compose2(
custom.labels<TestCaseExtractorContext>({
suite: ({ testCase, filePath }) => testCase.ancestorTitles[0] ?? filePath.at(-1),
subSuite: ({ testCase }) => testCase.ancestorTitles.slice(1).join(' '),
}),
({ testCaseMetadata }): Label[] => testCaseMetadata.labels ?? [],
),
links: ({ testCaseMetadata }) => testCaseMetadata.links ?? [],
};
function getTestCaseStatus(testCase: TestCaseResult): Status {
const hasErrors = testCase.failureMessages?.length > 0;
const hasBuiltinErrors = hasErrors && testCase.failureMessages.some(looksLikeBroken);
switch (testCase.status) {
case 'passed': {
return 'passed';
}
case 'failed': {
return hasBuiltinErrors ? 'broken' : 'failed';
}
case 'skipped': {
return 'skipped';
}
case 'pending':
case 'todo':
case 'disabled': {
return 'skipped';
}
case 'focused': {
return hasErrors ? 'failed' : 'passed';
}
default: {
return 'unknown' as Status;
}
}
}
function looksLikeBroken(errorMessage: string): boolean {
return errorMessage
? errorMessage.startsWith('Error: \n') ||
errorMessage.startsWith('EvalError:') ||
errorMessage.startsWith('RangeError:') ||
errorMessage.startsWith('ReferenceError:') ||
errorMessage.startsWith('SyntaxError:') ||
errorMessage.startsWith('TypeError:') ||
errorMessage.startsWith('URIError:') ||
errorMessage.startsWith('AggregateError:') ||
errorMessage.startsWith('InternalError:') ||
errorMessage.startsWith('AllureRuntimeError:') ||
errorMessage.startsWith('AllureReporterError:')
: true;
}
function getTestCaseStage(testCase: TestCaseResult): Stage {
switch (testCase.status) {
case 'passed':
case 'focused': {
return 'finished';
}
case 'todo':
case 'disabled':
case 'pending':
case 'skipped': {
return 'pending';
}
default: {
return 'interrupted';
}
}
}