diff --git a/.babelrc.json b/.babelrc.json new file mode 100644 index 000000000..f3d8eaf3c --- /dev/null +++ b/.babelrc.json @@ -0,0 +1,3 @@ +{ + "presets": [["@babel/preset-env", { "modules": "cjs", "targets": { "node": "current" } }]] +} diff --git a/.changeset/wicked-actors-grin.md b/.changeset/wicked-actors-grin.md new file mode 100644 index 000000000..a845151cc --- /dev/null +++ b/.changeset/wicked-actors-grin.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/babel.config.cjs b/babel.config.cjs deleted file mode 100644 index 01f28736e..000000000 --- a/babel.config.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env', { modules: 'cjs', targets: { node: 'current' } }]], -} diff --git a/jest.config.js b/jest.config.js index 0e3fed5ce..c8ab8a141 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,21 +1,18 @@ const config = { collectCoverageFrom: [ 'lib/**/*.js', - // Avoid ESM import.meta parse error. - // (Can't measure coverage anyway, it's always mocked) + /** + * Instanbul uses babel to parse coverage data, + * so `import.meta` is not available + */ '!lib/resolveConfig.js', ], moduleDirectories: ['node_modules'], prettierPath: null, - setupFiles: ['./testSetup.js'], - snapshotSerializers: ['jest-snapshot-serializer-ansi'], + setupFiles: ['./test/testSetup.js'], + snapshotSerializers: ['./test/serializer.cjs'], testEnvironment: 'node', - transform: { - '\\.[jt]sx?$': 'babel-jest', - '\\.mjs$': 'babel-jest', - }, - /** Also transform ESM packages in `node_modules` */ - transformIgnorePatterns: [], + transform: {}, } export default config diff --git a/package-lock.json b/package-lock.json index fa1ddb68b..b85dbdba8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,9 +31,8 @@ "@changesets/cli": "2.27.1", "@commitlint/cli": "18.4.3", "@commitlint/config-conventional": "18.4.3", - "babel-jest": "29.7.0", - "babel-plugin-transform-imports": "2.0.0", "consolemock": "1.1.0", + "cross-env": "7.0.3", "eslint": "8.55.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-import": "2.29.0", @@ -3597,6 +3596,15 @@ } } }, + "node_modules/@jest/core/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3646,6 +3654,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -3761,6 +3781,15 @@ } } }, + "node_modules/@jest/reporters/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3853,6 +3882,18 @@ "node": ">=10" } }, + "node_modules/@jest/reporters/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/reporters/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -4873,16 +4914,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-transform-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-imports/-/babel-plugin-transform-imports-2.0.0.tgz", - "integrity": "sha512-65ewumYJ85QiXdcB/jmiU0y0jg6eL6CdnDqQAqQ8JMOKh1E52VPG3NJzbVKWcgovUR5GBH8IWpCXQ7I8Q3wjgw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.4", - "is-valid-path": "^0.1.1" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -5211,6 +5242,15 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5273,6 +5313,18 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5580,6 +5632,24 @@ "optional": true, "peer": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5963,6 +6033,27 @@ "node": ">=8.6" } }, + "node_modules/enquirer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6381,6 +6472,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6506,6 +6606,18 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -7686,39 +7798,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-invalid-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-0.1.0.tgz", - "integrity": "sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==", - "dev": true, - "dependencies": { - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-invalid-path/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-invalid-path/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -7898,18 +7977,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-valid-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-valid-path/-/is-valid-path-0.1.1.tgz", - "integrity": "sha512-+kwPrVDu9Ms03L90Qaml+79+6DZHqHyRoANI6IsZJ/g8frhnfchDOBCa0RbQ6/kdHt5CS5OeIEyrYznNuVN+8A==", - "dev": true, - "dependencies": { - "is-invalid-path": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -9150,21 +9217,6 @@ "node": ">=16" } }, - "node_modules/jest-snapshot-serializer-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9861,20 +9913,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/log-update/node_modules/type-fest": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", @@ -11459,6 +11497,15 @@ "node": ">=6" } }, + "node_modules/smartwrap/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/smartwrap/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -11569,6 +11616,18 @@ "node": ">=8" } }, + "node_modules/smartwrap/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/smartwrap/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -11813,6 +11872,27 @@ "node": ">=10" } }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.0.0.tgz", @@ -11829,20 +11909,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -11912,24 +11978,17 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-bom": { @@ -12245,6 +12304,15 @@ "node": ">=8.0.0" } }, + "node_modules/tty-table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/tty-table/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -12303,6 +12371,18 @@ "node": ">=6" } }, + "node_modules/tty-table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -12700,20 +12780,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -12793,6 +12859,15 @@ "node": ">=6" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -12822,6 +12897,18 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/package.json b/package.json index 609b800c8..68e491c8e 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,8 @@ ], "scripts": { "lint": "eslint .", - "test": "jest --coverage", - "test:watch": "jest --watch", + "test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --coverage", + "test:watch": "npm run test -- --watch", "version": "npx changeset version", "postversion": "npm i --package-lock-only && git commit -am \"chore(changeset): release\"", "tag": "npx changeset tag" @@ -55,9 +55,8 @@ "@changesets/cli": "2.27.1", "@commitlint/cli": "18.4.3", "@commitlint/config-conventional": "18.4.3", - "babel-jest": "29.7.0", - "babel-plugin-transform-imports": "2.0.0", "consolemock": "1.1.0", + "cross-env": "7.0.3", "eslint": "8.55.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-import": "2.29.0", diff --git a/test/e2e/__utils__/getLintStagedExecutor.js b/test/e2e/__utils__/getLintStagedExecutor.js index cbbff6245..deb40ff65 100644 --- a/test/e2e/__utils__/getLintStagedExecutor.js +++ b/test/e2e/__utils__/getLintStagedExecutor.js @@ -1,8 +1,11 @@ -import { resolve } from 'node:path' +import path from 'node:path' +import { fileURLToPath } from 'node:url' import { execaCommand } from 'execa' -const lintStagedBin = resolve(__dirname, '../../../bin/lint-staged.js') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const lintStagedBin = path.resolve(__dirname, '../../../bin/lint-staged.js') /** * @param {string} cwd diff --git a/test/e2e/no-stash.test.js b/test/e2e/no-stash.test.js index e454835f9..d46296cdb 100644 --- a/test/e2e/no-stash.test.js +++ b/test/e2e/no-stash.test.js @@ -1,5 +1,3 @@ -import '../integration/__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from '../integration/__utils__/withGitIntegration.js' diff --git a/test/e2e/stdin-config.test.js b/test/e2e/stdin-config.test.js index 9c002fdc4..e3ad8db15 100644 --- a/test/e2e/stdin-config.test.js +++ b/test/e2e/stdin-config.test.js @@ -1,5 +1,3 @@ -import '../integration/__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from '../integration/__utils__/withGitIntegration.js' diff --git a/test/integration/__mocks__/dynamicImport.js b/test/integration/__mocks__/dynamicImport.js deleted file mode 100644 index 5fd38b13d..000000000 --- a/test/integration/__mocks__/dynamicImport.js +++ /dev/null @@ -1,4 +0,0 @@ -jest.mock('../../../lib/dynamicImport.js', () => ({ - // 'pathToFileURL' is not supported with Jest + Babel - dynamicImport: jest.fn().mockImplementation(async (input) => require(input)), -})) diff --git a/test/integration/__mocks__/resolveConfig.js b/test/integration/__mocks__/resolveConfig.js deleted file mode 100644 index 842f9e17a..000000000 --- a/test/integration/__mocks__/resolveConfig.js +++ /dev/null @@ -1,10 +0,0 @@ -/** Unfortunately necessary due to non-ESM tests. */ -jest.mock('../../../lib/resolveConfig.js', () => ({ - resolveConfig: (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } - }, -})) diff --git a/test/integration/allow-empty.test.js b/test/integration/allow-empty.test.js index 33a71b32d..d742471f0 100644 --- a/test/integration/allow-empty.test.js +++ b/test/integration/allow-empty.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/basic-functionality.test.js b/test/integration/basic-functionality.test.js index 51d53df65..da6b76679 100644 --- a/test/integration/basic-functionality.test.js +++ b/test/integration/basic-functionality.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import path from 'node:path' diff --git a/test/integration/binary-files.test.js b/test/integration/binary-files.test.js index c61ca93d7..af563f894 100644 --- a/test/integration/binary-files.test.js +++ b/test/integration/binary-files.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/diff-options.test.js b/test/integration/diff-options.test.js index ba3e8611b..7df7e32c8 100644 --- a/test/integration/diff-options.test.js +++ b/test/integration/diff-options.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' diff --git a/test/integration/file-resurrection.test.js b/test/integration/file-resurrection.test.js index aee4d4235..b25073dee 100644 --- a/test/integration/file-resurrection.test.js +++ b/test/integration/file-resurrection.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import path from 'node:path' diff --git a/test/integration/files-outside-cwd.test.js b/test/integration/files-outside-cwd.test.js index 1beb1cea3..bfcbc79f3 100644 --- a/test/integration/files-outside-cwd.test.js +++ b/test/integration/files-outside-cwd.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import path from 'node:path' import { jest } from '@jest/globals' diff --git a/test/integration/git-amend.test.js b/test/integration/git-amend.test.js index 77f5c49a8..8bdf3faa5 100644 --- a/test/integration/git-amend.test.js +++ b/test/integration/git-amend.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/git-lock-file.test.js b/test/integration/git-lock-file.test.js index f1dd3f8bd..f53e98a71 100644 --- a/test/integration/git-lock-file.test.js +++ b/test/integration/git-lock-file.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/git-submodules.test.js b/test/integration/git-submodules.test.js index 9e5587f7f..96245863e 100644 --- a/test/integration/git-submodules.test.js +++ b/test/integration/git-submodules.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import path from 'node:path' diff --git a/test/integration/git-worktree.test.js b/test/integration/git-worktree.test.js index b8bef8fb1..68fbcfb5a 100644 --- a/test/integration/git-worktree.test.js +++ b/test/integration/git-worktree.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import path from 'node:path' import { jest } from '@jest/globals' diff --git a/test/integration/gitWorkFlow.test.js b/test/integration/gitWorkFlow.test.js index 7ae752e0c..bd0fbb211 100644 --- a/test/integration/gitWorkFlow.test.js +++ b/test/integration/gitWorkFlow.test.js @@ -1,10 +1,7 @@ -import './__mocks__/resolveConfig.js' - import path from 'node:path' -import { jest as jestGlobals } from '@jest/globals' +import { jest } from '@jest/globals' -import { writeFile } from '../../lib/file.js' import { GitWorkflow } from '../../lib/gitWorkflow.js' import { getInitialState } from '../../lib/state.js' import { @@ -17,15 +14,14 @@ import { import { normalizeWindowsNewlines } from './__utils__/normalizeWindowsNewlines.js' import { withGitIntegration } from './__utils__/withGitIntegration.js' -jestGlobals.mock('../../lib/file.js', () => { - return { - // notice `jestGlobals` vs `jest` here... this will be changed with `jest.unstable_mockModule` - writeFile: jest.fn(() => Promise.resolve()), - } -}) +jest.unstable_mockModule('../../lib/file.js', () => ({ + writeFile: jest.fn(() => Promise.resolve()), +})) + +const { writeFile } = await import('../../lib/file.js') -jestGlobals.setTimeout(20000) -jestGlobals.retryTimes(2) +jest.setTimeout(20000) +jest.retryTimes(2) describe('gitWorkflow', () => { describe('prepare', () => { diff --git a/test/integration/merge-conflict.test.js b/test/integration/merge-conflict.test.js index 63c3cf3b4..601552a55 100644 --- a/test/integration/merge-conflict.test.js +++ b/test/integration/merge-conflict.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs' import path from 'node:path' diff --git a/test/integration/multiple-config-files.test.js b/test/integration/multiple-config-files.test.js index 70387e512..f3a771a21 100644 --- a/test/integration/multiple-config-files.test.js +++ b/test/integration/multiple-config-files.test.js @@ -1,6 +1,3 @@ -import './__mocks__/resolveConfig.js' -import './__mocks__/dynamicImport.js' - import path from 'node:path' import { jest as jestGlobals } from '@jest/globals' diff --git a/test/integration/no-initial-commit.test.js b/test/integration/no-initial-commit.test.js index 507289301..52d2430f3 100644 --- a/test/integration/no-initial-commit.test.js +++ b/test/integration/no-initial-commit.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/no-stash.test.js b/test/integration/no-stash.test.js index 769efbb8d..5463a8717 100644 --- a/test/integration/no-stash.test.js +++ b/test/integration/no-stash.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs' import path from 'node:path' diff --git a/test/integration/non-ascii.test.js b/test/integration/non-ascii.test.js index 9db92fd83..89645e676 100644 --- a/test/integration/non-ascii.test.js +++ b/test/integration/non-ascii.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/integration/not-inside-git-repo.test.js b/test/integration/not-inside-git-repo.test.js index fffee9439..7fb97225a 100644 --- a/test/integration/not-inside-git-repo.test.js +++ b/test/integration/not-inside-git-repo.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import { jest } from '@jest/globals' diff --git a/test/integration/parent-globs.test.js b/test/integration/parent-globs.test.js index 51229f88d..e2c097293 100644 --- a/test/integration/parent-globs.test.js +++ b/test/integration/parent-globs.test.js @@ -1,6 +1,3 @@ -import './__mocks__/resolveConfig.js' -import './__mocks__/dynamicImport.js' - import path from 'node:path' import { jest } from '@jest/globals' diff --git a/test/integration/partially-staged-changes.test.js b/test/integration/partially-staged-changes.test.js index 450fe5769..1356caf0b 100644 --- a/test/integration/partially-staged-changes.test.js +++ b/test/integration/partially-staged-changes.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { normalizeWindowsNewlines } from './__utils__/normalizeWindowsNewlines.js' diff --git a/test/integration/symlink-git-dir.test.js b/test/integration/symlink-git-dir.test.js index cea8e4c66..1f8261e22 100644 --- a/test/integration/symlink-git-dir.test.js +++ b/test/integration/symlink-git-dir.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import path from 'node:path' diff --git a/test/integration/symlinked-config.test.js b/test/integration/symlinked-config.test.js index 3b1adc0f6..35022446c 100644 --- a/test/integration/symlinked-config.test.js +++ b/test/integration/symlinked-config.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import fs from 'node:fs/promises' import path from 'node:path' diff --git a/test/integration/untracked-files.test.js b/test/integration/untracked-files.test.js index b5df9fb9e..986cfcf7a 100644 --- a/test/integration/untracked-files.test.js +++ b/test/integration/untracked-files.test.js @@ -1,5 +1,3 @@ -import './__mocks__/resolveConfig.js' - import { jest } from '@jest/globals' import { withGitIntegration } from './__utils__/withGitIntegration.js' diff --git a/test/serializer.cjs b/test/serializer.cjs new file mode 100644 index 000000000..243a67e95 --- /dev/null +++ b/test/serializer.cjs @@ -0,0 +1,40 @@ +/** + * Inlined functionality of `jest-snapshot-serializer-ansi` converted to CJS + * until Jest supports loading ESM snapshot serializers. + * @see https://github.com/jestjs/jest/issues/11167 + */ + +/** @see https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js */ +const ansiRegex = ({ onlyFirst = false } = {}) => { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))', + ].join('|') + + return new RegExp(pattern, onlyFirst ? undefined : 'g') +} + +const onlyFirstRegex = ansiRegex({ onlyFirst: true }) + +/** @see https://github.com/chalk/has-ansi/blob/a285373adebe5e01f325d5a2e9df2686a09bc0d7/index.js */ +const hasAnsi = (string) => onlyFirstRegex.test(string) + +const allRegex = ansiRegex() + +/** @see https://github.com/chalk/strip-ansi/blob/1fdc531d4046cbaa830460f5c74452bf1f0a0884/index.js */ +const stripAnsi = (string) => { + if (typeof string !== 'string') { + throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``) + } + + // Even though the regex is global, we don't need to reset the `.lastIndex` + // because unlike `.exec()` and `.test()`, `.replace()` does it automatically + // and doing it manually has a performance penalty. + return string.replace(allRegex, '') +} + +/** @see https://github.com/ikatyang/jest-snapshot-serializer-ansi/blob/3ca79ba5a2201124b4b616f728b4a92b7388fc68/src/index.ts */ +module.exports = { + test: (value) => typeof value === 'string' && hasAnsi(value), + print: (value, serialize) => serialize(stripAnsi(value)), +} diff --git a/testSetup.js b/test/testSetup.js similarity index 100% rename from testSetup.js rename to test/testSetup.js diff --git a/test/unit/__mocks__/advanced-config.js b/test/unit/__mocks__/advanced-cjs-config.cjs similarity index 100% rename from test/unit/__mocks__/advanced-config.js rename to test/unit/__mocks__/advanced-cjs-config.cjs diff --git a/test/unit/__mocks__/advanced-esm-config.js b/test/unit/__mocks__/advanced-esm-config.js new file mode 100644 index 000000000..6f470c436 --- /dev/null +++ b/test/unit/__mocks__/advanced-esm-config.js @@ -0,0 +1,4 @@ +export default { + '*.css': (filenames) => `echo ${filenames.join(' ')}`, + '*.js': (filenames) => filenames.map((filename) => `echo ${filename}`), +} diff --git a/test/unit/__utils__/getMockExeca.js b/test/unit/__utils__/getMockExeca.js new file mode 100644 index 000000000..496731ba0 --- /dev/null +++ b/test/unit/__utils__/getMockExeca.js @@ -0,0 +1,12 @@ +import { jest } from '@jest/globals' + +import { mockExecaReturnValue } from './mockExecaReturnValue.js' + +export const getMockExeca = async (mockReturnValue = {}) => { + jest.unstable_mockModule('execa', () => { + const execa = jest.fn().mockImplementation(() => mockExecaReturnValue(mockReturnValue)) + return { execa, execaCommand: execa } + }) + + return import('execa') +} diff --git a/test/unit/__utils__/getMockListr2.js b/test/unit/__utils__/getMockListr2.js new file mode 100644 index 000000000..7769ef297 --- /dev/null +++ b/test/unit/__utils__/getMockListr2.js @@ -0,0 +1,16 @@ +import { jest } from '@jest/globals' +import { figures } from 'listr2' + +export const getMockListr2 = async () => { + const mockRunner = jest.fn() + mockRunner.run = jest.fn() + + jest.unstable_mockModule('listr2', () => ({ + Listr: jest.fn(() => mockRunner), + ListrLogger: jest.fn(), + figures, + ProcessOutput: jest.fn(), + })) + + return import('listr2') +} diff --git a/test/unit/execGit.spec.js b/test/unit/execGit.spec.js index 8b49dca50..97b40117a 100644 --- a/test/unit/execGit.spec.js +++ b/test/unit/execGit.spec.js @@ -1,14 +1,9 @@ import path from 'node:path' -import { execa } from 'execa' +import { getMockExeca } from './__utils__/getMockExeca.js' -import { execGit, GIT_GLOBAL_OPTIONS } from '../../lib/execGit.js' - -import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' - -jest.mock('execa', () => ({ - execa: jest.fn(() => mockExecaReturnValue()), -})) +const { execa } = await getMockExeca() +const { execGit, GIT_GLOBAL_OPTIONS } = await import('../../lib/execGit.js') test('GIT_GLOBAL_OPTIONS', () => { expect(GIT_GLOBAL_OPTIONS).toMatchInlineSnapshot(` diff --git a/test/unit/getBackupStash.spec.js b/test/unit/getBackupStash.spec.js index 4b53819c1..85f64be37 100644 --- a/test/unit/getBackupStash.spec.js +++ b/test/unit/getBackupStash.spec.js @@ -1,12 +1,18 @@ -import { execGit } from '../../lib/execGit.js' -import { GitWorkflow, STASH } from '../../lib/gitWorkflow.js' +import { jest } from '@jest/globals' + import { getInitialState } from '../../lib/state.js' import { GetBackupStashError } from '../../lib/symbols' -jest.mock('../../lib/execGit.js', () => ({ - execGit: jest.fn(async () => ''), +jest.unstable_mockModule('../../lib/execGit.js', () => ({ + execGit: jest.fn(async () => { + /** Mock fails by default */ + return '' + }), })) +const { execGit } = await import('../../lib/execGit.js') +const { GitWorkflow, STASH } = await import('../../lib/gitWorkflow.js') + describe('gitWorkflow', () => { const options = { gitConfigDir: '.' } diff --git a/test/unit/getStagedFiles.spec.js b/test/unit/getStagedFiles.spec.js index 901c0c5dc..b8efb6536 100644 --- a/test/unit/getStagedFiles.spec.js +++ b/test/unit/getStagedFiles.spec.js @@ -1,10 +1,15 @@ import path from 'node:path' -import { execGit } from '../../lib/execGit.js' -import { getStagedFiles } from '../../lib/getStagedFiles.js' +import { jest } from '@jest/globals' + import { normalizePath } from '../../lib/normalizePath.js' -jest.mock('../../lib/execGit.js') +jest.unstable_mockModule('../../lib/execGit.js', () => ({ + execGit: jest.fn(async () => ''), +})) + +const { execGit } = await import('../../lib/execGit.js') +const { getStagedFiles } = await import('../../lib/getStagedFiles.js') // Windows filepaths const normalizeWindowsPath = (input) => normalizePath(path.resolve('/', input)) diff --git a/test/unit/index.spec.js b/test/unit/index.spec.js index e4041c72e..60da63c00 100644 --- a/test/unit/index.spec.js +++ b/test/unit/index.spec.js @@ -1,47 +1,21 @@ -import { lilconfig } from 'lilconfig' import makeConsoleMock from 'consolemock' +import { jest } from '@jest/globals' -import { getStagedFiles } from '../../lib/getStagedFiles.js' -import lintStaged from '../../lib/index.js' +jest.unstable_mockModule('lilconfig', () => ({ + lilconfig: jest.fn(), +})) -jest.unmock('execa') +jest.unstable_mockModule('../../lib/getStagedFiles.js', () => ({ getStagedFiles: jest.fn() })) -jest.mock('lilconfig', () => { - const actual = jest.requireActual('lilconfig') - return { - lilconfig: jest.fn((name, options) => actual.lilconfig(name, options)), - } -}) +jest.unstable_mockModule('../../lib/gitWorkflow.js', () => ({ GitWorkflow: jest.fn() })) -const mockLilConfig = (result) => { - lilconfig.mockImplementationOnce(() => ({ - search: () => Promise.resolve(result), - })) -} - -/** - * This converts paths into `file://` urls, but this doesn't - * work with `import()` when using babel + jest. - */ -jest.mock('node:url', () => ({ - pathToFileURL: (path) => path, +jest.unstable_mockModule('../../lib/validateOptions.js', () => ({ + validateOptions: jest.fn().mockImplementation(async () => void {}), })) -jest.mock('../../lib/getStagedFiles.js') -jest.mock('../../lib/gitWorkflow.js') -jest.mock('../../lib/resolveConfig.js', () => ({ - /** Unfortunately necessary due to non-ESM tests. */ - resolveConfig: (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } - }, -})) -jest.mock('../../lib/validateOptions.js', () => ({ - validateOptions: jest.fn().mockImplementation(async () => {}), -})) +const { lilconfig } = await import('lilconfig') +const { getStagedFiles } = await import('../../lib/getStagedFiles.js') +const { default: lintStaged } = await import('../../lib/index.js') // TODO: Never run tests in the project's WC because this might change source files git status @@ -56,7 +30,7 @@ describe('lintStaged', () => { expect.assertions(1) const config = { '*': 'mytask' } - mockLilConfig({ config }) + lilconfig({ config }) await lintStaged(undefined, logger) @@ -79,7 +53,7 @@ describe('lintStaged', () => { it('should use use the console if no logger is passed', async () => { expect.assertions(1) - mockLilConfig({ config: {} }) + lilconfig({ config: {} }) const previousConsole = console const mockedConsole = makeConsoleMock() diff --git a/test/unit/index2.spec.js b/test/unit/index2.spec.js index 890c5aa82..98afacb45 100644 --- a/test/unit/index2.spec.js +++ b/test/unit/index2.spec.js @@ -1,40 +1,35 @@ import path from 'node:path' +import { fileURLToPath } from 'node:url' -import { Listr } from 'listr2' +import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' -import lintStaged from '../../lib/index.js' +import { getMockListr2 } from './__utils__/getMockListr2.js' -import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' +const { Listr } = await getMockListr2() -jest.mock('execa', () => ({ - execa: jest.fn(() => mockExecaReturnValue()), -})) - -jest.mock('listr2') +const __dirname = path.dirname(fileURLToPath(import.meta.url)) const MOCK_CONFIG_FILE = path.join(__dirname, '__mocks__', 'my-config.json') const MOCK_STAGED_FILE = path.resolve(__dirname, '__mocks__', 'sample.js') -jest.mock('../../lib/getStagedFiles.js', () => ({ - getStagedFiles: async () => [MOCK_STAGED_FILE], +jest.unstable_mockModule('../../lib/execGit.js', () => ({ + execGit: jest.fn(async () => { + /** Mock fails by default */ + return '' + }), })) -jest.mock('../../lib/resolveConfig.js', () => ({ - /** Unfortunately necessary due to non-ESM tests. */ - resolveConfig: (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } - }, +jest.unstable_mockModule('../../lib/getStagedFiles.js', () => ({ + getStagedFiles: jest.fn(async () => [MOCK_STAGED_FILE]), })) -jest.mock('../../lib/resolveGitRepo.js', () => ({ - resolveGitRepo: async () => ({ gitDir: 'foo', gitConfigDir: 'bar' }), +jest.unstable_mockModule('../../lib/resolveGitRepo.js', () => ({ + resolveGitRepo: jest.fn(async () => ({ gitDir: 'foo', gitConfigDir: 'bar' })), })) +const { default: lintStaged } = await import('../../lib/index.js') + describe('lintStaged', () => { afterEach(() => { Listr.mockClear() @@ -67,7 +62,7 @@ describe('lintStaged', () => { }) }) - it('should catch errors from js function config', async () => { + it.only('should catch errors from js function config', async () => { const logger = makeConsoleMock() const config = { '*': () => { diff --git a/test/unit/index3.spec.js b/test/unit/index3.spec.js index 051984544..5e6a0304f 100644 --- a/test/unit/index3.spec.js +++ b/test/unit/index3.spec.js @@ -1,18 +1,21 @@ +import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' -import lintStaged from '../../lib/index.js' -import { runAll } from '../../lib/runAll.js' -import { getInitialState } from '../../lib/state.js' -import { ApplyEmptyCommitError, ConfigNotFoundError, GitError } from '../../lib/symbols.js' - -jest.mock('../../lib/validateOptions.js', () => ({ +jest.unstable_mockModule('../../lib/validateOptions.js', () => ({ validateOptions: jest.fn(async () => {}), })) -jest.mock('../../lib/runAll.js', () => ({ +jest.unstable_mockModule('../../lib/runAll.js', () => ({ runAll: jest.fn(async () => {}), })) +const { default: lintStaged } = await import('../../lib/index.js') +const { runAll } = await import('../../lib/runAll.js') +const { getInitialState } = await import('../../lib/state.js') +const { ApplyEmptyCommitError, ConfigNotFoundError, GitError } = await import( + '../../lib/symbols.js' +) + describe('lintStaged', () => { it('should log error when configuration not found', async () => { const ctx = getInitialState() diff --git a/test/unit/loadConfig.spec.js b/test/unit/loadConfig.spec.js index 963700210..3fa633493 100644 --- a/test/unit/loadConfig.spec.js +++ b/test/unit/loadConfig.spec.js @@ -1,29 +1,14 @@ import fs from 'node:fs/promises' import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' import { createTempDir } from '../__utils__/createTempDir.js' import { loadConfig } from '../../lib/loadConfig.js' -/** Unfortunately necessary due to non-ESM tests. */ -jest.mock('../../lib/resolveConfig.js', () => ({ - resolveConfig: (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } - }, -})) - -/** - * This converts paths into `file://` urls, but this doesn't - * work with `import()` when using babel + jest. - */ -jest.mock('node:url', () => ({ - pathToFileURL: (path) => path, -})) +const __dirname = path.dirname(fileURLToPath(import.meta.url)) describe('loadConfig', () => { const logger = makeConsoleMock() @@ -73,11 +58,43 @@ describe('loadConfig', () => { expect(config).toBeUndefined() }) - it('should load CommonJS config file from absolute path', async () => { + it('should load advanced config from absolute .js filepath', async () => { + expect.assertions(1) + + const { config } = await loadConfig( + { configPath: path.join(__dirname, '__mocks__', 'advanced-esm-config.js') }, + logger + ) + + expect(config).toMatchInlineSnapshot(` + { + "*.css": [Function], + "*.js": [Function], + } + `) + }) + + it('should load advanced config file from relative .js filepath', async () => { + expect.assertions(1) + + const { config } = await loadConfig( + { configPath: path.join('test', 'unit', '__mocks__', 'advanced-esm-config.js') }, + logger + ) + + expect(config).toMatchInlineSnapshot(` + { + "*.css": [Function], + "*.js": [Function], + } + `) + }) + + it('should load CommonJS config from absolute .cjs file', async () => { expect.assertions(1) const { config } = await loadConfig( - { configPath: path.join(__dirname, '__mocks__', 'advanced-config.js') }, + { configPath: path.join(__dirname, '__mocks__', 'advanced-cjs-config.cjs') }, logger ) @@ -93,7 +110,7 @@ describe('loadConfig', () => { expect.assertions(1) const { config } = await loadConfig( - { configPath: path.join('test', 'unit', '__mocks__', 'advanced-config.js') }, + { configPath: path.join('test', 'unit', '__mocks__', 'advanced-cjs-config.cjs') }, logger ) @@ -105,7 +122,7 @@ describe('loadConfig', () => { `) }) - it('should load CommonJS config file from .cjs file', async () => { + it('should load CommonJS from relative .cjs file', async () => { expect.assertions(1) const { config } = await loadConfig( diff --git a/test/unit/makeCmdTasks.spec.js b/test/unit/makeCmdTasks.spec.js index fe1569250..a599fd056 100644 --- a/test/unit/makeCmdTasks.spec.js +++ b/test/unit/makeCmdTasks.spec.js @@ -1,12 +1,8 @@ -import { execa } from 'execa' +import { getMockExeca } from './__utils__/getMockExeca.js' -import { makeCmdTasks } from '../../lib/makeCmdTasks.js' +const { execa } = await getMockExeca() -import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' - -jest.mock('execa', () => ({ - execa: jest.fn(() => mockExecaReturnValue()), -})) +const { makeCmdTasks } = await import('../../lib/makeCmdTasks.js') describe('makeCmdTasks', () => { const gitDir = process.cwd() diff --git a/test/unit/printTaskOutput.spec.js b/test/unit/printTaskOutput.spec.js index f7ba4ce7e..f6a94173b 100644 --- a/test/unit/printTaskOutput.spec.js +++ b/test/unit/printTaskOutput.spec.js @@ -1,3 +1,5 @@ +import { jest } from '@jest/globals' + import { printTaskOutput } from '../../lib/printTaskOutput.js' const logger = { diff --git a/test/unit/resolveGitRepo.spec.js b/test/unit/resolveGitRepo.spec.js index 9f63d0835..11cd00e01 100644 --- a/test/unit/resolveGitRepo.spec.js +++ b/test/unit/resolveGitRepo.spec.js @@ -1,12 +1,11 @@ import path from 'node:path' +import { fileURLToPath } from 'node:url' import { normalizePath } from '../../lib/normalizePath.js' import { determineGitDir, resolveGitRepo } from '../../lib/resolveGitRepo.js' -/** - * resolveGitRepo runs execa, so the mock needs to be disabled for these tests - */ -jest.unmock('execa') +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) describe('resolveGitRepo', () => { it('should resolve to current working dir when .git is in the same dir', async () => { diff --git a/test/unit/resolveTaskFn.spec.js b/test/unit/resolveTaskFn.spec.js index 3de8b29de..8df03bf25 100644 --- a/test/unit/resolveTaskFn.spec.js +++ b/test/unit/resolveTaskFn.spec.js @@ -1,27 +1,24 @@ -import { execa, execaCommand } from 'execa' -import pidTree from 'pidtree' +import { jest } from '@jest/globals' -import { resolveTaskFn } from '../../lib/resolveTaskFn.js' import { getInitialState } from '../../lib/state.js' import { TaskError } from '../../lib/symbols.js' +import { getMockExeca } from './__utils__/getMockExeca.js' import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' -jest.useFakeTimers() +const { execa, execaCommand } = await getMockExeca() -jest.mock('execa', () => ({ - execa: jest.fn(() => mockExecaReturnValue()), - execaCommand: jest.fn(() => mockExecaReturnValue()), +jest.unstable_mockModule('pidtree', () => ({ + default: jest.fn(async () => []), })) -jest.mock('pidtree', () => jest.fn(async () => [])) +const { default: pidTree } = await import('pidtree') -const defaultOpts = { files: ['test.js'] } +const { resolveTaskFn } = await import('../../lib/resolveTaskFn.js') + +jest.useFakeTimers() -const mockExecaImplementationOnce = (value) => { - execa.mockImplementationOnce(() => mockExecaReturnValue(value)) - execaCommand.mockImplementationOnce(() => mockExecaReturnValue(value)) -} +const defaultOpts = { files: ['test.js'] } describe('resolveTaskFn', () => { beforeEach(() => { @@ -153,13 +150,15 @@ describe('resolveTaskFn', () => { it('should throw error for failed linters', async () => { expect.assertions(1) - mockExecaImplementationOnce({ - stdout: 'Mock error', - stderr: '', - code: 0, - failed: true, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: 'Mock error', + stderr: '', + code: 0, + failed: true, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock-fail-linter' }) await expect(taskFn()).rejects.toThrowErrorMatchingInlineSnapshot(`"mock-fail-linter [FAILED]"`) @@ -167,15 +166,17 @@ describe('resolveTaskFn', () => { it('should throw error for interrupted processes', async () => { expect.assertions(1) - mockExecaImplementationOnce({ - stdout: 'Mock error', - stderr: '', - code: 0, - failed: false, - killed: false, - signal: 'SIGINT', - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: 'Mock error', + stderr: '', + code: 0, + failed: false, + killed: false, + signal: 'SIGINT', + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock-killed-linter' }) await expect(taskFn()).rejects.toThrowErrorMatchingInlineSnapshot( @@ -185,15 +186,17 @@ describe('resolveTaskFn', () => { it('should throw error for killed processes without signal', async () => { expect.assertions(1) - mockExecaImplementationOnce({ - stdout: 'Mock error', - stderr: '', - code: 0, - failed: false, - killed: true, - signal: undefined, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: 'Mock error', + stderr: '', + code: 0, + failed: false, + killed: true, + signal: undefined, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock-killed-linter' }) await expect(taskFn()).rejects.toThrowErrorMatchingInlineSnapshot( @@ -210,13 +213,16 @@ describe('resolveTaskFn', () => { }) it('should add TaskError on error', async () => { - mockExecaImplementationOnce({ - stdout: 'Mock error', - stderr: '', - code: 0, - failed: true, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: 'Mock error', + stderr: '', + code: 0, + failed: true, + cmd: 'mock cmd', + }) + ) + const context = getInitialState() const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock-fail-linter' }) expect.assertions(2) @@ -228,15 +234,17 @@ describe('resolveTaskFn', () => { it('should not add output when there is none', async () => { expect.assertions(2) - mockExecaImplementationOnce({ - stdout: '', - stderr: '', - code: 0, - failed: false, - killed: false, - signal: undefined, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: '', + stderr: '', + code: 0, + failed: false, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd', verbose: true }) const context = getInitialState() @@ -247,15 +255,17 @@ describe('resolveTaskFn', () => { it('should add output even when task succeeds if `verbose: true`', async () => { expect.assertions(2) - mockExecaImplementationOnce({ - stdout: 'Mock success', - stderr: '', - code: 0, - failed: false, - killed: false, - signal: undefined, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: 'Mock success', + stderr: '', + code: 0, + failed: false, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd', verbose: true }) const context = getInitialState() @@ -272,15 +282,17 @@ describe('resolveTaskFn', () => { it('should not add title to output when task errors while quiet', async () => { expect.assertions(2) - mockExecaImplementationOnce({ - stdout: '', - stderr: 'stderr', - code: 1, - failed: true, - killed: false, - signal: undefined, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: '', + stderr: 'stderr', + code: 1, + failed: true, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd' }) const context = getInitialState({ quiet: true }) @@ -295,15 +307,17 @@ describe('resolveTaskFn', () => { it('should not print anything when task errors without output while quiet', async () => { expect.assertions(2) - mockExecaImplementationOnce({ - stdout: '', - stderr: '', - code: 1, - failed: true, - killed: false, - signal: undefined, - cmd: 'mock cmd', - }) + execa.mockReturnValueOnce( + mockExecaReturnValue({ + stdout: '', + stderr: '', + code: 1, + failed: true, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + ) const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd' }) const context = getInitialState({ quiet: true }) diff --git a/test/unit/resolveTaskFn.unmocked.spec.js b/test/unit/resolveTaskFn.unmocked.spec.js index e60649d09..61502791f 100644 --- a/test/unit/resolveTaskFn.unmocked.spec.js +++ b/test/unit/resolveTaskFn.unmocked.spec.js @@ -1,8 +1,6 @@ import { resolveTaskFn } from '../../lib/resolveTaskFn.js' import { getInitialState } from '../../lib/state.js' -jest.unmock('execa') - describe('resolveTaskFn', () => { it('should call execa with shell when configured so', async () => { const taskFn = resolveTaskFn({ diff --git a/test/unit/runAll.spec.js b/test/unit/runAll.spec.js index fc5990ade..7f45d3aa4 100644 --- a/test/unit/runAll.spec.js +++ b/test/unit/runAll.spec.js @@ -1,46 +1,49 @@ import path from 'node:path' +import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' -import { execa } from 'execa' +import normalize from 'normalize-path' -import { getStagedFiles } from '../../lib/getStagedFiles.js' -import { GitWorkflow } from '../../lib/gitWorkflow.js' import { normalizePath } from '../../lib/normalizePath.js' -import { resolveGitRepo } from '../../lib/resolveGitRepo.js' -import { runAll } from '../../lib/runAll.js' -import * as searchConfigsNS from '../../lib/searchConfigs.js' -import { ConfigNotFoundError, GitError } from '../../lib/symbols.js' import { mockExecaReturnValue } from './__utils__/mockExecaReturnValue.js' +import { getMockExeca } from './__utils__/getMockExeca.js' -jest.mock('execa', () => ({ - execa: jest.fn(() => mockExecaReturnValue()), -})) +const { execa } = await getMockExeca() -jest.mock('../../lib/file.js') -jest.mock('../../lib/getStagedFiles.js') -jest.mock('../../lib/gitWorkflow.js') -jest.mock('../../lib/resolveGitRepo.js') +jest.unstable_mockModule('../../lib/getStagedFiles.js', () => ({ + getStagedFiles: jest.fn(async () => []), +})) -jest.mock('../../lib/resolveConfig.js', () => ({ - /** Unfortunately necessary due to non-ESM tests. */ - resolveConfig: (configPath) => { - try { - return require.resolve(configPath) - } catch { - return configPath - } - }, +const mockGitWorkflow = { + prepare: jest.fn(() => Promise.resolve()), + hideUnstagedChanges: jest.fn(() => Promise.resolve()), + applyModifications: jest.fn(() => Promise.resolve()), + restoreUnstagedChanges: jest.fn(() => Promise.resolve()), + restoreOriginalState: jest.fn(() => Promise.resolve()), + cleanup: jest.fn(() => Promise.resolve()), +} + +jest.unstable_mockModule('../../lib/gitWorkflow.js', () => ({ + GitWorkflow: jest.fn(() => mockGitWorkflow), })) -const searchConfigs = jest.spyOn(searchConfigsNS, 'searchConfigs') +jest.unstable_mockModule('../../lib/resolveGitRepo.js', () => ({ + resolveGitRepo: jest.fn(async () => { + const cwd = process.cwd() + return { gitConfigDir: normalize(path.resolve(cwd, '.git')), gitDir: normalize(cwd) } + }), +})) -getStagedFiles.mockImplementation(async () => []) +jest.unstable_mockModule('../../lib/searchConfigs.js', () => ({ + searchConfigs: jest.fn(async () => ({})), +})) -resolveGitRepo.mockImplementation(async () => { - const cwd = process.cwd() - return { gitConfigDir: normalizePath(path.resolve(cwd, '.git')), gitDir: normalizePath(cwd) } -}) +const { getStagedFiles } = await import('../../lib/getStagedFiles.js') +const { GitWorkflow } = await import('../../lib/gitWorkflow.js') +const { runAll } = await import('../../lib/runAll.js') +const { searchConfigs } = await import('../../lib/searchConfigs.js') +const { ConfigNotFoundError, GitError } = await import('../../lib/symbols.js') const configPath = '.lintstagedrc.json' @@ -62,7 +65,7 @@ describe('runAll', () => { it('should resolve the promise with no tasks', async () => { expect.assertions(1) - await expect(runAll({ configObject: {}, configPath })).resolves.toBeTruthy() + await expect(runAll({})).resolves.toBeTruthy() }) it('should throw when failed to find staged files', async () => { @@ -111,40 +114,56 @@ describe('runAll', () => { }) it('should exit without output when no staged files match configured tasks and quiet', async () => { - expect.assertions(1) + expect.assertions(2) + getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await runAll({ configObject: { '*.css': ['echo "sample"'] }, configPath, quiet: true }) + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.css': 'echo "sample"' }, + })) + + await expect(runAll({ quiet: true })).resolves.toBeTruthy() + expect(console.printHistory()).toMatchInlineSnapshot(`""`) }) it('should not skip tasks if there are files', async () => { expect.assertions(1) getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await runAll({ configObject: { '*.js': ['echo "sample"'] }, configPath }) + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.js': 'echo "sample"' }, + })) + + await runAll({}) + expect(console.printHistory()).toMatch(/"data":"COMPLETED".*Running tasks for staged files/) }) it('should skip tasks if previous git error', async () => { expect.assertions(2) + getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - GitWorkflow.mockImplementationOnce(() => ({ - ...jest.requireActual('../../lib/gitWorkflow.js'), - prepare: (ctx) => { - ctx.errors.add(GitError) - throw new Error('test error') - }, + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.js': 'echo "sample"' }, })) - await expect( - runAll({ configObject: { '*.js': ['echo "sample"'] }, configPath }) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) + mockGitWorkflow.prepare.mockImplementationOnce((ctx) => { + ctx.errors.add(GitError) + throw new Error('test') + }) + + await expect(runAll({})).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) expect(console.printHistory()).toMatch(/"data":"SKIPPED".*Running tasks for staged files/) }) it('should skip applying unstaged modifications if there are errors during linting', async () => { expect.assertions(2) + getStagedFiles.mockImplementationOnce(async () => ['sample.js']) + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.js': 'echo "sample"' }, + })) + execa.mockImplementation(() => mockExecaReturnValue({ stdout: '', @@ -155,16 +174,19 @@ describe('runAll', () => { }) ) - await expect( - runAll({ configObject: { '*.js': ['echo "sample"'] }, configPath }) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) + await expect(runAll({})).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) expect(console.printHistory()).toMatch(/"data":"SKIPPED".*Applying modifications from tasks/) }) it('should skip tasks and restore state if terminated', async () => { expect.assertions(2) + getStagedFiles.mockImplementationOnce(async () => ['sample.js']) + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.js': 'echo "sample"' }, + })) + execa.mockImplementation(() => mockExecaReturnValue({ stdout: '', @@ -177,9 +199,7 @@ describe('runAll', () => { }) ) - await expect( - runAll({ configObject: { '*.js': ['echo "sample"'] }, configPath }) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) + await expect(runAll({})).rejects.toThrowErrorMatchingInlineSnapshot(`"lint-staged failed"`) expect(console.printHistory()).toMatch( /"data":"COMPLETED".*Reverting to original state because of errors/ @@ -197,6 +217,10 @@ describe('runAll', () => { const mockTask = jest.fn(() => ['echo "sample"']) + searchConfigs.mockImplementationOnce(async () => ({ + '': { '*.js': mockTask }, + })) + // actual cwd const cwd = process.cwd() // For the test, set cwd in test/ @@ -206,8 +230,6 @@ describe('runAll', () => { // This means the sample task will receive `foo.js` await expect( runAll({ - configObject: { '*.js': mockTask }, - configPath, stash: false, relative: true, cwd: innerCwd, @@ -297,7 +319,11 @@ describe('runAll', () => { it('should warn when "git add" was used in commands', async () => { getStagedFiles.mockImplementationOnce(async () => ['sample.js']) - await expect(runAll({ configObject: { '*.js': ['git add'] } })).rejects.toThrowError() + searchConfigs.mockResolvedValueOnce({ + '.lintstagedrc.json': { '*.js': 'git add' }, + }) + + await expect(runAll({})).rejects.toThrowError() expect(console.printHistory()).toMatch('Some of your tasks use `git add` command') }) diff --git a/test/unit/searchConfigs.spec.js b/test/unit/searchConfigs.spec.js index 9739e62b2..fcc156831 100644 --- a/test/unit/searchConfigs.spec.js +++ b/test/unit/searchConfigs.spec.js @@ -1,11 +1,11 @@ -import path from 'node:path' +import path from 'path' +import { fileURLToPath } from 'url' + +import { jest } from '@jest/globals' -import { execGit } from '../../lib/execGit.js' -import { loadConfig } from '../../lib/loadConfig.js' import { normalizePath } from '../../lib/normalizePath.js' -import { searchConfigs } from '../../lib/searchConfigs.js' -jest.mock('../../lib/resolveConfig', () => ({ +jest.unstable_mockModule('../../lib/resolveConfig.js', () => ({ /** Unfortunately necessary due to non-ESM tests. */ resolveConfig: (configPath) => { try { @@ -16,24 +16,25 @@ jest.mock('../../lib/resolveConfig', () => ({ }, })) -jest.mock('../../lib/execGit.js', () => ({ +jest.unstable_mockModule('../../lib/execGit.js', () => ({ execGit: jest.fn(async () => { /** Mock fails by default */ return '' }), })) -jest.mock('../../lib/loadConfig.js', () => { - const { searchPlaces } = jest.requireActual('../../lib/loadConfig.js') +jest.unstable_mockModule('../../lib/loadConfig.js', () => ({ + loadConfig: jest.fn(async () => { + /** Mock fails by default */ + return {} + }), +})) + +const { execGit } = await import('../../lib/execGit.js') +const { loadConfig } = await import('../../lib/loadConfig.js') +const { searchConfigs } = await import('../../lib/searchConfigs.js') - return { - searchPlaces, - loadConfig: jest.fn(async () => { - /** Mock fails by default */ - return {} - }), - } -}) +const __dirname = path.dirname(fileURLToPath(import.meta.url)) describe('searchConfigs', () => { afterEach(() => { diff --git a/test/unit/validateOptions.spec.js b/test/unit/validateOptions.spec.js index d0f928e47..2de937bfe 100644 --- a/test/unit/validateOptions.spec.js +++ b/test/unit/validateOptions.spec.js @@ -2,6 +2,7 @@ import { constants } from 'node:fs' import fs from 'node:fs/promises' import path from 'node:path' +import { jest } from '@jest/globals' import makeConsoleMock from 'consolemock' import { validateOptions } from '../../lib/validateOptions.js'