meocord 1.8.1 → 1.8.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.
|
@@ -399,8 +399,32 @@ function findPrototypeMethod(instance, name) {
|
|
|
399
399
|
}
|
|
400
400
|
/**
|
|
401
401
|
* Creates a mock channel of the given class (e.g. `TextChannel`, `DMChannel`).
|
|
402
|
-
*
|
|
403
|
-
|
|
402
|
+
*
|
|
403
|
+
* Manager properties that are constructor-assigned in discord.js are
|
|
404
|
+
* pre-initialized as prototype-based stubs so all methods are auto-stubbed
|
|
405
|
+
* as `jest.fn()`:
|
|
406
|
+
* - Guild text channels (`TextChannel`, `NewsChannel`): `messages`, `threads`
|
|
407
|
+
* - `DMChannel`: `messages`
|
|
408
|
+
* - `ThreadChannel`: `messages`, `members`
|
|
409
|
+
*/ function createMockChannel(Class) {
|
|
410
|
+
const instance = Object.create(Class.prototype);
|
|
411
|
+
// Guild text channels (TextChannel, NewsChannel) — messages & threads
|
|
412
|
+
// assigned in BaseGuildTextChannel constructor
|
|
413
|
+
if ('messages' in Class.prototype || Class.name === 'TextChannel' || Class.name === 'NewsChannel') {
|
|
414
|
+
instance.messages = stubDeep(Object.create(discord_js.GuildMessageManager.prototype));
|
|
415
|
+
instance.threads = stubDeep(Object.create(discord_js.ThreadManager.prototype));
|
|
416
|
+
}
|
|
417
|
+
// DMChannel — messages assigned in DMChannel constructor
|
|
418
|
+
if (Class.name === 'DMChannel') {
|
|
419
|
+
instance.messages = stubDeep(Object.create(discord_js.DMMessageManager.prototype));
|
|
420
|
+
}
|
|
421
|
+
// ThreadChannel — messages & members assigned in ThreadChannel constructor
|
|
422
|
+
if (Class.name === 'ThreadChannel') {
|
|
423
|
+
instance.messages = stubDeep(Object.create(discord_js.MessageManager.prototype));
|
|
424
|
+
instance.members = stubDeep(Object.create(discord_js.ThreadMemberManager.prototype));
|
|
425
|
+
}
|
|
426
|
+
return stubDeep(instance);
|
|
427
|
+
}
|
|
404
428
|
/**
|
|
405
429
|
* Creates a smart mock {@link Message}.
|
|
406
430
|
*
|
|
@@ -408,14 +432,54 @@ function findPrototypeMethod(instance, name) {
|
|
|
408
432
|
* `pin()`, and `unpin()` throw if the message has already been deleted.
|
|
409
433
|
* `edit()` and `reply()` resolve to a new mock `Message` instance.
|
|
410
434
|
*
|
|
435
|
+
* Constructor-assigned and getter properties are pre-initialized as
|
|
436
|
+
* prototype-based stubs so `msg.author.send`, `msg.member.fetch`,
|
|
437
|
+
* `msg.channel.send`, `msg.guild.members.fetch`, `msg.thread.fetch`,
|
|
438
|
+
* and `msg.mentions.has` all work out of the box.
|
|
439
|
+
*
|
|
411
440
|
* All methods remain `jest.fn()` — overridable per test.
|
|
412
441
|
*
|
|
413
442
|
* Note: `createMockInteraction`'s `followUp()` and `editReply()` stubs return
|
|
414
443
|
* a `createMockMessage()` by default, matching the official return types.
|
|
415
|
-
*/
|
|
444
|
+
*/ /**
|
|
445
|
+
* Internal guild stub for use inside createMockMessage.
|
|
446
|
+
* Reuses the same manager stubs as createMockGuild but avoids
|
|
447
|
+
* a circular reference in the module.
|
|
448
|
+
*/ function createMockGuildForMessage() {
|
|
449
|
+
const guild = Object.create(discord_js.Guild.prototype);
|
|
450
|
+
guild.members = stubDeep(Object.create(discord_js.GuildMemberManager.prototype));
|
|
451
|
+
guild.channels = stubDeep(Object.create(discord_js.GuildChannelManager.prototype));
|
|
452
|
+
guild.roles = stubDeep(Object.create(discord_js.RoleManager.prototype));
|
|
453
|
+
guild.bans = stubDeep(Object.create(discord_js.GuildBanManager.prototype));
|
|
454
|
+
return stubDeep(guild);
|
|
455
|
+
}
|
|
456
|
+
function createMockMessage() {
|
|
416
457
|
const instance = Object.create(discord_js.Message.prototype);
|
|
417
458
|
const stubs = new Map();
|
|
418
459
|
instance.deleted = false;
|
|
460
|
+
// Constructor-assigned — set as prototype-based stubs
|
|
461
|
+
instance.author = stubDeep(Object.create(discord_js.User.prototype));
|
|
462
|
+
// Getters on the prototype — the proxy sees them as functions and returns
|
|
463
|
+
// jest.fn(), which is wrong. Pre-initialize as own properties to shadow
|
|
464
|
+
// the prototype getters.
|
|
465
|
+
Object.defineProperty(instance, 'member', {
|
|
466
|
+
value: stubDeep(Object.create(discord_js.GuildMember.prototype)),
|
|
467
|
+
writable: true
|
|
468
|
+
});
|
|
469
|
+
Object.defineProperty(instance, 'channel', {
|
|
470
|
+
value: stubDeep(Object.create(discord_js.TextChannel.prototype)),
|
|
471
|
+
writable: true
|
|
472
|
+
});
|
|
473
|
+
Object.defineProperty(instance, 'guild', {
|
|
474
|
+
value: createMockGuildForMessage(),
|
|
475
|
+
writable: true
|
|
476
|
+
});
|
|
477
|
+
Object.defineProperty(instance, 'thread', {
|
|
478
|
+
value: stubDeep(Object.create(discord_js.ThreadChannel.prototype)),
|
|
479
|
+
writable: true
|
|
480
|
+
});
|
|
481
|
+
// MessageMentions — constructor-assigned, has methods like .has(), .members
|
|
482
|
+
instance.mentions = stubDeep(Object.create(discord_js.MessageMentions.prototype));
|
|
419
483
|
const alreadyDeleted = ()=>new Error('This message has already been deleted.');
|
|
420
484
|
stubs.set('delete', globals.jest.fn(async ()=>{
|
|
421
485
|
if (instance.deleted) throw alreadyDeleted();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { jest } from '@jest/globals';
|
|
3
|
-
import { InteractionType, ComponentType, ApplicationCommandType, CommandInteractionOptionResolver, Client, ApplicationCommandManager, UserManager, ChannelManager, GuildManager, ClientUser, Guild, GuildMemberManager, GuildChannelManager, RoleManager, GuildBanManager, Message, User } from 'discord.js';
|
|
3
|
+
import { InteractionType, ComponentType, ApplicationCommandType, CommandInteractionOptionResolver, GuildMessageManager, ThreadManager, DMMessageManager, MessageManager, ThreadMemberManager, Client, ApplicationCommandManager, UserManager, ChannelManager, GuildManager, ClientUser, Guild, GuildMemberManager, GuildChannelManager, RoleManager, GuildBanManager, Message, User, GuildMember, TextChannel, ThreadChannel, MessageMentions } from 'discord.js';
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// stubDeep — Proxy that auto-creates jest.fn() on any property access
|
|
@@ -288,8 +288,32 @@ function findPrototypeMethod(instance, name) {
|
|
|
288
288
|
}
|
|
289
289
|
/**
|
|
290
290
|
* Creates a mock channel of the given class (e.g. `TextChannel`, `DMChannel`).
|
|
291
|
-
*
|
|
292
|
-
|
|
291
|
+
*
|
|
292
|
+
* Manager properties that are constructor-assigned in discord.js are
|
|
293
|
+
* pre-initialized as prototype-based stubs so all methods are auto-stubbed
|
|
294
|
+
* as `jest.fn()`:
|
|
295
|
+
* - Guild text channels (`TextChannel`, `NewsChannel`): `messages`, `threads`
|
|
296
|
+
* - `DMChannel`: `messages`
|
|
297
|
+
* - `ThreadChannel`: `messages`, `members`
|
|
298
|
+
*/ function createMockChannel(Class) {
|
|
299
|
+
const instance = Object.create(Class.prototype);
|
|
300
|
+
// Guild text channels (TextChannel, NewsChannel) — messages & threads
|
|
301
|
+
// assigned in BaseGuildTextChannel constructor
|
|
302
|
+
if ('messages' in Class.prototype || Class.name === 'TextChannel' || Class.name === 'NewsChannel') {
|
|
303
|
+
instance.messages = stubDeep(Object.create(GuildMessageManager.prototype));
|
|
304
|
+
instance.threads = stubDeep(Object.create(ThreadManager.prototype));
|
|
305
|
+
}
|
|
306
|
+
// DMChannel — messages assigned in DMChannel constructor
|
|
307
|
+
if (Class.name === 'DMChannel') {
|
|
308
|
+
instance.messages = stubDeep(Object.create(DMMessageManager.prototype));
|
|
309
|
+
}
|
|
310
|
+
// ThreadChannel — messages & members assigned in ThreadChannel constructor
|
|
311
|
+
if (Class.name === 'ThreadChannel') {
|
|
312
|
+
instance.messages = stubDeep(Object.create(MessageManager.prototype));
|
|
313
|
+
instance.members = stubDeep(Object.create(ThreadMemberManager.prototype));
|
|
314
|
+
}
|
|
315
|
+
return stubDeep(instance);
|
|
316
|
+
}
|
|
293
317
|
/**
|
|
294
318
|
* Creates a smart mock {@link Message}.
|
|
295
319
|
*
|
|
@@ -297,14 +321,54 @@ function findPrototypeMethod(instance, name) {
|
|
|
297
321
|
* `pin()`, and `unpin()` throw if the message has already been deleted.
|
|
298
322
|
* `edit()` and `reply()` resolve to a new mock `Message` instance.
|
|
299
323
|
*
|
|
324
|
+
* Constructor-assigned and getter properties are pre-initialized as
|
|
325
|
+
* prototype-based stubs so `msg.author.send`, `msg.member.fetch`,
|
|
326
|
+
* `msg.channel.send`, `msg.guild.members.fetch`, `msg.thread.fetch`,
|
|
327
|
+
* and `msg.mentions.has` all work out of the box.
|
|
328
|
+
*
|
|
300
329
|
* All methods remain `jest.fn()` — overridable per test.
|
|
301
330
|
*
|
|
302
331
|
* Note: `createMockInteraction`'s `followUp()` and `editReply()` stubs return
|
|
303
332
|
* a `createMockMessage()` by default, matching the official return types.
|
|
304
|
-
*/
|
|
333
|
+
*/ /**
|
|
334
|
+
* Internal guild stub for use inside createMockMessage.
|
|
335
|
+
* Reuses the same manager stubs as createMockGuild but avoids
|
|
336
|
+
* a circular reference in the module.
|
|
337
|
+
*/ function createMockGuildForMessage() {
|
|
338
|
+
const guild = Object.create(Guild.prototype);
|
|
339
|
+
guild.members = stubDeep(Object.create(GuildMemberManager.prototype));
|
|
340
|
+
guild.channels = stubDeep(Object.create(GuildChannelManager.prototype));
|
|
341
|
+
guild.roles = stubDeep(Object.create(RoleManager.prototype));
|
|
342
|
+
guild.bans = stubDeep(Object.create(GuildBanManager.prototype));
|
|
343
|
+
return stubDeep(guild);
|
|
344
|
+
}
|
|
345
|
+
function createMockMessage() {
|
|
305
346
|
const instance = Object.create(Message.prototype);
|
|
306
347
|
const stubs = new Map();
|
|
307
348
|
instance.deleted = false;
|
|
349
|
+
// Constructor-assigned — set as prototype-based stubs
|
|
350
|
+
instance.author = stubDeep(Object.create(User.prototype));
|
|
351
|
+
// Getters on the prototype — the proxy sees them as functions and returns
|
|
352
|
+
// jest.fn(), which is wrong. Pre-initialize as own properties to shadow
|
|
353
|
+
// the prototype getters.
|
|
354
|
+
Object.defineProperty(instance, 'member', {
|
|
355
|
+
value: stubDeep(Object.create(GuildMember.prototype)),
|
|
356
|
+
writable: true
|
|
357
|
+
});
|
|
358
|
+
Object.defineProperty(instance, 'channel', {
|
|
359
|
+
value: stubDeep(Object.create(TextChannel.prototype)),
|
|
360
|
+
writable: true
|
|
361
|
+
});
|
|
362
|
+
Object.defineProperty(instance, 'guild', {
|
|
363
|
+
value: createMockGuildForMessage(),
|
|
364
|
+
writable: true
|
|
365
|
+
});
|
|
366
|
+
Object.defineProperty(instance, 'thread', {
|
|
367
|
+
value: stubDeep(Object.create(ThreadChannel.prototype)),
|
|
368
|
+
writable: true
|
|
369
|
+
});
|
|
370
|
+
// MessageMentions — constructor-assigned, has methods like .has(), .members
|
|
371
|
+
instance.mentions = stubDeep(Object.create(MessageMentions.prototype));
|
|
308
372
|
const alreadyDeleted = ()=>new Error('This message has already been deleted.');
|
|
309
373
|
stubs.set('delete', jest.fn(async ()=>{
|
|
310
374
|
if (instance.deleted) throw alreadyDeleted();
|
|
@@ -138,21 +138,15 @@ declare function createMockClient(): DeepMocked<Client>;
|
|
|
138
138
|
declare function createMockGuild(): DeepMocked<Guild>;
|
|
139
139
|
/**
|
|
140
140
|
* Creates a mock channel of the given class (e.g. `TextChannel`, `DMChannel`).
|
|
141
|
-
* All methods are auto-stubbed as `jest.fn()`.
|
|
142
|
-
*/
|
|
143
|
-
declare const createMockChannel: <T extends Channel>(Class: InteractionClass<T>) => DeepMocked<T>;
|
|
144
|
-
/**
|
|
145
|
-
* Creates a smart mock {@link Message}.
|
|
146
|
-
*
|
|
147
|
-
* Tracks a `deleted` boolean. `delete()`, `edit()`, `reply()`, `react()`,
|
|
148
|
-
* `pin()`, and `unpin()` throw if the message has already been deleted.
|
|
149
|
-
* `edit()` and `reply()` resolve to a new mock `Message` instance.
|
|
150
|
-
*
|
|
151
|
-
* All methods remain `jest.fn()` — overridable per test.
|
|
152
141
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
142
|
+
* Manager properties that are constructor-assigned in discord.js are
|
|
143
|
+
* pre-initialized as prototype-based stubs so all methods are auto-stubbed
|
|
144
|
+
* as `jest.fn()`:
|
|
145
|
+
* - Guild text channels (`TextChannel`, `NewsChannel`): `messages`, `threads`
|
|
146
|
+
* - `DMChannel`: `messages`
|
|
147
|
+
* - `ThreadChannel`: `messages`, `members`
|
|
155
148
|
*/
|
|
149
|
+
declare function createMockChannel<T extends Channel>(Class: InteractionClass<T>): DeepMocked<T>;
|
|
156
150
|
declare function createMockMessage(): DeepMocked<Message>;
|
|
157
151
|
interface ChatInputOptions {
|
|
158
152
|
subcommandGroup?: string | null;
|
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": "1.8.
|
|
4
|
+
"version": "1.8.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "eslint --fix . && tsc --noEmit && tsc --noEmit --project tsconfig.test.json",
|