meocord 2.0.0-beta.1 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
### Prerequisites
|
|
43
43
|
|
|
44
|
-
- **Runtime**: Node.js
|
|
44
|
+
- **Runtime**: Node.js 22 or newer, or Bun 1.x+
|
|
45
45
|
- **TypeScript**: 5.0+
|
|
46
46
|
- **Package manager**: npm, yarn, pnpm, or bun
|
|
47
47
|
|
|
@@ -410,6 +410,33 @@ interaction.guildId = 'guild-123'
|
|
|
410
410
|
|
|
411
411
|
Works for any discord.js class — interactions, `Message`, `MessageReaction`, and anything else. No per-type maintenance.
|
|
412
412
|
|
|
413
|
+
**Assignable to the real class** — the returned mock can be passed straight to code that expects the discord.js type. No `as unknown as ButtonInteraction` at the call site.
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
const interaction = createMockInteraction(ButtonInteraction)
|
|
417
|
+
|
|
418
|
+
await controller.handleButton(interaction) // takes a real ButtonInteraction
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Property overrides at construction** — pass a second argument to set properties as the mock is built. This is required for anything discord.js declares `readonly` (`ModalSubmitInteraction#customId` and `#fields`, `MessageComponentInteraction#message`, `client`, `guildId` on some classes), since those cannot be assigned afterwards. It is also how you set a property backed by a getter-only prototype accessor, such as `targetUser` or `targetMessage` on a context menu.
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import { createMockInteraction, createMockUser } from 'meocord/testing'
|
|
425
|
+
import { ModalSubmitInteraction, UserContextMenuCommandInteraction } from 'discord.js'
|
|
426
|
+
|
|
427
|
+
const modal = createMockInteraction(ModalSubmitInteraction, {
|
|
428
|
+
customId: 'wish-import-800000000',
|
|
429
|
+
fields: { getTextInputValue: () => '{"pulls":[]}' } as unknown as ModalSubmitInteraction['fields'],
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
const contextMenu = createMockInteraction(UserContextMenuCommandInteraction, {
|
|
433
|
+
commandName: 'profile',
|
|
434
|
+
targetUser: createMockUser(),
|
|
435
|
+
})
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
The override record is typed as `MockProps<T>`, exported from `meocord/testing`. Every key is optional, and a misspelled property name is a compile error.
|
|
439
|
+
|
|
413
440
|
### `createChatInputOptions`
|
|
414
441
|
|
|
415
442
|
Builds a typed options resolver from a plain record. Type routing mirrors the real `CommandInteractionOptionResolver`: wrong-type access returns `null`, `required=true` throws if the option is absent.
|
|
@@ -502,6 +529,19 @@ const module = MeoCordTestingModule.create({
|
|
|
502
529
|
|
|
503
530
|
`canActivate: () => true` allows the method to run. `() => false` blocks it. Multiple guards chain fluently.
|
|
504
531
|
|
|
532
|
+
### `overrideProvider`
|
|
533
|
+
|
|
534
|
+
Replaces a provider already registered on the module. The value is typed as `Partial<T>`, so a double only has to cover the methods the test exercises — a class with a private member could never be satisfied by a full object literal anyway. A misspelled method name is still a compile error.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
const module = MeoCordTestingModule.create({
|
|
538
|
+
controllers: [GreetingSlashController],
|
|
539
|
+
providers: [{ provide: GreetingService, useValue: realGreetingService }],
|
|
540
|
+
})
|
|
541
|
+
.overrideProvider(GreetingService).useValue({ buildGreeting: createMockFn() })
|
|
542
|
+
.compile()
|
|
543
|
+
```
|
|
544
|
+
|
|
505
545
|
### Full example
|
|
506
546
|
|
|
507
547
|
```typescript
|
|
@@ -747,7 +747,14 @@ function createMockMessage() {
|
|
|
747
747
|
* interaction.options.getSubcommand() // → 'notes'
|
|
748
748
|
* interaction.options.getNumber('uid') // → 12345678
|
|
749
749
|
* ```
|
|
750
|
-
*/
|
|
750
|
+
*/ // `any` is the default rather than `CacheType` because TypeScript types a generic
|
|
751
|
+
// class's `prototype` with `any` for its parameters, and createMockInteraction infers
|
|
752
|
+
// T from exactly that — `createMockInteraction(ChatInputCommandInteraction)` produces
|
|
753
|
+
// an interaction whose `options` is `CommandInteractionOptionResolver<any>`. Defaulting
|
|
754
|
+
// to `CacheType` instead makes CacheTypeReducer widen getChannel's return with a `null`
|
|
755
|
+
// the target rejects, and the resolver stops being assignable to the property it exists
|
|
756
|
+
// to fill. Pass Cached explicitly when the interaction under test is pinned.
|
|
757
|
+
function createChatInputOptions(opts = {}) {
|
|
751
758
|
const { subcommandGroup = null, subcommand = null, ...values } = opts;
|
|
752
759
|
function resolveOrThrow(name, value, required) {
|
|
753
760
|
if (value === null) {
|
|
@@ -434,7 +434,14 @@ function createMockMessage() {
|
|
|
434
434
|
* interaction.options.getSubcommand() // → 'notes'
|
|
435
435
|
* interaction.options.getNumber('uid') // → 12345678
|
|
436
436
|
* ```
|
|
437
|
-
*/
|
|
437
|
+
*/ // `any` is the default rather than `CacheType` because TypeScript types a generic
|
|
438
|
+
// class's `prototype` with `any` for its parameters, and createMockInteraction infers
|
|
439
|
+
// T from exactly that — `createMockInteraction(ChatInputCommandInteraction)` produces
|
|
440
|
+
// an interaction whose `options` is `CommandInteractionOptionResolver<any>`. Defaulting
|
|
441
|
+
// to `CacheType` instead makes CacheTypeReducer widen getChannel's return with a `null`
|
|
442
|
+
// the target rejects, and the resolver stops being assignable to the property it exists
|
|
443
|
+
// to fill. Pass Cached explicitly when the interaction under test is pinned.
|
|
444
|
+
function createChatInputOptions(opts = {}) {
|
|
438
445
|
const { subcommandGroup = null, subcommand = null, ...values } = opts;
|
|
439
446
|
function resolveOrThrow(name, value, required) {
|
|
440
447
|
if (value === null) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ServiceIdentifier, Container } from 'inversify';
|
|
2
2
|
import { GuardInterface } from '../interface/index.js';
|
|
3
|
-
import { CommandInteractionOptionResolver, Channel, Client, Guild, Message, User } from 'discord.js';
|
|
3
|
+
import { CacheType, CommandInteractionOptionResolver, Channel, Client, Guild, Message, User } from 'discord.js';
|
|
4
4
|
import 'webpack';
|
|
5
5
|
import '../controller.enum-QA-IuReF.js';
|
|
6
6
|
|
|
@@ -272,7 +272,7 @@ interface ChatInputOptions {
|
|
|
272
272
|
* interaction.options.getNumber('uid') // → 12345678
|
|
273
273
|
* ```
|
|
274
274
|
*/
|
|
275
|
-
declare function createChatInputOptions(opts?: ChatInputOptions): DeepMocked<CommandInteractionOptionResolver
|
|
275
|
+
declare function createChatInputOptions<Cached extends CacheType = any>(opts?: ChatInputOptions): DeepMocked<CommandInteractionOptionResolver<Cached>>;
|
|
276
276
|
|
|
277
277
|
export { MeoCordTestingModule, TestingModule, TestingModuleBuilder, createChatInputOptions, createMockChannel, createMockClient, createMockFn, createMockGuild, createMockInteraction, createMockMessage, createMockUser, isMockFunction };
|
|
278
278
|
export type { ChatInputOptions, ClassProvider, DeepMocked, Mock, MockInstance, MockProps, MockResult, MockState, MockedFunction, Provider, TestingModuleOptions, ValueProvider };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meocord",
|
|
3
3
|
"description": "Decorator-based Discord bot framework built on discord.js. Brings NestJS-style controllers, dependency injection, guards, and testing utilities to bot development — with a full CLI and TypeScript-first design.",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=22"
|