Skip to main content
The Factories module provides factory classes that make it easy to create and configure AdonisJS applications, Ignitor instances, and test utilities. These factories are particularly useful for testing scenarios and programmatic application setup.

Import

import { 
  IgnitorFactory, 
  TestUtilsFactory,
  AceFactory 
} from '@adonisjs/core/factories'

IgnitorFactory

Factory for creating and configuring AdonisJS Ignitor instances. The Ignitor is responsible for bootstrapping AdonisJS applications.

Constructor

Create a new IgnitorFactory instance.
const factory = new IgnitorFactory()

Methods

withCoreProviders

Include core AdonisJS providers when booting the application. Returns: this - Factory instance for method chaining
const ignitor = new IgnitorFactory()
  .withCoreProviders()
  .create(new URL('../', import.meta.url))
This adds the following core providers:
  • @adonisjs/core/providers/app_provider
  • @adonisjs/core/providers/hash_provider
  • @adonisjs/core/providers/repl_provider

withCoreConfig

Merge default configuration for core AdonisJS features. Returns: this - Factory instance for method chaining
const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .create(appRoot)
This adds default configurations for:
  • HTTP server settings
  • Hash driver (scrypt)
  • Logger configuration
  • Body parser settings
  • Encryption (AES-256-GCM)
  • Validator settings
A shallow merge is performed with any existing configuration.

merge

Merge custom factory parameters with existing configuration.
params
object
required
Parameters to merge
params.config
Record<string, any>
Application configuration to merge
params.rcFileContents
Record<string, any>
RC file contents to merge (providers, commands, etc.)
Returns: this - Factory instance for method chaining
const ignitor = new IgnitorFactory()
  .merge({
    config: {
      database: {
        connection: 'mysql',
        connections: {
          mysql: {
            client: 'mysql2',
            connection: {
              host: '127.0.0.1',
              database: 'test_db'
            }
          }
        }
      }
    },
    rcFileContents: {
      providers: [
        () => import('@adonisjs/lucid/database_provider')
      ],
      commands: [
        () => import('./commands/CustomCommand.ts')
      ]
    }
  })
  .create(appRoot)

preload

Define preload actions to run during application initialization.
action
(app: ApplicationService) => void | Promise<void>
required
Function to execute during preload phase
Returns: this - Factory instance for method chaining
const ignitor = new IgnitorFactory()
  .preload((app) => {
    // Register custom bindings
    app.container.bind('customService', () => {
      return new CustomService()
    })
  })
  .preload(async (app) => {
    // Async initialization
    const config = await loadRemoteConfig()
    app.container.bind('remoteConfig', () => config)
  })
  .create(appRoot)
Preload actions are executed after the application is booted.

create

Create a configured Ignitor instance.
appRoot
URL
required
Application root directory URL
options
IgnitorOptions
Optional Ignitor configuration options
options.importer
function
Custom module importer function
Returns: Ignitor - Configured Ignitor instance
const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .create(new URL('../', import.meta.url))

const app = ignitor.createApp('web')
await app.boot()
await app.start()

Usage Examples

Basic Setup

import { IgnitorFactory } from '@adonisjs/core/factories'

const ignitor = new IgnitorFactory()
  .withCoreProviders()
  .withCoreConfig()
  .create(new URL('../', import.meta.url))

const app = ignitor.createApp('web')
await app.boot()

Testing Setup

import { test } from '@japa/runner'
import { IgnitorFactory } from '@adonisjs/core/factories'

test('can create application', async ({ assert }) => {
  const ignitor = new IgnitorFactory()
    .withCoreConfig()
    .withCoreProviders()
    .merge({
      config: {
        database: {
          connection: 'sqlite',
          connections: {
            sqlite: {
              client: 'sqlite3',
              connection: { filename: ':memory:' }
            }
          }
        }
      }
    })
    .create(new URL('../', import.meta.url))
  
  const app = ignitor.createApp('test')
  await app.boot()
  
  assert.isTrue(app.isBooted)
})

Custom Providers

const ignitor = new IgnitorFactory()
  .withCoreProviders()
  .merge({
    rcFileContents: {
      providers: [
        () => import('@adonisjs/lucid/database_provider'),
        () => import('@adonisjs/auth/auth_provider'),
        () => import('./providers/AppProvider.ts')
      ]
    }
  })
  .create(appRoot)

Preload Actions

const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .preload((app) => {
    // Register global error handler
    app.container.bind('errorHandler', () => {
      return new CustomErrorHandler()
    })
  })
  .preload(async (app) => {
    // Initialize database connection
    const db = await app.container.make('lucid.db')
    await db.connection().raw('SELECT 1')
  })
  .create(appRoot)

TestUtilsFactory

Factory for creating TestUtils instances for AdonisJS testing scenarios.

Constructor

Create a new TestUtilsFactory instance.
const factory = new TestUtilsFactory()

Methods

create (from Ignitor)

Create TestUtils from an existing Ignitor instance.
ignitor
Ignitor
required
Existing Ignitor instance configured for testing
Returns: TestUtils - Test utilities instance
import { IgnitorFactory, TestUtilsFactory } from '@adonisjs/core/factories'

const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .create(appRoot)

const testUtils = new TestUtilsFactory().create(ignitor)
await testUtils.boot()

create (from URL)

Create TestUtils from application root URL.
appRoot
URL
required
Application root directory URL
options
IgnitorOptions
Optional Ignitor configuration options
Returns: TestUtils - Test utilities instance
const testUtils = new TestUtilsFactory()
  .create(new URL('../', import.meta.url))

await testUtils.boot()

const ctx = await testUtils.createHttpContext()
When creating from URL, core providers and config are automatically included.

