diff --git a/.gcloudignore b/.gcloudignore index 2a32cd7..484db1a 100644 --- a/.gcloudignore +++ b/.gcloudignore @@ -7,11 +7,9 @@ test/ .env .env.example -.eslintignore -.eslintrc.js .gcloudignore .git .gitignore -jest.config.js +vitest.config.js README.md yarn-error.log diff --git a/.gitignore b/.gitignore index 1c75d3b..5230c3f 100755 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ /scripts/import/*.json .env -.eslintcache yarn-error.log diff --git a/README.md b/README.md index e110910..4e7b37f 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [frank.gairal.rocks](https://frank.gairal.rocks) RESTful API ![CI status](https://github.com/gairal/frank-bo-node/actions/workflows/ci.yml/badge.svg) > A REST API built with [TypeScript](https://www.typescriptlang.org/), [Koa](https://koajs.com/), -> [Jest](https://jestjs.io/), [bun](https://bun.sh/), [biome](https://biomejs.dev/) and ❤️ +> [Vitest](https://vitest.dev), [bun](https://bun.sh/), [biome](https://biomejs.dev/) and ❤️ ## TOC @@ -33,8 +33,8 @@ bun start - `bun dev`: launches a ts-node-dev watcher - `bun lint`: lints the whole sources and tests with eslint - `bun start`: runs the project in production mode -- `bun test-cov`: runs Jest tests with coverage -- `bun run test`: runs Jest tests +- `bun test-cov`: runs vitest tests with coverage +- `bun run test`: runs vitest tests ## To-do diff --git a/biome.json b/biome.json index 1d0ede5..b1ca8d9 100644 --- a/biome.json +++ b/biome.json @@ -23,7 +23,7 @@ } }, "javascript": { - "globals": ["afterEach", "describe", "expect", "it", "test", "jest"] + "globals": ["afterEach", "describe", "expect", "it", "test"] }, "overrides": [ { diff --git a/bun.lockb b/bun.lockb index ce15969..f7f7939 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index c30146e..0000000 --- a/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - collectCoverageFrom: ["/src/**/*.ts"], - coverageDirectory: "coverage", - coveragePathIgnorePatterns: [ - "/dist/", - "/node_modules/", - "/src/app.ts", - ], - coverageReporters: ["html", "text", "text-summary"], - moduleFileExtensions: ["js", "ts", "json"], - setupFilesAfterEnv: ["/test/setupAfterEnv.ts"], - testPathIgnorePatterns: ["/dist/", "/node_modules/"], - testRegex: "/__tests__/.*\\.test\\.ts$", - transform: { "\\.ts$": "ts-jest" }, -}; diff --git a/package.json b/package.json index 946eb81..dbda0a9 100644 --- a/package.json +++ b/package.json @@ -13,26 +13,25 @@ "lint": "biome check", "prepare": "husky", "start": "node dist", - "test": "LOG_LEVEL=error jest", - "test-cov": "bun run test --collectCoverage" + "test": "LOG_LEVEL=error vitest", + "test-cov": "bun run test --coverage" }, "devDependencies": { "@biomejs/biome": "^1.8.3", "@tsconfig/node20": "^20.1.4", - "@types/jest": "^29.5.12", "@types/koa": "^2.15.0", "@types/koa-logger": "^3.1.5", "@types/koa__cors": "^5.0.0", "@types/koa__router": "^12.0.4", "@types/node": "^22.1.0", "@types/supertest": "^6.0.2", - "firestore-jest-mock": "^0.25.0", + "@vitest/coverage-v8": "^2.0.5", + "firestore-vitest-mock": "^0.6.0", "husky": "^9.1.4", - "jest": "^29.7.0", "lint-staged": "^15.2.8", "supertest": "^7.0.0", - "ts-jest": "^29.2.3", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "vitest": "^2.0.5" }, "dependencies": { "@google-cloud/firestore": "^7.9.0", diff --git a/src/__tests__/error.test.ts b/src/__tests__/error.test.ts index e8e0bf8..b06c800 100644 --- a/src/__tests__/error.test.ts +++ b/src/__tests__/error.test.ts @@ -1,5 +1,6 @@ import request from "supertest"; +import { test, vi } from "vitest"; import { app } from "../app"; // biome-ignore lint/style/noNamespaceImport: exception import * as educationModel from "../model/education"; @@ -14,9 +15,9 @@ describe("error", () => { }); test("returns a 500 status on error", async () => { - jest - .spyOn(educationModel, "getAll") - .mockRejectedValueOnce(new Error("NETWORK_ERROR")); + vi.spyOn(educationModel, "getAll").mockRejectedValueOnce( + new Error("NETWORK_ERROR"), + ); const { body, status } = await subject("/educations"); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index a6f3095..dcfc93e 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -1,17 +1,17 @@ +import { vi } from "vitest"; import { app } from "../app"; import { PORT } from "../env"; +import "../index"; -const mockListen = jest.fn(); +const mockListen = vi.fn(); -app.listen = mockListen; +vi.mock("../app", () => ({ app: { listen: vi.fn() } })); afterEach(() => { mockListen.mockClear(); }); test("server works", () => { - // eslint-disable-next-line global-require - require(".."); expect(app.listen).toHaveBeenCalledTimes(1); expect(app.listen).toHaveBeenCalledWith(PORT, expect.any(Function)); }); diff --git a/src/routes/__tests__/work.test.ts b/src/routes/__tests__/work.test.ts index fba7003..c0f4446 100644 --- a/src/routes/__tests__/work.test.ts +++ b/src/routes/__tests__/work.test.ts @@ -1,5 +1,6 @@ import request from "supertest"; +import { test } from "vitest"; import { app } from "../../app"; const subject = () => request(app.callback()).get("/works"); diff --git a/test/fixtures/education.ts b/test/fixtures/education.ts index dfdd9df..e25478d 100644 --- a/test/fixtures/education.ts +++ b/test/fixtures/education.ts @@ -1,8 +1,8 @@ -import { Timestamp } from "@google-cloud/firestore"; +import { type DocumentData, Timestamp } from "@google-cloud/firestore"; import type { FirestoreEducation } from "../../src/types/education"; -export const educationFixture = (): FirestoreEducation[] => [ +export const educationFixture = (): (FirestoreEducation & DocumentData)[] => [ { dateIn: Timestamp.fromDate(new Date("2005-09-01")), dateOut: Timestamp.fromDate(new Date("2008-07-31")), diff --git a/test/fixtures/interest.ts b/test/fixtures/interest.ts index df0e7b4..1cde32c 100644 --- a/test/fixtures/interest.ts +++ b/test/fixtures/interest.ts @@ -1,6 +1,7 @@ +import type { DocumentData } from "@google-cloud/firestore"; import type { FirestoreInterest } from "../../src/types/interest"; -export const interestFixture = (): FirestoreInterest[] => [ +export const interestFixture = (): (FirestoreInterest & DocumentData)[] => [ { description: "China, Vietnam, Thaïland, Laos, Cambodia, Malaysia, Indonesia, India, Iceland, Ecuador, USA, Brazil, Spain, and more...", diff --git a/test/fixtures/skill.ts b/test/fixtures/skill.ts index 3a71564..34258e7 100644 --- a/test/fixtures/skill.ts +++ b/test/fixtures/skill.ts @@ -1,6 +1,7 @@ +import type { DocumentData } from "@google-cloud/firestore"; import type { FirestoreSkillByCategory } from "../../src/types/skill"; -export const skillFixture = (): FirestoreSkillByCategory[] => [ +export const skillFixture = (): (FirestoreSkillByCategory & DocumentData)[] => [ { id: "server-administration", label: "Server administration", diff --git a/test/fixtures/travel.ts b/test/fixtures/travel.ts index 7d27b10..c82cbe9 100644 --- a/test/fixtures/travel.ts +++ b/test/fixtures/travel.ts @@ -1,8 +1,8 @@ -import { GeoPoint } from "@google-cloud/firestore"; +import { type DocumentData, GeoPoint } from "@google-cloud/firestore"; import type { FirestoreTravel } from "../../src/types/travel"; -export const travelFixture = (): FirestoreTravel[] => [ +export const travelFixture = (): (FirestoreTravel & DocumentData)[] => [ { coordinates: new GeoPoint(52.3702, 4.89517), id: "amsterdam", diff --git a/test/fixtures/work.ts b/test/fixtures/work.ts index ffca0ae..8c744e0 100644 --- a/test/fixtures/work.ts +++ b/test/fixtures/work.ts @@ -1,8 +1,8 @@ -import { Timestamp } from "@google-cloud/firestore"; +import { type DocumentData, Timestamp } from "@google-cloud/firestore"; import type { FirestoreWork } from "../../src/types/work"; -export const workFixture = (): FirestoreWork[] => [ +export const workFixture = (): (FirestoreWork & DocumentData)[] => [ { achievements: [ { diff --git a/test/setupAfterEnv.ts b/test/setup.ts similarity index 87% rename from test/setupAfterEnv.ts rename to test/setup.ts index 8ebe091..10d8197 100644 --- a/test/setupAfterEnv.ts +++ b/test/setup.ts @@ -1,4 +1,4 @@ -import { mockGoogleCloudFirestore } from "firestore-jest-mock"; +import { mockGoogleCloudFirestore } from "firestore-vitest-mock"; import { educationFixture } from "./fixtures/education"; import { interestFixture } from "./fixtures/interest"; diff --git a/tsconfig.json b/tsconfig.json index 35c12f3..1f10f5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "extends": "@tsconfig/node20/tsconfig.json", "compilerOptions": { "forceConsistentCasingInFileNames": true, - "outDir": "./dist" + "outDir": "./dist", + "types": ["vitest/globals"] }, "exclude": [ "./__mocks__", diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000..b16132d --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1,22 @@ +import { defineConfig } from "vitest/config"; + +// biome-ignore lint/style/noDefaultExport: exception +export default defineConfig({ + test: { + coverage: { + reporter: ["text", "html", "json-summary", "json"], + reportOnFailure: true, + thresholds: { + lines: 80, + branches: 80, + functions: 60, + statements: 80, + }, + include: ["src/**"], + exclude: ["src/**/*.d.ts"], + }, + globals: true, + include: ["src/**/*.test.ts"], + setupFiles: ["./test/setup.ts"], + }, +});