mirror of
https://github.com/dorny/test-reporter.git
synced 2026-03-21 23:52:12 +01:00
Merge pull request #629 from dorny/feature/601_eslint_v9
This commit is contained in:
commit
b3a9df8841
13 changed files with 898 additions and 751 deletions
|
|
@ -1,4 +0,0 @@
|
|||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
jest.config.js
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
{
|
||||
"plugins": ["import", "jest", "@typescript-eslint"],
|
||||
"extends": ["plugin:github/recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"i18n-text/no-en": "off",
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"import/no-named-as-default": "off",
|
||||
"no-shadow": "off",
|
||||
"no-unused-vars": "off",
|
||||
"prefer-template": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", {"varsIgnorePattern": "^_"}],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-comment": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"settings": {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts", ".tsx"]
|
||||
},
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## 2.6.0
|
||||
* Fix: For `workflow_run` events, resolve the commit of the check run from related pull request head commits first (matching `workflow_run.head_branch`, then first PR), and fall back to `workflow_run.head_sha` for non-PR runs https://github.com/dorny/test-reporter/pull/673
|
||||
* Maintenance: Upgrade to ESLint v9 https://github.com/dorny/test-reporter/pull/629
|
||||
|
||||
## 2.5.0
|
||||
* Feature: Add Nette Tester support with `tester-junit` reporter https://github.com/dorny/test-reporter/pull/707
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ describe('getBadge', () => {
|
|||
badgeTitle: 'tests'
|
||||
}
|
||||
const badge = getBadge(5, 0, 1, options)
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('handles badge title with single hyphen', () => {
|
||||
|
|
@ -28,7 +30,9 @@ describe('getBadge', () => {
|
|||
}
|
||||
const badge = getBadge(10, 0, 0, options)
|
||||
// All hyphens in the title should be encoded as --
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('handles badge title with multiple underscores', () => {
|
||||
|
|
@ -38,7 +42,9 @@ describe('getBadge', () => {
|
|||
}
|
||||
const badge = getBadge(10, 0, 0, options)
|
||||
// All underscores in the title should be encoded as __
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('handles badge title with version format containing hyphen', () => {
|
||||
|
|
@ -48,7 +54,9 @@ describe('getBadge', () => {
|
|||
}
|
||||
const badge = getBadge(1, 0, 0, options)
|
||||
// The hyphen in "12.0-ubi" should be encoded as --
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('handles badge title with dots and hyphens', () => {
|
||||
|
|
@ -57,7 +65,9 @@ describe('getBadge', () => {
|
|||
badgeTitle: 'v1.2.3-beta-test'
|
||||
}
|
||||
const badge = getBadge(4, 1, 0, options)
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves structural hyphens between label and message', () => {
|
||||
|
|
@ -67,7 +77,9 @@ describe('getBadge', () => {
|
|||
}
|
||||
const badge = getBadge(2, 3, 1, options)
|
||||
// The URI should have literal hyphens separating title-message-color
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -107,7 +119,9 @@ describe('getBadge', () => {
|
|||
it('includes passed, failed and skipped counts', () => {
|
||||
const options: ReportOptions = {...DEFAULT_OPTIONS}
|
||||
const badge = getBadge(5, 2, 1, options)
|
||||
expect(badge).toBe('')
|
||||
expect(badge).toBe(
|
||||
''
|
||||
)
|
||||
})
|
||||
|
||||
it('uses "none" message when no tests', () => {
|
||||
|
|
@ -117,4 +131,3 @@ describe('getBadge', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
27
dist/index.js
generated
vendored
27
dist/index.js
generated
vendored
|
|
@ -56676,7 +56676,8 @@ class DotnetTrxParser {
|
|||
}
|
||||
}
|
||||
getTestClasses(trx) {
|
||||
if (trx.TestRun.TestDefinitions === undefined || trx.TestRun.Results === undefined ||
|
||||
if (trx.TestRun.TestDefinitions === undefined ||
|
||||
trx.TestRun.Results === undefined ||
|
||||
!trx.TestRun.TestDefinitions.some(td => td.UnitTest && Array.isArray(td.UnitTest))) {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -56692,7 +56693,7 @@ class DotnetTrxParser {
|
|||
}));
|
||||
const testClasses = {};
|
||||
for (const r of unitTestsResults) {
|
||||
const className = r.test.TestMethod[0].$.className ?? "Unclassified";
|
||||
const className = r.test.TestMethod[0].$.className ?? 'Unclassified';
|
||||
let tc = testClasses[className];
|
||||
if (tc === undefined) {
|
||||
tc = new TestClass(className);
|
||||
|
|
@ -56799,7 +56800,10 @@ class GolangJsonParser {
|
|||
return this.getTestRunResult(path, events);
|
||||
}
|
||||
async getGolangTestEvents(path, content) {
|
||||
return content.trim().split('\n').map((line, index) => {
|
||||
return content
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line, index) => {
|
||||
try {
|
||||
return JSON.parse(line);
|
||||
}
|
||||
|
|
@ -56833,9 +56837,8 @@ class GolangJsonParser {
|
|||
if (!event.Test) {
|
||||
continue;
|
||||
}
|
||||
let groupName;
|
||||
let rest;
|
||||
[groupName, ...rest] = event.Test.split('/');
|
||||
const [first, ...rest] = event.Test.split('/');
|
||||
let groupName = first;
|
||||
let testName = rest.join('/');
|
||||
if (!testName) {
|
||||
testName = groupName;
|
||||
|
|
@ -56847,9 +56850,7 @@ class GolangJsonParser {
|
|||
suite.groups.push(group);
|
||||
}
|
||||
const lastEvent = eventGroup.at(-1);
|
||||
const result = lastEvent.Action === 'pass' ? 'success'
|
||||
: lastEvent.Action === 'skip' ? 'skipped'
|
||||
: 'failed';
|
||||
const result = lastEvent.Action === 'pass' ? 'success' : lastEvent.Action === 'skip' ? 'skipped' : 'failed';
|
||||
if (lastEvent.Elapsed === undefined) {
|
||||
throw new Error('missing elapsed on final test event');
|
||||
}
|
||||
|
|
@ -56860,14 +56861,14 @@ class GolangJsonParser {
|
|||
.filter(e => e.Action === 'output')
|
||||
.map(e => e.Output ?? '')
|
||||
// Go output prepends indentation to help group tests - remove it
|
||||
.map(o => o.replace(/^ /, ''));
|
||||
.map(o => o.replace(/^ {4}/, ''));
|
||||
// First and last lines will be generic "test started" and "test finished" lines - remove them
|
||||
outputEvents.splice(0, 1);
|
||||
outputEvents.splice(-1, 1);
|
||||
const details = outputEvents.join('');
|
||||
error = {
|
||||
message: details,
|
||||
details: details
|
||||
details
|
||||
};
|
||||
}
|
||||
group.tests.push(new TestCaseResult(testName, result, time, error));
|
||||
|
|
@ -57402,7 +57403,7 @@ class PhpunitJunitParser {
|
|||
return undefined;
|
||||
}
|
||||
const failure = failures[0];
|
||||
const details = typeof failure === 'string' ? failure : failure._ ?? '';
|
||||
const details = typeof failure === 'string' ? failure : (failure._ ?? '');
|
||||
// PHPUnit provides file path directly in testcase attributes
|
||||
let filePath;
|
||||
let line;
|
||||
|
|
@ -57790,7 +57791,7 @@ class NetteTesterJunitParser {
|
|||
}
|
||||
const failure = failures[0];
|
||||
// For Nette Tester, details are in the message attribute, not as inner text
|
||||
const details = typeof failure === 'string' ? failure : failure._ ?? failure.$?.message ?? '';
|
||||
const details = typeof failure === 'string' ? failure : (failure._ ?? failure.$?.message ?? '');
|
||||
// Try to extract file path and line from error details
|
||||
let errorFilePath;
|
||||
let line;
|
||||
|
|
|
|||
73
eslint.config.mjs
Normal file
73
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import github from 'eslint-plugin-github'
|
||||
import jest from 'eslint-plugin-jest'
|
||||
|
||||
export default [
|
||||
github.getFlatConfigs().recommended,
|
||||
...github.getFlatConfigs().typescript,
|
||||
{
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx']
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: './tsconfig.json',
|
||||
alwaysTryTypes: true
|
||||
},
|
||||
node: {
|
||||
extensions: ['.js', '.mjs', '.ts', '.tsx']
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['src/**/*.ts'],
|
||||
rules: {
|
||||
'i18n-text/no-en': 'off',
|
||||
'eslint-comments/no-use': 'off',
|
||||
'import/no-namespace': 'off',
|
||||
'import/no-named-as-default': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'prefer-template': 'off',
|
||||
camelcase: 'off',
|
||||
semi: 'off',
|
||||
'@typescript-eslint/array-type': ['error', {default: 'array'}],
|
||||
'@typescript-eslint/no-unused-vars': ['error', {varsIgnorePattern: '^_'}],
|
||||
'@typescript-eslint/no-shadow': ['error'],
|
||||
// Modern replacements for deprecated rules from the legacy config.
|
||||
'@typescript-eslint/no-empty-object-type': 'error',
|
||||
'@typescript-eslint/no-require-imports': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['__tests__/**/*.test.ts'],
|
||||
...jest.configs['flat/recommended'],
|
||||
plugins: {
|
||||
jest
|
||||
},
|
||||
languageOptions: {
|
||||
globals: jest.environments.globals.globals
|
||||
},
|
||||
rules: {
|
||||
'i18n-text/no-en': 'off',
|
||||
'import/no-namespace': 'off',
|
||||
'@typescript-eslint/array-type': ['error', {default: 'array'}],
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: [
|
||||
'dist/**',
|
||||
'lib/**',
|
||||
'node_modules/**',
|
||||
'__tests__/__snapshots__/**',
|
||||
'__tests__/__results__/**',
|
||||
'assets/**',
|
||||
'reports/**',
|
||||
'eslint.config.mjs',
|
||||
'jest.config.cjs'
|
||||
]
|
||||
}
|
||||
]
|
||||
1367
package-lock.json
generated
1367
package-lock.json
generated
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
|
@ -9,7 +9,7 @@
|
|||
"build": "tsc",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"lint": "eslint",
|
||||
"package": "ncc build --license licenses.txt && eolConverter lf 'dist/*'",
|
||||
"version": "npm run build && npm run package && git add dist/*",
|
||||
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --ci --reporters=default --reporters=jest-junit",
|
||||
|
|
@ -52,16 +52,16 @@
|
|||
"@types/node": "^20.19.23",
|
||||
"@types/picomatch": "^4.0.2",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
||||
"@typescript-eslint/parser": "^8.56.1",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"eol-converter-cli": "^1.1.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-import-resolver-typescript": "^3.10.1",
|
||||
"eslint-plugin-github": "^4.10.2",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-github": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^28.14.0",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-jest": "^29.15.0",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"jest": "^30.2.0",
|
||||
"jest-junit": "^16.0.0",
|
||||
"js-yaml": "^4.1.1",
|
||||
|
|
|
|||
|
|
@ -62,8 +62,11 @@ export class DotnetTrxParser implements TestParser {
|
|||
}
|
||||
|
||||
private getTestClasses(trx: TrxReport): TestClass[] {
|
||||
if (trx.TestRun.TestDefinitions === undefined || trx.TestRun.Results === undefined ||
|
||||
!trx.TestRun.TestDefinitions.some(td => td.UnitTest && Array.isArray(td.UnitTest))) {
|
||||
if (
|
||||
trx.TestRun.TestDefinitions === undefined ||
|
||||
trx.TestRun.Results === undefined ||
|
||||
!trx.TestRun.TestDefinitions.some(td => td.UnitTest && Array.isArray(td.UnitTest))
|
||||
) {
|
||||
return []
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +84,7 @@ export class DotnetTrxParser implements TestParser {
|
|||
|
||||
const testClasses: {[name: string]: TestClass} = {}
|
||||
for (const r of unitTestsResults) {
|
||||
const className = r.test.TestMethod[0].$.className ?? "Unclassified"
|
||||
const className = r.test.TestMethod[0].$.className ?? 'Unclassified'
|
||||
let tc = testClasses[className]
|
||||
if (tc === undefined) {
|
||||
tc = new TestClass(className)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { ParseOptions, TestParser } from '../../test-parser.js'
|
||||
import {ParseOptions, TestParser} from '../../test-parser.js'
|
||||
|
||||
import { GoTestEvent } from './golang-json-types.js'
|
||||
import { getExceptionSource } from '../../utils/node-utils.js'
|
||||
import { getBasePath, normalizeFilePath } from '../../utils/path-utils.js'
|
||||
import {GoTestEvent} from './golang-json-types.js'
|
||||
|
||||
import {
|
||||
TestExecutionResult,
|
||||
|
|
@ -16,7 +14,7 @@ import {
|
|||
export class GolangJsonParser implements TestParser {
|
||||
assumedWorkDir: string | undefined
|
||||
|
||||
constructor(readonly options: ParseOptions) { }
|
||||
constructor(readonly options: ParseOptions) {}
|
||||
|
||||
async parse(path: string, content: string): Promise<TestRunResult> {
|
||||
const events = await this.getGolangTestEvents(path, content)
|
||||
|
|
@ -24,7 +22,10 @@ export class GolangJsonParser implements TestParser {
|
|||
}
|
||||
|
||||
private async getGolangTestEvents(path: string, content: string): Promise<GoTestEvent[]> {
|
||||
return content.trim().split('\n').map((line, index) => {
|
||||
return content
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line, index) => {
|
||||
try {
|
||||
return JSON.parse(line) as GoTestEvent
|
||||
} catch (e) {
|
||||
|
|
@ -63,9 +64,8 @@ export class GolangJsonParser implements TestParser {
|
|||
continue
|
||||
}
|
||||
|
||||
let groupName: string | null
|
||||
let rest: string[]
|
||||
[groupName, ...rest] = event.Test.split('/')
|
||||
const [first, ...rest] = event.Test.split('/')
|
||||
let groupName: string | null = first
|
||||
let testName = rest.join('/')
|
||||
if (!testName) {
|
||||
testName = groupName
|
||||
|
|
@ -80,9 +80,8 @@ export class GolangJsonParser implements TestParser {
|
|||
|
||||
const lastEvent = eventGroup.at(-1)!
|
||||
|
||||
const result: TestExecutionResult = lastEvent.Action === 'pass' ? 'success'
|
||||
: lastEvent.Action === 'skip' ? 'skipped'
|
||||
: 'failed'
|
||||
const result: TestExecutionResult =
|
||||
lastEvent.Action === 'pass' ? 'success' : lastEvent.Action === 'skip' ? 'skipped' : 'failed'
|
||||
if (lastEvent.Elapsed === undefined) {
|
||||
throw new Error('missing elapsed on final test event')
|
||||
}
|
||||
|
|
@ -94,7 +93,7 @@ export class GolangJsonParser implements TestParser {
|
|||
.filter(e => e.Action === 'output')
|
||||
.map(e => e.Output ?? '')
|
||||
// Go output prepends indentation to help group tests - remove it
|
||||
.map(o => o.replace(/^ /, ''))
|
||||
.map(o => o.replace(/^ {4}/, ''))
|
||||
|
||||
// First and last lines will be generic "test started" and "test finished" lines - remove them
|
||||
outputEvents.splice(0, 1)
|
||||
|
|
@ -103,7 +102,7 @@ export class GolangJsonParser implements TestParser {
|
|||
const details = outputEvents.join('')
|
||||
error = {
|
||||
message: details,
|
||||
details: details
|
||||
details
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,4 @@
|
|||
export type GoTestAction = 'start'
|
||||
| 'run'
|
||||
| 'pause'
|
||||
| 'cont'
|
||||
| 'pass'
|
||||
| 'bench'
|
||||
| 'fail'
|
||||
| 'output'
|
||||
| 'skip'
|
||||
export type GoTestAction = 'start' | 'run' | 'pause' | 'cont' | 'pass' | 'bench' | 'fail' | 'output' | 'skip'
|
||||
|
||||
export type GoTestEvent = {
|
||||
Time: string
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export class PhpunitJunitParser implements TestParser {
|
|||
}
|
||||
|
||||
const failure = failures[0]
|
||||
const details = typeof failure === 'string' ? failure : failure._ ?? ''
|
||||
const details = typeof failure === 'string' ? failure : (failure._ ?? '')
|
||||
|
||||
// PHPUnit provides file path directly in testcase attributes
|
||||
let filePath: string | undefined
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ export class NetteTesterJunitParser implements TestParser {
|
|||
|
||||
const failure = failures[0]
|
||||
// For Nette Tester, details are in the message attribute, not as inner text
|
||||
const details = typeof failure === 'string' ? failure : failure._ ?? failure.$?.message ?? ''
|
||||
const details = typeof failure === 'string' ? failure : (failure._ ?? failure.$?.message ?? '')
|
||||
|
||||
// Try to extract file path and line from error details
|
||||
let errorFilePath: string | undefined
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue