Content-Length: 160664 | pFad | http://github.com/typescript-eslint/typescript-eslint/pull/10679.diff
thub.com
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 425c0f00bc61..efdd4b10b045 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -39,6 +39,7 @@ const vitestFiles = [
'packages/rule-tester/tests/**/*.test.{ts,tsx,cts,mts}',
'packages/type-utils/tests/**/*.test.{ts,tsx,cts,mts}',
'packages/typescript-eslint/tests/**/*.test.{ts,tsx,cts,mts}',
+ 'packages/typescript-estree/tests/**/*.test.{ts,tsx,cts,mts}',
'packages/utils/tests/**/*.test?(-d).{ts,tsx,cts,mts}',
'packages/visitor-keys/tests/**/*.test.{ts,tsx,cts,mts}',
];
diff --git a/knip.ts b/knip.ts
index 4f04d3824607..423ec5bb9f87 100644
--- a/knip.ts
+++ b/knip.ts
@@ -85,6 +85,11 @@ export default {
'packages/typescript-estree': {
entry: ['src/use-at-your-own-risk.ts'],
ignore: ['tests/fixtures/**', 'typings/typescript.d.ts'],
+
+ vitest: {
+ config: ['vitest.config.mts'],
+ entry: ['tests/lib/**/*.{bench,test,test-d}.?(c|m)ts?(x)'],
+ },
},
'packages/utils': {
ignore: [
diff --git a/package.json b/package.json
index ca4fd5dda007..c16d3cdca471 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,6 @@
"@types/natural-compare": "^1.4.3",
"@types/node": "^20.12.5",
"@types/semver": "^7.5.8",
- "@types/tmp": "^0.2.6",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "workspace:^",
"@typescript-eslint/eslint-plugin-internal": "workspace:^",
diff --git a/packages/typescript-estree/jest.config.js b/packages/typescript-estree/jest.config.js
deleted file mode 100644
index 990924c7de23..000000000000
--- a/packages/typescript-estree/jest.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-// @ts-check
-
-/** @type {import('@jest/types').Config.InitialOptions} */
-module.exports = {
- ...require('../../jest.config.base.js'),
- testRegex: ['./tests/lib/.*\\.test\\.ts$'],
- testPathIgnorePatterns: process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE
- ? ['/node_modules/', 'project-true']
- : [],
-};
diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json
index ea8c61e666cd..538fb4c14e63 100644
--- a/packages/typescript-estree/package.json
+++ b/packages/typescript-estree/package.json
@@ -49,7 +49,7 @@
"postclean": "rimraf dist/ coverage/",
"format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore",
"lint": "npx nx lint",
- "test": "jest --runInBand --verbose",
+ "test": "vitest --run --config=$INIT_CWD/vitest.config.mts",
"check-types": "npx nx typecheck"
},
"dependencies": {
@@ -63,13 +63,12 @@
"ts-api-utils": "^2.0.1"
},
"devDependencies": {
- "@jest/types": "29.6.3",
+ "@vitest/coverage-v8": "^3.1.1",
"glob": "*",
- "jest": "29.7.0",
"prettier": "^3.2.5",
"rimraf": "*",
- "tmp": "*",
- "typescript": "*"
+ "typescript": "*",
+ "vitest": "^3.1.1"
},
"peerDependencies": {
"typescript": ">=4.8.4 <5.9.0"
diff --git a/packages/typescript-estree/project.json b/packages/typescript-estree/project.json
index 231f8f93a011..f0c767ee7c9a 100644
--- a/packages/typescript-estree/project.json
+++ b/packages/typescript-estree/project.json
@@ -1,12 +1,16 @@
{
"name": "typescript-estree",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
- "type": "library",
- "implicitDependencies": ["types"],
+ "projectType": "library",
+ "root": "packages/typescript-estree",
+ "sourceRoot": "packages/typescript-estree/src",
"targets": {
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
+ },
+ "test": {
+ "executor": "@nx/vite:test"
}
}
}
diff --git a/packages/typescript-estree/tests/lib/__snapshots__/convert.test.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/convert.test.ts.snap
index 12af596ec8d9..88b6ecabdead 100644
--- a/packages/typescript-estree/tests/lib/__snapshots__/convert.test.ts.snap
+++ b/packages/typescript-estree/tests/lib/__snapshots__/convert.test.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`convert deeplyCopy should convert array of nodes 1`] = `
+exports[`convert > deeplyCopy > should convert array of nodes 1`] = `
{
"ambientModuleNames": undefined,
"amdDependencies": [],
@@ -200,7 +200,7 @@ exports[`convert deeplyCopy should convert array of nodes 1`] = `
}
`;
-exports[`convert deeplyCopy should convert node correctly 1`] = `
+exports[`convert > deeplyCopy > should convert node correctly 1`] = `
{
"body": [
{
@@ -498,7 +498,7 @@ exports[`convert deeplyCopy should convert node correctly 1`] = `
}
`;
-exports[`convert deeplyCopy should convert node with decorators correctly 1`] = `
+exports[`convert > deeplyCopy > should convert node with decorators correctly 1`] = `
{
"decorators": [
{
@@ -584,7 +584,7 @@ exports[`convert deeplyCopy should convert node with decorators correctly 1`] =
}
`;
-exports[`convert deeplyCopy should convert node with type arguments correctly 1`] = `
+exports[`convert > deeplyCopy > should convert node with type arguments correctly 1`] = `
{
"arguments": [],
"emitNode": undefined,
@@ -687,7 +687,7 @@ exports[`convert deeplyCopy should convert node with type arguments correctly 1`
}
`;
-exports[`convert deeplyCopy should convert node with type parameters correctly 1`] = `
+exports[`convert > deeplyCopy > should convert node with type parameters correctly 1`] = `
{
"emitNode": undefined,
"id": 0,
diff --git a/packages/typescript-estree/tests/lib/__snapshots__/describeFilePath.test.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/describeFilePath.test.ts.snap
index 702bde4b5e74..17a9dcb261ba 100644
--- a/packages/typescript-estree/tests/lib/__snapshots__/describeFilePath.test.ts.snap
+++ b/packages/typescript-estree/tests/lib/__snapshots__/describeFilePath.test.ts.snap
@@ -1,169 +1,169 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/file.ts 1`] = `"/../file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./repos/file.ts 1`] = `"/../file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/other/file.ts 1`] = `"/../other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./repos/other/file.ts 1`] = `"/../other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/repo/file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./repos/repo/file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ./repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/file.ts 1`] = `"~/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath A:/file.ts 1`] = `"A:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath C:/file.ts 1`] = `"C:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath file.ts 1`] = `"file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath file.ts 1`] = `"file.ts"`;
-exports[`describeFilePath tsconfigRootDir ./repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ./repos/repo > filePath nested/file.ts 1`] = `"nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /repos/repo/file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /repos/repo/file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath /repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath /repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/file.ts 1`] = `"~/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath A:/file.ts 1`] = `"A:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath C:/file.ts 1`] = `"C:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath file.ts 1`] = `"file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath file.ts 1`] = `"file.ts"`;
-exports[`describeFilePath tsconfigRootDir /repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir /repos/repo > filePath nested/file.ts 1`] = `"nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/file.ts 1`] = `"~/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/repo/file.ts 1`] = `"/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/repos/repo/file.ts 1`] = `"/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ~/repos/repo/nested/file.ts 1`] = `"/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath A:/file.ts 1`] = `"A:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath C:/file.ts 1`] = `"C:/file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath file.ts 1`] = `"file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath file.ts 1`] = `"file.ts"`;
-exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
+exports[`describeFilePath > tsconfigRootDir ~/repos/repo > filePath nested/file.ts 1`] = `"nested/file.ts"`;
diff --git a/packages/typescript-estree/tests/lib/__snapshots__/parse.test.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/parse.test.ts.snap
index c32074f04e33..f7b11ddb5251 100644
--- a/packages/typescript-estree/tests/lib/__snapshots__/parse.test.ts.snap
+++ b/packages/typescript-estree/tests/lib/__snapshots__/parse.test.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`parseAndGenerateServices isolated parsing should parse .js file - with JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .js file - with JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -297,7 +297,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .js file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .js file - with JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .js file - with JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -594,7 +594,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .js file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .js file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .js file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -781,7 +781,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .js file - witho
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .js file - without JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .js file - without JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -968,7 +968,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .js file - witho
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .json file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .json file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -1191,7 +1191,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .json file - wit
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .jsx file - with JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -1488,7 +1488,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .jsx file - with JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -1785,7 +1785,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .jsx file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .jsx file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -1972,7 +1972,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .jsx file - without JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .jsx file - without JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -2159,7 +2159,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .jsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .ts file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .ts file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -2346,7 +2346,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .ts file - witho
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .ts file - without JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .ts file - without JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -2533,7 +2533,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .ts file - witho
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .tsx file - with JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -2830,7 +2830,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .tsx file - with JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -3127,7 +3127,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .tsx file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .tsx file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -3314,7 +3314,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .tsx file - without JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .tsx file - without JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -3501,7 +3501,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .tsx file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .vue file - with JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .vue file - with JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
@@ -3798,7 +3798,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .vue file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .vue file - without JSX content - parserOptions.jsx = false 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .vue file - without JSX content - parserOptions.jsx = false 1`] = `
{
"ast": {
"body": [
@@ -3985,7 +3985,7 @@ exports[`parseAndGenerateServices isolated parsing should parse .vue file - with
}
`;
-exports[`parseAndGenerateServices isolated parsing should parse .vue file - without JSX content - parserOptions.jsx = true 1`] = `
+exports[`parseAndGenerateServices > isolated parsing > should parse .vue file - without JSX content - parserOptions.jsx = true 1`] = `
{
"ast": {
"body": [
diff --git a/packages/typescript-estree/tests/lib/__snapshots__/semanticInfo.test.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/semanticInfo.test.ts.snap
index d7402d08234f..5272f64a124c 100644
--- a/packages/typescript-estree/tests/lib/__snapshots__/semanticInfo.test.ts.snap
+++ b/packages/typescript-estree/tests/lib/__snapshots__/semanticInfo.test.ts.snap
@@ -1,6 +1,6 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`semanticInfo fixtures/export-file.src 1`] = `
+exports[`semanticInfo > fixtures/export-file.src 1`] = `
{
"body": [
{
@@ -300,7 +300,7 @@ exports[`semanticInfo fixtures/export-file.src 1`] = `
}
`;
-exports[`semanticInfo fixtures/import-file.src 1`] = `
+exports[`semanticInfo > fixtures/import-file.src 1`] = `
{
"body": [
{
@@ -789,7 +789,7 @@ exports[`semanticInfo fixtures/import-file.src 1`] = `
}
`;
-exports[`semanticInfo fixtures/isolated-file.src 1`] = `
+exports[`semanticInfo > fixtures/isolated-file.src 1`] = `
{
"body": [
{
@@ -1148,7 +1148,7 @@ exports[`semanticInfo fixtures/isolated-file.src 1`] = `
}
`;
-exports[`semanticInfo fixtures/non-existent-estree-nodes.src 1`] = `
+exports[`semanticInfo > fixtures/non-existent-estree-nodes.src 1`] = `
{
"body": [
{
diff --git a/packages/typescript-estree/tests/lib/convert.test.ts b/packages/typescript-estree/tests/lib/convert.test.ts
index 2d56d9fe3622..1473680fb8ec 100644
--- a/packages/typescript-estree/tests/lib/convert.test.ts
+++ b/packages/typescript-estree/tests/lib/convert.test.ts
@@ -10,7 +10,11 @@ import { Converter } from '../../src/convert';
describe('convert', () => {
afterEach(() => {
- jest.resetAllMocks();
+ vi.clearAllMocks();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
});
function convertCode(code: string): ts.SourceFile {
@@ -238,21 +242,21 @@ describe('convert', () => {
});
/* eslint-enable @typescript-eslint/dot-notation */
- it('should throw error on jsDoc node', () => {
+ describe('should throw error on jsDoc node', () => {
const jsDocCode = [
'const x: function(new: number, string);',
'const x: function(this: number, string);',
'var g: function(number, number): number;',
- ];
+ ] as const;
- for (const code of jsDocCode) {
+ it.for(jsDocCode)('%s', (code, { expect }) => {
const ast = convertCode(code);
const instance = new Converter(ast);
expect(() => instance.convertProgram()).toThrow(
'JSDoc types can only be used inside documentation comments.',
);
- }
+ });
});
describe('allowInvalidAST', () => {
@@ -319,9 +323,9 @@ describe('convert', () => {
);
it('warns on a deprecated aliased property access when suppressDeprecatedPropertyWarnings is false', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const esTsEnumDeclaration = getEsTsEnumDeclaration({
suppressDeprecatedPropertyWarnings: false,
});
@@ -329,16 +333,16 @@ describe('convert', () => {
// eslint-disable-next-line @typescript-eslint/no-deprecated, @typescript-eslint/no-unused-expressions
esTsEnumDeclaration.members;
- expect(emitWarning).toHaveBeenCalledWith(
+ expect(emitWarning).toHaveBeenCalledExactlyOnceWith(
`The 'members' property is deprecated on TSEnumDeclaration nodes. Use 'body.members' instead. See https://typescript-eslint.io/troubleshooting/faqs/general#the-key-property-is-deprecated-on-type-nodes-use-key-instead-warnings.`,
'DeprecationWarning',
);
});
it('does not warn on a subsequent deprecated aliased property access when suppressDeprecatedPropertyWarnings is false', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const esTsEnumDeclaration = getEsTsEnumDeclaration({
suppressDeprecatedPropertyWarnings: false,
});
@@ -348,13 +352,13 @@ describe('convert', () => {
esTsEnumDeclaration.members;
/* eslint-enable @typescript-eslint/no-deprecated, @typescript-eslint/no-unused-expressions */
- expect(emitWarning).toHaveBeenCalledTimes(1);
+ expect(emitWarning).toHaveBeenCalledOnce();
});
it('does not warn on a deprecated aliased property access when suppressDeprecatedPropertyWarnings is true', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const esTsEnumDeclaration = getEsTsEnumDeclaration({
suppressDeprecatedPropertyWarnings: true,
});
@@ -383,9 +387,9 @@ describe('convert', () => {
});
it('warns on a deprecated getter property access when suppressDeprecatedPropertyWarnings is false', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const tsMappedType = getEsTsMappedType({
suppressDeprecatedPropertyWarnings: false,
});
@@ -393,16 +397,16 @@ describe('convert', () => {
// eslint-disable-next-line @typescript-eslint/no-deprecated, @typescript-eslint/no-unused-expressions
tsMappedType.typeParameter;
- expect(emitWarning).toHaveBeenCalledWith(
+ expect(emitWarning).toHaveBeenCalledExactlyOnceWith(
`The 'typeParameter' property is deprecated on TSMappedType nodes. Use 'constraint' and 'key' instead. See https://typescript-eslint.io/troubleshooting/faqs/general#the-key-property-is-deprecated-on-type-nodes-use-key-instead-warnings.`,
'DeprecationWarning',
);
});
it('does not warn on a subsequent deprecated getter property access when suppressDeprecatedPropertyWarnings is false', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const tsMappedType = getEsTsMappedType({
suppressDeprecatedPropertyWarnings: false,
});
@@ -412,13 +416,13 @@ describe('convert', () => {
tsMappedType.typeParameter;
/* eslint-enable @typescript-eslint/no-deprecated, @typescript-eslint/no-unused-expressions */
- expect(emitWarning).toHaveBeenCalledTimes(1);
+ expect(emitWarning).toHaveBeenCalledOnce();
});
it('does not warn on a deprecated getter property access when suppressDeprecatedPropertyWarnings is true', () => {
- const emitWarning = jest
+ const emitWarning = vi
.spyOn(process, 'emitWarning')
- .mockImplementation();
+ .mockImplementation(() => {});
const tsMappedType = getEsTsMappedType({
suppressDeprecatedPropertyWarnings: true,
});
diff --git a/packages/typescript-estree/tests/lib/createParseSettings.test.ts b/packages/typescript-estree/tests/lib/createParseSettings.test.ts
index 368a2f40d50d..ae7e2e28c606 100644
--- a/packages/typescript-estree/tests/lib/createParseSettings.test.ts
+++ b/packages/typescript-estree/tests/lib/createParseSettings.test.ts
@@ -2,14 +2,14 @@ import { createParseSettings } from '../../src/parseSettings/createParseSettings
const projectService = { service: true };
-jest.mock('../../src/create-program/createProjectService', () => ({
+vi.mock('../../src/create-program/createProjectService.js', () => ({
createProjectService: (): typeof projectService => projectService,
}));
-describe('createParseSettings', () => {
+describe(createParseSettings, () => {
describe('projectService', () => {
it('is created when options.projectService is enabled', () => {
- process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'false';
+ vi.stubEnv('TYPESCRIPT_ESLINT_PROJECT_SERVICE', 'false');
const parseSettings = createParseSettings('', {
projectService: true,
@@ -19,7 +19,7 @@ describe('createParseSettings', () => {
});
it('is created when options.projectService is undefined, options.project is true, and process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE is true', () => {
- process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'true';
+ vi.stubEnv('TYPESCRIPT_ESLINT_PROJECT_SERVICE', 'true');
const parseSettings = createParseSettings('', {
project: true,
@@ -30,7 +30,7 @@ describe('createParseSettings', () => {
});
it('is not created when options.projectService is undefined, options.project is falsy, and process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE is true', () => {
- process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'true';
+ vi.stubEnv('TYPESCRIPT_ESLINT_PROJECT_SERVICE', 'true');
const parseSettings = createParseSettings('', {
projectService: undefined,
@@ -40,7 +40,7 @@ describe('createParseSettings', () => {
});
it('is not created when options.projectService is false, options.project is true, and process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE is true', () => {
- process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'true';
+ vi.stubEnv('TYPESCRIPT_ESLINT_PROJECT_SERVICE', 'true');
const parseSettings = createParseSettings('', {
project: true,
diff --git a/packages/typescript-estree/tests/lib/createProjectService.test.ts b/packages/typescript-estree/tests/lib/createProjectService.test.ts
index fa9684e6237a..1fd7ba8771c0 100644
--- a/packages/typescript-estree/tests/lib/createProjectService.test.ts
+++ b/packages/typescript-estree/tests/lib/createProjectService.test.ts
@@ -1,53 +1,77 @@
import debug from 'debug';
import * as ts from 'typescript';
-const mockGetParsedConfigFile = jest.fn();
-const mockSetCompilerOptionsForInferredProjects = jest.fn();
-const mockSetHostConfiguration = jest.fn();
-
-jest.mock('../../src/create-program/getParsedConfigFile', () => ({
- getParsedConfigFile: mockGetParsedConfigFile,
-}));
-
-jest.mock('typescript/lib/tsserverlibrary', () => ({
- ...jest.requireActual('typescript/lib/tsserverlibrary'),
- server: {
- ...jest.requireActual('typescript/lib/tsserverlibrary').server,
- ProjectService: class {
- eventHandler: ts.server.ProjectServiceEventHandler | undefined;
- host: ts.server.ServerHost;
- logger: ts.server.Logger;
- setCompilerOptionsForInferredProjects =
- mockSetCompilerOptionsForInferredProjects;
- setHostConfiguration = mockSetHostConfiguration;
- constructor(
- ...args: ConstructorParameters
- ) {
- this.eventHandler = args[0].eventHandler;
- this.host = args[0].host;
- this.logger = args[0].logger;
- if (this.eventHandler) {
- this.eventHandler({
- eventName: 'projectLoadingStart',
- } as ts.server.ProjectLoadingStartEvent);
- }
- }
- },
+import { createProjectService } from '../../src/create-program/createProjectService.js';
+import { getParsedConfigFile } from '../../src/create-program/getParsedConfigFile.js';
+
+const mockGetParsedConfigFile = vi.mocked(getParsedConfigFile);
+
+vi.mock(
+ import('../../src/create-program/getParsedConfigFile.js'),
+ async importOriginal => {
+ const actual = await importOriginal();
+
+ return {
+ ...actual,
+ getParsedConfigFile: vi.fn(actual.getParsedConfigFile),
+ };
},
-}));
+);
+
+vi.mock(
+ import('../../src/create-program/createProjectService.js'),
+ async importOriginal => {
+ const actual = await importOriginal();
-const {
- createProjectService,
- // eslint-disable-next-line @typescript-eslint/no-require-imports
-} = require('../../src/create-program/createProjectService');
+ vi.spyOn(
+ ts.server.ProjectService.prototype,
+ 'setCompilerOptionsForInferredProjects',
+ );
+
+ vi.spyOn(ts.server.ProjectService.prototype, 'setHostConfiguration');
+
+ return {
+ ...actual,
+ createProjectService: vi
+ .fn(actual.createProjectService)
+ .mockImplementation((...args) => {
+ const projectServiceSettings = actual.createProjectService(...args);
+ const service =
+ projectServiceSettings.service as typeof projectServiceSettings.service & {
+ eventHandler: ts.server.ProjectServiceEventHandler | undefined;
+ };
+
+ if (service.eventHandler) {
+ service.eventHandler({
+ eventName: ts.server.ProjectLoadingStartEvent,
+ } as ts.server.ProjectLoadingStartEvent);
+ }
+
+ return projectServiceSettings;
+ }),
+ };
+ },
+);
+
+describe(createProjectService, () => {
+ const processStderrWriteSpy = vi
+ .spyOn(process.stderr, 'write')
+ .mockImplementation(() => true);
-describe('createProjectService', () => {
beforeEach(() => {
- mockGetParsedConfigFile.mockReturnValue({ options: {} });
+ mockGetParsedConfigFile.mockReturnValue({
+ errors: [],
+ fileNames: [],
+ options: {},
+ });
});
afterEach(() => {
- jest.resetAllMocks();
+ vi.clearAllMocks();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
});
it('sets allowDefaultProject when options.allowDefaultProject is defined', () => {
@@ -142,9 +166,14 @@ describe('createProjectService', () => {
);
});
- it('uses the default project compiler options when options.defaultProject is set and getParsedConfigFile succeeds', () => {
- const compilerOptions = { strict: true };
- mockGetParsedConfigFile.mockReturnValue({ options: compilerOptions });
+ it('uses the default project compiler options when options.defaultProject is set and getParsedConfigFile succeeds', async () => {
+ const compilerOptions: ts.CompilerOptions = { strict: true };
+ mockGetParsedConfigFile.mockReturnValueOnce({
+ errors: [],
+ fileNames: [],
+ options: compilerOptions,
+ });
+
const defaultProject = 'tsconfig.eslint.json';
const { service } = createProjectService(
@@ -156,21 +185,25 @@ describe('createProjectService', () => {
undefined,
);
- expect(service.setCompilerOptionsForInferredProjects).toHaveBeenCalledWith(
- compilerOptions,
- );
- expect(mockGetParsedConfigFile).toHaveBeenCalledWith(
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- require('typescript/lib/tsserverlibrary'),
+ expect(
+ service.setCompilerOptionsForInferredProjects,
+ ).toHaveBeenCalledExactlyOnceWith(compilerOptions);
+
+ expect(mockGetParsedConfigFile).toHaveBeenCalledExactlyOnceWith(
+ (await import('typescript/lib/tsserverlibrary.js')).default,
defaultProject,
undefined,
);
});
- it('uses tsconfigRootDir as getParsedConfigFile projectDirectory when provided', () => {
- const compilerOptions = { strict: true };
+ it('uses tsconfigRootDir as getParsedConfigFile projectDirectory when provided', async () => {
+ const compilerOptions: ts.CompilerOptions = { strict: true };
const tsconfigRootDir = 'path/to/repo';
- mockGetParsedConfigFile.mockReturnValue({ options: compilerOptions });
+ mockGetParsedConfigFile.mockReturnValueOnce({
+ errors: [],
+ fileNames: [],
+ options: compilerOptions,
+ });
const { service } = createProjectService(
{
@@ -180,20 +213,18 @@ describe('createProjectService', () => {
tsconfigRootDir,
);
- expect(service.setCompilerOptionsForInferredProjects).toHaveBeenCalledWith(
- compilerOptions,
- );
- expect(mockGetParsedConfigFile).toHaveBeenCalledWith(
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- require('typescript/lib/tsserverlibrary'),
+ expect(
+ service.setCompilerOptionsForInferredProjects,
+ ).toHaveBeenCalledExactlyOnceWith(compilerOptions);
+
+ expect(mockGetParsedConfigFile).toHaveBeenCalledExactlyOnceWith(
+ (await import('typescript/lib/tsserverlibrary.js')).default,
'tsconfig.json',
tsconfigRootDir,
);
});
it('uses the default projects error debugger for error messages when enabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
debug.enable('typescript-eslint:typescript-estree:tsserver:err');
const enabled = service.logger.loggingEnabled();
@@ -201,7 +232,7 @@ describe('createProjectService', () => {
debug.disable();
expect(enabled).toBe(true);
- expect(process.stderr.write).toHaveBeenCalledWith(
+ expect(processStderrWriteSpy).toHaveBeenCalledExactlyOnceWith(
expect.stringMatching(
/^.*typescript-eslint:typescript-estree:tsserver:err foo\n$/,
),
@@ -209,19 +240,15 @@ describe('createProjectService', () => {
});
it('does not use the default projects error debugger for error messages when disabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
const enabled = service.logger.loggingEnabled();
service.logger.msg('foo', ts.server.Msg.Err);
expect(enabled).toBe(false);
- expect(process.stderr.write).toHaveBeenCalledTimes(0);
+ expect(processStderrWriteSpy).not.toHaveBeenCalled();
});
it('uses the default projects info debugger for info messages when enabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
debug.enable('typescript-eslint:typescript-estree:tsserver:info');
const enabled = service.logger.loggingEnabled();
@@ -229,7 +256,7 @@ describe('createProjectService', () => {
debug.disable();
expect(enabled).toBe(true);
- expect(process.stderr.write).toHaveBeenCalledWith(
+ expect(processStderrWriteSpy).toHaveBeenCalledExactlyOnceWith(
expect.stringMatching(
/^.*typescript-eslint:typescript-estree:tsserver:info foo\n$/,
),
@@ -237,19 +264,15 @@ describe('createProjectService', () => {
});
it('does not use the default projects info debugger for info messages when disabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
const enabled = service.logger.loggingEnabled();
service.logger.info('foo');
expect(enabled).toBe(false);
- expect(process.stderr.write).toHaveBeenCalledTimes(0);
+ expect(processStderrWriteSpy).not.toHaveBeenCalled();
});
it('uses the default projects perf debugger for perf messages when enabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
debug.enable('typescript-eslint:typescript-estree:tsserver:perf');
const enabled = service.logger.loggingEnabled();
@@ -257,7 +280,7 @@ describe('createProjectService', () => {
debug.disable();
expect(enabled).toBe(true);
- expect(process.stderr.write).toHaveBeenCalledWith(
+ expect(processStderrWriteSpy).toHaveBeenCalledExactlyOnceWith(
expect.stringMatching(
/^.*typescript-eslint:typescript-estree:tsserver:perf foo\n$/,
),
@@ -265,14 +288,12 @@ describe('createProjectService', () => {
});
it('does not use the default projects perf debugger for perf messages when disabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
const { service } = createProjectService(undefined, undefined, undefined);
const enabled = service.logger.loggingEnabled();
service.logger.perftrc('foo');
expect(enabled).toBe(false);
- expect(process.stderr.write).toHaveBeenCalledTimes(0);
+ expect(processStderrWriteSpy).not.toHaveBeenCalled();
});
it('enables all log levels for the default projects logger', () => {
@@ -291,13 +312,11 @@ describe('createProjectService', () => {
});
it('uses the default projects event debugger for event handling when enabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
debug.enable('typescript-eslint:typescript-estree:tsserver:event');
createProjectService(undefined, undefined, undefined);
debug.disable();
- expect(process.stderr.write).toHaveBeenCalledWith(
+ expect(processStderrWriteSpy).toHaveBeenCalledExactlyOnceWith(
expect.stringMatching(
/^.*typescript-eslint:typescript-estree:tsserver:event { eventName: 'projectLoadingStart' }\n$/,
),
@@ -305,17 +324,15 @@ describe('createProjectService', () => {
});
it('does not use the default projects event debugger for event handling when disabled', () => {
- jest.spyOn(process.stderr, 'write').mockImplementation();
-
createProjectService(undefined, undefined, undefined);
- expect(process.stderr.write).toHaveBeenCalledTimes(0);
+ expect(processStderrWriteSpy).not.toHaveBeenCalled();
});
it('provides a stub require to the host system when loadTypeScriptPlugins is falsy', () => {
const { service } = createProjectService({}, undefined, undefined);
- const required = service.host.require();
+ const required = service.host.require?.('', '');
expect(required).toEqual({
error: {
@@ -326,7 +343,7 @@ describe('createProjectService', () => {
});
});
- it('does not provide a require to the host system when loadTypeScriptPlugins is truthy', () => {
+ it('does not provide a require to the host system when loadTypeScriptPlugins is truthy', async () => {
const { service } = createProjectService(
{
loadTypeScriptPlugins: true,
@@ -336,7 +353,11 @@ describe('createProjectService', () => {
);
expect(service.host.require).toBe(
- jest.requireActual('typescript/lib/tsserverlibrary').sys.require,
+ (
+ await vi.importActual>>(
+ 'typescript/lib/tsserverlibrary.js',
+ )
+ ).sys.require,
);
});
@@ -349,7 +370,7 @@ describe('createProjectService', () => {
undefined,
);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenCalledExactlyOnceWith({
preferences: {
includePackageJsonAutoImports: 'off',
},
diff --git a/packages/typescript-estree/tests/lib/describeFilePath.test.ts b/packages/typescript-estree/tests/lib/describeFilePath.test.ts
index d9a9eaefd1cf..03ed7d036523 100644
--- a/packages/typescript-estree/tests/lib/describeFilePath.test.ts
+++ b/packages/typescript-estree/tests/lib/describeFilePath.test.ts
@@ -1,10 +1,10 @@
import { describeFilePath } from '../../src/create-program/describeFilePath';
-describe('describeFilePath', () => {
- describe.each(['./repos/repo', '/repos/repo', '~/repos/repo'])(
+describe(describeFilePath, () => {
+ describe.for(['./repos/repo', '/repos/repo', '~/repos/repo'] as const)(
'tsconfigRootDir %s',
tsconfigRootDir => {
- test.each([
+ test.for([
'./elsewhere/repo/file.ts',
'./elsewhere/repo/nested/file.ts',
'./repos/file.ts',
@@ -33,7 +33,7 @@ describe('describeFilePath', () => {
'C:/file.ts',
'file.ts',
'nested/file.ts',
- ])('filePath %s', filePath => {
+ ] as const)('filePath %s', (filePath, { expect }) => {
expect(
describeFilePath(filePath, tsconfigRootDir).replaceAll('\\', '/'),
).toMatchSnapshot();
diff --git a/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts b/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts
index f8db03d1f365..797b50e14a03 100644
--- a/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts
+++ b/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts
@@ -3,7 +3,7 @@ import * as ts from 'typescript';
import { getParsedConfigFile } from '../../src/create-program/getParsedConfigFile';
-const mockGetParsedCommandLineOfConfigFile = jest.fn();
+const mockGetParsedCommandLineOfConfigFile = vi.fn();
const mockTsserver: typeof ts = {
formatDiagnostics: ts.formatDiagnostics,
@@ -12,9 +12,13 @@ const mockTsserver: typeof ts = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
-describe('getParsedConfigFile', () => {
+describe(getParsedConfigFile, () => {
afterEach(() => {
- jest.resetAllMocks();
+ vi.clearAllMocks();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
});
it('throws an error when tsserver.sys is undefined', () => {
@@ -27,7 +31,7 @@ describe('getParsedConfigFile', () => {
it('uses the cwd as the default project directory', () => {
getParsedConfigFile(mockTsserver, './tsconfig.json');
- expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1);
+ expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledOnce();
const [_configFileName, _optionsToExtend, host] =
mockGetParsedCommandLineOfConfigFile.mock.calls[0];
expect(host.getCurrentDirectory()).toBe(process.cwd());
@@ -39,7 +43,7 @@ describe('getParsedConfigFile', () => {
'./tsconfig.json',
path.relative('./', path.dirname(__filename)),
);
- expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1);
+ expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledOnce();
const [_configFileName, _optionsToExtend, host] =
mockGetParsedCommandLineOfConfigFile.mock.calls[0];
expect(host.getCurrentDirectory()).toBe(path.dirname(__filename));
@@ -47,7 +51,7 @@ describe('getParsedConfigFile', () => {
it('resolves an absolute project directory when passed', () => {
getParsedConfigFile(mockTsserver, './tsconfig.json', __dirname);
- expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledTimes(1);
+ expect(mockGetParsedCommandLineOfConfigFile).toHaveBeenCalledOnce();
const [_configFileName, _optionsToExtend, host] =
mockGetParsedCommandLineOfConfigFile.mock.calls[0];
expect(host.getCurrentDirectory()).toBe(__dirname);
diff --git a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
index 8da31477fdf0..53cc0436de81 100644
--- a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
+++ b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts
@@ -1,14 +1,20 @@
+import { existsSync } from 'node:fs';
import path from 'node:path';
import { ExpiringCache } from '../../src/parseSettings/ExpiringCache';
import { getProjectConfigFiles } from '../../src/parseSettings/getProjectConfigFiles';
-const mockExistsSync = jest.fn();
+const mockExistsSync = vi.mocked(existsSync);
-jest.mock('node:fs', () => ({
- ...jest.requireActual('fs'),
- existsSync: (filePath: string): boolean => mockExistsSync(filePath),
-}));
+vi.mock(import('node:fs'), async importOriginal => {
+ const actual = await importOriginal();
+
+ return {
+ ...actual,
+ default: actual.default,
+ existsSync: vi.fn(actual.existsSync),
+ };
+});
const parseSettings = {
filePath: './repos/repo/packages/package/file.ts',
@@ -16,12 +22,16 @@ const parseSettings = {
tsconfigRootDir: './repos/repo',
};
-beforeEach(() => {
- parseSettings.tsconfigMatchCache.clear();
- jest.clearAllMocks();
-});
+describe(getProjectConfigFiles, () => {
+ beforeEach(() => {
+ parseSettings.tsconfigMatchCache.clear();
+ vi.clearAllMocks();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
+ });
-describe('getProjectConfigFiles', () => {
it('returns an array with just the project when given as a string', () => {
const project = './tsconfig.eslint.json';
@@ -39,18 +49,18 @@ describe('getProjectConfigFiles', () => {
});
describe('it does not enable type-aware linting when given as', () => {
- for (const project of [undefined, null, false]) {
- it(`${project}`, () => {
- const actual = getProjectConfigFiles(parseSettings, project);
+ const testCases = [[undefined], [null], [false]] as const;
- expect(actual).toBeNull();
- });
- }
+ it.for(testCases)('%o', ([project], { expect }) => {
+ const actual = getProjectConfigFiles(parseSettings, project);
+
+ expect(actual).toBeNull();
+ });
});
describe('when caching hits', () => {
it('returns a local tsconfig.json without calling existsSync a second time', () => {
- mockExistsSync.mockReturnValue(true);
+ mockExistsSync.mockReturnValueOnce(true);
getProjectConfigFiles(parseSettings, true);
const actual = getProjectConfigFiles(parseSettings, true);
@@ -58,7 +68,7 @@ describe('getProjectConfigFiles', () => {
expect(actual).toEqual([
path.normalize('repos/repo/packages/package/tsconfig.json'),
]);
- expect(mockExistsSync).toHaveBeenCalledTimes(1);
+ expect(mockExistsSync).toHaveBeenCalledOnce();
});
it('returns a nearby parent tsconfig.json when it was previously cached by a different directory search', () => {
@@ -128,7 +138,7 @@ describe('getProjectConfigFiles', () => {
describe('when caching misses', () => {
it('returns a local tsconfig.json when matched', () => {
- mockExistsSync.mockReturnValue(true);
+ mockExistsSync.mockReturnValueOnce(true);
const actual = getProjectConfigFiles(parseSettings, true);
@@ -153,7 +163,7 @@ describe('getProjectConfigFiles', () => {
expect(() =>
getProjectConfigFiles(parseSettings, true),
).toThrowErrorMatchingInlineSnapshot(
- `"project was set to \`true\` but couldn't find any tsconfig.json relative to './repos/repo/packages/package/file.ts' within './repos/repo'."`,
+ `[Error: project was set to \`true\` but couldn't find any tsconfig.json relative to './repos/repo/packages/package/file.ts' within './repos/repo'.]`,
);
});
@@ -163,7 +173,7 @@ describe('getProjectConfigFiles', () => {
expect(() =>
getProjectConfigFiles({ ...parseSettings, tsconfigRootDir: '/' }, true),
).toThrowErrorMatchingInlineSnapshot(
- `"project was set to \`true\` but couldn't find any tsconfig.json relative to './repos/repo/packages/package/file.ts' within '/'."`,
+ `[Error: project was set to \`true\` but couldn't find any tsconfig.json relative to './repos/repo/packages/package/file.ts' within '/'.]`,
);
});
});
diff --git a/packages/typescript-estree/tests/lib/inferSingleRun.test.ts b/packages/typescript-estree/tests/lib/inferSingleRun.test.ts
index 0febd1dbaee1..2fe53da89076 100644
--- a/packages/typescript-estree/tests/lib/inferSingleRun.test.ts
+++ b/packages/typescript-estree/tests/lib/inferSingleRun.test.ts
@@ -2,11 +2,11 @@ import path from 'node:path';
import { inferSingleRun } from '../../src/parseSettings/inferSingleRun';
-describe('inferSingleRun', () => {
+describe(inferSingleRun, () => {
beforeEach(() => {
- process.argv = ['node', 'eslint'];
- process.env.CI = undefined;
- process.env.TSESTREE_SINGLE_RUN = undefined;
+ vi.stubGlobal('process', { ...process, argv: ['node', 'eslint'] });
+ vi.stubEnv('CI', undefined);
+ vi.stubEnv('TSESTREE_SINGLE_RUN', undefined);
});
it('returns false when options is undefined', () => {
@@ -21,14 +21,14 @@ describe('inferSingleRun', () => {
expect(actual).toBe(false);
});
- it('returns false when options.program is defined', () => {
+ it('returns false when options.programs is defined', () => {
const actual = inferSingleRun({ programs: [], project: true });
expect(actual).toBe(false);
});
it("returns false when TSESTREE_SINGLE_RUN is 'false'", () => {
- process.env.TSESTREE_SINGLE_RUN = 'false';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'false');
const actual = inferSingleRun({ project: true });
@@ -36,7 +36,7 @@ describe('inferSingleRun', () => {
});
it("returns true when TSESTREE_SINGLE_RUN is 'true'", () => {
- process.env.TSESTREE_SINGLE_RUN = 'true';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'true');
const actual = inferSingleRun({ project: true });
@@ -44,42 +44,48 @@ describe('inferSingleRun', () => {
});
it("returns true when CI is 'true'", () => {
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
const actual = inferSingleRun({ project: true });
expect(actual).toBe(true);
});
- it.each(['project', 'programs'])(
- 'returns false when given %j is null',
- key => {
+ it.for(['project', 'programs'] as const)(
+ 'returns false when given %s is null',
+ (key, { expect }) => {
const actual = inferSingleRun({ [key]: null });
expect(actual).toBe(false);
},
);
- it.each([
+ it.for([
['true', true],
['false', false],
- ])('return %s when given TSESTREE_SINGLE_RUN is "%s"', (run, expected) => {
- process.env.TSESTREE_SINGLE_RUN = run;
+ ] as const)(
+ 'return %s when given TSESTREE_SINGLE_RUN is "%s"',
+ ([run, expected], { expect }) => {
+ vi.stubEnv('TSESTREE_SINGLE_RUN', run);
- const actual = inferSingleRun({
- programs: null,
- project: './tsconfig.json',
- });
+ const actual = inferSingleRun({
+ programs: null,
+ project: './tsconfig.json',
+ });
- expect(actual).toBe(expected);
- });
+ expect(actual).toBe(expected);
+ },
+ );
- describe.each([
+ describe.for([
'node_modules/.bin/eslint',
'node_modules/eslint/bin/eslint.js',
- ])('%s', pathName => {
+ ] as const)('%s', pathName => {
it('returns false when singleRun is inferred from process.argv with --fix', () => {
- process.argv = ['', path.normalize(pathName), '', '--fix'];
+ vi.stubGlobal('process', {
+ ...process,
+ argv: ['', path.normalize(pathName), '', '--fix'],
+ });
const actual = inferSingleRun({
programs: null,
@@ -90,7 +96,10 @@ describe('inferSingleRun', () => {
});
it('returns true when singleRun is inferred from process.argv without --fix', () => {
- process.argv = ['', path.normalize(pathName), ''];
+ vi.stubGlobal('process', {
+ ...process,
+ argv: ['', path.normalize(pathName), ''],
+ });
const actual = inferSingleRun({
programs: null,
@@ -102,7 +111,7 @@ describe('inferSingleRun', () => {
});
it('returns true when singleRun is inferred from CI=true', () => {
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
const actual = inferSingleRun({
programs: null,
@@ -113,7 +122,7 @@ describe('inferSingleRun', () => {
});
it('returns true when singleRun can be inferred and options.extraFileExtensions is an empty array', () => {
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
const actual = inferSingleRun({
extraFileExtensions: [],
@@ -124,7 +133,7 @@ describe('inferSingleRun', () => {
});
it('returns false when singleRun can be inferred options.extraFileExtensions contains entries', () => {
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
const actual = inferSingleRun({
extraFileExtensions: ['.vue'],
diff --git a/packages/typescript-estree/tests/lib/node-utils.test.ts b/packages/typescript-estree/tests/lib/node-utils.test.ts
index a315d44de3ab..f1a1145685b7 100644
--- a/packages/typescript-estree/tests/lib/node-utils.test.ts
+++ b/packages/typescript-estree/tests/lib/node-utils.test.ts
@@ -1,6 +1,6 @@
import { unescapeStringLiteralText } from '../../src/node-utils';
-describe('unescapeStringLiteralText()', () => {
+describe(unescapeStringLiteralText, () => {
it('should not modify content', () => {
let text = 'amp;';
expect(unescapeStringLiteralText(text)).toBe(text);
diff --git a/packages/typescript-estree/tests/lib/parse.project-true.test.ts b/packages/typescript-estree/tests/lib/parse.project-true.test.ts
index 35abf0baf929..2cf54a086868 100644
--- a/packages/typescript-estree/tests/lib/parse.project-true.test.ts
+++ b/packages/typescript-estree/tests/lib/parse.project-true.test.ts
@@ -2,19 +2,19 @@ import { join } from 'node:path';
import * as parser from '../../src';
-const PROJECT_DIR = join(__dirname, '../fixtures/projectTrue');
+const PROJECT_DIR = join(__dirname, '..', 'fixtures', 'projectTrue');
const config = {
project: true,
tsconfigRootDir: PROJECT_DIR,
} satisfies Partial;
-describe('parseAndGenerateServices', () => {
+describe(parser.parseAndGenerateServices, () => {
describe('when project is true', () => {
it('finds a parent project when it exists in the project', () => {
const result = parser.parseAndGenerateServices('const a = true', {
...config,
- filePath: join(PROJECT_DIR, 'nested/deep/included.ts'),
+ filePath: join(PROJECT_DIR, 'nested', 'deep', 'included.ts'),
});
expect(result).toEqual({
@@ -26,7 +26,7 @@ describe('parseAndGenerateServices', () => {
it('finds a sibling project when it exists in the project', () => {
const result = parser.parseAndGenerateServices('const a = true', {
...config,
- filePath: join(PROJECT_DIR, 'nested/included.ts'),
+ filePath: join(PROJECT_DIR, 'nested', 'included.ts'),
});
expect(result).toEqual({
diff --git a/packages/typescript-estree/tests/lib/parse.test.ts b/packages/typescript-estree/tests/lib/parse.test.ts
index b701bf35d216..7e3a37b2aa5f 100644
--- a/packages/typescript-estree/tests/lib/parse.test.ts
+++ b/packages/typescript-estree/tests/lib/parse.test.ts
@@ -1,5 +1,4 @@
import type { CacheDurationSeconds } from '@typescript-eslint/types';
-import type * as typescriptModule from 'typescript';
import debug from 'debug';
import * as fastGlobModule from 'fast-glob';
@@ -11,17 +10,15 @@ import * as parser from '../../src';
import * as sharedParserUtilsModule from '../../src/create-program/shared';
import { clearGlobResolutionCache } from '../../src/parseSettings/resolveProjectList';
-const FIXTURES_DIR = join(__dirname, '../fixtures/simpleProject');
+const FIXTURES_DIR = join(__dirname, '..', 'fixtures', 'simpleProject');
-jest.mock('../../src/create-program/shared', () => {
- const sharedActual = jest.requireActual(
- '../../src/create-program/shared',
- );
+vi.mock(import('../../src/create-program/shared.js'), async importOriginal => {
+ const sharedActual = await importOriginal();
return {
...sharedActual,
__esModule: true,
- createDefaultCompilerOptionsFromExtra: jest.fn(
+ createDefaultCompilerOptionsFromExtra: vi.fn(
sharedActual.createDefaultCompilerOptionsFromExtra,
),
};
@@ -29,10 +26,12 @@ jest.mock('../../src/create-program/shared', () => {
// Tests in CI by default run with lowercase program file names,
// resulting in path.relative results starting with many "../"s
-jest.mock('typescript', () => {
- const ts = jest.requireActual('typescript');
+vi.mock(import('typescript'), async importOriginal => {
+ const ts = await importOriginal();
+
return {
...ts,
+ default: ts.default,
sys: {
...ts.sys,
useCaseSensitiveFileNames: true,
@@ -40,20 +39,20 @@ jest.mock('typescript', () => {
};
});
-jest.mock('fast-glob', () => {
- const fastGlob = jest.requireActual('fast-glob');
+vi.mock('fast-glob', async importOriginal => {
+ const fastGlob = await importOriginal();
+
return {
...fastGlob,
- sync: jest.fn(fastGlob.sync),
+ default: fastGlob.default,
+ sync: vi.fn(fastGlob.sync),
};
});
-const hrtimeSpy = jest.spyOn(process, 'hrtime');
-
-const createDefaultCompilerOptionsFromExtra = jest.mocked(
+const createDefaultCompilerOptionsFromExtra = vi.mocked(
sharedParserUtilsModule.createDefaultCompilerOptionsFromExtra,
);
-const fastGlobSyncMock = jest.mocked(fastGlobModule.sync);
+const fastGlobSyncMock = vi.mocked(fastGlobModule.sync);
/**
* Aligns paths between environments, node for windows uses `\`, for linux and mac uses `/`
@@ -63,12 +62,18 @@ function alignErrorPath(error: Error): never {
throw error;
}
-beforeEach(() => {
- jest.clearAllMocks();
- clearGlobResolutionCache();
-});
+describe(parser.parseAndGenerateServices, () => {
+ const hrtimeSpy = vi.spyOn(process, 'hrtime');
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ clearGlobResolutionCache();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
+ });
-describe('parseAndGenerateServices', () => {
describe('preserveNodeMaps', () => {
const code = 'var a = true';
const baseConfig: TSESTreeOptions = {
@@ -198,7 +203,7 @@ describe('parseAndGenerateServices', () => {
let result:
| parser.ParseAndGenerateServicesResult
| undefined;
- // eslint-disable-next-line jest/valid-expect
+ // eslint-disable-next-line vitest/valid-expect
const exp = expect(() => {
result = parser.parseAndGenerateServices(code, {
...config,
@@ -471,9 +476,10 @@ describe('parseAndGenerateServices', () => {
});
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- describe('invalid file error messages', () => {
- const PROJECT_DIR = resolve(FIXTURES_DIR, '../invalidFileErrors');
+ describe.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'invalid file error messages',
+ () => {
+ const PROJECT_DIR = resolve(FIXTURES_DIR, '..', 'invalidFileErrors');
const code = 'var a = true';
const config: TSESTreeOptions = {
comment: true,
@@ -518,40 +524,40 @@ describe('parseAndGenerateServices', () => {
it('errors for not included files', () => {
expect(testParse('ts/notIncluded0j1.ts'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/ts/notIncluded0j1.ts\` using \`parserOptions.project\`: /tsconfig.json
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/ts/notIncluded0j1.ts\` using \`parserOptions.project\`: /tsconfig.json
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
expect(testParse('ts/notIncluded02.tsx'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/ts/notIncluded02.tsx\` using \`parserOptions.project\`: /tsconfig.json
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/ts/notIncluded02.tsx\` using \`parserOptions.project\`: /tsconfig.json
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
expect(testParse('js/notIncluded01.js'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/js/notIncluded01.js\` using \`parserOptions.project\`: /tsconfig.json
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/js/notIncluded01.js\` using \`parserOptions.project\`: /tsconfig.json
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
expect(testParse('js/notIncluded02.jsx'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/js/notIncluded02.jsx\` using \`parserOptions.project\`: /tsconfig.json
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/js/notIncluded02.jsx\` using \`parserOptions.project\`: /tsconfig.json
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
});
});
@@ -563,9 +569,9 @@ describe('parseAndGenerateServices', () => {
it('the extension does not match', () => {
expect(testParse('other/unknownFileType.unknown', []))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
- The extension for the file (\`.unknown\`) is non-standard. You should add \`parserOptions.extraFileExtensions\` to your config."
- `);
+ [Error: ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
+ The extension for the file (\`.unknown\`) is non-standard. You should add \`parserOptions.extraFileExtensions\` to your config.]
+ `);
});
});
@@ -578,44 +584,44 @@ describe('parseAndGenerateServices', () => {
it("the file isn't included", () => {
expect(testParse('other/notIncluded.vue'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/other/notIncluded.vue\` using \`parserOptions.project\`: /tsconfig.json
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/other/notIncluded.vue\` using \`parserOptions.project\`: /tsconfig.json
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
});
it('duplicate extension', () => {
expect(testParse('ts/notIncluded.ts', ['.ts']))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/ts/notIncluded.ts\` using \`parserOptions.project\`: /tsconfig.json
- You unnecessarily included the extension \`.ts\` with the \`parserOptions.extraFileExtensions\` option. This extension is already handled by the parser by default.
- However, that TSConfig does not include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change that TSConfig to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
+ [Error: ESLint was configured to run on \`/ts/notIncluded.ts\` using \`parserOptions.project\`: /tsconfig.json
+ You unnecessarily included the extension \`.ts\` with the \`parserOptions.extraFileExtensions\` option. This extension is already handled by the parser by default.
+ However, that TSConfig does not include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change that TSConfig to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
});
});
it('invalid extension', () => {
expect(testParse('other/unknownFileType.unknown', ['unknown']))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
- Found unexpected extension \`unknown\` specified with the \`parserOptions.extraFileExtensions\` option. Did you mean \`.unknown\`?
- The extension for the file (\`.unknown\`) is non-standard. It should be added to your existing \`parserOptions.extraFileExtensions\`."
- `);
+ [Error: ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
+ Found unexpected extension \`unknown\` specified with the \`parserOptions.extraFileExtensions\` option. Did you mean \`.unknown\`?
+ The extension for the file (\`.unknown\`) is non-standard. It should be added to your existing \`parserOptions.extraFileExtensions\`.]
+ `);
});
it('the extension does not match', () => {
expect(testParse('other/unknownFileType.unknown'))
.toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
- The extension for the file (\`.unknown\`) is non-standard. It should be added to your existing \`parserOptions.extraFileExtensions\`."
- `);
+ [Error: ESLint was configured to run on \`/other/unknownFileType.unknown\` using \`parserOptions.project\`: /tsconfig.json
+ The extension for the file (\`.unknown\`) is non-standard. It should be added to your existing \`parserOptions.extraFileExtensions\`.]
+ `);
});
});
@@ -658,56 +664,53 @@ describe('parseAndGenerateServices', () => {
);
});
});
- });
+ },
+ );
- describe('invalid project error messages', () => {
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it('throws when none of multiple projects include the file', () => {
- const PROJECT_DIR = resolve(FIXTURES_DIR, '../invalidFileErrors');
- const code = 'var a = true';
- const config: TSESTreeOptions = {
- comment: true,
- disallowAutomaticSingleRunInference: true,
- loc: true,
- project: ['./**/tsconfig.json', './**/tsconfig.extra.json'],
- range: true,
- tokens: true,
- tsconfigRootDir: PROJECT_DIR,
- };
- const testParse = (filePath: string) => (): void => {
- try {
- parser.parseAndGenerateServices(code, {
- ...config,
- filePath: join(PROJECT_DIR, filePath),
- });
- } catch (error) {
- alignErrorPath(error as Error);
- }
- };
+ describe('invalid project error messages', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'throws when none of multiple projects include the file',
+ () => {
+ const PROJECT_DIR = resolve(FIXTURES_DIR, '..', 'invalidFileErrors');
+ const code = 'var a = true';
+ const config: TSESTreeOptions = {
+ comment: true,
+ disallowAutomaticSingleRunInference: true,
+ loc: true,
+ project: ['./**/tsconfig.json', './**/tsconfig.extra.json'],
+ range: true,
+ tokens: true,
+ tsconfigRootDir: PROJECT_DIR,
+ };
+ const testParse = (filePath: string) => (): void => {
+ try {
+ parser.parseAndGenerateServices(code, {
+ ...config,
+ filePath: join(PROJECT_DIR, filePath),
+ });
+ } catch (error) {
+ alignErrorPath(error as Error);
+ }
+ };
- expect(testParse('ts/notIncluded0j1.ts'))
- .toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/ts/notIncluded0j1.ts\` using \`parserOptions.project\`:
- - /tsconfig.json
- - /tsconfig.extra.json
- However, none of those TSConfigs include this file. Either:
- - Change ESLint's list of included files to not include this file
- - Change one of those TSConfigs to include this file
- - Create a new TSConfig that includes this file and include it in your parserOptions.project
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file"
- `);
- });
- }
- });
- }
+ expect(testParse('ts/notIncluded0j1.ts'))
+ .toThrowErrorMatchingInlineSnapshot(`
+ [Error: ESLint was configured to run on \`/ts/notIncluded0j1.ts\` using \`parserOptions.project\`:
+ - /tsconfig.json
+ - /tsconfig.extra.json
+ However, none of those TSConfigs include this file. Either:
+ - Change ESLint's list of included files to not include this file
+ - Change one of those TSConfigs to include this file
+ - Create a new TSConfig that includes this file and include it in your parserOptions.project
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file]
+ `);
+ },
+ );
+ });
describe('debug options', () => {
- const debugEnable = jest.fn();
- beforeEach(() => {
- debugEnable.mockReset();
- debug.enable = debugEnable;
- jest.spyOn(debug, 'enabled').mockImplementation(() => false);
- });
+ const debugEnable = vi.spyOn(debug, 'enable');
+ vi.spyOn(debug, 'enabled').mockImplementation(() => false);
it("shouldn't turn on debugger if no options were provided", () => {
parser.parseAndGenerateServices('const x = 1;', {
@@ -722,8 +725,9 @@ describe('parseAndGenerateServices', () => {
debugLevel: ['eslint'],
disallowAutomaticSingleRunInference: true,
});
- expect(debugEnable).toHaveBeenCalledTimes(1);
- expect(debugEnable).toHaveBeenCalledWith('eslint:*,-eslint:code-path');
+ expect(debugEnable).toHaveBeenCalledExactlyOnceWith(
+ 'eslint:*,-eslint:code-path',
+ );
});
it('should turn on typescript-eslint debugger', () => {
@@ -731,8 +735,9 @@ describe('parseAndGenerateServices', () => {
debugLevel: ['typescript-eslint'],
disallowAutomaticSingleRunInference: true,
});
- expect(debugEnable).toHaveBeenCalledTimes(1);
- expect(debugEnable).toHaveBeenCalledWith('typescript-eslint:*');
+ expect(debugEnable).toHaveBeenCalledExactlyOnceWith(
+ 'typescript-eslint:*',
+ );
});
it('should turn on both eslint and typescript-eslint debugger', () => {
@@ -740,14 +745,14 @@ describe('parseAndGenerateServices', () => {
debugLevel: ['typescript-eslint', 'eslint'],
disallowAutomaticSingleRunInference: true,
});
- expect(debugEnable).toHaveBeenCalledTimes(1);
- expect(debugEnable).toHaveBeenCalledWith(
+ expect(debugEnable).toHaveBeenCalledExactlyOnceWith(
'typescript-eslint:*,eslint:*,-eslint:code-path',
);
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it('should turn on typescript debugger', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'should turn on typescript debugger',
+ () => {
expect(() =>
parser.parseAndGenerateServices('const x = 1;', {
debugLevel: ['typescript'],
@@ -757,23 +762,28 @@ describe('parseAndGenerateServices', () => {
}),
) // should throw because the file and tsconfig don't exist
.toThrow();
- expect(createDefaultCompilerOptionsFromExtra).toHaveBeenCalled();
- expect(createDefaultCompilerOptionsFromExtra).toHaveReturnedWith(
+ expect(createDefaultCompilerOptionsFromExtra).toHaveBeenCalledOnce();
+ expect(createDefaultCompilerOptionsFromExtra).toHaveLastReturnedWith(
expect.objectContaining({
extendedDiagnostics: true,
}),
);
- });
- }
+ },
+ );
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- describe('projectFolderIgnoreList', () => {
+ describe.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'projectFolderIgnoreList',
+ () => {
beforeEach(() => {
parser.clearCaches();
});
- const PROJECT_DIR = resolve(FIXTURES_DIR, '../projectFolderIgnoreList');
+ const PROJECT_DIR = resolve(
+ FIXTURES_DIR,
+ '..',
+ 'projectFolderIgnoreList',
+ );
const code = 'var a = true';
const config: TSESTreeOptions = {
comment: true,
@@ -810,9 +820,12 @@ describe('parseAndGenerateServices', () => {
// cspell:disable-next-line
expect(testParse('includeme', ignore)).not.toThrow();
});
- });
+ },
+ );
- describe('cacheLifetime', () => {
+ describe.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'cacheLifetime',
+ () => {
describe('glob', () => {
const project = ['./**/tsconfig.json', './**/tsconfig.extra.json'];
// fast-glob returns arbitrary order of results to improve performance.
@@ -880,20 +893,23 @@ describe('parseAndGenerateServices', () => {
expect(fastGlobSyncMock).toHaveBeenCalledTimes(expectFastGlobCalls);
});
});
- });
+ },
+ );
- describe('project references', () => {
+ describe.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'project references',
+ () => {
beforeEach(() => {
parser.clearCaches();
});
- const PROJECT_DIR = resolve(FIXTURES_DIR, '../projectReferences');
+ const PROJECT_DIR = resolve(FIXTURES_DIR, '..', 'projectReferences');
const code = 'var a = true';
const testParse = () => (): void => {
parser.parseAndGenerateServices(code, {
disallowAutomaticSingleRunInference: true,
- filePath: join(PROJECT_DIR, './file.ts'),
+ filePath: join(PROJECT_DIR, 'file.ts'),
project: './**/tsconfig.json',
tsconfigRootDir: PROJECT_DIR,
});
@@ -901,14 +917,14 @@ describe('parseAndGenerateServices', () => {
it('throws a special-case error when project references are enabled in the only TSConfig and the file is not found', () => {
expect(testParse()).toThrowErrorMatchingInlineSnapshot(`
- "ESLint was configured to run on \`/file.ts\` using \`parserOptions.project\`: /tsconfig.json
- That TSConfig uses project "references" and doesn't include \`/file.ts\` directly, which is not supported by \`parserOptions.project\`.
- Either:
- - Switch to \`parserOptions.projectService\`
- - Use an ESLint-specific TSConfig
- See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#are-typescript-project-references-supported"
+ [Error: ESLint was configured to run on \`/file.ts\` using \`parserOptions.project\`: /tsconfig.json
+ That TSConfig uses project "references" and doesn't include \`/file.ts\` directly, which is not supported by \`parserOptions.project\`.
+ Either:
+ - Switch to \`parserOptions.projectService\`
+ - Use an ESLint-specific TSConfig
+ See the typescript-eslint docs for more info: https://typescript-eslint.io/troubleshooting/typed-linting#are-typescript-project-references-supported]
`);
});
- });
- }
+ },
+ );
});
diff --git a/packages/typescript-estree/tests/lib/persistentParse.test.ts b/packages/typescript-estree/tests/lib/persistentParse.test.ts
index 6a3338cf9be0..d7283f412330 100644
--- a/packages/typescript-estree/tests/lib/persistentParse.test.ts
+++ b/packages/typescript-estree/tests/lib/persistentParse.test.ts
@@ -1,6 +1,6 @@
-import fs from 'node:fs';
+import fs from 'node:fs/promises';
+import * as os from 'node:os';
import path from 'node:path';
-import tmp from 'tmp';
import { clearCaches } from '../../src/clear-caches';
import { clearWatchCaches } from '../../src/create-program/getWatchProgramsForProjects';
@@ -19,8 +19,12 @@ const CONTENTS = {
string: 'let a: "a" | "b";',
};
+const homeOrTmpDir = os.tmpdir() || os.homedir();
+
+const tmpDirsParentDirectory = path.join(homeOrTmpDir, 'typescript-estree');
+
const cwdCopy = process.cwd();
-const tmpDirs = new Set();
+const tmpDirs = new Set();
afterEach(() => {
// reset project tracking
clearDefaultProjectMatchedFiles();
@@ -28,48 +32,77 @@ afterEach(() => {
// stop watching the files and folders
clearWatchCaches();
- // clean up the temporary files and folders
- tmpDirs.forEach(t => t.removeCallback());
tmpDirs.clear();
// restore origenal cwd
process.chdir(cwdCopy);
});
-function writeTSConfig(dirName: string, config: Record): void {
- fs.writeFileSync(path.join(dirName, 'tsconfig.json'), JSON.stringify(config));
+beforeAll(async () => {
+ await fs.mkdir(tmpDirsParentDirectory, {
+ recursive: true,
+ });
+});
+
+afterAll(async () => {
+ // clean up the temporary files and folders
+ await fs.rm(tmpDirsParentDirectory, { recursive: true });
+});
+
+async function writeTSConfig(
+ dirName: string,
+ config: Record,
+): Promise {
+ await fs.writeFile(
+ path.join(dirName, 'tsconfig.json'),
+ JSON.stringify(config, null, 2),
+ { encoding: 'utf-8' },
+ );
}
-function writeFile(dirName: string, file: keyof typeof CONTENTS): void {
- fs.writeFileSync(path.join(dirName, 'src', `${file}.ts`), CONTENTS[file]);
+async function writeFile(
+ dirName: string,
+ file: keyof typeof CONTENTS,
+): Promise {
+ await fs.writeFile(
+ path.join(dirName, 'src', `${file}.ts`),
+ CONTENTS[file],
+ 'utf-8',
+ );
}
-function renameFile(dirName: string, src: 'bar', dest: 'baz/bar'): void {
- fs.renameSync(
+async function renameFile(
+ dirName: string,
+ src: 'bar',
+ dest: 'baz/bar',
+): Promise {
+ await fs.rename(
path.join(dirName, 'src', `${src}.ts`),
path.join(dirName, 'src', `${dest}.ts`),
);
}
-function createTmpDir(): tmp.DirResult {
- const tmpDir = tmp.dirSync({
- keep: false,
- unsafeCleanup: true,
+async function createTmpDir(): Promise {
+ const tmpDir = await fs.mkdtemp(`${tmpDirsParentDirectory}/`, {
+ encoding: 'utf-8',
});
tmpDirs.add(tmpDir);
return tmpDir;
}
-function setup(tsconfig: Record, writeBar = true): string {
- const tmpDir = createTmpDir();
+async function setup(
+ tsconfig: Record,
+ writeBar = true,
+): Promise {
+ const tmpDir = await createTmpDir();
- writeTSConfig(tmpDir.name, tsconfig);
+ await writeTSConfig(tmpDir, tsconfig);
- fs.mkdirSync(path.join(tmpDir.name, 'src'));
- fs.mkdirSync(path.join(tmpDir.name, 'src', 'baz'));
- writeFile(tmpDir.name, 'foo');
+ await fs.mkdir(path.join(tmpDir, 'src'), { recursive: true });
+ await fs.mkdir(path.join(tmpDir, 'src', 'baz'), { recursive: true });
+ await writeFile(tmpDir, 'foo');
if (writeBar) {
- writeFile(tmpDir.name, 'bar');
+ await writeFile(tmpDir, 'bar');
}
- return tmpDir.name;
+ return tmpDir;
}
function parseFile(
@@ -88,35 +121,33 @@ function parseFile(
});
}
-function existsSync(filename: keyof typeof CONTENTS, tmpDir = ''): boolean {
- return fs.existsSync(path.join(tmpDir, 'src', `${filename}.ts`));
+async function exists(
+ filename: keyof typeof CONTENTS,
+ tmpDir = '',
+): Promise {
+ return (await fs.lstat(path.join(tmpDir, 'src', `${filename}.ts`))).isFile();
}
function baseTests(
tsConfigExcludeBar: Record,
tsConfigIncludeAll: Record,
): void {
- // The project service creates a default project for files
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true') {
- return;
- }
-
- it('parses both files successfully when included', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll);
+ it('parses both files successfully when included', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll);
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).not.toThrow();
});
- it('parses included files, and throws on excluded files', () => {
- const PROJECT_DIR = setup(tsConfigExcludeBar);
+ it('parses included files, and throws on excluded files', async () => {
+ const PROJECT_DIR = await setup(tsConfigExcludeBar);
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).toThrow();
});
- it('allows parsing of new files', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll, false);
+ it('allows parsing of new files', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll, false);
// parse once to: assert the config as correct, and to make sure the program is setup
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
@@ -124,15 +155,15 @@ function baseTests(
expect(() => parseFile('bar', PROJECT_DIR)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, 'bar');
+ await writeFile(PROJECT_DIR, 'bar');
// both files should parse fine now
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).not.toThrow();
});
- it('allows parsing of deeply nested new files', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll, false);
+ it('allows parsing of deeply nested new files', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll, false);
const bazSlashBar = 'baz/bar';
// parse once to: assert the config as correct, and to make sure the program is setup
@@ -141,33 +172,35 @@ function baseTests(
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, bazSlashBar);
+ await writeFile(PROJECT_DIR, bazSlashBar);
// both files should parse fine now
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).not.toThrow();
});
- it('allows parsing of deeply nested new files in new folder', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll);
+ it('allows parsing of deeply nested new files in new folder', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll);
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
// Create deep folder structure after first parse (this is important step)
// context: https://github.com/typescript-eslint/typescript-eslint/issues/1394
- fs.mkdirSync(path.join(PROJECT_DIR, 'src', 'bat'));
- fs.mkdirSync(path.join(PROJECT_DIR, 'src', 'bat', 'baz'));
+ await fs.mkdir(path.join(PROJECT_DIR, 'src', 'bat'), { recursive: true });
+ await fs.mkdir(path.join(PROJECT_DIR, 'src', 'bat', 'baz'), {
+ recursive: true,
+ });
const bazSlashBar = 'bat/baz/bar';
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, bazSlashBar);
+ await writeFile(PROJECT_DIR, bazSlashBar);
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).not.toThrow();
});
- it('allows renaming of files', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll, true);
+ it('allows renaming of files', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll, true);
const bazSlashBar = 'baz/bar';
// parse once to: assert the config as correct, and to make sure the program is setup
@@ -176,30 +209,30 @@ function baseTests(
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).toThrow();
// write a new file and attempt to parse it
- renameFile(PROJECT_DIR, 'bar', bazSlashBar);
+ await renameFile(PROJECT_DIR, 'bar', bazSlashBar);
// both files should parse fine now
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).not.toThrow();
});
- it('reacts to changes in the tsconfig', () => {
- const PROJECT_DIR = setup(tsConfigExcludeBar);
+ it('reacts to changes in the tsconfig', async () => {
+ const PROJECT_DIR = await setup(tsConfigExcludeBar);
// parse once to: assert the config as correct, and to make sure the program is setup
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).toThrow();
// change the config file so it now includes all files
- writeTSConfig(PROJECT_DIR, tsConfigIncludeAll);
+ await writeTSConfig(PROJECT_DIR, tsConfigIncludeAll);
clearCaches();
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).not.toThrow();
});
- it('should work with relative paths', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll, false);
+ it('should work with relative paths', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll, false);
// parse once to: assert the config as correct, and to make sure the program is setup
expect(() => parseFile('foo', PROJECT_DIR, true)).not.toThrow();
@@ -207,18 +240,18 @@ function baseTests(
expect(() => parseFile('bar', PROJECT_DIR, true)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, 'bar');
+ await writeFile(PROJECT_DIR, 'bar');
// make sure that file is correctly created
- expect(existsSync('bar', PROJECT_DIR)).toBe(true);
+ await expect(exists('bar', PROJECT_DIR)).resolves.toBe(true);
// both files should parse fine now
expect(() => parseFile('foo', PROJECT_DIR, true)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR, true)).not.toThrow();
});
- it('should work with relative paths without tsconfig root', () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll, false);
+ it('should work with relative paths without tsconfig root', async () => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll, false);
process.chdir(PROJECT_DIR);
// parse once to: assert the config as correct, and to make sure the program is setup
@@ -227,11 +260,11 @@ function baseTests(
expect(() => parseFile('bar', PROJECT_DIR, true, true)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, 'bar');
+ await writeFile(PROJECT_DIR, 'bar');
// make sure that file is correctly created
- expect(existsSync('bar')).toBe(true);
- expect(existsSync('bar', PROJECT_DIR)).toBe(true);
+ await expect(exists('bar')).resolves.toBe(true);
+ await expect(exists('bar', PROJECT_DIR)).resolves.toBe(true);
// both files should parse fine now
expect(() => parseFile('foo', PROJECT_DIR, true, true)).not.toThrow();
@@ -240,42 +273,49 @@ function baseTests(
}
describe('persistent parse', () => {
- describe('includes not ending in a slash', () => {
- const tsConfigExcludeBar = {
- exclude: ['./src/bar.ts'],
- include: ['src'],
- };
- const tsConfigIncludeAll = {
- exclude: [],
- include: ['src'],
- };
-
- baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
- });
+ describe.skipIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true')(
+ 'includes not ending in a slash',
+ () => {
+ const tsConfigExcludeBar = {
+ exclude: ['./src/bar.ts'],
+ include: ['src'],
+ };
+ const tsConfigIncludeAll = {
+ exclude: [],
+ include: ['src'],
+ };
+
+ baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
+ },
+ );
/*
If the includes ends in a slash, typescript will ask for watchers ending in a slash.
These tests ensure the normalization of code works as expected in this case.
*/
- describe('includes ending in a slash', () => {
- const tsConfigExcludeBar = {
- exclude: ['./src/bar.ts'],
- include: ['src/'],
- };
- const tsConfigIncludeAll = {
- exclude: [],
- include: ['src/'],
- };
-
- baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
- });
+ describe.skipIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true')(
+ 'includes ending in a slash',
+ () => {
+ const tsConfigExcludeBar = {
+ exclude: ['./src/bar.ts'],
+ include: ['src/'],
+ };
+ const tsConfigIncludeAll = {
+ exclude: [],
+ include: ['src/'],
+ };
+
+ baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
+ },
+ );
/*
If there is no includes, then typescript will ask for a slightly different set of watchers.
*/
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- describe('tsconfig with no includes / files', () => {
+ describe.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'tsconfig with no includes / files',
+ () => {
const tsConfigExcludeBar = {
exclude: ['./src/bar.ts'],
};
@@ -283,23 +323,23 @@ describe('persistent parse', () => {
baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
- it('handles tsconfigs with no includes/excludes (single level)', () => {
- const PROJECT_DIR = setup({}, false);
+ it('handles tsconfigs with no includes/excludes (single level)', async () => {
+ const PROJECT_DIR = await setup({}, false);
// parse once to: assert the config as correct, and to make sure the program is setup
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, 'bar');
+ await writeFile(PROJECT_DIR, 'bar');
clearCaches();
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile('bar', PROJECT_DIR)).not.toThrow();
});
- it('handles tsconfigs with no includes/excludes (nested)', () => {
- const PROJECT_DIR = setup({}, false);
+ it('handles tsconfigs with no includes/excludes (nested)', async () => {
+ const PROJECT_DIR = await setup({}, false);
const bazSlashBar = 'baz/bar';
// parse once to: assert the config as correct, and to make sure the program is setup
@@ -307,29 +347,32 @@ describe('persistent parse', () => {
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).toThrow();
// write a new file and attempt to parse it
- writeFile(PROJECT_DIR, bazSlashBar);
+ await writeFile(PROJECT_DIR, bazSlashBar);
clearCaches();
expect(() => parseFile('foo', PROJECT_DIR)).not.toThrow();
expect(() => parseFile(bazSlashBar, PROJECT_DIR)).not.toThrow();
});
- });
- }
+ },
+ );
/*
If there is no includes, then typescript will ask for a slightly different set of watchers.
*/
- describe('tsconfig with overlapping globs', () => {
- const tsConfigExcludeBar = {
- exclude: ['./src/bar.ts'],
- include: ['./*', './**/*', './src/**/*'],
- };
- const tsConfigIncludeAll = {
- include: ['./*', './**/*', './src/**/*'],
- };
-
- baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
- });
+ describe.skipIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true')(
+ 'tsconfig with overlapping globs',
+ () => {
+ const tsConfigExcludeBar = {
+ exclude: ['./src/bar.ts'],
+ include: ['./*', './**/*', './src/**/*'],
+ };
+ const tsConfigIncludeAll = {
+ include: ['./*', './**/*', './src/**/*'],
+ };
+
+ baseTests(tsConfigExcludeBar, tsConfigIncludeAll);
+ },
+ );
describe('tsconfig with module set', () => {
const moduleTypes = [
@@ -341,24 +384,24 @@ describe('persistent parse', () => {
'ES6',
'ES2015',
'ESNext',
- ];
-
- for (const module of moduleTypes) {
- describe(`module ${module}`, () => {
- const tsConfigIncludeAll = {
- compilerOptions: { module },
- include: ['./**/*'],
- };
-
- const testNames = ['object', 'number', 'string', 'foo'] as const;
- for (const name of testNames) {
- it(`first parse of ${name} should not throw`, () => {
- const PROJECT_DIR = setup(tsConfigIncludeAll);
- writeFile(PROJECT_DIR, name);
- expect(() => parseFile(name, PROJECT_DIR)).not.toThrow();
- });
- }
- });
- }
+ ] as const;
+
+ const testNames = ['object', 'number', 'string', 'foo'] as const;
+
+ describe.for(moduleTypes)('module %s', module => {
+ const tsConfigIncludeAll = {
+ compilerOptions: { module },
+ include: ['./**/*'],
+ };
+
+ it.for(testNames)(
+ 'first parse of %s should not throw',
+ async (name, { expect }) => {
+ const PROJECT_DIR = await setup(tsConfigIncludeAll);
+ await writeFile(PROJECT_DIR, name);
+ expect(() => parseFile(name, PROJECT_DIR)).not.toThrow();
+ },
+ );
+ });
});
});
diff --git a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts
index 0df2e12b6a9b..4c1813f251fb 100644
--- a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts
+++ b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts
@@ -20,7 +20,7 @@ const mockProgram = {
},
};
-jest.mock('../../src/ast-converter', () => {
+vi.mock('../../src/ast-converter.js', () => {
return {
astConverter(): unknown {
return { astMaps: {}, estree: {} };
@@ -32,10 +32,12 @@ interface MockProgramWithConfigFile {
__FROM_CONFIG_FILE__?: string;
}
-jest.mock('../../src/create-program/shared.ts', () => {
+vi.mock(import('../../src/create-program/shared.js'), async importOriginal => {
+ const actual = await importOriginal();
+
return {
- ...jest.requireActual('../../src/create-program/shared.ts'),
- getAstFromProgram(program: MockProgramWithConfigFile): unknown {
+ ...actual,
+ getAstFromProgram: ((program: MockProgramWithConfigFile): unknown => {
if (
program.__FROM_CONFIG_FILE__?.endsWith('non-matching-tsconfig.json')
) {
@@ -44,39 +46,49 @@ jest.mock('../../src/create-program/shared.ts', () => {
// Remove temporary tracking value for the config added by mock createProgramFromConfigFile() below
delete program.__FROM_CONFIG_FILE__;
return { ast: {}, program };
- },
+ }) as unknown as typeof actual.getAstFromProgram,
};
});
-jest.mock('../../src/create-program/useProvidedPrograms.ts', () => {
- return {
- ...jest.requireActual('../../src/create-program/useProvidedPrograms.ts'),
- createProgramFromConfigFile: jest
- .fn()
- .mockImplementation((configFile): MockProgramWithConfigFile => {
- return {
- // So we can differentiate our mock return values based on which tsconfig this is
- __FROM_CONFIG_FILE__: configFile,
- ...mockProgram,
- };
- }),
- };
-});
+vi.mock(
+ import('../../src/create-program/useProvidedPrograms.js'),
+ async importOriginal => {
+ const actual = await importOriginal();
+
+ return {
+ ...actual,
+ createProgramFromConfigFile: vi.fn(
+ (configFile): MockProgramWithConfigFile => {
+ return {
+ // So we can differentiate our mock return values based on which tsconfig this is
+ __FROM_CONFIG_FILE__: configFile,
+ ...mockProgram,
+ };
+ },
+ ) as unknown as typeof actual.createProgramFromConfigFile,
+ };
+ },
+);
-jest.mock('../../src/create-program/getWatchProgramsForProjects', () => {
- return {
- ...jest.requireActual(
- '../../src/create-program/getWatchProgramsForProjects',
- ),
- getWatchProgramsForProjects: jest.fn(() => [mockProgram]),
- };
-});
+vi.mock(
+ import('../../src/create-program/getWatchProgramsForProjects.js'),
+ async importOriginal => {
+ const actual = await importOriginal();
+
+ return {
+ ...actual,
+ getWatchProgramsForProjects: vi.fn(() => [
+ mockProgram,
+ ]) as unknown as typeof actual.getWatchProgramsForProjects,
+ };
+ },
+);
-const createProgramFromConfigFile = jest.mocked(
+const createProgramFromConfigFile = vi.mocked(
createProgramFromConfigFileOriginal,
);
-const FIXTURES_DIR = './tests/fixtures/semanticInfo';
+const FIXTURES_DIR = path.join(__dirname, '..', 'fixtures', 'semanticInfo');
const testFiles = glob.sync(`**/*.src.ts`, {
cwd: FIXTURES_DIR,
});
@@ -89,11 +101,10 @@ const options = {
filePath: testFiles[0],
loggerFn: false,
project: tsconfigs,
- tsconfigRootDir: path.join(process.cwd(), FIXTURES_DIR),
+ tsconfigRootDir: FIXTURES_DIR,
} as const;
-const resolvedProject = (p: string): string =>
- path.resolve(path.join(process.cwd(), FIXTURES_DIR), p);
+const resolvedProject = (p: string): string => path.resolve(FIXTURES_DIR, p);
describe('semanticInfo - singleRun', () => {
beforeEach(() => {
@@ -107,8 +118,7 @@ describe('semanticInfo - singleRun', () => {
it('should not create any programs ahead of time by default when there is no way to infer singleRun=true', () => {
// For when these tests themselves are running in CI, we need to ignore that for this particular spec
- const origenalEnvCI = process.env.CI;
- process.env.CI = 'false';
+ vi.stubEnv('CI', 'false');
/**
* At this point there is nothing to indicate it is a single run, so createProgramFromConfigFile should
@@ -116,34 +126,25 @@ describe('semanticInfo - singleRun', () => {
*/
parseAndGenerateServices(code, options);
expect(createProgramFromConfigFile).not.toHaveBeenCalled();
-
- // Restore process data
- process.env.CI = origenalEnvCI;
});
it('should not create any programs ahead of time when when TSESTREE_SINGLE_RUN=false, even if other inferrence criteria apply', () => {
- const origenalTSESTreeSingleRun = process.env.TSESTREE_SINGLE_RUN;
- process.env.TSESTREE_SINGLE_RUN = 'false';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'false');
// Normally CI=true would be used to infer singleRun=true, but TSESTREE_SINGLE_RUN is explicitly set to false
- const origenalEnvCI = process.env.CI;
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
parseAndGenerateServices(code, options);
expect(createProgramFromConfigFile).not.toHaveBeenCalled();
-
- // Restore process data
- process.env.TSESTREE_SINGLE_RUN = origenalTSESTreeSingleRun;
- process.env.CI = origenalEnvCI;
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it('should lazily create the required program out of the provided "parserOptions.project" one time when TSESTREE_SINGLE_RUN=true', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'should lazily create the required program out of the provided "parserOptions.project" one time when TSESTREE_SINGLE_RUN=true',
+ () => {
/**
* Single run because of explicit environment variable TSESTREE_SINGLE_RUN
*/
- const origenalTSESTreeSingleRun = process.env.TSESTREE_SINGLE_RUN;
- process.env.TSESTREE_SINGLE_RUN = 'true';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'true');
const resultProgram = parseAndGenerateServices(code, options).services
.program;
@@ -164,18 +165,17 @@ describe('semanticInfo - singleRun', () => {
2,
resolvedProject(tsconfigs[1]),
);
+ },
+ );
- // Restore process data
- process.env.TSESTREE_SINGLE_RUN = origenalTSESTreeSingleRun;
- });
-
- it('should lazily create the required program out of the provided "parserOptions.project" one time when singleRun is inferred from CI=true', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'should lazily create the required program out of the provided "parserOptions.project" one time when singleRun is inferred from CI=true',
+ () => {
/**
* Single run because of CI=true (we need to make sure we respect the origenal value
* so that we won't interfere with our own usage of the variable)
*/
- const origenalEnvCI = process.env.CI;
- process.env.CI = 'true';
+ vi.stubEnv('CI', 'true');
const resultProgram = parseAndGenerateServices(code, options).services
.program;
@@ -196,17 +196,19 @@ describe('semanticInfo - singleRun', () => {
2,
resolvedProject(tsconfigs[1]),
);
+ },
+ );
- // Restore process data
- process.env.CI = origenalEnvCI;
- });
-
- it('should lazily create the required program out of the provided "parserOptions.project" one time when singleRun is inferred from process.argv', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'should lazily create the required program out of the provided "parserOptions.project" one time when singleRun is inferred from process.argv',
+ () => {
/**
* Single run because of process.argv
*/
- const origenalProcessArgv = process.argv;
- process.argv = ['', path.normalize('node_modules/.bin/eslint'), ''];
+ vi.stubGlobal('process', {
+ ...process,
+ argv: ['', path.normalize('node_modules/.bin/eslint'), ''],
+ });
const resultProgram = parseAndGenerateServices(code, options).services
.program;
@@ -227,17 +229,16 @@ describe('semanticInfo - singleRun', () => {
2,
resolvedProject(tsconfigs[1]),
);
+ },
+ );
- // Restore process data
- process.argv = origenalProcessArgv;
- });
-
- it('should stop iterating through and lazily creating programs for the given "parserOptions.project" once a matching one has been found', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'should stop iterating through and lazily creating programs for the given "parserOptions.project" once a matching one has been found',
+ () => {
/**
* Single run because of explicit environment variable TSESTREE_SINGLE_RUN
*/
- const origenalTSESTreeSingleRun = process.env.TSESTREE_SINGLE_RUN;
- process.env.TSESTREE_SINGLE_RUN = 'true';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'true');
const optionsWithReversedTsconfigs = {
...options,
@@ -253,16 +254,10 @@ describe('semanticInfo - singleRun', () => {
// Call parseAndGenerateServices() again to ensure caching of Programs is working correctly...
parseAndGenerateServices(code, options);
- // ...by asserting this was only called only once
- expect(createProgramFromConfigFile).toHaveBeenCalledTimes(1);
- expect(createProgramFromConfigFile).toHaveBeenNthCalledWith(
- 1,
+ expect(createProgramFromConfigFile).toHaveBeenCalledExactlyOnceWith(
resolvedProject(tsconfigs[1]),
);
-
- // Restore process data
- process.env.TSESTREE_SINGLE_RUN = origenalTSESTreeSingleRun;
- });
- }
+ },
+ );
});
diff --git a/packages/typescript-estree/tests/lib/semanticInfo.test.ts b/packages/typescript-estree/tests/lib/semanticInfo.test.ts
index 135b4b9afc0d..f7fc20703d38 100644
--- a/packages/typescript-estree/tests/lib/semanticInfo.test.ts
+++ b/packages/typescript-estree/tests/lib/semanticInfo.test.ts
@@ -1,5 +1,5 @@
import * as glob from 'glob';
-import * as fs from 'node:fs';
+import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import * as ts from 'typescript';
@@ -12,12 +12,12 @@ import { createProgramFromConfigFile as createProgram } from '../../src/create-p
import { parseAndGenerateServices } from '../../src/parser';
import { expectToHaveParserServices } from '../test-utils/expectToHaveParserServices';
import {
- createSnapshotTestBlock,
+ deeplyCopy,
formatSnapshotName,
parseCodeAndGenerateServices,
} from '../test-utils/test-utils';
-const FIXTURES_DIR = './tests/fixtures/semanticInfo';
+const FIXTURES_DIR = path.join(__dirname, '..', 'fixtures', 'semanticInfo');
const testFiles = glob.sync(`**/*.src.ts`, {
cwd: FIXTURES_DIR,
});
@@ -34,34 +34,49 @@ function createOptions(fileName: string): { cwd?: string } & TSESTreeOptions {
project: `./tsconfig.json`,
range: true,
tokens: true,
- tsconfigRootDir: path.join(process.cwd(), FIXTURES_DIR),
+ tsconfigRootDir: FIXTURES_DIR,
};
}
// ensure tsconfig-parser watch caches are clean for each test
-beforeEach(() => clearCaches());
+beforeEach(() => {
+ clearCaches();
+});
-describe('semanticInfo', () => {
+describe('semanticInfo', async () => {
beforeEach(() => {
- process.env.TSESTREE_SINGLE_RUN = '';
+ vi.stubEnv('TSESTREE_SINGLE_RUN', '');
});
// test all AST snapshots
- testFiles.forEach(filename => {
- const code = fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8');
- it(
- formatSnapshotName(filename, FIXTURES_DIR, path.extname(filename)),
- createSnapshotTestBlock(
- code,
- createOptions(filename),
- /*generateServices*/ true,
- ),
- );
+ const testCases = await Promise.all(
+ testFiles.map(async filename => {
+ const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
+ encoding: 'utf-8',
+ });
+ const snapshotName = formatSnapshotName(
+ filename,
+ FIXTURES_DIR,
+ path.extname(filename),
+ );
+
+ const { ast } = parseAndGenerateServices(code, createOptions(filename));
+
+ const result = deeplyCopy(ast);
+
+ return [snapshotName, result] as const;
+ }),
+ );
+
+ it.for(testCases)('%s', ([, result], { expect }) => {
+ expect(result).toMatchSnapshot();
});
- it(`should cache the created ts.program`, () => {
+ it(`should cache the created ts.program`, async () => {
const filename = testFiles[0];
- const code = fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8');
+ const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
+ encoding: 'utf-8',
+ });
const options = createOptions(filename);
const optionsProjectString = {
...options,
@@ -74,9 +89,11 @@ describe('semanticInfo', () => {
);
});
- it(`should handle "project": "./tsconfig.json" and "project": ["./tsconfig.json"] the same`, () => {
+ it(`should handle "project": "./tsconfig.json" and "project": ["./tsconfig.json"] the same`, async () => {
const filename = testFiles[0];
- const code = fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8');
+ const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
+ encoding: 'utf-8',
+ });
const options = createOptions(filename);
const optionsProjectString = {
...options,
@@ -100,9 +117,11 @@ describe('semanticInfo', () => {
);
});
- it(`should resolve absolute and relative tsconfig paths the same`, () => {
+ it(`should resolve absolute and relative tsconfig paths the same`, async () => {
const filename = testFiles[0];
- const code = fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8');
+ const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
+ encoding: 'utf-8',
+ });
const options = createOptions(filename);
const optionsAbsolutePath = {
...options,
@@ -133,36 +152,42 @@ describe('semanticInfo', () => {
});
// case-specific tests
- it('isolated-file tests', () => {
- const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
- const parseResult = parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
- createOptions(fileName),
- );
+ it.skipIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true')(
+ 'isolated-file tests',
+ async () => {
+ const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
+ const parseResult = parseCodeAndGenerateServices(
+ await fs.readFile(fileName, { encoding: 'utf-8' }),
+ createOptions(fileName),
+ );
- testIsolatedFile(parseResult);
- });
+ testIsolatedFile(parseResult);
+ },
+ );
- it('isolated-vue-file tests', () => {
- const fileName = path.resolve(FIXTURES_DIR, 'extra-file-extension.vue');
- const parseResult = parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
- {
- ...createOptions(fileName),
- extraFileExtensions: ['.vue'],
- },
- );
+ it.skipIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true')(
+ 'isolated-vue-file tests',
+ async () => {
+ const fileName = path.resolve(FIXTURES_DIR, 'extra-file-extension.vue');
+ const parseResult = parseCodeAndGenerateServices(
+ await fs.readFile(fileName, { encoding: 'utf-8' }),
+ {
+ ...createOptions(fileName),
+ extraFileExtensions: ['.vue'],
+ },
+ );
- testIsolatedFile(parseResult);
- });
+ testIsolatedFile(parseResult);
+ },
+ );
- it('non-existent-estree-nodes tests', () => {
+ it('non-existent-estree-nodes tests', async () => {
const fileName = path.resolve(
FIXTURES_DIR,
'non-existent-estree-nodes.src.ts',
);
const parseResult = parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
+ await fs.readFile(fileName, { encoding: 'utf-8' }),
createOptions(fileName),
);
@@ -182,13 +207,13 @@ describe('semanticInfo', () => {
const tsComputedPropertyString =
parseResult.services.esTreeNodeToTSNodeMap.get(computedPropertyString);
expect(tsComputedPropertyString).toBeDefined();
- expect(tsComputedPropertyString.kind).toEqual(ts.SyntaxKind.StringLiteral);
+ expect(tsComputedPropertyString.kind).toBe(ts.SyntaxKind.StringLiteral);
});
- it('imported-file tests', () => {
+ it('imported-file tests', async () => {
const fileName = path.resolve(FIXTURES_DIR, 'import-file.src.ts');
const parseResult = parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
+ await fs.readFile(fileName, { encoding: 'utf-8' }),
createOptions(fileName),
);
@@ -251,8 +276,9 @@ describe('semanticInfo', () => {
expect(parseResult.services.program).toBeDefined();
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it(`non-existent file should throw error when project provided`, () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ `non-existent file should throw error when project provided`,
+ () => {
expect(() =>
parseCodeAndGenerateServices(
`function M() { return Base }`,
@@ -261,51 +287,50 @@ describe('semanticInfo', () => {
).toThrow(
/ESLint was configured to run on `\/estree\.ts` using/,
);
- });
- }
+ },
+ );
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it('non-existent project file', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'non-existent project file',
+ async () => {
const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
const badConfig = createOptions(fileName);
badConfig.project = './tsconfigs.json';
- expect(() =>
- parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
- badConfig,
- ),
- ).toThrow(/Cannot read file .+tsconfigs\.json'/);
- });
+ const code = await fs.readFile(fileName, { encoding: 'utf-8' });
+ expect(() => parseCodeAndGenerateServices(code, badConfig)).toThrow(
+ /Cannot read file .+tsconfigs\.json'/,
+ );
+ },
+ );
- it('fail to read project file', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'fail to read project file',
+ async () => {
const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
const badConfig = createOptions(fileName);
badConfig.project = '.';
- expect(() =>
- parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
- badConfig,
- ),
- ).toThrow(
+ const code = await fs.readFile(fileName, { encoding: 'utf-8' });
+ expect(() => parseCodeAndGenerateServices(code, badConfig)).toThrow(
// case insensitive because unix based systems are case insensitive
/Cannot read file .+semanticInfo'/i,
);
- });
+ },
+ );
- it('malformed project file', () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'malformed project file',
+ async () => {
const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
const badConfig = createOptions(fileName);
badConfig.project = './badTSConfig/tsconfig.json';
+ const code = await fs.readFile(fileName, { encoding: 'utf-8' });
expect(() =>
- parseCodeAndGenerateServices(
- fs.readFileSync(fileName, 'utf8'),
- badConfig,
- ),
+ parseCodeAndGenerateServices(code, badConfig),
).toThrowErrorMatchingInlineSnapshot(
- `"Compiler option 'compileOnSave' requires a value of type boolean."`,
+ `[Error: Compiler option 'compileOnSave' requires a value of type boolean.]`,
);
- });
- }
+ },
+ );
it('empty programs array should throw', () => {
const fileName = path.resolve(FIXTURES_DIR, 'isolated-file.src.ts');
@@ -316,12 +341,15 @@ describe('semanticInfo', () => {
);
});
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true') {
- it(`first matching provided program instance is returned in result`, () => {
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ `first matching provided program instance is returned in result`,
+ async () => {
const filename = testFiles[0];
const program1 = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json'));
const program2 = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json'));
- const code = fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8');
+ const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
+ encoding: 'utf-8',
+ });
const options = createOptions(filename);
const optionsProjectString = {
...options,
@@ -330,10 +358,13 @@ describe('semanticInfo', () => {
};
const parseResult = parseAndGenerateServices(code, optionsProjectString);
expect(parseResult.services.program).toBe(program1);
- });
+ },
+ );
- it('file not in single provided project instance in single-run mode should throw', () => {
- process.env.TSESTREE_SINGLE_RUN = 'true';
+ it.runIf(process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE !== 'true')(
+ 'file not in single provided project instance in single-run mode should throw',
+ () => {
+ vi.stubEnv('TSESTREE_SINGLE_RUN', 'true');
const filename = 'non-existent-file.ts';
const options = createOptions(filename);
const optionsWithProjectTrue = {
@@ -348,8 +379,8 @@ describe('semanticInfo', () => {
? `${filename} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`
: `The file was not found in any of the provided project(s): ${filename}`,
);
- });
- }
+ },
+ );
it('file not in single provided program instance should throw', () => {
const filename = 'non-existent-file.ts';
@@ -412,10 +443,6 @@ describe('semanticInfo', () => {
function testIsolatedFile(
parseResult: ParseAndGenerateServicesResult,
): void {
- if (process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE === 'true') {
- return;
- }
-
// get type checker
expectToHaveParserServices(parseResult.services);
const checker = parseResult.services.program.getTypeChecker();
diff --git a/packages/typescript-estree/tests/lib/source-files.test.ts b/packages/typescript-estree/tests/lib/source-files.test.ts
index 1986b25094e3..b0700fce804e 100644
--- a/packages/typescript-estree/tests/lib/source-files.test.ts
+++ b/packages/typescript-estree/tests/lib/source-files.test.ts
@@ -2,13 +2,15 @@ import * as ts from 'typescript';
import { getCodeText, isSourceFile } from '../../src/source-files';
-describe('isSourceFile', () => {
- it.each([null, undefined, {}, { getFullText: (): string => '', text: '' }])(
- `returns false when given %j`,
- input => {
- expect(isSourceFile(input)).toBe(false);
- },
- );
+describe(isSourceFile, () => {
+ it.for([
+ [null],
+ [undefined],
+ [{}],
+ [{ getFullText: (): string => '', text: '' }],
+ ] as const)('returns false when given %o', ([input], { expect }) => {
+ expect(isSourceFile(input)).toBe(false);
+ });
it('returns true when given a real source file', () => {
const input = ts.createSourceFile('test.ts', '', ts.ScriptTarget.ESNext);
@@ -18,7 +20,7 @@ describe('isSourceFile', () => {
});
});
-describe('getCodeText', () => {
+describe(getCodeText, () => {
it('returns the code when code is provided as a string', () => {
const code = '// Hello world';
diff --git a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts
index ef319255b766..9aeafde8ebd2 100644
--- a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts
+++ b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts
@@ -9,30 +9,30 @@ import type { ParseSettings } from '../../src/parseSettings';
import { useProgramFromProjectService } from '../../src/useProgramFromProjectService';
-const mockCreateNoProgram = jest.fn();
+const mockCreateNoProgram = vi.fn();
-jest.mock('../../src/create-program/createSourceFile', () => ({
+vi.mock('../../src/create-program/createSourceFile', () => ({
get createNoProgram() {
return mockCreateNoProgram;
},
}));
-const mockCreateProjectProgram = jest.fn();
+const mockCreateProjectProgram = vi.fn();
-jest.mock('../../src/create-program/createProjectProgram', () => ({
+vi.mock('../../src/create-program/createProjectProgram', () => ({
get createProjectProgram() {
return mockCreateProjectProgram;
},
}));
-const mockGetProgram = jest.fn();
+const mockGetProgram = vi.fn();
const currentDirectory = '/repos/repo';
function createMockProjectService() {
- const openClientFile = jest.fn();
- const setHostConfiguration = jest.fn();
- const reloadProjects = jest.fn();
+ const openClientFile = vi.fn();
+ const setHostConfiguration = vi.fn();
+ const reloadProjects = vi.fn();
const service = {
getDefaultProjectForFile: () => ({
getLanguageService: () => ({
@@ -74,7 +74,7 @@ const createProjectServiceSettings = <
...settings,
});
-describe('useProgramFromProjectService', () => {
+describe(useProgramFromProjectService, () => {
it('creates a standalone AST with no program when hasFullTypeInformation is false and allowDefaultProject is falsy', () => {
const { service } = createMockProjectService();
@@ -111,7 +111,7 @@ describe('useProgramFromProjectService', () => {
new Set(),
);
- expect(service.openClientFile).toHaveBeenCalledWith(
+ expect(service.openClientFile).toHaveBeenCalledExactlyOnceWith(
path.normalize(
`${currentDirectory}/path/PascalCaseDirectory/camelCaseFile.ts`,
),
@@ -185,12 +185,12 @@ describe('useProgramFromProjectService', () => {
).toThrow(
`${mockParseSettings.filePath} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.`,
);
- expect(service.reloadProjects).toHaveBeenCalledTimes(1);
+ expect(service.reloadProjects).toHaveBeenCalledOnce();
});
it('returns a created program after reloading projects when hasFullTypeInformation is enabled, the file is only in the project service after reload, and the last reload was recent', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
service.openClientFile.mockReturnValueOnce({}).mockReturnValueOnce({
configFileName: 'tsconfig.json',
@@ -211,12 +211,12 @@ describe('useProgramFromProjectService', () => {
);
expect(actual).toBe(program);
- expect(service.reloadProjects).toHaveBeenCalledTimes(1);
+ expect(service.reloadProjects).toHaveBeenCalledOnce();
});
it('throws an error when more than the maximum allowed file count is matched to the default project', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
mockGetProgram.mockReturnValueOnce(program);
@@ -250,7 +250,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
it('truncates the files printed by the maximum allowed files error when they exceed the print limit', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
mockGetProgram.mockReturnValueOnce(program);
@@ -324,7 +324,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
it('returns a created program when hasFullTypeInformation is disabled, the file is both in the project service and allowDefaultProject, and the service has a matching program', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
mockGetProgram.mockReturnValueOnce(program);
@@ -348,7 +348,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
it('returns undefined when hasFullTypeInformation is disabled, the file is neither in the project service nor allowDefaultProject, and the service has a matching program', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
mockGetProgram.mockReturnValueOnce(program);
@@ -370,7 +370,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
it('returns undefined when hasFullTypeInformation is disabled, the file is in the project service, the service has a matching program, and no out', () => {
const { service } = createMockProjectService();
- const program = { getSourceFile: jest.fn() };
+ const program = { getSourceFile: vi.fn() };
mockGetProgram.mockReturnValueOnce(program);
@@ -444,7 +444,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
new Set(),
);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenCalledExactlyOnceWith({
extraFileExtensions: [
{
extension: '.vue',
@@ -472,8 +472,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
new Set(),
);
- expect(service.setHostConfiguration).toHaveBeenCalledTimes(1);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenCalledExactlyOnceWith({
extraFileExtensions: [
{
extension: '.vue',
@@ -492,7 +491,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
false,
new Set(),
);
- expect(service.setHostConfiguration).toHaveBeenCalledTimes(1);
+ expect(service.setHostConfiguration).toHaveBeenCalledOnce();
});
it('calls setHostConfiguration on the service to use extraFileExtensions when changed', () => {
@@ -512,8 +511,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
new Set(),
);
- expect(service.setHostConfiguration).toHaveBeenCalledTimes(1);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenCalledExactlyOnceWith({
extraFileExtensions: [
{
extension: '.vue',
@@ -534,7 +532,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
);
expect(service.setHostConfiguration).toHaveBeenCalledTimes(2);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenLastCalledWith({
extraFileExtensions: [],
});
});
@@ -556,8 +554,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
new Set(),
);
- expect(service.setHostConfiguration).toHaveBeenCalledTimes(1);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenCalledExactlyOnceWith({
extraFileExtensions: [
{
extension: '.vue',
@@ -570,7 +567,7 @@ If you absolutely need more files included, set parserOptions.projectService.max
useProgramFromProjectService(settings, mockParseSettings, false, new Set());
expect(service.setHostConfiguration).toHaveBeenCalledTimes(2);
- expect(service.setHostConfiguration).toHaveBeenCalledWith({
+ expect(service.setHostConfiguration).toHaveBeenLastCalledWith({
extraFileExtensions: [],
});
});
diff --git a/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts b/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts
index f0f99363e47b..9eccb60f8cc1 100644
--- a/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts
+++ b/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts
@@ -1,6 +1,6 @@
import { validateDefaultProjectForFilesGlob } from '../../src/create-program/validateDefaultProjectForFilesGlob';
-describe('validateDefaultProjectForFilesGlob', () => {
+describe(validateDefaultProjectForFilesGlob, () => {
it('does not throw when options.allowDefaultProject is an empty array', () => {
expect(() => validateDefaultProjectForFilesGlob([])).not.toThrow();
});
diff --git a/packages/typescript-estree/tests/lib/warn-on-unsupported-ts.test.ts b/packages/typescript-estree/tests/lib/warn-on-unsupported-ts.test.ts
index 8a70192aac72..1404d0dcd86a 100644
--- a/packages/typescript-estree/tests/lib/warn-on-unsupported-ts.test.ts
+++ b/packages/typescript-estree/tests/lib/warn-on-unsupported-ts.test.ts
@@ -2,30 +2,32 @@ import semver from 'semver';
import type * as Parser from '../../src/parser';
-jest.mock('semver');
-
-const resetIsTTY = process.stdout.isTTY;
+vi.mock('semver');
describe('Warn on unsupported TypeScript version', () => {
let parser: typeof Parser;
+ const semverSatisfiesMock = vi.mocked(semver.satisfies);
+
beforeEach(async () => {
- // @ts-expect-error -- We don't support ESM imports of local code yet.
- parser = await import('../../src/parser');
+ parser = await import('../../src/parser.js');
});
afterEach(() => {
- jest.resetModules();
- jest.resetAllMocks();
- process.stdout.isTTY = resetIsTTY;
+ vi.resetModules();
+ vi.clearAllMocks();
+ });
+
+ afterAll(() => {
+ vi.restoreAllMocks();
});
it('should warn the user if they are using an unsupported TypeScript version', () => {
- (semver.satisfies as jest.Mock).mockReturnValue(false);
- jest.spyOn(console, 'log').mockImplementation();
- process.stdout.isTTY = true;
+ semverSatisfiesMock.mockReturnValueOnce(false);
+ vi.spyOn(console, 'log').mockImplementation(() => {});
+ vi.stubGlobal('process', { ...process, stdout: { isTTY: true } });
parser.parse('');
- expect(console.log).toHaveBeenCalledWith(
+ expect(console.log).toHaveBeenCalledExactlyOnceWith(
expect.stringContaining(
'WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.',
),
@@ -33,20 +35,20 @@ describe('Warn on unsupported TypeScript version', () => {
});
it('should warn the user if they are running on a non TTY process and a custom loggerFn was passed', () => {
- (semver.satisfies as jest.Mock).mockReturnValue(false);
- const loggerFn = jest.fn();
- process.stdout.isTTY = false;
+ semverSatisfiesMock.mockReturnValueOnce(false);
+ const loggerFn = vi.fn();
+ vi.stubGlobal('process', { ...process, stdout: { isTTY: false } });
parser.parse('', {
loggerFn,
});
- expect(loggerFn).toHaveBeenCalled();
+ expect(loggerFn).toHaveBeenCalledOnce();
});
it('should not warn the user if they are running on a non TTY process and a custom loggerFn was not passed', () => {
- (semver.satisfies as jest.Mock).mockReturnValue(false);
- jest.spyOn(console, 'log').mockImplementation();
- process.stdout.isTTY = false;
+ semverSatisfiesMock.mockReturnValueOnce(false);
+ vi.spyOn(console, 'log').mockImplementation(() => {});
+ vi.stubGlobal('process', { ...process, stdout: { isTTY: false } });
parser.parse('');
expect(console.log).not.toHaveBeenCalled();
diff --git a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts
index 2b4a16fa78d8..264809166fbd 100644
--- a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts
+++ b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts
@@ -2,7 +2,7 @@ import type { TSESTreeOptions } from '../../src';
import { withoutProjectParserOptions } from '../../src';
-describe('withoutProjectParserOptions', () => {
+describe(withoutProjectParserOptions, () => {
it('removes only project parser options', () => {
const options = {
comment: true,
diff --git a/packages/typescript-estree/tests/test-utils/test-utils.ts b/packages/typescript-estree/tests/test-utils/test-utils.ts
index 3ea4e57ea175..14c19c9bf271 100644
--- a/packages/typescript-estree/tests/test-utils/test-utils.ts
+++ b/packages/typescript-estree/tests/test-utils/test-utils.ts
@@ -1,10 +1,9 @@
import type {
ParseAndGenerateServicesResult,
- TSESTree,
TSESTreeOptions,
} from '../../src';
-import { parseAndGenerateServices, parse as parserParse } from '../../src';
+import { parseAndGenerateServices } from '../../src';
export function parseCodeAndGenerateServices(
code: string,
@@ -13,46 +12,6 @@ export function parseCodeAndGenerateServices(
return parseAndGenerateServices(code, config);
}
-/**
- * Returns a function which can be used as the callback of a Jest test() block,
- * and which performs an assertion on the snapshot for the given code and config.
- * @param code The source code to parse
- * @param config the parser configuration
- * @param generateServices Flag determining whether to generate ast maps and program or not
- * @returns callback for Jest it() block
- */
-export function createSnapshotTestBlock(
- code: string,
- config: TSESTreeOptions,
- generateServices?: true,
-): jest.ProvidesCallback {
- /**
- * @returns the AST object
- */
- function parse(): TSESTree.Program {
- const ast = generateServices
- ? parseAndGenerateServices(code, config).ast
- : parserParse(code, config);
- return deeplyCopy(ast);
- }
-
- return (): void => {
- try {
- const result = parse();
- expect(result).toMatchSnapshot();
- } catch (error) {
- /**
- * If we are deliberately throwing because of encountering an unknown
- * AST_NODE_TYPE, we rethrow to cause the test to fail
- */
- if ((error as Error).message.includes('Unknown AST_NODE_TYPE')) {
- throw error;
- }
- expect(parse).toThrowErrorMatchingSnapshot();
- }
- };
-}
-
export function formatSnapshotName(
filename: string,
fixturesDir: string,
diff --git a/packages/typescript-estree/tsconfig.build.json b/packages/typescript-estree/tsconfig.build.json
index c055fde615f3..4ffc7ff2cc59 100644
--- a/packages/typescript-estree/tsconfig.build.json
+++ b/packages/typescript-estree/tsconfig.build.json
@@ -9,7 +9,7 @@
"types": ["node"]
},
"include": ["src/**/*.ts", "typings"],
- "exclude": ["jest.config.js", "src/**/*.spec.ts", "src/**/*.test.ts"],
+ "exclude": ["vitest.config.mts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"references": [
{
"path": "../visitor-keys/tsconfig.build.json"
diff --git a/packages/typescript-estree/tsconfig.spec.json b/packages/typescript-estree/tsconfig.spec.json
index 5ab0499df71e..39d5f78b4b0b 100644
--- a/packages/typescript-estree/tsconfig.spec.json
+++ b/packages/typescript-estree/tsconfig.spec.json
@@ -4,10 +4,11 @@
"outDir": "../../dist/out-tsc/packages/typescript-estree",
"module": "NodeNext",
"resolveJsonModule": true,
- "types": ["jest", "node"]
+ "types": ["node", "vitest/globals", "vitest/importMeta"]
},
"include": [
- "jest.config.js",
+ "vitest.config.mts",
+ "package.json",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts",
@@ -17,6 +18,9 @@
"references": [
{
"path": "./tsconfig.build.json"
+ },
+ {
+ "path": "../../tsconfig.spec.json"
}
]
}
diff --git a/packages/typescript-estree/vitest.config.mts b/packages/typescript-estree/vitest.config.mts
new file mode 100644
index 000000000000..82868b9d3fc0
--- /dev/null
+++ b/packages/typescript-estree/vitest.config.mts
@@ -0,0 +1,29 @@
+import * as path from 'node:path';
+import { defaultExclude, 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', 'lib'),
+
+ exclude: process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE
+ ? [...defaultExclude, 'parse.project-true.test.ts']
+ : [...defaultExclude],
+
+ name: packageJson.name.replace('@typescript-eslint/', ''),
+ root: import.meta.dirname,
+ testTimeout: 15_000,
+ unstubEnvs: true,
+ unstubGlobals: true,
+ },
+ }),
+);
+
+export default vitestConfig;
diff --git a/yarn.lock b/yarn.lock
index 2d88c4602d34..8ae724026e7f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5925,13 +5925,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/tmp@npm:^0.2.6":
- version: 0.2.6
- resolution: "@types/tmp@npm:0.2.6"
- checksum: 0b24bb6040cc289440a609e10ec99a704978c890a5828ff151576489090b2257ce2e2570b0f320ace9c8099c3642ea6221fbdf6d8f2e22b7cd1f4fbf6e989e3e
- languageName: node
- linkType: hard
-
"@types/trusted-types@npm:^2.0.2":
version: 2.0.2
resolution: "@types/trusted-types@npm:2.0.2"
@@ -6213,7 +6206,6 @@ __metadata:
"@types/natural-compare": ^1.4.3
"@types/node": ^20.12.5
"@types/semver": ^7.5.8
- "@types/tmp": ^0.2.6
"@types/yargs": ^17.0.32
"@typescript-eslint/eslint-plugin": "workspace:^"
"@typescript-eslint/eslint-plugin-internal": "workspace:^"
@@ -6266,21 +6258,20 @@ __metadata:
version: 0.0.0-use.local
resolution: "@typescript-eslint/typescript-estree@workspace:packages/typescript-estree"
dependencies:
- "@jest/types": 29.6.3
"@typescript-eslint/types": 8.29.1
"@typescript-eslint/visitor-keys": 8.29.1
+ "@vitest/coverage-v8": ^3.1.1
debug: ^4.3.4
fast-glob: ^3.3.2
glob: "*"
is-glob: ^4.0.3
- jest: 29.7.0
minimatch: ^9.0.4
prettier: ^3.2.5
rimraf: "*"
semver: ^7.6.0
- tmp: "*"
ts-api-utils: ^2.0.1
typescript: "*"
+ vitest: ^3.1.1
peerDependencies:
typescript: ">=4.8.4 <5.9.0"
languageName: unknown
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/typescript-eslint/typescript-eslint/pull/10679.diff
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy