MeoCordTestingModule
class in meocord/testing Since 4.0.0
class MeoCordTestingModuleBuilds testing modules: the classes a test needs, in a container of their own, with no Discord connection.
Use it for a controller, or anything MeoCord resolves for you: a service with injected dependencies, a guard, an
interceptor, a presenter. A service that takes plain values needs no module; build it with new.
Examples
import { expect } from 'vitest'
@Controller()
class PingController {
@Command('ping', CommandType.SLASH)
async ping(interaction: ChatInputCommandInteraction) {
await respond(interaction).send('pong')
}
}
const module = MeoCordTestingModule.create({ controllers: [PingController] }).compile()
const interaction = createMockInteraction(ChatInputCommandInteraction, { commandName: 'ping' })
await module.invoke(PingController, 'ping', interaction)
expect(getResponse(interaction).calls[0].method).toBe('reply')Members
constructor
new MeoCordTestingModule()create
static create(options: TestingModuleOptions): TestingModuleBuilderStarts building a testing module from the classes a test needs.
Parameters
| Name | Type | Since | Description |
|---|---|---|---|
options | TestingModuleOptions | The controllers, providers, observers and app the module is built from. | |
options.controllers? | (new (...args: any[]) => any)[] | The controllers the module builds, with every class they inject. | |
options.providers? | Provider[] | Providers for what those classes inject, in any shape | |
options.app? | new (...args: any[]) => unknown | 4.1.0 | The |
options.observers? | (new (...args: any[]) => DispatchObserver)[] | 4.1.0 |
|
options.shutdownTimeout? | number | 4.1.0 | How long |
Returns
TestingModuleBuilderThe builder, to override what the test replaces before compile().
fromApp Since 4.1.0
static fromApp(
app: new (...args: any[]) => unknown,
options?: FromAppOptions,
): TestingModuleBuilderStarts building a testing module from a whole @MeoCord app, wired as the bot wires it.
Use it to test the app as it runs: every controller, service, provider and the cooldown store come from its
@MeoCord({...}), with its stages, translator, presenter, message options, theme and observers, as
TestingModuleOptions.app gives them. A test replaces what it must, by token, before anything is made.
Parameters
| Name | Type | Description |
|---|---|---|
app | new (...args: any[]) => unknown | The class |
options? | FromAppOptions | Providers that replace the app's by token, extra controllers, and observers. |
options.providers? | Provider[] | Providers that replace the app's own by token, or add what it lacks, such as the Discord |
options.controllers? | (new (...args: any[]) => any)[] | Controllers built beside the app's, such as one only a test uses. |
options.observers? | (new (...args: any[]) => DispatchObserver)[] |
|
options.shutdownTimeout? | number | How long |
Returns
TestingModuleBuilderThe builder, whose override* methods still apply, for compile().
Throws
TypeError when
appis not a@MeoCordclass.
Examples
import { expect } from 'vitest'
const DATABASE = createToken<{ query(sql: string): Promise<unknown[]> }>('Database')
@Service()
class Notes {
constructor(@Inject(DATABASE) private readonly db: { query(sql: string): Promise<unknown[]> }) {}
list() {
return this.db.query('select * from notes')
}
}
@Controller()
class NotesController {
constructor(private readonly notes: Notes) {}
@Command('notes', CommandType.SLASH)
async show(interaction: ChatInputCommandInteraction) {
await respond(interaction).send(`${(await this.notes.list()).length} notes`)
}
}
@MeoCord({
controllers: [NotesController],
providers: [{ provide: DATABASE, useFactory: async () => ({ query: async () => [] }) }],
clientOptions: { intents: [] },
})
class App {}
// The app's own wiring, with an in-memory database in place of the real one
const module = await MeoCordTestingModule.fromApp(App, {
providers: [{ provide: DATABASE, useValue: { query: async () => [{ id: 1 }] } }],
})
.compile()
.init()
const interaction = createMockInteraction(ChatInputCommandInteraction, { commandName: 'notes' })
await module.dispatch(interaction)
expect(getResponse(interaction).calls[0].payload).toMatchObject({ content: '1 notes' })See also
- TestingModuleBuilder
- TestingModule
- The testing module