TestingModuleBuilder
class in meocord/testing Since 4.0.0
class TestingModuleBuilderBuilds a testing module, with stand-ins for the providers, stages and theme a test replaces.
Use its override* methods before compile() to replace what a handler depends on, then run the handler with the
TestingModule it returns.
Examples
@Controller()
class ProfileController {
constructor(private readonly profiles: ProfileService) {}
@Command('profile', CommandType.SLASH)
@UseGuard(StaffGuard)
async profile(interaction: ChatInputCommandInteraction) {
await respond(interaction).send({ embeds: [await this.profiles.render(interaction.user.id)] })
}
}
const module = MeoCordTestingModule.create({ controllers: [ProfileController] })
.overrideProvider(ProfileService).useValue({ render: async () => new EmbedBuilder().setTitle('Ada') })
.overrideGuard(StaffGuard).useValue({ canActivate: () => true })
.compile()Members
constructor
new TestingModuleBuilder(
options: TestingModuleOptions,
wiring?: AppWiring | undefined,
)Parameters
| Name | Type | Since | Description |
|---|---|---|---|
options | TestingModuleOptions | ||
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 |
wiring? | AppWiring | undefined | 4.1.0 |
compile
compile(): TestingModuleBinds the controllers, providers and overrides into a module ready to resolve and run handlers.
It runs the bot's startup checks on commands and autocomplete handlers, except a command no builder registers,
since a handler declared with a CommandType and no builder is how a test fixture is written. A subcommand path
its command's builder does not register, a customId pattern given as a command name, a builder that registers
another name, and component patterns that can match the same customId are named, as the bot names them.
Returns
TestingModuleThe compiled module.
overrideFilter Since 4.1.0
overrideFilter(filter: new (...args: any[]) => ExceptionFilter<any>): {
useValue: (stub: Partial<ExceptionFilter<any>>) => TestingModuleBuilder
}Replaces an exception filter with a stub wherever it applies. The filter's @Catch still decides
which errors reach the stub.
Parameters
| Name | Type | Description |
|---|---|---|
filter | new (...args: any[]) => ExceptionFilter<any> | The filter class to replace. |
Returns
{ useValue: (stub: Partial<ExceptionFilter<any>>) => TestingModuleBuilder }Examples
builder.overrideFilter(RateLimitedFilter).useValue({ catch: vi.fn() })overrideGuard
overrideGuard(guard: new (...args: any[]) => GuardInterface): {
useValue: (stub: Partial<GuardInterface>) => TestingModuleBuilder
}Replaces a guard with a stub wherever it applies, globally or on a controller or handler.
Parameters
| Name | Type | Description |
|---|---|---|
guard | new (...args: any[]) => GuardInterface | The guard class to replace. |
Returns
{ useValue: (stub: Partial<GuardInterface>) => TestingModuleBuilder }Examples
builder.overrideGuard(RateLimitGuard).useValue({ canActivate: () => true })overrideInterceptor Since 4.1.0
overrideInterceptor(
interceptor: new (...args: any[]) => InterceptorInterface,
): { useValue: (stub: Partial<InterceptorInterface>) => TestingModuleBuilder }Replaces an interceptor with a stub wherever it applies, globally or on a controller or handler.
The stub's intercept receives the context and next; call next.handle() to run the handler.
Parameters
| Name | Type | Description |
|---|---|---|
interceptor | new (...args: any[]) => InterceptorInterface | The interceptor class to replace. |
Returns
{ useValue: (stub: Partial<InterceptorInterface>) => TestingModuleBuilder }Examples
builder.overrideInterceptor(TimingInterceptor).useValue({ intercept: (_context, next) => next.handle() })overrideProvider
overrideProvider<T>(token: ProviderToken<T> | ServiceIdentifier<T>): {
useValue: (value: Partial<T>) => TestingModuleBuilder
}Replaces a provider with a test double.
The double needs only the members the test uses; misspelled member names are still rejected.
Parameters
| Name | Type | Description |
|---|---|---|
token | ProviderToken<T> | ServiceIdentifier<T> | The provider to replace. |
Returns
{ useValue: (value: Partial<T>) => TestingModuleBuilder }Examples
builder.overrideProvider(UserService).useValue({ findUser: vi.fn() })overrideTheme Since 4.1.0
overrideTheme(theme: ThemeOverride): TestingModuleBuilderChanges part of the app's @MeoCord({ theme }) for this module, or gives a module without an app a
theme. It goes over the app's theme, so it names only the tokens it changes; each @UseTheme, and what
themeFor looks up, still goes over it.
Parameters
| Name | Type | Description |
|---|---|---|
theme | ThemeOverride | The tokens to change, checked as |
theme.colors? | {
primary?: ColorResolvable
neutral?: ColorResolvable
success?: ColorResolvable
warning?: ColorResolvable
danger?: ColorResolvable
info?: ColorResolvable
} | Colours by role. |
theme.colors.primary? | ColorResolvable | The app's own colour, for what is neither good nor bad news. |
theme.colors.neutral? | ColorResolvable | A quiet colour, for what needs no attention. |
theme.colors.success? | ColorResolvable | Something went as asked. |
theme.colors.warning? | ColorResolvable | Something needs the user's attention, or was refused because of what they did. |
theme.colors.danger? | ColorResolvable | Something failed, a fault in the bot rather than the user. |
theme.colors.info? | ColorResolvable | Information, with no action needed. |
theme.emojis? | {
loading?: string
success?: string
warning?: string
danger?: string
info?: string
} | Emojis by role. |
theme.emojis.loading? | string | Shown while a deferred call is still working. |
theme.emojis.success? | string | Something went as asked. |
theme.emojis.warning? | string | Something needs the user's attention, or was refused because of what they did. |
theme.emojis.danger? | string | Something failed, a fault in the bot rather than the user. |
theme.emojis.info? | string | Information, with no action needed. |
theme.buttons? | {
primary?: ThemeButtonStyle
neutral?: ThemeButtonStyle
success?: ThemeButtonStyle
danger?: ThemeButtonStyle
} | Button styles by role. |
theme.buttons.primary? | ThemeButtonStyle | The action the app most expects, such as Submit. |
theme.buttons.neutral? | ThemeButtonStyle | A secondary action, such as Cancel or Back. |
theme.buttons.success? | ThemeButtonStyle | An action that confirms or approves, such as Approve. |
theme.buttons.danger? | ThemeButtonStyle | An action that removes or refuses, such as Delete or Reject. |
Returns
TestingModuleBuilderThrows
Error naming each token that is not valid.
Examples
const module = MeoCordTestingModule.create({ app: App, controllers: [ShopController] })
.overrideTheme({ colors: { primary: '#E3606D' } })
.compile()overrideThemeFor Since 4.1.0
overrideThemeFor(
resolvers:
ThemeResolvers | (new (...args: any[]) => ThemeResolver) | undefined,
): TestingModuleBuilderReplaces the app's @MeoCord({ themeFor }) for this module, or removes it with undefined. The app's
themeCache and themeForTimeoutMs still apply, and the results are cached in TestingModule.themeCache,
as the bot caches them. A mock resolver shows each lookup. A class implementing ThemeResolver is bound as
the app binds one, so overrideProvider replaces it or what it injects.
Parameters
| Name | Type | Description |
|---|---|---|
resolvers | | ThemeResolvers
| (new (...args: any[]) => ThemeResolver)
| undefined | The server's and the user's resolvers, a class implementing |
Returns
TestingModuleBuilderThrows
TypeError when a resolver is not a function, or is neither
guildnoruser, or a class has neither method.
Examples
const guild = vi.fn(() => ({ colors: { primary: '#26A042' as const } }))
const module = MeoCordTestingModule.create({ app: App, controllers: [ShopController] }).overrideThemeFor({ guild }).compile()See also
- MeoCordTestingModule
- The testing module