From c783087cf8dee35df3adad95c7359dc0ed86709e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Chalk?= Date: Tue, 23 Jun 2026 11:05:49 +0200 Subject: [PATCH 1/2] test(eslint-config): catch disabled rules in tests --- .../tests/configs/angular.spec.js | 21 +++++++--- .../tests/configs/cypress.spec.js | 2 +- .../tests/configs/graphql.spec.js | 9 ++-- .../tests/configs/javascript.spec.js | 23 +++++++---- .../eslint-config/tests/configs/jest.spec.js | 6 +-- .../eslint-config/tests/configs/ngrx.spec.js | 5 ++- .../eslint-config/tests/configs/node.spec.js | 4 +- .../tests/configs/playwright.spec.js | 10 +++-- .../configs/react-testing-library.spec.js | 41 ++++++++++--------- .../eslint-config/tests/configs/react.spec.js | 10 +++-- .../tests/configs/storybook.spec.js | 9 ++-- .../tests/configs/typescript.spec.js | 17 +++++--- .../tests/configs/vitest.spec.js | 7 +++- .../eslint-config/tests/helpers/lint-utils.js | 9 ++-- 14 files changed, 107 insertions(+), 66 deletions(-) diff --git a/packages/eslint-config/tests/configs/angular.spec.js b/packages/eslint-config/tests/configs/angular.spec.js index 0a6fc3d..6ff30d6 100644 --- a/packages/eslint-config/tests/configs/angular.spec.js +++ b/packages/eslint-config/tests/configs/angular.spec.js @@ -30,44 +30,53 @@ describe('angular config', () => { const config = await loadConfig('src/app/app.component.ts'); expect(config.rules).toHaveProperty( '@angular-eslint/prefer-on-push-component-change-detection', + [1], ); }); it('should have explicitly added rule for HTML file', async () => { const config = await loadConfig('src/app/app.component.html'); - expect(config.rules).toHaveProperty('@angular-eslint/template/no-any'); + expect(config.rules).toHaveProperty('@angular-eslint/template/no-any', [2]); }); it('should have rule from extended typescript config', async () => { const config = await loadConfig('src/app/app.component.ts'); expect(config.rules).toHaveProperty( '@typescript-eslint/no-non-null-assertion', + [2], ); }); it('should have rule from extended recommended angular config', async () => { const config = await loadConfig('src/app/app.component.ts'); - expect(config.rules).toHaveProperty('@angular-eslint/contextual-lifecycle'); + expect(config.rules).toHaveProperty( + '@angular-eslint/contextual-lifecycle', + [2], + ); }); it('should have rule from extended recommended angular template config', async () => { const config = await loadConfig('src/app/app.component.html'); expect(config.rules).toHaveProperty( '@angular-eslint/template/banana-in-box', + [2], ); }); it('should have rule from extended angular template accessibility config', async () => { const config = await loadConfig('src/app/app.component.html'); - expect(config.rules).toHaveProperty('@angular-eslint/template/alt-text'); + expect(config.rules).toHaveProperty('@angular-eslint/template/alt-text', [ + 2, + ]); }); it('should have rule disabled if test file pattern matches', async () => { const config = await loadConfig( 'src/app/components/accordion/accordion.component.stories.ts', ); - expect( - config.rules?.['@angular-eslint/component-max-inline-declarations'], - ).toEqual([0]); + expect(config.rules).toHaveProperty( + '@angular-eslint/component-max-inline-declarations', + [0], + ); }); }); diff --git a/packages/eslint-config/tests/configs/cypress.spec.js b/packages/eslint-config/tests/configs/cypress.spec.js index a3b7833..89eb13e 100644 --- a/packages/eslint-config/tests/configs/cypress.spec.js +++ b/packages/eslint-config/tests/configs/cypress.spec.js @@ -31,6 +31,6 @@ describe('cypress config', () => { it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('cypress/no-force'); + expect(config.rules).toHaveProperty('cypress/no-force', [1]); }); }); diff --git a/packages/eslint-config/tests/configs/graphql.spec.js b/packages/eslint-config/tests/configs/graphql.spec.js index e48a046..cd7a80a 100644 --- a/packages/eslint-config/tests/configs/graphql.spec.js +++ b/packages/eslint-config/tests/configs/graphql.spec.js @@ -21,20 +21,23 @@ describe('graphql config', () => { it('should have rule from extended schema config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('@graphql-eslint/naming-convention'); + expect(config.rules).toHaveProperty('@graphql-eslint/naming-convention', [ + 2, + expect.any(Object), + ]); }); it('should have rule from extended relay config', async () => { const config = await loadConfig(); expect(config.rules).toHaveProperty( '@graphql-eslint/relay-connection-types', + [2], ); }); it('should have customized rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('@graphql-eslint/description-style'); - expect(config.rules?.['@graphql-eslint/description-style']).toEqual([ + expect(config.rules).toHaveProperty('@graphql-eslint/description-style', [ 1, { style: 'inline' }, ]); diff --git a/packages/eslint-config/tests/configs/javascript.spec.js b/packages/eslint-config/tests/configs/javascript.spec.js index 62a90b6..d6b7895 100644 --- a/packages/eslint-config/tests/configs/javascript.spec.js +++ b/packages/eslint-config/tests/configs/javascript.spec.js @@ -20,12 +20,16 @@ describe('javascript config', () => { it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('eqeqeq'); + expect(config.rules).toHaveProperty('eqeqeq', [ + 2, + 'always', + { null: 'never' }, + ]); }); it('should have implicitly extended rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('no-const-assign'); + expect(config.rules).toHaveProperty('no-const-assign', [2]); }); it('should not include any rule which requires type checking', async () => { @@ -38,21 +42,26 @@ describe('javascript config', () => { it('should have rule disabled if test file pattern matches', async () => { const config = await loadConfig('utils.spec.js'); - expect(config.rules?.['@typescript-eslint/no-non-null-assertion']).toEqual([ - 0, - ]); + expect(config.rules).toHaveProperty( + '@typescript-eslint/no-non-null-assertion', + [0], + ); }); it('should have rule disabled if known config file pattern matches', async () => { const config = await loadConfig('jest.config.ts'); - expect(config.rules?.['import/no-anonymous-default-export']).toEqual([0]); + expect(config.rules).toHaveProperty('import/no-anonymous-default-export', [ + 0, + ]); }); it('should have rule disabled if generated file pattern matches', async () => { const config = await loadConfig( 'src/graphql/generated/introspection-result.ts', ); - expect(config.rules?.['unicorn/no-abusive-eslint-disable']).toEqual([0]); + expect(config.rules).toHaveProperty('unicorn/no-abusive-eslint-disable', [ + 0, + ]); }); it('should not throw when linting project without tsconfig', async () => { diff --git a/packages/eslint-config/tests/configs/jest.spec.js b/packages/eslint-config/tests/configs/jest.spec.js index 36aa9c9..cfe0970 100644 --- a/packages/eslint-config/tests/configs/jest.spec.js +++ b/packages/eslint-config/tests/configs/jest.spec.js @@ -21,16 +21,16 @@ describe('jest config', () => { it('should have rule from extended recommended jest config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('jest/no-identical-title'); + expect(config.rules).toHaveProperty('jest/no-identical-title', [2]); }); it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('jest/no-test-return-statement'); + expect(config.rules).toHaveProperty('jest/no-test-return-statement', [1]); }); it('should have customized severity level for rule from extended config', async () => { const config = await loadConfig(); - expect(config.rules?.['jest/no-mocks-import']).toEqual([1]); + expect(config.rules).toHaveProperty('jest/no-mocks-import', [1]); }); }); diff --git a/packages/eslint-config/tests/configs/ngrx.spec.js b/packages/eslint-config/tests/configs/ngrx.spec.js index 146d1f1..f51907e 100644 --- a/packages/eslint-config/tests/configs/ngrx.spec.js +++ b/packages/eslint-config/tests/configs/ngrx.spec.js @@ -17,18 +17,19 @@ describe('ngrx config', () => { it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('rxjs-x/no-unsafe-catch'); + expect(config.rules).toHaveProperty('rxjs-x/no-unsafe-catch', [2]); }); it('should have rule from extended angular config', async () => { const config = await loadConfig(); expect(config.rules).toHaveProperty( '@angular-eslint/prefer-on-push-component-change-detection', + [1], ); }); it('should have rule from extended recommended ngrx config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('@ngrx/good-action-hygiene'); + expect(config.rules).toHaveProperty('@ngrx/good-action-hygiene', [1]); }); }); diff --git a/packages/eslint-config/tests/configs/node.spec.js b/packages/eslint-config/tests/configs/node.spec.js index ad17508..9d15e6d 100644 --- a/packages/eslint-config/tests/configs/node.spec.js +++ b/packages/eslint-config/tests/configs/node.spec.js @@ -16,12 +16,12 @@ describe('node config', () => { it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('n/prefer-promises/fs'); + expect(config.rules).toHaveProperty('n/prefer-promises/fs', [1]); }); it('should have rule from extended base config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('import/no-commonjs'); + expect(config.rules).toHaveProperty('import/no-commonjs', [2]); }); it('should not include any rule which requires type checking', async () => { diff --git a/packages/eslint-config/tests/configs/playwright.spec.js b/packages/eslint-config/tests/configs/playwright.spec.js index afdd9b5..fd00e74 100644 --- a/packages/eslint-config/tests/configs/playwright.spec.js +++ b/packages/eslint-config/tests/configs/playwright.spec.js @@ -36,16 +36,20 @@ describe('playwright config', () => { it('should have rule from extended recommended playwright config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('playwright/valid-expect'); + expect(config.rules).toHaveProperty('playwright/valid-expect', [2]); }); it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('playwright/prefer-native-locators'); + expect(config.rules).toHaveProperty('playwright/prefer-native-locators', [ + 1, + ]); }); it('should have customized severity level for rule from extended config', async () => { const config = await loadConfig(); - expect(config.rules?.['playwright/no-conditional-expect']).toEqual([1]); + expect(config.rules).toHaveProperty('playwright/no-conditional-expect', [ + 1, + ]); }); }); diff --git a/packages/eslint-config/tests/configs/react-testing-library.spec.js b/packages/eslint-config/tests/configs/react-testing-library.spec.js index 69ee271..7d389f5 100644 --- a/packages/eslint-config/tests/configs/react-testing-library.spec.js +++ b/packages/eslint-config/tests/configs/react-testing-library.spec.js @@ -28,39 +28,42 @@ describe('react-testing-library config', () => { it('should have rule from extended recommended react-testing-library config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('testing-library/await-async-events'); + expect(config.rules).toHaveProperty('testing-library/await-async-queries', [ + 2, + ]); }); it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('testing-library/prefer-user-event'); + expect(config.rules).toHaveProperty('testing-library/prefer-user-event', [ + 1, + ]); }); it('should have customized severity level for rule from extended config', async () => { const config = await loadConfig(); - expect(config.rules?.['testing-library/no-await-sync-queries']).toEqual([ - 1, - ]); + expect(config.rules).toHaveProperty( + 'testing-library/no-await-sync-queries', + [1], + ); }); it('should have customized rule', async () => { const config = await loadConfig(); expect(config.rules).toHaveProperty( 'testing-library/prefer-query-matchers', + [ + 1, + { + validEntries: [ + { matcher: 'toBeVisible', query: 'get' }, + { matcher: 'toHaveTextContent', query: 'get' }, + { matcher: 'toBeEnabled', query: 'get' }, + { matcher: 'toBeDisabled', query: 'get' }, + { matcher: 'toBeChecked', query: 'get' }, + ], + }, + ], ); - expect( - config.rules?.['testing-library/prefer-query-matchers'], - ).toStrictEqual([ - 1, - { - validEntries: [ - { matcher: 'toBeVisible', query: 'get' }, - { matcher: 'toHaveTextContent', query: 'get' }, - { matcher: 'toBeEnabled', query: 'get' }, - { matcher: 'toBeDisabled', query: 'get' }, - { matcher: 'toBeChecked', query: 'get' }, - ], - }, - ]); }); }); diff --git a/packages/eslint-config/tests/configs/react.spec.js b/packages/eslint-config/tests/configs/react.spec.js index 0b0da36..abee918 100644 --- a/packages/eslint-config/tests/configs/react.spec.js +++ b/packages/eslint-config/tests/configs/react.spec.js @@ -21,17 +21,19 @@ describe('react config', () => { it('should have rule from extended javascript config', async () => { const config = await loadConfig('components/Button.tsx'); - expect(config.rules).toHaveProperty('@typescript-eslint/no-unused-vars'); + expect(config.rules).toHaveProperty('@typescript-eslint/no-explicit-any', [ + 2, + ]); }); it('should have rule from extended recommended react config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('react/jsx-key'); + expect(config.rules).toHaveProperty('react/jsx-key', [2]); }); it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('react/no-array-index-key'); + expect(config.rules).toHaveProperty('react/no-array-index-key', [2]); }); it('should include react-hooks rule', async () => { @@ -41,6 +43,6 @@ describe('react config', () => { it('should have rule from extended recommended jsx-a11y config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('jsx-a11y/alt-text'); + expect(config.rules).toHaveProperty('jsx-a11y/alt-text', [2]); }); }); diff --git a/packages/eslint-config/tests/configs/storybook.spec.js b/packages/eslint-config/tests/configs/storybook.spec.js index 718037c..8ed03da 100644 --- a/packages/eslint-config/tests/configs/storybook.spec.js +++ b/packages/eslint-config/tests/configs/storybook.spec.js @@ -26,16 +26,19 @@ describe('storybook config', () => { it('should include storybook rule for .storybook directory', async () => { const config = await loadConfig('.storybook/main.js'); - expect(config.rules).toHaveProperty('storybook/no-uninstalled-addons'); + expect(config.rules).toHaveProperty( + 'storybook/no-uninstalled-addons', + expect.arrayContaining([2]), + ); }); it('should have rule from extended recommended config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('storybook/story-exports'); + expect(config.rules).toHaveProperty('storybook/story-exports', [2]); }); it('should have rule from extended csf config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('storybook/csf-component'); + expect(config.rules).toHaveProperty('storybook/csf-component', [1]); }); }); diff --git a/packages/eslint-config/tests/configs/typescript.spec.js b/packages/eslint-config/tests/configs/typescript.spec.js index 72f29bd..1646e72 100644 --- a/packages/eslint-config/tests/configs/typescript.spec.js +++ b/packages/eslint-config/tests/configs/typescript.spec.js @@ -1,5 +1,6 @@ // @ts-check +import { NAMING_CONVENTION_OPTIONS } from '../../src/lib/rule-options.js'; import { createLintUtils } from '../helpers/lint-utils.js'; describe('typescript config', () => { @@ -22,18 +23,22 @@ describe('typescript config', () => { it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('@typescript-eslint/naming-convention'); + expect(config.rules).toHaveProperty( + '@typescript-eslint/naming-convention', + [1, ...NAMING_CONVENTION_OPTIONS], + ); }); it('should have rule from extended base config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('@typescript-eslint/no-shadow'); + expect(config.rules).toHaveProperty('@typescript-eslint/no-shadow', [1]); }); it('should have rule from extended recommended type-checked config', async () => { const config = await loadConfig(); expect(config.rules).toHaveProperty( '@typescript-eslint/no-unsafe-assignment', + [2], ); }); @@ -41,14 +46,16 @@ describe('typescript config', () => { const config = await loadConfig(); expect(config.rules).toHaveProperty( '@typescript-eslint/no-non-null-assertion', + [2], ); }); it('should have rule disabled if test file pattern matches', async () => { const config = await loadConfig('index.test.ts'); - expect(config.rules?.['@typescript-eslint/no-unsafe-assignment']).toEqual([ - 0, - ]); + expect(config.rules).toHaveProperty( + '@typescript-eslint/no-unsafe-assignment', + [0], + ); }); it('should not include extra rules for non-TS file', async () => { diff --git a/packages/eslint-config/tests/configs/vitest.spec.js b/packages/eslint-config/tests/configs/vitest.spec.js index 18d4ef0..751b612 100644 --- a/packages/eslint-config/tests/configs/vitest.spec.js +++ b/packages/eslint-config/tests/configs/vitest.spec.js @@ -24,11 +24,14 @@ describe('vitest config', () => { it('should have rule from extended recommended vitest config', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('vitest/expect-expect'); + expect(config.rules).toHaveProperty( + 'vitest/expect-expect', + expect.arrayContaining([2]), + ); }); it('should have explicitly added rule', async () => { const config = await loadConfig(); - expect(config.rules).toHaveProperty('vitest/prefer-to-have-length'); + expect(config.rules).toHaveProperty('vitest/prefer-to-have-length', [1]); }); }); diff --git a/packages/eslint-config/tests/helpers/lint-utils.js b/packages/eslint-config/tests/helpers/lint-utils.js index afafd1b..05c80a5 100644 --- a/packages/eslint-config/tests/helpers/lint-utils.js +++ b/packages/eslint-config/tests/helpers/lint-utils.js @@ -71,18 +71,15 @@ export default [ }; /** @param {string[]} ruleIds */ - const loadRulesByIds = async (ruleIds, filePath = defaultFilePath) => { - const results = await eslint.lintFiles(filePath); - return eslint.getRulesMetaForResults([ + const loadRulesByIds = async (ruleIds, filePath = defaultFilePath) => + eslint.getRulesMetaForResults([ { - filePath: results[0]?.filePath ?? filePath, + filePath, // @ts-expect-error incomplete message (hack to load rule metadata) messages: ruleIds.map(ruleId => ({ ruleId })), suppressedMessages: [], }, ]); - }; - /** @param {string | string[]} patterns */ const lint = (patterns = defaultFilePath) => eslint.lintFiles(patterns); From 591e7154f18a33215da8a39339077b0c724fc720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Chalk?= Date: Tue, 23 Jun 2026 11:07:11 +0200 Subject: [PATCH 2/2] fix(eslint-config): enable type-checked rules --- packages/eslint-config/src/configs/typescript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-config/src/configs/typescript.js b/packages/eslint-config/src/configs/typescript.js index 452fb9a..ef78526 100644 --- a/packages/eslint-config/src/configs/typescript.js +++ b/packages/eslint-config/src/configs/typescript.js @@ -167,7 +167,7 @@ export default defineConfig( }, { name: 'code-pushup/typescript/disable-type-checked-for-javascript', - files: negatePatterns(TYPESCRIPT_EXTENDED_FILE_PATTERNS), + ignores: TYPESCRIPT_EXTENDED_FILE_PATTERNS, ...tseslint.configs.disableTypeChecked, }, );