1
0
Fork 0
mirror of https://github.com/dorny/test-reporter.git synced 2026-03-21 23:52:12 +01:00

Modernize ESLint configuration

This commit is contained in:
Jozef Izso 2026-03-02 17:15:02 +01:00
parent 393efa337c
commit eed2d2d031
Failed to extract signature
8 changed files with 86 additions and 121 deletions

View file

@ -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`
}
}
}
}

View file

@ -8,7 +8,9 @@ describe('getBadge', () => {
badgeTitle: 'tests'
}
const badge = getBadge(5, 0, 1, options)
expect(badge).toBe('![Tests passed successfully](https://img.shields.io/badge/tests-5%20passed%2C%201%20skipped-success)')
expect(badge).toBe(
'![Tests passed successfully](https://img.shields.io/badge/tests-5%20passed%2C%201%20skipped-success)'
)
})
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('![Tests passed successfully](https://img.shields.io/badge/integration--api--tests-10%20passed-success)')
expect(badge).toBe(
'![Tests passed successfully](https://img.shields.io/badge/integration--api--tests-10%20passed-success)'
)
})
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('![Tests passed successfully](https://img.shields.io/badge/my__integration__test-10%20passed-success)')
expect(badge).toBe(
'![Tests passed successfully](https://img.shields.io/badge/my__integration__test-10%20passed-success)'
)
})
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('![Tests passed successfully](https://img.shields.io/badge/MariaDb%2012.0--ubi%20database%20tests-1%20passed-success)')
expect(badge).toBe(
'![Tests passed successfully](https://img.shields.io/badge/MariaDb%2012.0--ubi%20database%20tests-1%20passed-success)'
)
})
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('![Tests failed](https://img.shields.io/badge/v1.2.3--beta--test-4%20passed%2C%201%20failed-critical)')
expect(badge).toBe(
'![Tests failed](https://img.shields.io/badge/v1.2.3--beta--test-4%20passed%2C%201%20failed-critical)'
)
})
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('![Tests failed](https://img.shields.io/badge/test--suite-2%20passed%2C%203%20failed%2C%201%20skipped-critical)')
expect(badge).toBe(
'![Tests failed](https://img.shields.io/badge/test--suite-2%20passed%2C%203%20failed%2C%201%20skipped-critical)'
)
})
})
@ -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('![Tests failed](https://img.shields.io/badge/tests-5%20passed%2C%202%20failed%2C%201%20skipped-critical)')
expect(badge).toBe(
'![Tests failed](https://img.shields.io/badge/tests-5%20passed%2C%202%20failed%2C%201%20skipped-critical)'
)
})
it('uses "none" message when no tests', () => {
@ -117,4 +131,3 @@ describe('getBadge', () => {
})
})
})

View file

@ -4,32 +4,58 @@ 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: {
'no-shadow': 'off',
'import/no-namespace': 'off',
'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/array-type": ['error', {default: 'array'}],
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,
jest
},
languageOptions: {
globals: jest.environments.globals.globals,
globals: jest.environments.globals.globals
},
rules: {
'i18n-text/no-en': 'off',
'import/no-namespace': 'off',
"@typescript-eslint/array-type": ['error', {default: 'array'}],
},
'@typescript-eslint/array-type': ['error', {default: 'array'}],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-function-return-type': 'off'
}
},
{
ignores: [
@ -41,7 +67,7 @@ export default [
'assets/**',
'reports/**',
'eslint.config.mjs',
'jest.config.cjs',
],
},
'jest.config.cjs'
]
}
]

View file

@ -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)

View file

@ -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,13 +22,16 @@ export class GolangJsonParser implements TestParser {
}
private async getGolangTestEvents(path: string, content: string): Promise<GoTestEvent[]> {
return content.trim().split('\n').map((line, index) => {
try {
return JSON.parse(line) as GoTestEvent
} catch (e) {
throw new Error(`Invalid JSON at ${path} line ${index + 1}\n\n${e}`)
}
})
return content
.trim()
.split('\n')
.map((line, index) => {
try {
return JSON.parse(line) as GoTestEvent
} catch (e) {
throw new Error(`Invalid JSON at ${path} line ${index + 1}\n\n${e}`)
}
})
}
private getTestRunResult(path: string, events: GoTestEvent[]): TestRunResult {
@ -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
}
}

View file

@ -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

View file

@ -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

View file

@ -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