diff --git a/eslint.config.mjs b/eslint.config.mjs index f9ef9468..c695a2e2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,5 +1,6 @@ import tsBaseConfig, { namingConventions } from '@map-colonies/eslint-config/ts-base'; import { config } from '@map-colonies/eslint-config/helpers'; +import vitestConfig from '@map-colonies/eslint-config/vitest'; const AllowedSqlOperators = { selector: 'objectLiteralProperty', @@ -25,6 +26,6 @@ const customConfig = { }, }; -export default config(tsBaseConfig, customConfig, { +export default config(vitestConfig, tsBaseConfig, customConfig, { ignores: ['src/db/prisma/generated', 'src/common/generated', 'vitest.config.mts'], }); diff --git a/package-lock.json b/package-lock.json index d5a0024c..2bbb3efb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "@commitlint/cli": "^20.2.0", "@faker-js/faker": "^9.9.0", "@map-colonies/commitlint-config": "^2.0.0", - "@map-colonies/eslint-config": "^7.1.0", + "@map-colonies/eslint-config": "^8.0.0", "@map-colonies/infra-copilot-instructions": "^1.2.0", "@map-colonies/prettier-config": "^1.0.0", "@map-colonies/tsconfig": "^2.0.0", @@ -60,6 +60,7 @@ "@types/supertest": "^6.0.2", "@types/swagger-ui-express": "^4.1.8", "@vitest/coverage-v8": "^4.0.16", + "@vitest/eslint-plugin": "^1.6.9", "@vitest/ui": "^4.0.16", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", @@ -1662,9 +1663,9 @@ } }, "node_modules/@map-colonies/eslint-config": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@map-colonies/eslint-config/-/eslint-config-7.1.0.tgz", - "integrity": "sha512-jYgpokmKfl7mfB3tGMNESLaZV4wCEQ5MDkdHn5PT+EXwKudQOSg38lb2nJg4ew4DcBWZ7Yh+VW2LhvaHyPCPeA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@map-colonies/eslint-config/-/eslint-config-8.1.0.tgz", + "integrity": "sha512-j4v8zQAAsRm4LRbJ588NmJXER80SC3zC5Cc+tC7sSDsbqIYJ4I/1ROmaAhGAlBzXy+lmJSM6Wne+BPdHosij0Q==", "dev": true, "dependencies": { "@eslint/js": "^9.19.0", @@ -1673,12 +1674,14 @@ "eslint-config-prettier": "^10.0.1", "eslint-import-resolver-typescript": "^4.0.0", "eslint-plugin-import-x": "^4.16.1", + "eslint-plugin-unicorn": "^63.0.0", "typescript-eslint": "^8.23.0" }, "engines": { "node": ">=24" }, "peerDependencies": { + "@vitest/eslint-plugin": "^1.6.7", "eslint": "^9.19.0", "eslint-plugin-jest": "^28.11.0 || ^29.0.0", "eslint-plugin-react": "^7.37.4", @@ -1686,6 +1689,9 @@ "globals": "^15.14.0 || ^17.0.0" }, "peerDependenciesMeta": { + "@vitest/eslint-plugin": { + "optional": true + }, "eslint-plugin-jest": { "optional": true }, @@ -6810,6 +6816,231 @@ "source-map-js": "^1.2.1" } }, + "node_modules/@vitest/eslint-plugin": { + "version": "1.6.19", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.19.tgz", + "integrity": "sha512-zodmXRsVKFsuHxHJILuTFaaKsrsxm0YsiOX65clk+LpCW9JrVXaf6ERXr0caDs+NEk0S62Jyk0K7XYQ7gWXheA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "^8.58.0", + "@typescript-eslint/utils": "^8.58.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "*", + "eslint": ">=8.57.0", + "typescript": ">=5.0.0", + "vitest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/project-service": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.60.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/eslint-plugin/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vitest/expect": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", @@ -7236,6 +7467,19 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/better-ajv-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz", @@ -7378,12 +7622,60 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, + "node_modules/builtin-modules": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", + "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -7531,6 +7823,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chai": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", @@ -7585,9 +7898,9 @@ } }, "node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, "funding": [ { @@ -7623,6 +7936,29 @@ "dev": true, "license": "MIT" }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -8038,6 +8374,20 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -8386,6 +8736,13 @@ "fast-check": "^3.23.1" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.366", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.366.tgz", + "integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -8759,6 +9116,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/eslint-plugin-unicorn": { + "version": "63.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-63.0.0.tgz", + "integrity": "sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "@eslint-community/eslint-utils": "^4.9.0", + "change-case": "^5.4.4", + "ci-info": "^4.3.1", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.46.0", + "find-up-simple": "^1.0.1", + "globals": "^16.4.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.13.0", + "semver": "^7.7.3", + "strip-indent": "^4.1.1" + }, + "engines": { + "node": "^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -9448,6 +9852,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -10100,6 +10517,19 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/index-to-position": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", @@ -10169,6 +10599,22 @@ "node": ">=8" } }, + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^5.0.0" + }, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-bun-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", @@ -10682,6 +11128,19 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -11485,6 +11944,16 @@ "es6-promise": "^3.2.1" } }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/noms": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", @@ -13541,6 +14010,29 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -14345,6 +14837,19 @@ "node": ">=8" } }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -14772,9 +15277,9 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -15059,6 +15564,37 @@ "node": ">=8" } }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index 8ff69cbe..929581e7 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "generate:openapi-types": "openapi-helpers generate types ./openapi3.yaml ./src/openapi.d.ts --format --add-typed-request-handler", "generate:openapi-errors": "openapi-helpers generate errors ./openapi3.yaml ./src/common/generated/errors.ts --format --errors-output classes", "prepare": "node .husky/install.mjs", + "type-check": "tsc --noEmit", "migration:validate": "npx prisma validate --schema ./src/db/prisma/schema.prisma ", "migration:format": "npx prisma format --check --schema ./src/db/prisma/schema.prisma ", "migration:format-fix": "npx prisma format --schema ./src/db/prisma/schema.prisma ", @@ -77,7 +78,8 @@ "@commitlint/cli": "^20.2.0", "@faker-js/faker": "^9.9.0", "@map-colonies/commitlint-config": "^2.0.0", - "@map-colonies/eslint-config": "^7.1.0", + "@map-colonies/eslint-config": "^8.0.0", + "@vitest/eslint-plugin": "^1.6.9", "@map-colonies/infra-copilot-instructions": "^1.2.0", "@map-colonies/prettier-config": "^1.0.0", "@map-colonies/tsconfig": "^2.0.0", diff --git a/scripts/generateVersionedOpenApi.mts b/scripts/generateVersionedOpenApi.mts index 599846a1..c74c53f3 100644 --- a/scripts/generateVersionedOpenApi.mts +++ b/scripts/generateVersionedOpenApi.mts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -import { readFile, writeFile, readdir, unlink } from 'fs/promises'; +import { readFile, writeFile, readdir, unlink } from 'node:fs/promises'; +import { execSync } from 'node:child_process'; import { parse, stringify } from 'yaml'; -import { execSync } from 'child_process'; import type { OpenAPIV3 } from 'openapi-types'; import { format } from 'prettier'; @@ -55,10 +55,8 @@ const addVersionToSpec = (spec: OpenAPIV3.Document, version: string): OpenAPIV3. if (pathItem) { for (const [, operation] of Object.entries(pathItem)) { - if (typeof operation === 'object' && 'operationId' in operation) { - if (operation.operationId !== undefined) { - operation.operationId = `${operation.operationId}${version.toUpperCase()}`; - } + if (typeof operation === 'object' && 'operationId' in operation && operation.operationId !== undefined) { + operation.operationId = `${operation.operationId}${version.toUpperCase()}`; } } } diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 88222892..647bfab3 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -1,7 +1,8 @@ { "extends": "@map-colonies/tsconfig/tsconfig-app", "compilerOptions": { - "erasableSyntaxOnly": true + "erasableSyntaxOnly": true, + "types": ["node"] }, "include": ["."], "exclude": ["node_modules", "dist"] diff --git a/src/api/v1/index.ts b/src/api/v1/index.ts index 6b1333a9..df1ff850 100644 --- a/src/api/v1/index.ts +++ b/src/api/v1/index.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { FactoryFunction } from 'tsyringe'; +import type { FactoryFunction } from 'tsyringe'; import { ROUTERS } from '@common/constants'; /** diff --git a/src/api/v1/jobs/router.ts b/src/api/v1/jobs/router.ts index 1804faa1..37aebe5e 100644 --- a/src/api/v1/jobs/router.ts +++ b/src/api/v1/jobs/router.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { FactoryFunction } from 'tsyringe'; +import type { FactoryFunction } from 'tsyringe'; import { StageControllerV1 } from '../stages/controller'; import { JobControllerV1 } from './controller'; diff --git a/src/api/v1/stages/router.ts b/src/api/v1/stages/router.ts index b119c2da..b0a363d3 100644 --- a/src/api/v1/stages/router.ts +++ b/src/api/v1/stages/router.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { FactoryFunction } from 'tsyringe'; +import type { FactoryFunction } from 'tsyringe'; import { TaskControllerV1 } from '../tasks/controller'; import { StageControllerV1 } from './controller'; diff --git a/src/api/v1/tasks/router.ts b/src/api/v1/tasks/router.ts index bce930be..b86576b9 100644 --- a/src/api/v1/tasks/router.ts +++ b/src/api/v1/tasks/router.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { FactoryFunction } from 'tsyringe'; +import type { FactoryFunction } from 'tsyringe'; import { TaskControllerV1 } from '../tasks/controller'; const taskV1RouterFactory: FactoryFunction = (dependencyContainer) => { diff --git a/src/app.ts b/src/app.ts index 8ef08291..bb2036ce 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,9 +1,9 @@ -import { Application } from 'express'; -import { DependencyContainer } from 'tsyringe'; +import type { Application } from 'express'; +import type { DependencyContainer } from 'tsyringe'; import { schedule, validate } from 'node-cron'; -import { PrismaClient } from '@prismaClient'; +import type { PrismaClient } from '@prismaClient'; import type { ConfigType } from '@common/config'; -import { registerExternalValues, RegisterOptions } from './containerConfig'; +import { registerExternalValues, type RegisterOptions } from './containerConfig'; import { ServerBuilder } from './serverBuilder'; import { SERVICES } from './common/constants'; import { verifyDbSetup } from './db/createConnection'; diff --git a/src/common/constants.ts b/src/common/constants.ts index b9837482..1c587ffe 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -1,6 +1,6 @@ import { readPackageJsonSync } from '@map-colonies/read-pkg'; -import { CamelCase, ScreamingSnakeCase } from 'type-fest'; -import { components } from '@src/openapi'; +import type { CamelCase, ScreamingSnakeCase } from 'type-fest'; +import type { components } from '@src/openapi'; type SuccessMessages = components['schemas']['successMessages']; type SuccessMessagesObj = { diff --git a/src/common/dependencyRegistration.ts b/src/common/dependencyRegistration.ts index a591ff93..273c7a1e 100644 --- a/src/common/dependencyRegistration.ts +++ b/src/common/dependencyRegistration.ts @@ -1,7 +1,9 @@ -import { ClassProvider, container as defaultContainer, FactoryProvider, InjectionToken, ValueProvider } from 'tsyringe'; -import { constructor, DependencyContainer } from 'tsyringe/dist/typings/types'; +import type { ClassProvider, DependencyContainer, FactoryProvider, InjectionToken, ValueProvider } from 'tsyringe'; +import { container as defaultContainer } from 'tsyringe'; -export type Providers = ValueProvider | FactoryProvider | ClassProvider | constructor; +type Constructor = new (...args: unknown[]) => T; + +export type Providers = ValueProvider | FactoryProvider | ClassProvider | Constructor; export interface InjectionObject { token: InjectionToken; @@ -17,11 +19,11 @@ export const registerDependencies = ( dependencies.forEach((injectionObj) => { const inject = override?.find((overrideObj) => overrideObj.token === injectionObj.token) === undefined; if (inject) { - container.register(injectionObj.token, injectionObj.provider as constructor); + container.register(injectionObj.token, injectionObj.provider as Constructor); } }); override?.forEach((injectionObj) => { - container.register(injectionObj.token, injectionObj.provider as constructor); + container.register(injectionObj.token, injectionObj.provider as Constructor); }); return container; }; diff --git a/src/common/errors.ts b/src/common/errors.ts index 965a48dc..4351d9fb 100644 --- a/src/common/errors.ts +++ b/src/common/errors.ts @@ -1,4 +1,4 @@ -import { JobOperationStatus, StageOperationStatus, TaskOperationStatus } from '@src/db/prisma/generated/client'; +import type { JobOperationStatus, StageOperationStatus, TaskOperationStatus } from '@src/db/prisma/generated/client'; export const prismaKnownErrors = { /**An operation failed because it depends on one or more records that were required but not found. {cause} */ diff --git a/src/common/serviceMetrics.ts b/src/common/serviceMetrics.ts index 154cbc15..d35c5058 100644 --- a/src/common/serviceMetrics.ts +++ b/src/common/serviceMetrics.ts @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type { Logger } from '@map-colonies/js-logger'; import type { FactoryFunction } from 'tsyringe'; -import { Gauge, Registry } from 'prom-client'; +import type { Registry } from 'prom-client'; +import { Gauge } from 'prom-client'; import { TaskOperationStatus, StageOperationStatus, JobOperationStatus, type PrismaClient } from '@prismaClient'; import { SERVICES } from '@common/constants'; diff --git a/src/common/utils/error-express-handler.ts b/src/common/utils/error-express-handler.ts index b1273064..f4fde087 100644 --- a/src/common/utils/error-express-handler.ts +++ b/src/common/utils/error-express-handler.ts @@ -1,4 +1,4 @@ -import { NextFunction, ErrorRequestHandler } from 'express'; +import type { NextFunction, ErrorRequestHandler } from 'express'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; /** diff --git a/src/containerConfig.ts b/src/containerConfig.ts index 05cf4cce..4ccf9b69 100644 --- a/src/containerConfig.ts +++ b/src/containerConfig.ts @@ -1,12 +1,12 @@ import { getOtelMixin } from '@map-colonies/tracing-utils'; import { trace } from '@opentelemetry/api'; import { Registry } from 'prom-client'; -import { DependencyContainer } from 'tsyringe/dist/typings/types'; +import type { DependencyContainer } from 'tsyringe/dist/typings/types'; import { jsLogger } from '@map-colonies/js-logger'; import { instanceCachingFactory, instancePerContainerCachingFactory } from 'tsyringe'; -import { HealthCheck } from '@godaddy/terminus'; -import { PrismaClient } from '@prismaClient'; -import { InjectionObject, registerDependencies } from '@common/dependencyRegistration'; +import type { HealthCheck } from '@godaddy/terminus'; +import type { PrismaClient } from '@prismaClient'; +import { type InjectionObject, registerDependencies } from '@common/dependencyRegistration'; import { DB_CONNECTION_TIMEOUT, ROUTERS, SERVICES, SERVICE_NAME } from '@common/constants'; import { getTracing } from '@common/tracing'; import { getConfig } from './common/config'; diff --git a/src/db/createConnection.ts b/src/db/createConnection.ts index 21cce3d0..6f55ac1b 100644 --- a/src/db/createConnection.ts +++ b/src/db/createConnection.ts @@ -1,6 +1,6 @@ import { readFileSync } from 'node:fs'; import { hostname } from 'node:os'; -import { commonDbFullV1Type } from '@map-colonies/schemas'; +import type { commonDbFullV1Type } from '@map-colonies/schemas'; import type { PoolConfig } from 'pg'; import { PrismaPg } from '@prisma/adapter-pg'; import { TX_TIMEOUT_MS } from '@src/common/constants'; diff --git a/src/db/helpers.ts b/src/db/helpers.ts index 1aecb41c..ffffc3db 100644 --- a/src/db/helpers.ts +++ b/src/db/helpers.ts @@ -1,5 +1,5 @@ import path from 'node:path'; -import { commonDbFullV1Type } from '@map-colonies/schemas'; +import type { commonDbFullV1Type } from '@map-colonies/schemas'; /** * Extract and build DB connection url based on configuration diff --git a/src/index.ts b/src/index.ts index 3c208fc5..eb3d028c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ // this import must be called before the first import of tsyringe import 'reflect-metadata'; -import { createServer } from 'http'; -import { createTerminus, HealthCheck } from '@godaddy/terminus'; -import { Logger } from '@map-colonies/js-logger'; +import { createServer } from 'node:http'; +import { createTerminus, type HealthCheck } from '@godaddy/terminus'; +import type { Logger } from '@map-colonies/js-logger'; import { container } from 'tsyringe'; import { SERVICES } from '@common/constants'; -import { ConfigType } from '@common/config'; +import type { ConfigType } from '@common/config'; import { getApp } from './app'; void getApp() diff --git a/src/jobs/models/models.ts b/src/jobs/models/models.ts index bd5450b1..ad806f54 100644 --- a/src/jobs/models/models.ts +++ b/src/jobs/models/models.ts @@ -1,4 +1,4 @@ -import { Prisma } from '@prismaClient'; +import type { Prisma } from '@prismaClient'; import type { components, operations } from '@src/openapi'; type JobModel = components['schemas']['job']; diff --git a/src/serverBuilder.ts b/src/serverBuilder.ts index 8c78daa5..476067a6 100644 --- a/src/serverBuilder.ts +++ b/src/serverBuilder.ts @@ -1,5 +1,4 @@ -import express, { Router } from 'express'; -import bodyParser from 'body-parser'; +import express, { json, type Router } from 'express'; import compression from 'compression'; import { OpenapiViewerRouter } from '@map-colonies/openapi-express-viewer'; import { middleware as OpenApiMiddleware } from 'express-openapi-validator'; @@ -81,7 +80,7 @@ export class ServerBuilder { this.serverInstance.use(compression(this.config.get('server.response.compression.options') as unknown as compression.CompressionFilter)); } - this.serverInstance.use(bodyParser.json(this.config.get('server.request.payload'))); + this.serverInstance.use(json(this.config.get('server.request.payload'))); this.serverInstance.use(getTraceContexHeaderMiddleware()); const ignorePathRegex = new RegExp(`^${this.config.get('openapiConfig.basePath')}/.*`, 'i'); diff --git a/src/stages/models/helper.ts b/src/stages/models/helper.ts index 57f00d02..55055be7 100644 --- a/src/stages/models/helper.ts +++ b/src/stages/models/helper.ts @@ -2,7 +2,7 @@ import { createActor } from 'xstate'; import { TaskOperationStatus } from '@prismaClient'; import { convertArrayPrismaTaskToTaskResponse } from '@src/tasks/models/helper'; import { createCamelCaseMapper } from '@src/common/utils/formatter'; -import { StageCreateModel, StageModel, StagePrismaObject, StageSummary } from './models'; +import type { StageCreateModel, StageModel, StagePrismaObject, StageSummary } from './models'; import { stageStateMachine } from './stageStateMachine'; /** diff --git a/src/stages/models/models.ts b/src/stages/models/models.ts index 3e5c2c4c..c12eb8c9 100644 --- a/src/stages/models/models.ts +++ b/src/stages/models/models.ts @@ -1,8 +1,8 @@ -import { Snapshot } from 'xstate'; -import { Prisma, TaskOperationStatus } from '@prismaClient'; +import type { Snapshot } from 'xstate'; +import type { Prisma, TaskOperationStatus } from '@prismaClient'; import type { components, operations } from '@src/openapi'; -import { JobPrismaObject } from '@src/jobs/models/models'; -import { PrismaTransaction } from '@src/db/types'; +import type { JobPrismaObject } from '@src/jobs/models/models'; +import type { PrismaTransaction } from '@src/db/types'; type StageModel = components['schemas']['getStageResponse']; type StageCreateModel = components['schemas']['createStagePayloadRequest']; diff --git a/src/tasks/models/helper.ts b/src/tasks/models/helper.ts index 6c92f649..8e78828e 100644 --- a/src/tasks/models/helper.ts +++ b/src/tasks/models/helper.ts @@ -1,7 +1,7 @@ -import { Snapshot } from 'xstate'; -import { Prisma } from '@prismaClient'; -import { findAndLockTask } from '@src/db/prisma/generated/client/sql'; -import { TaskModel, TaskPrismaObject } from './models'; +import type { Snapshot } from 'xstate'; +import type { Prisma } from '@prismaClient'; +import type { findAndLockTask } from '@src/db/prisma/generated/client/sql'; +import type { TaskModel, TaskPrismaObject } from './models'; /** * This function converts a Prisma stage object to a TaskModel API object. diff --git a/src/tasks/models/models.ts b/src/tasks/models/models.ts index a7e9238b..bb2e7f98 100644 --- a/src/tasks/models/models.ts +++ b/src/tasks/models/models.ts @@ -1,4 +1,4 @@ -import { Prisma } from '@prismaClient'; +import type { Prisma } from '@prismaClient'; import type { components, operations } from '@src/openapi'; type TaskModel = components['schemas']['taskResponse']; diff --git a/src/tasks/models/taskStateMachine.ts b/src/tasks/models/taskStateMachine.ts index b9f67b07..ba952283 100644 --- a/src/tasks/models/taskStateMachine.ts +++ b/src/tasks/models/taskStateMachine.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { createActor, setup, Snapshot } from 'xstate'; +import type { Snapshot } from 'xstate'; +import { createActor, setup } from 'xstate'; import { TaskOperationStatus } from '@prismaClient'; import { IllegalTaskStatusTransitionError } from '@src/common/generated/errors'; import { illegalStatusTransitionErrorMessage } from '@src/common/errors'; diff --git a/tests/configurations/integration/globalSetup.ts b/tests/configurations/integration/globalSetup.ts index 17e00756..54fffc69 100644 --- a/tests/configurations/integration/globalSetup.ts +++ b/tests/configurations/integration/globalSetup.ts @@ -7,7 +7,8 @@ import isCI from 'is-ci'; import { initConfig, getConfig } from '../../../src/common/config'; import { createDbConnectUrl } from '../../../src/db/helpers'; import { createConnectionOptions, createPrismaClient } from '../../../src/db/createConnection'; -import { Config, getLocalTestConfig, updateLocalTestConfig } from './utils'; +import type { Config } from './utils'; +import { getLocalTestConfig, updateLocalTestConfig } from './utils'; async function getSelectedPort(config: Config): Promise { if (config.db?.port !== undefined) { diff --git a/tests/integration/common/utils.ts b/tests/integration/common/utils.ts index 03611850..53cc271d 100644 --- a/tests/integration/common/utils.ts +++ b/tests/integration/common/utils.ts @@ -1,8 +1,7 @@ import { faker } from '@faker-js/faker'; import { type Snapshot } from 'xstate'; -import { type Prisma, type PrismaClient, JobOperationStatus } from '@prismaClient'; -import { Job, Stage, Task } from '@src/db/prisma/generated/client'; -import { JobCreateModel } from '@src/jobs/models/models'; +import type { JobOperationStatus, Prisma, PrismaClient, Job, Stage, Task } from '@prismaClient'; +import type { JobCreateModel } from '@src/jobs/models/models'; import { createJobRecord, createJobRequestBody } from '../jobs/helpers'; import { createStageBody, addStageRecord } from '../stages/helpers'; import { createTaskBody, createTaskRecords } from '../tasks/helpers'; diff --git a/tests/integration/docs/docs.spec.ts b/tests/integration/docs/docs.spec.ts index a82695af..1221ab7b 100644 --- a/tests/integration/docs/docs.spec.ts +++ b/tests/integration/docs/docs.spec.ts @@ -2,7 +2,7 @@ import { describe, beforeEach, afterEach, it, expect, beforeAll } from 'vitest'; import { jsLogger } from '@map-colonies/js-logger'; import { trace } from '@opentelemetry/api'; import httpStatusCodes from 'http-status-codes'; -import { PrismaClient } from '@prismaClient'; +import type { PrismaClient } from '@prismaClient'; import { getApp } from '@src/app'; import { SERVICES } from '@src/common/constants'; import { initConfig } from '@src/common/config'; diff --git a/tests/integration/jobs/helpers.ts b/tests/integration/jobs/helpers.ts index f56711b3..520ba946 100644 --- a/tests/integration/jobs/helpers.ts +++ b/tests/integration/jobs/helpers.ts @@ -1,8 +1,8 @@ import { createActor, type Snapshot } from 'xstate'; import { faker } from '@faker-js/faker'; -import { type Prisma, type PrismaClient, JobOperationStatus } from '@prismaClient'; +import type { JobOperationStatus, Prisma, PrismaClient } from '@prismaClient'; import { jobStateMachine } from '@src/jobs/models/jobStateMachine'; -import { JobCreateModel, JobPrismaObject } from '@src/jobs/models/models'; +import type { JobCreateModel, JobPrismaObject } from '@src/jobs/models/models'; import { DEFAULT_TRACEPARENT } from '@src/common/utils/tracingHelpers'; type JobTestCreateModel = JobCreateModel & { diff --git a/tests/integration/jobs/jobs.spec.ts b/tests/integration/jobs/jobs.spec.ts index 169dc3e3..175f2535 100644 --- a/tests/integration/jobs/jobs.spec.ts +++ b/tests/integration/jobs/jobs.spec.ts @@ -4,7 +4,7 @@ import { jsLogger } from '@map-colonies/js-logger'; import { InMemorySpanExporter, NodeTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; import { trace } from '@opentelemetry/api'; import { StatusCodes } from 'http-status-codes'; -import { createRequestSender, RequestSender } from '@map-colonies/openapi-helpers/requestSender'; +import { createRequestSender, type RequestSender } from '@map-colonies/openapi-helpers/requestSender'; import type { paths, operations } from '@openapi'; import { JobOperationStatus, Priority, StageOperationStatus, type PrismaClient } from '@prismaClient'; import type { PrismaTransaction } from '@src/db/types'; @@ -14,7 +14,7 @@ import { initConfig } from '@src/common/config'; import { errorMessages as jobsErrorMessages } from '@src/jobs/models/errors'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { abortedStageXstatePersistentSnapshot, completedStageXstatePersistentSnapshot, pendingStageXstatePersistentSnapshot } from '@tests/unit/data'; -import { JobCreateModel } from '@src/jobs/models/models'; +import type { JobCreateModel } from '@src/jobs/models/models'; import { DEFAULT_TRACEPARENT } from '@src/common/utils/tracingHelpers'; import { illegalStatusTransitionErrorMessage } from '@src/common/errors'; import { createProxyMock } from '@tests/configurations/mockPrisma'; @@ -694,6 +694,7 @@ describe('job', function () { pathParams: { jobId: 'someBadUuid' }, requestBody: { status: JobOperationStatus.PENDING }, }); + expect(getJobResponse).toSatisfyApiSpec(); expect(getJobResponse).toMatchObject({ status: StatusCodes.BAD_REQUEST, diff --git a/tests/integration/stages/helpers.ts b/tests/integration/stages/helpers.ts index 91aa75c2..eef872a5 100644 --- a/tests/integration/stages/helpers.ts +++ b/tests/integration/stages/helpers.ts @@ -1,10 +1,10 @@ import { createActor } from 'xstate'; import { faker } from '@faker-js/faker'; import { type Prisma, type PrismaClient } from '@prismaClient'; -import { StagePrismaObject } from '@src/stages/models/models'; +import type { StagePrismaObject } from '@src/stages/models/models'; import { stageStateMachine } from '@src/stages/models/stageStateMachine'; import { defaultStatusCounts } from '@src/stages/models/helper'; -import { JobPrismaObject } from '@src/jobs/models/models'; +import type { JobPrismaObject } from '@src/jobs/models/models'; import { DEFAULT_TRACEPARENT } from '@src/common/utils/tracingHelpers'; const persistedSnapshot = createActor(stageStateMachine).start().getPersistedSnapshot(); diff --git a/tests/integration/stages/stages.spec.ts b/tests/integration/stages/stages.spec.ts index 0cf37747..31b50841 100644 --- a/tests/integration/stages/stages.spec.ts +++ b/tests/integration/stages/stages.spec.ts @@ -4,7 +4,7 @@ import { jsLogger } from '@map-colonies/js-logger'; import { trace } from '@opentelemetry/api'; import { StatusCodes } from 'http-status-codes'; import { InMemorySpanExporter, NodeTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; -import { createRequestSender, RequestSender } from '@map-colonies/openapi-helpers/requestSender'; +import { createRequestSender, type RequestSender } from '@map-colonies/openapi-helpers/requestSender'; import { faker } from '@faker-js/faker'; import type { paths, operations } from '@openapi'; import { JobOperationStatus, StageOperationStatus, TaskOperationStatus, type PrismaClient } from '@prismaClient'; @@ -13,7 +13,7 @@ import { getApp } from '@src/app'; import { SERVICES } from '@common/constants'; import { initConfig } from '@src/common/config'; import { errorMessages as jobsErrorMessages } from '@src/jobs/models/errors'; -import { StageCreateModel, StageModel } from '@src/stages/models/models'; +import type { StageCreateModel, StageModel } from '@src/stages/models/models'; import { errorMessages as stagesErrorMessages } from '@src/stages/models/errors'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { @@ -92,6 +92,7 @@ describe('stage', function () { it('should return 200 status code and empty array', async function () { const response = await requestSender.getStagesV1({ queryParams: { job_id: faker.string.uuid() } }); + expect(response).toSatisfyApiSpec(); expect(response).toMatchObject({ status: StatusCodes.OK, @@ -1139,6 +1140,7 @@ describe('stage', function () { // Sanity check to ensure stage1 has order 1 and stage2 has order 2 expect(stage1).toHaveProperty('order', 1); expect(stage2).toHaveProperty('order', 2); + const setStatusResponse = await requestSender.updateStageStatusV1({ pathParams: { stageId: stage1.id }, requestBody: { status: StageOperationStatus.PENDING }, diff --git a/tests/integration/tasks/helpers.ts b/tests/integration/tasks/helpers.ts index 4406b4f8..f44efd27 100644 --- a/tests/integration/tasks/helpers.ts +++ b/tests/integration/tasks/helpers.ts @@ -1,7 +1,7 @@ import { createActor } from 'xstate'; import { faker } from '@faker-js/faker'; import { type Prisma, type PrismaClient } from '@prismaClient'; -import { TaskPrismaObject } from '@src/tasks/models/models'; +import type { TaskPrismaObject } from '@src/tasks/models/models'; import { taskStateMachine } from '@src/tasks/models/taskStateMachine'; import { DEFAULT_TRACEPARENT } from '@src/common/utils/tracingHelpers'; diff --git a/tests/integration/tasks/tasks.spec.ts b/tests/integration/tasks/tasks.spec.ts index 388b8724..289a676c 100644 --- a/tests/integration/tasks/tasks.spec.ts +++ b/tests/integration/tasks/tasks.spec.ts @@ -4,7 +4,7 @@ import { jsLogger } from '@map-colonies/js-logger'; import { trace } from '@opentelemetry/api'; import { StatusCodes } from 'http-status-codes'; import { InMemorySpanExporter, NodeTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; -import { createRequestSender, RequestSender } from '@map-colonies/openapi-helpers/requestSender'; +import { createRequestSender, type RequestSender } from '@map-colonies/openapi-helpers/requestSender'; import { faker } from '@faker-js/faker'; import type { paths, operations } from '@openapi'; import { JobOperationStatus, Priority, Prisma, StageOperationStatus, TaskOperationStatus, type PrismaClient } from '@prismaClient'; @@ -14,7 +14,7 @@ import { SERVICES } from '@common/constants'; import { initConfig } from '@src/common/config'; import { errorMessages as tasksErrorMessages } from '@src/tasks/models/errors'; import { errorMessages as stagesErrorMessages } from '@src/stages/models/errors'; -import { TaskCreateModel, TaskModel } from '@src/tasks/models/models'; +import type { TaskCreateModel, TaskModel } from '@src/tasks/models/models'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { abortedStageXstatePersistentSnapshot, @@ -704,6 +704,7 @@ describe('task', function () { const getTaskResponse = await requestSender.getTaskByIdV1({ pathParams: { taskId } }); const getStageResponse = await requestSender.getStageByIdV1({ pathParams: { stageId: stage.id } }); + expect(updateStatusResponse).toSatisfyApiSpec(); expect(getTaskResponse.body).toMatchObject(updateStatusInput); expect(getStageResponse.body).toMatchObject({ summary: expectedSummary }); @@ -728,6 +729,7 @@ describe('task', function () { }); const getTaskResponse = await requestSender.getTaskByIdV1({ pathParams: { taskId } }); + expect(updateStatusResponse).toSatisfyApiSpec(); expect(getTaskResponseBeforeUpdate.body).not.toHaveProperty('endTime'); expect(getTaskResponse.body).toHaveProperty('endTime'); @@ -784,6 +786,7 @@ describe('task', function () { const getTaskResponse = await requestSender.getTaskByIdV1({ pathParams: { taskId } }); const getStageResponse = await requestSender.getStageByIdV1({ pathParams: { stageId } }); + expect(updateStatusResponse).toSatisfyApiSpec(); expect(getTaskResponse.body).toMatchObject(updateStatusInput); expect(getStageResponse.body).toMatchObject({ summary: expectedSummary, status: StageOperationStatus.IN_PROGRESS, percentage: 99 }); @@ -1092,6 +1095,7 @@ describe('task', function () { }); const getStageResponse = await requestSender.getStageByIdV1({ pathParams: { stageId } }); + expect(dequeueResponse).toSatisfyApiSpec(); expect(dequeueResponse).toMatchObject({ status: StatusCodes.OK, @@ -1128,6 +1132,7 @@ describe('task', function () { }); const getStageResponse = await requestSender.getStageByIdV1({ pathParams: { stageId } }); + expect(dequeueResponse).toSatisfyApiSpec(); expect(dequeueResponse).toMatchObject({ status: StatusCodes.OK, @@ -1278,6 +1283,7 @@ describe('task', function () { const dequeueResponseLow = await requestSender.dequeueTaskV1({ pathParams: { stageType: 'SOME_TEST_TYPE_DEQUEUE_BY_PRIORITY' }, }); + expect(dequeueResponseHigh).toSatisfyApiSpec(); expect(dequeueResponseHigh).toMatchObject({ status: StatusCodes.OK, @@ -1534,6 +1540,7 @@ describe('task', function () { it('should prevent multiple dequeue of the same task using database-level locking', async function () { expect.assertions(4); + const initialSummary = { ...defaultStatusCounts, pending: 1, total: 1 }; const { stage, tasks } = await createJobnikTree( @@ -1631,6 +1638,7 @@ describe('task', function () { it('should handle multiple concurrent updateStatus operations with race condition protection', async function () { expect.assertions(4); + const initialSummary = { ...defaultStatusCounts, inProgress: 1, total: 1 }; const { tasks } = await createJobnikTree( diff --git a/tests/unit/db/helpers.spec.ts b/tests/unit/db/helpers.spec.ts index 9df897d6..cfb8d68e 100644 --- a/tests/unit/db/helpers.spec.ts +++ b/tests/unit/db/helpers.spec.ts @@ -25,6 +25,7 @@ function createQueryParamsObject(paramsString: string) { const queryObject: object = Object.fromEntries(queryParamsPairs); return queryObject; } + describe('DB helpers', () => { describe('#createConnectionUrl', () => { it('should return no ssl url string', function () { diff --git a/tests/unit/generator.ts b/tests/unit/generator.ts index aa481111..f802840e 100644 --- a/tests/unit/generator.ts +++ b/tests/unit/generator.ts @@ -1,11 +1,12 @@ import { faker } from '@faker-js/faker'; import { createActor } from 'xstate'; -import { JobOperationStatus, Priority, Prisma, Stage, StageOperationStatus, Task, TaskOperationStatus } from '@prismaClient'; +import type { Prisma, Stage, Task } from '@prismaClient'; +import { JobOperationStatus, Priority, StageOperationStatus, TaskOperationStatus } from '@prismaClient'; import type { findAndLockTask } from '@src/db/prisma/generated/client/sql'; import { jobStateMachine } from '@src/jobs/models/jobStateMachine'; -import { JobCreateModel } from '@src/jobs/models/models'; +import type { JobCreateModel } from '@src/jobs/models/models'; import { stageStateMachine } from '@src/stages/models/stageStateMachine'; -import { TaskPrismaObject } from '@src/tasks/models/models'; +import type { TaskPrismaObject } from '@src/tasks/models/models'; import { taskStateMachine } from '@src/tasks/models/taskStateMachine'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { DEFAULT_TRACEPARENT } from '@src/common/utils/tracingHelpers'; diff --git a/tests/unit/jobs/jobs.spec.ts b/tests/unit/jobs/jobs.spec.ts index 95fff7fd..48aa5832 100644 --- a/tests/unit/jobs/jobs.spec.ts +++ b/tests/unit/jobs/jobs.spec.ts @@ -1,5 +1,6 @@ import { describe, beforeEach, afterEach, it, expect, vi, beforeAll } from 'vitest'; -import { jsLogger, Logger } from '@map-colonies/js-logger'; +import type { Logger } from '@map-colonies/js-logger'; +import { jsLogger } from '@map-colonies/js-logger'; import { trace } from '@opentelemetry/api'; import { mockDeep, type DeepMockProxy } from 'vitest-mock-extended'; import type { PrismaClient } from '@prismaClient'; @@ -7,7 +8,7 @@ import { Prisma, JobOperationStatus, Priority } from '@prismaClient'; import { illegalStatusTransitionErrorMessage, prismaKnownErrors } from '@src/common/errors'; import { JobManager } from '@src/jobs/models/manager'; import { errorMessages as jobsErrorMessages } from '@src/jobs/models/errors'; -import { JobCreateModel } from '@src/jobs/models/models'; +import type { JobCreateModel } from '@src/jobs/models/models'; import { randomUuid } from '@tests/unit/generator'; import { SERVICE_NAME } from '@src/common/constants'; import { jobEntityWithAbortStatus, jobEntityWithoutStages, jobEntityWithStages } from '../data'; @@ -45,6 +46,7 @@ describe('JobManager', () => { } satisfies JobCreateModel; const job = await jobManager.createJob(createJobParams); + expect(job).toMatchObject(createJobParams); }); }); diff --git a/tests/unit/stages/helpers.spec.ts b/tests/unit/stages/helpers.spec.ts index f0f04ab6..cc1e4cc8 100644 --- a/tests/unit/stages/helpers.spec.ts +++ b/tests/unit/stages/helpers.spec.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; import { getCurrentPercentage, summaryCountsMapper, getInitialXstate } from '@src/stages/models/helper'; -import { StageSummary, StageCreateModel } from '@src/stages/models/models'; +import type { StageSummary, StageCreateModel } from '@src/stages/models/models'; describe('helpers', function () { const createSummary = (completed: number, total: number): StageSummary => { @@ -21,30 +21,35 @@ describe('helpers', function () { it('should return 0% when no tasks are completed', function () { const summary = createSummary(0, 100); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(0); }); it('should return 100% when all tasks are completed', function () { const summary = createSummary(50, 50); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(100); }); it('should return 50% when half of tasks are completed', function () { const summary = createSummary(50, 100); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(50); }); it('should return 25% when a quarter of tasks are completed', function () { const summary = createSummary(25, 100); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(25); }); it('should return 75% when three-quarters of tasks are completed', function () { const summary = createSummary(75, 100); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(75); }); @@ -52,6 +57,7 @@ describe('helpers', function () { // 33.33% should be floored to 33% const summary = createSummary(1, 3); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(33); }); @@ -60,6 +66,7 @@ describe('helpers', function () { const LARGE_NUMBER = 1000000; const summary = createSummary(LARGE_NUMBER / 4, LARGE_NUMBER); const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(25); }); @@ -71,6 +78,7 @@ describe('helpers', function () { } as StageSummary; const percentage = getCurrentPercentage(summary); + expect(percentage).toBe(75); }); }); @@ -79,6 +87,7 @@ describe('helpers', function () { it('should handle negative completed counts', function () { const summary = createSummary(-10, 100); const percentage = getCurrentPercentage(summary); + // Negative percentages should be handled appropriately expect(percentage).toBe(-10); }); @@ -86,6 +95,7 @@ describe('helpers', function () { it('should handle case where completed count exceeds total', function () { const summary = createSummary(150, 100); const percentage = getCurrentPercentage(summary); + // Should be capped at 100% or return the actual value expect(percentage).toBe(150); }); diff --git a/tests/unit/stages/repository.spec.ts b/tests/unit/stages/repository.spec.ts index abc9da0b..730f8522 100644 --- a/tests/unit/stages/repository.spec.ts +++ b/tests/unit/stages/repository.spec.ts @@ -4,7 +4,7 @@ import { faker } from '@faker-js/faker'; import { mockDeep, type DeepMockProxy } from 'vitest-mock-extended'; import type { PrismaClient } from '@prismaClient'; import { TaskOperationStatus } from '@prismaClient'; -import { UpdateSummaryCount } from '@src/stages/models/models'; +import type { UpdateSummaryCount } from '@src/stages/models/models'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { StageRepository } from '@src/stages/DAL/stageRepository'; import { createStageEntity } from '../generator'; diff --git a/tests/unit/stages/stages.spec.ts b/tests/unit/stages/stages.spec.ts index ac10923d..f041d011 100644 --- a/tests/unit/stages/stages.spec.ts +++ b/tests/unit/stages/stages.spec.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { describe, beforeEach, afterEach, it, expect, vi, beforeAll } from 'vitest'; -import { jsLogger, Logger } from '@map-colonies/js-logger'; +import type { Logger } from '@map-colonies/js-logger'; +import { jsLogger } from '@map-colonies/js-logger'; import { faker } from '@faker-js/faker'; import { trace } from '@opentelemetry/api'; import { mockDeep, type DeepMockProxy } from 'vitest-mock-extended'; @@ -11,10 +12,10 @@ import { JobManager } from '@src/jobs/models/manager'; import { errorMessages as jobsErrorMessages } from '@src/jobs/models/errors'; import { illegalStatusTransitionErrorMessage, prismaKnownErrors } from '@src/common/errors'; import { errorMessages as stagesErrorMessages } from '@src/stages/models/errors'; -import { StageCreateModel, StageIncludingJob, UpdateSummaryCount } from '@src/stages/models/models'; +import type { StageCreateModel, StageIncludingJob, UpdateSummaryCount } from '@src/stages/models/models'; import { defaultStatusCounts } from '@src/stages/models/helper'; import { StageRepository } from '@src/stages/DAL/stageRepository'; -import { JobPrismaObject } from '@src/jobs/models/models'; +import type { JobPrismaObject } from '@src/jobs/models/models'; import { SERVICE_NAME } from '@src/common/constants'; import { JobInFiniteStateError } from '@src/common/generated/errors'; import { @@ -26,7 +27,8 @@ import { pendingStageXstatePersistentSnapshot, stageEntity, } from '../data'; -import { createStageEntity, createJobEntity, createTaskEntity, StageWithTasks } from '../generator'; +import type { StageWithTasks } from '../generator'; +import { createStageEntity, createJobEntity, createTaskEntity } from '../generator'; let jobManager: JobManager; let stageManager: StageManager; diff --git a/tests/unit/tasks/taskRepository.spec.ts b/tests/unit/tasks/taskRepository.spec.ts index 07425405..fc450f53 100644 --- a/tests/unit/tasks/taskRepository.spec.ts +++ b/tests/unit/tasks/taskRepository.spec.ts @@ -35,6 +35,7 @@ describe('TaskRepository', () => { } as unknown as Parameters[1]; const result = await taskRepository.findAndLockTaskForDequeue(stageType, mockTx); + expect(result).toMatchObject({ stageId: stageId, status: TaskOperationStatus.PENDING, id: taskId }); expect(mockTx.$queryRawTyped).toHaveBeenCalledOnce(); }); diff --git a/tests/unit/tasks/tasks.spec.ts b/tests/unit/tasks/tasks.spec.ts index 7bcb7274..3b95e7d6 100644 --- a/tests/unit/tasks/tasks.spec.ts +++ b/tests/unit/tasks/tasks.spec.ts @@ -13,7 +13,7 @@ import { errorMessages as stagesErrorMessages } from '@src/stages/models/errors' import { errorMessages as tasksErrorMessages } from '@src/tasks/models/errors'; import { TaskManager } from '@src/tasks/models/manager'; import { prismaKnownErrors } from '@src/common/errors'; -import { TaskCreateModel } from '@src/tasks/models/models'; +import type { TaskCreateModel } from '@src/tasks/models/models'; import { StageRepository } from '@src/stages/DAL/stageRepository'; import { TaskRepository } from '@src/tasks/DAL/taskRepository'; import { SERVICE_NAME } from '@src/common/constants'; @@ -555,6 +555,7 @@ describe('JobManager', () => { } as unknown as Omit; return callback(mockTx); }); + await expect(taskManager.updateStatus(taskId, TaskOperationStatus.CREATED)).rejects.toThrow(IllegalTaskStatusTransitionError); }); }); diff --git a/vitest.config.mts b/vitest.config.mts index 64eccc5a..1ecd89fc 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -30,7 +30,7 @@ export default defineConfig({ environment: 'node', server: { deps: { - external: ['node-cron'], + external: ['node-cron', /prisma[\/]generated[\/]client[\/]runtime[\/]library/], }, }, }, @@ -47,7 +47,7 @@ export default defineConfig({ environment: 'node', server: { deps: { - external: ['node-cron'], + external: ['node-cron', /prisma[\/]generated[\/]client[\/]runtime[\/]library/], }, }, },