Usage Examples

Basic Testing Setup

import { test } from '@japa/runner'
import { TestUtilsFactory } from '@adonisjs/core/factories'

test.group('Users', (group) => {
  let testUtils
  
  group.setup(async () => {
    testUtils = new TestUtilsFactory()
      .create(new URL('../../', import.meta.url))
    await testUtils.boot()
  })
  
  test('can create http context', async ({ assert }) => {
    const ctx = await testUtils.createHttpContext()
    assert.exists(ctx.request)
    assert.exists(ctx.response)
  })
})

Shared Test Setup

// tests/helpers.ts
import { TestUtilsFactory } from '@adonisjs/core/factories'

export async function setupTestUtils() {
  const factory = new TestUtilsFactory()
  const testUtils = factory.create(new URL('../../', import.meta.url))
  await testUtils.boot()
  return testUtils
}

// tests/users.spec.ts
import { test } from '@japa/runner'
import { setupTestUtils } from './helpers.ts'

test.group('Users', (group) => {
  let testUtils
  
  group.setup(async () => {
    testUtils = await setupTestUtils()
  })
  
  // ... your tests
})

With Custom Ignitor

import { IgnitorFactory, TestUtilsFactory } from '@adonisjs/core/factories'

const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .merge({
    config: {
      database: { connection: 'sqlite' }
    }
  })
  .preload(async (app) => {
    // Custom test setup
    await seedDatabase(app)
  })
  .create(appRoot)

const testUtils = new TestUtilsFactory().create(ignitor)
await testUtils.boot()

AceFactory

Factory for creating and testing Ace commands.
import { AceFactory } from '@adonisjs/core/factories'
Detailed documentation for AceFactory is available in the Ace commands section.

Additional Factory Exports

The factories module also re-exports factories from related packages:

HTTP Factories

// Re-exported from @adonisjs/http-server/factories
import { 
  RequestFactory,
  ResponseFactory,
  HttpContextFactory 
} from '@adonisjs/core/factories'

Hash Factories

// Re-exported from @adonisjs/hash/factories
import { HashFactory } from '@adonisjs/core/factories'

Encryption Factories

// Re-exported from @boringnode/encryption/factories
import { EncryptionFactory } from '@adonisjs/core/factories'

Application Factories

// Re-exported from @adonisjs/application/factories
import { ApplicationFactory } from '@adonisjs/core/factories'
Refer to the respective package documentation for detailed usage of these factories.

Best Practices

1. Reuse Factory Configurations

Create a base factory configuration for tests:
// tests/factories.ts
export function createTestIgnitor() {
  return new IgnitorFactory()
    .withCoreConfig()
    .withCoreProviders()
    .merge({
      config: {
        database: { connection: 'sqlite' }
      }
    })
}

2. Use Method Chaining

Take advantage of fluent API:
const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .merge({ config: { /* ... */ } })
  .preload(setupApp)
  .create(appRoot)

3. Isolate Test Environments

test.group('Integration Tests', (group) => {
  let testUtils
  let app
  
  group.setup(async () => {
    const ignitor = new IgnitorFactory()
      .withCoreConfig()
      .withCoreProviders()
      .create(appRoot)
    
    app = ignitor.createApp('test')
    await app.boot()
    
    testUtils = new TestUtils(app)
    await testUtils.boot()
  })
  
  group.teardown(async () => {
    await app.terminate()
  })
})

4. Custom Preload Actions

Use preload for test-specific setup:
const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .preload(async (app) => {
    // Seed test data
    const db = await app.container.make('lucid.db')
    await db.table('users').insert({ email: 'test@example.com' })
  })
  .create(appRoot)

5. Environment-Specific Configuration

const isCI = process.env.CI === 'true'

const ignitor = new IgnitorFactory()
  .withCoreConfig()
  .withCoreProviders()
  .merge({
    config: {
      database: {
        connection: isCI ? 'pg' : 'sqlite'
      }
    }
  })
  .create(appRoot)

Complete Testing Example

import { test } from '@japa/runner'
import { IgnitorFactory, TestUtilsFactory } from '@adonisjs/core/factories'
import supertest from 'supertest'

test.group('User Registration', (group) => {
  let testUtils
  let closeServer
  
  group.setup(async () => {
    // Create custom ignitor
    const ignitor = new IgnitorFactory()
      .withCoreConfig()
      .withCoreProviders()
      .merge({
        config: {
          database: {
            connection: 'sqlite',
            connections: {
              sqlite: {
                client: 'sqlite3',
                connection: { filename: ':memory:' }
              }
            }
          }
        },
        rcFileContents: {
          providers: [
            () => import('@adonisjs/lucid/database_provider')
          ]
        }
      })
      .preload(async (app) => {
        // Run migrations
        const db = await app.container.make('lucid.db')
        await db.connection().schema.createTable('users', (table) => {
          table.increments('id')
          table.string('email').unique()
          table.string('password')
        })
      })
      .create(new URL('../../', import.meta.url))
    
    // Create test utils
    testUtils = new TestUtilsFactory().create(ignitor)
    await testUtils.boot()
    
    // Start HTTP server
    const httpUtils = testUtils.httpServer()
    closeServer = await httpUtils.start()
  })
  
  group.teardown(async () => {
    await closeServer()
  })
  
  test('can register new user', async ({ assert }) => {
    const baseUrl = `http://${process.env.HOST}:${process.env.PORT}`
    
    const response = await supertest(baseUrl)
      .post('/register')
      .send({
        email: 'test@example.com',
        password: 'secret123'
      })
      .expect(201)
    
    assert.exists(response.body.id)
    assert.equal(response.body.email, 'test@example.com')
  })
})