Files
twenty/packages/twenty-server/test/integration/utils/create-app.ts
T
Félix MalfaitandGitHub c6f11d8adb fix: migrate driver modules to DriverFactoryBase lazy-loading pattern (#18731)
## Summary

- Migrates `LogicFunctionModule`, `CodeInterpreterModule`, and
`CaptchaModule` from the `forRootAsync` + injection token pattern to the
`DriverFactoryBase` lazy-loading pattern (matching `EmailModule` and
`FileStorageModule`)
- Fixes #18724 where `LOGIC_FUNCTION_TYPE` was not respected in worker
processes because the driver was created at module boot time before the
DB config cache was loaded
- Removes `isEnvOnly` from `LOGIC_FUNCTION_TYPE`,
`CODE_INTERPRETER_TYPE`, `CAPTCHA_DRIVER`, `IS_MULTIWORKSPACE_ENABLED`,
and `FRONTEND_URL` — these can now be safely configured via the database
at runtime

## How it works

Each migrated module now uses a `DriverFactory` (extending
`DriverFactoryBase`) instead of a module-level async factory + Symbol
injection token:

1. **Lazy creation**: `getCurrentDriver()` creates the driver on first
call, after `DatabaseConfigDriver.onModuleInit()` has loaded the DB
cache
2. **Auto-recreation**: If config changes in the DB, the next
`getCurrentDriver()` call detects the key mismatch and creates a new
driver instance
3. **Unified config**: Both server and worker read from the same
database — driver config only needs to be set once

### Files deleted (old pattern)
- `logic-function-module.factory.ts`,
`logic-function-drivers.module.ts`, `logic-function-driver.constants.ts`
- `code-interpreter-module.factory.ts`
- `captcha.module-factory.ts`, `captcha-driver.constants.ts`

### Files created (new pattern)
- `logic-function-driver.factory.ts`
- `code-interpreter-driver.factory.ts`
- `captcha-driver.factory.ts`

Net: **-150 lines**

## Test plan

- [x] `npx nx typecheck twenty-server` passes
- [x] `npx nx lint:diff-with-main twenty-server` passes
- [ ] Integration tests pass (`npx nx run
twenty-server:test:integration:with-db-reset`)
- [ ] Verify logic functions execute in workflow runs (the original bug)
- [ ] Verify code interpreter works in workflow code steps
- [ ] Verify captcha validation works on sign-up (when captcha is
configured)


Made with [Cursor](https://cursor.com)
2026-03-18 16:00:45 +01:00

114 lines
3.6 KiB
TypeScript

import { APP_FILTER } from '@nestjs/core';
import { type NestExpressApplication } from '@nestjs/platform-express';
import {
Test,
type TestingModule,
type TestingModuleBuilder,
} from '@nestjs/testing';
import bytes from 'bytes';
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
import { AppModule } from 'src/app.module';
import { CommandModule } from 'src/command/command.module';
import { settings } from 'src/engine/constants/settings';
import { StripeSDKMockService } from 'src/engine/core-modules/billing/stripe/stripe-sdk/mocks/stripe-sdk-mock.service';
import { StripeSDKService } from 'src/engine/core-modules/billing/stripe/stripe-sdk/services/stripe-sdk.service';
import { CaptchaDriverFactory } from 'src/engine/core-modules/captcha/captcha-driver.factory';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { ExceptionHandlerMockService } from 'src/engine/core-modules/exception-handler/mocks/exception-handler-mock.service';
import { MockedUnhandledExceptionFilter } from 'src/engine/core-modules/exception-handler/mocks/mock-unhandled-exception.filter';
import { SyncDriver } from 'src/engine/core-modules/message-queue/drivers/sync.driver';
import { JobsModule } from 'src/engine/core-modules/message-queue/jobs.module';
import { QUEUE_DRIVER } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueModule } from 'src/engine/core-modules/message-queue/message-queue.module';
interface TestingModuleCreatePreHook {
(moduleBuilder: TestingModuleBuilder): TestingModuleBuilder;
}
/**
* Hook for adding items to nest application
*/
export type TestingAppCreatePreHook = (
app: NestExpressApplication,
) => Promise<void>;
// Shared SyncDriver instance for all queues in tests
// This enables synchronous processing of jobs during integration tests
const syncDriver = new SyncDriver();
/**
* Sets basic integration testing module of app
*/
export const createApp = async (
config: {
moduleBuilderHook?: TestingModuleCreatePreHook;
appInitHook?: TestingAppCreatePreHook;
} = {},
): Promise<NestExpressApplication> => {
const stripeSDKMockService = new StripeSDKMockService();
const mockExceptionHandlerService = new ExceptionHandlerMockService();
let moduleBuilder: TestingModuleBuilder = Test.createTestingModule({
imports: [
AppModule,
CommandModule,
JobsModule,
MessageQueueModule.registerExplorer(),
],
providers: [
{
provide: APP_FILTER,
useClass: MockedUnhandledExceptionFilter,
},
],
})
.overrideProvider(StripeSDKService)
.useValue(stripeSDKMockService)
.overrideProvider(ExceptionHandlerService)
.useValue(mockExceptionHandlerService)
.overrideProvider(CaptchaDriverFactory)
.useValue({
getCurrentDriver: () => ({
validate: async () => ({ success: true }),
}),
})
.overrideProvider(QUEUE_DRIVER)
.useValue(syncDriver);
if (config.moduleBuilderHook) {
moduleBuilder = config.moduleBuilderHook(moduleBuilder);
}
const moduleFixture: TestingModule = await moduleBuilder.compile();
const app = moduleFixture.createNestApplication<NestExpressApplication>({
rawBody: true,
cors: true,
});
app.use(
'/graphql',
graphqlUploadExpress({
maxFieldSize: bytes(settings.storage.maxFileSize)!,
maxFiles: 10,
}),
);
app.use(
'/metadata',
graphqlUploadExpress({
maxFieldSize: bytes(settings.storage.maxFileSize)!,
maxFiles: 10,
}),
);
if (config.appInitHook) {
await config.appInitHook(app);
}
await app.init();
return app;
};