diff --git a/.gitignore b/.gitignore index 9dc454418417..56a07006992d 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,6 @@ packages/**/.yarn .nx/cache .nx/workspace-data + +# Vitest type tests +tsconfig*.vitest-temp.json diff --git a/eslint.config.mjs b/eslint.config.mjs index fa6080adb037..d31a648c0327 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -35,6 +35,7 @@ const vitestFiles = [ 'packages/visitor-keys/tests/**/*.test.{ts,tsx,cts,mts}', 'packages/parser/tests/lib/**/*.test.{ts,tsx,cts,mts}', 'packages/parser/tests/test-utils/**/*.{ts,tsx,cts,mts}', + 'packages/utils/tests/**/*.test?(-d).{ts,tsx,cts,mts}', ]; export default tseslint.config( diff --git a/knip.ts b/knip.ts index e3bd837e2e7e..c718f12a580e 100644 --- a/knip.ts +++ b/knip.ts @@ -86,7 +86,6 @@ export default { }, 'packages/utils': { ignore: [ - 'tests/**/*.type-test.ts', 'typings/eslint.d.ts', 'typings/eslint-community-eslint-utils.d.ts', ], diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js deleted file mode 100644 index 910991b20cff..000000000000 --- a/packages/utils/jest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -// @ts-check -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - ...require('../../jest.config.base.js'), -}; diff --git a/packages/utils/package.json b/packages/utils/package.json index 3ae18a5a710b..60c8ea01fc5b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -57,10 +57,10 @@ "build": "tsc -b tsconfig.build.json", "postbuild": "downlevel-dts dist _ts4.3/dist --to=4.3", "clean": "tsc -b tsconfig.build.json --clean", - "postclean": "rimraf dist && rimraf _ts3.4 && rimraf _ts4.3 && rimraf coverage", + "postclean": "rimraf dist/ _ts4.3/ coverage/", "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", "lint": "npx nx lint", - "test": "jest", + "test": "vitest --run --config=$INIT_CWD/vitest.config.mts", "check-types": "npx nx typecheck" }, "dependencies": { @@ -74,11 +74,12 @@ "typescript": ">=4.8.4 <5.9.0" }, "devDependencies": { + "@vitest/coverage-v8": "^3.1.1", "downlevel-dts": "*", - "jest": "29.7.0", "prettier": "^3.2.5", "rimraf": "*", - "typescript": "*" + "typescript": "*", + "vitest": "^3.1.1" }, "funding": { "type": "opencollective", diff --git a/packages/utils/project.json b/packages/utils/project.json index fe765a0faff4..b5a83f94b080 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -1,12 +1,17 @@ { "name": "utils", "$schema": "../../node_modules/nx/schemas/project-schema.json", - "type": "library", - "implicitDependencies": [], + "projectType": "library", + "root": "packages/utils", + "sourceRoot": "packages/utils/src", "targets": { "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test", + "dependsOn": ["^build", "typecheck"] } } } diff --git a/packages/utils/tests/eslint-utils/RuleCreator.test.ts b/packages/utils/tests/eslint-utils/RuleCreator.test.ts index 6b78ece4a1ba..625ee3646f2f 100644 --- a/packages/utils/tests/eslint-utils/RuleCreator.test.ts +++ b/packages/utils/tests/eslint-utils/RuleCreator.test.ts @@ -1,6 +1,6 @@ import { ESLintUtils } from '../../src'; -describe('RuleCreator', () => { +describe(ESLintUtils.RuleCreator, () => { interface TestDocs { recommended?: 'yes'; } @@ -8,7 +8,7 @@ describe('RuleCreator', () => { const createRule = ESLintUtils.RuleCreator(name => `test/${name}`); it('createRule should be a function', () => { - expect(typeof createRule).toBe('function'); + expect(createRule).toBeTypeOf('function'); }); it('should create rule correctly', () => { diff --git a/packages/utils/tests/eslint-utils/applyDefault.test.ts b/packages/utils/tests/eslint-utils/applyDefault.test.ts index c56bdc4f83b9..d0da4243e890 100644 --- a/packages/utils/tests/eslint-utils/applyDefault.test.ts +++ b/packages/utils/tests/eslint-utils/applyDefault.test.ts @@ -1,6 +1,6 @@ import { ESLintUtils } from '../../src'; -describe('applyDefault', () => { +describe(ESLintUtils.applyDefault, () => { it('returns a clone of the default if no options given', () => { const defaults = [{ prop: 'setting' }]; const user = null; diff --git a/packages/utils/tests/eslint-utils/deepMerge.test.ts b/packages/utils/tests/eslint-utils/deepMerge.test.ts index 77ccaa140703..c7deb3158733 100644 --- a/packages/utils/tests/eslint-utils/deepMerge.test.ts +++ b/packages/utils/tests/eslint-utils/deepMerge.test.ts @@ -1,6 +1,6 @@ import { ESLintUtils } from '../../src'; -describe('deepMerge', () => { +describe(ESLintUtils.deepMerge, () => { it('creates a brand new object', () => { const a = {}; const b = {}; diff --git a/packages/utils/tests/eslint-utils/getParserServices.test.ts b/packages/utils/tests/eslint-utils/getParserServices.test.ts index cfe033c92034..62066108fc64 100644 --- a/packages/utils/tests/eslint-utils/getParserServices.test.ts +++ b/packages/utils/tests/eslint-utils/getParserServices.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any -- wild and wacky testing */ import type * as ts from 'typescript'; import type { ParserServices, TSESLint, TSESTree } from '../../src'; @@ -38,14 +37,14 @@ const unknownParserErrorRegex = (parser?: string): RegExp => Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.`, ); -describe('getParserServices', () => { +describe(ESLintUtils.getParserServices, () => { it('throws a standard error with the parser when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is typescript-eslint', () => { const context = createMockRuleContext({ sourceCode: { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - esTreeNodeToTSNodeMap: undefined as any, + esTreeNodeToTSNodeMap: undefined, }, }, }); @@ -69,7 +68,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - esTreeNodeToTSNodeMap: undefined as any, + esTreeNodeToTSNodeMap: undefined, }, }, }); @@ -87,7 +86,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - esTreeNodeToTSNodeMap: undefined as any, + esTreeNodeToTSNodeMap: undefined, }, }, }); @@ -107,7 +106,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - esTreeNodeToTSNodeMap: undefined as any, + esTreeNodeToTSNodeMap: undefined, }, }, }); @@ -124,7 +123,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - esTreeNodeToTSNodeMap: undefined as any, + esTreeNodeToTSNodeMap: undefined, }, }, }); @@ -139,7 +138,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - tsNodeToESTreeNodeMap: undefined as any, + tsNodeToESTreeNodeMap: undefined, }, }, }); @@ -155,7 +154,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - program: undefined as any, + program: undefined, }, }, }); @@ -171,7 +170,7 @@ describe('getParserServices', () => { ...defaults.sourceCode, parserServices: { ...defaults.sourceCode.parserServices, - program: undefined as any, + program: undefined, }, }, }); diff --git a/packages/utils/tests/eslint-utils/nullThrows.test.ts b/packages/utils/tests/eslint-utils/nullThrows.test.ts index 02fd549e0db7..c2ec078ba235 100644 --- a/packages/utils/tests/eslint-utils/nullThrows.test.ts +++ b/packages/utils/tests/eslint-utils/nullThrows.test.ts @@ -1,6 +1,6 @@ import { nullThrows, NullThrowsReasons } from '../../src/eslint-utils'; -describe('nullThrows', () => { +describe(nullThrows, () => { it('returns a falsy value when it exists', () => { const value = 0; diff --git a/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts b/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts index fb70c5e644e6..40ecc6e6939d 100644 --- a/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts +++ b/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts @@ -1,7 +1,7 @@ import { parserSeemsToBeTSESLint } from '../../src/eslint-utils/parserSeemsToBeTSESLint'; -describe('parserSeemsToBeTSESLint', () => { - test.each([ +describe(parserSeemsToBeTSESLint, () => { + test.for([ [undefined, false], ['espree', false], ['local.js', false], @@ -20,7 +20,7 @@ describe('parserSeemsToBeTSESLint', () => { ['/path/to/typescript-eslint/packages/parser/index.js', true], ['/path/to/@typescript-eslint/packages/parser/dist/index.js', true], ['/path/to/@typescript-eslint/packages/parser/index.js', true], - ])('%s', (parserPath, expected) => { + ] as const)('%s', ([parserPath, expected], { expect }) => { expect(parserSeemsToBeTSESLint(parserPath)).toBe(expected); }); }); diff --git a/packages/utils/tests/ts-eslint/Rule.type-test.ts b/packages/utils/tests/ts-eslint/Rule.test-d.ts similarity index 61% rename from packages/utils/tests/ts-eslint/Rule.type-test.ts rename to packages/utils/tests/ts-eslint/Rule.test-d.ts index 859d25165dd6..5b30b1bd1e24 100644 --- a/packages/utils/tests/ts-eslint/Rule.type-test.ts +++ b/packages/utils/tests/ts-eslint/Rule.test-d.ts @@ -14,8 +14,6 @@ type AllSelectors = | `${TSESTree.AST_NODE_TYPES}:exit` | `${TSESTree.AST_NODE_TYPES}`; -type ExpectNever = T; - type SelectorsWithWrongNodeType = { [K in TSESTree.AST_NODE_TYPES]: Parameters< NonNullable @@ -25,13 +23,11 @@ type SelectorsWithWrongNodeType = { : K : K; }[TSESTree.AST_NODE_TYPES]; -type _test_rule_listener_selectors_have_correct_node_types = - ExpectNever; -type ExtraSelectors = Exclude; -type _test_rule_listener_does_not_define_extra_selectors = - ExpectNever; +test('type tests', () => { + expectTypeOf().toBeNever(); + + expectTypeOf().exclude().toBeNever(); -type MissingSelectors = Exclude; -type _test_rule_listener_has_selectors_for_all_node_types = - ExpectNever; + expectTypeOf().exclude().toBeNever(); +}); diff --git a/packages/utils/tsconfig.build.json b/packages/utils/tsconfig.build.json index cb9cf84e1575..bff36900f2be 100644 --- a/packages/utils/tsconfig.build.json +++ b/packages/utils/tsconfig.build.json @@ -10,7 +10,7 @@ }, "include": ["src/**/*.ts", "typings"], "exclude": [ - "jest.config.js", + "vitest.config.mts", "src/**/*.spec.ts", "src/**/*.test.ts", "**/fixtures/**" diff --git a/packages/utils/tsconfig.spec.json b/packages/utils/tsconfig.spec.json index b07160a47b9b..ae7365b0ef8e 100644 --- a/packages/utils/tsconfig.spec.json +++ b/packages/utils/tsconfig.spec.json @@ -3,10 +3,12 @@ "compilerOptions": { "outDir": "../../dist/out-tsc/packages/utils", "module": "NodeNext", - "types": ["jest", "node"] + "resolveJsonModule": true, + "types": ["node", "vitest/globals", "vitest/importMeta"] }, "include": [ - "jest.config.js", + "vitest.config.mts", + "package.json", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts", @@ -16,6 +18,9 @@ "references": [ { "path": "./tsconfig.build.json" + }, + { + "path": "../../tsconfig.spec.json" } ] } diff --git a/packages/utils/vitest.config.mts b/packages/utils/vitest.config.mts new file mode 100644 index 000000000000..b29fd6f44121 --- /dev/null +++ b/packages/utils/vitest.config.mts @@ -0,0 +1,26 @@ +import * as path from 'node:path'; +import { defineProject, mergeConfig } from 'vitest/config'; + +import { vitestBaseConfig } from '../../vitest.config.base.mjs'; +import packageJson from './package.json' with { type: 'json' }; + +const vitestConfig = mergeConfig( + vitestBaseConfig, + + defineProject({ + root: import.meta.dirname, + + test: { + dir: path.join(import.meta.dirname, 'tests'), + name: packageJson.name.replace('@typescript-eslint/', ''), + root: import.meta.dirname, + + typecheck: { + enabled: true, + tsconfig: path.join(import.meta.dirname, 'tsconfig.spec.json'), + }, + }, + }), +); + +export default vitestConfig; diff --git a/yarn.lock b/yarn.lock index 0fa7bf88a16c..e4ecb0ad74d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6312,11 +6312,12 @@ __metadata: "@typescript-eslint/scope-manager": 8.29.1 "@typescript-eslint/types": 8.29.1 "@typescript-eslint/typescript-estree": 8.29.1 + "@vitest/coverage-v8": ^3.1.1 downlevel-dts: "*" - jest: 29.7.0 prettier: ^3.2.5 rimraf: "*" typescript: "*" + vitest: ^3.1.1 peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0"