node.js - Awilix در بارگذاری خودکار ماژولها در تستها با تنظیمات TypeScript شکست میخورد


من از تایپاسکریپت، ویتست، آویلیکس استفاده میکنم:

"typescript": "^5"
"vitest": "^1"
"awilix": "^8"

در اینجا ساختار دایرکتوری من است:

./
├── tsconfig.json
├── vitest.config.mts
./src/
   ├── Connection
   │   └── Mongoose.ts
   ├── Core
   │   └── Container.ts
   └── init.ts
./test/
   ├── Connection
   │   └── Mongoose.test.ts
   ├── Core
   │   └── Container.test.ts
   └── tsconfig.json

این فایل ریشه من است ./tsconfig.json:

{
  "extends": "@tsconfig/node-lts/tsconfig.json",
  "compilerOptions": {
    "lib": ["WebWorker", "ESNext", "ES2022", "DOM"],
    "rootDir": ".",
    "outDir": "build",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "importHelpers": true,
    "alwaysStrict": true,
    "sourceMap": true,
    "declaration": true,
    "declarationDir": "./build/@types",
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitAny": false,
    "noImplicitThis": false,
    "strictNullChecks": true,
    "useUnknownInCatchVariables": true,
  },
  "types": ["node"],
  "include": ["src/**/*.ts", ".eslintrc.js"],
  "exclude": ["node_modules", "**/node_modules/*", "**/dist/*", "**/build/*"]
}

این فایل vitest.config.mts من است:

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "node",
    globals: true,
    include: ['test/**/*.test.ts'],
    exclude: ['**/node_modules/**', '**/dist/**', '**/build/**'],
    deps: {
      moduleDirectories: ["node_modules"],
    },
    coverage: {
      all: true,
      provider: "v8",
      reportsDirectory: "./coverage",
      enabled: true,
      include: ['src/**/*'],
      reporter: [
        "text",
        "json",
        "html",
        "lcov",
        "clover",
        "json-summary",
        "text-summary",
      ],
    },
    poolOptions: {
      threads: {
        singleThread: true,
      },
    },
  },
});

من تلاش میکنم ماژولها را با استفاده از Awilix و تابع loadModules() بهطور خودکار بارگذاری کنم.

در اینجا اسکریپت src/Core/Container.ts من است که برای کل برنامهام کانتینر ایجاد میکنم:

import { resolve } from "path";
import {
  createContainer,
  AwilixContainer,
  Lifetime,
  asClass,
} from "awilix";

export interface Cradle {}

export default async (): Promise<AwilixContainer<Cradle>> => {
  const container = createContainer();

  container.loadModules(
    [
      `${resolve(__dirname, "../Connection/*.js")}`,
      `${resolve(__dirname, "../Connection/**/*.js")}`,
    ],
    {
      resolverOptions: {
        lifetime: Lifetime.SINGLETON,
        register: asClass,
      },
    }
  );

  return container;
};

وقتی تلاش میکنم container.registrations را خارج از هر آزمون ببینم، همه چیز خوب پیش میرود و میتوانم با استفاده از container.resolve('Mongoose'); آن را حل کنم

init.ts

import initContainer from "src/Core/Container";

export default async (): Promise<void> => {
  const container = await initContainer();

  console.log(container.resolve("Mongoose")); // Prints: Mongoose {}
};

اما Awilix ماژولها را وقتی که من کانتینر را در تستهایم ایجاد میکنم بارگذاری نمیکند:

Mongoose.test.ts

import initContainer from "src/init";

describe("Mongoose", () => {
  it("Connect", async () => {
    const container = await initContainer();

    console.log(container.registrations); // Prints: {}
    
    expect(true).toBeTruthy();
  });
});

تا جایی که من میدانم، همه چیز به دلیل فایل ./tsconfig.json من در دایرکتوری build/ ساخته میشود. همانطور که میبینیم دایرکتوری test/ در آن گنجانده نشده است ("include": ["src/**/*.ts", ".eslintrc.js"]).

من توانستم آن را با اضافه کردن دایرکتوری test/ برای ساخته شدن توسط tsc حل کنم. همچنین مجبور شدم vitest.config.mts خود را تغییر دهم تا تستها از build/test/ اجرا شوند.

جدید vitest.config.mts:

export default defineConfig({
  test: {
    // ...

    include: ["build/test/**/*.test.js"],
    // exclude: ["**/node_modules/**", "**/dist/**", "**/build/**"],
    coverage: {
      // ...
      include: ["build/src/**/*"],
    },
    // ...
  },
});

اما مطمئن نیستم که این یک راهحل مناسب برای گنجاندن تستها در build/dist و اجرای نسخه ساختهشده باشد.

همچنین من نمیخواهم از type: module در package.json خود استفاده کنم.

من به جای vitest از jest: "^29" استفاده کردم و با همان مشکل روبرو شدم.

jest.config.ts

import { type JestConfigWithTsJest } from 'ts-jest';

const jestConfig: JestConfigWithTsJest = {
  testRegex: '(/test/.*\\.(test|spec))\\.(ts|js)$',
  testPathIgnorePatterns: ['/lib/', '/node_modules/'],
  moduleFileExtensions: ['ts', 'js', 'json', 'node'],
  collectCoverage: true,
};

export default jestConfig;

آیا کسی میتواند به من در این مشکل کمک کند؟