-
Notifications
You must be signed in to change notification settings - Fork 528
Description
Hi 👋,
I’m running into an issue with tsoa when testing an Express app using Vitest in CI (GitHub Actions).
Everything works fine locally, but the same tests fail consistently in CI.
This looks like a runtime/import issue related to how tsoa-generated code behaves under ESM + Vitest + Node 20.
Context
-
Node.js: 20
-
Test runner: Vitest
-
Framework: Express
-
tsoa version: 7.x (alpha)
-
Environment:
- ✅ Works locally
- ❌ Fails in GitHub Actions (Ubuntu)
The API app is structured so that the Express app is created in a factory function (createApp) and then tested with supertest.
Test code
import { describe, it, expect } from 'vitest';
import request from 'supertest';
import { createApp } from '../src/app';
describe('API health', () => {
it('responds to /v1/hello', async () => {
const app = createApp();
const res = await request(app).get('/v1/hello');
expect(res.status).toBe(200);
expect(res.body).toHaveProperty('message');
});
});CI configuration
name: CI
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10.25.0
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Generate Prisma client
env:
DATABASE_URL: "postgresql://dummy:dummy@localhost:5432/dummy"
run: pnpm --filter @repo/db prisma generate
- name: Generate API client (Orval)
run: pnpm generate:api-client
- name: Run tests (no DB)
run: pnpm testError observed in CI
TypeError: Class extends value undefined is not a constructor or null
❯ src/controllers/HelloController.ts:4:38
@Route('v1/hello')
export class HelloController extends Controller {
^
❯ src/generated/routes.ts:7:1
❯ src/app.ts:6:1
Full log excerpt:
FAIL tests/health.test.ts
TypeError: Class extends value undefined is not a constructor or null
❯ src/controllers/HelloController.ts:4:38
❯ src/generated/routes.ts:7:1
❯ src/app.ts:6:1
Notes / Observations
reflect-metadatais already imported before any controller is loaded- Controllers correctly import
Controllerfromtsoa - The error only happens in CI (fresh environment)
- The failure happens when importing the tsoa-generated routes
- It looks like
Controllerisundefinedat runtime in this context
This suggests a possible incompatibility between:
- tsoa generated code
- ESM execution
- Vitest runtime (as opposed to ts-node / tsx)
Question
Is this a known limitation or incompatibility when using tsoa with Vitest + ESM + Node 20?
Is there a recommended way to test an Express app using tsoa-generated routes in a pure ESM / CI environment?
Any guidance would be appreciated. Thanks!