mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
testing n shi
This commit is contained in:
@@ -6,7 +6,7 @@ export function makePlugin<V extends unknown[]>(
|
||||
type: PluginType,
|
||||
execute: (...args: any[]) => any,
|
||||
): Plugin<V> {
|
||||
return { type, execute, } as Plugin<V>;
|
||||
return { type, execute } as Plugin<V>;
|
||||
}
|
||||
/**
|
||||
* @since 2.5.0
|
||||
|
||||
@@ -100,7 +100,7 @@ export function isModal(i: InteractionTypable): i is ModalSubmitInteraction {
|
||||
return i.type === InteractionType.ModalSubmit;
|
||||
}
|
||||
|
||||
export function resultPayload<T extends PayloadType>
|
||||
export function resultPayload<T extends 'success'|'warning'|'failure'>
|
||||
(type: T, module?: Module, reason?: unknown) {
|
||||
return { type, module, reason } as Payload & { type : T };
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ const parseParams = (event: { customId: string }, id: string, append: string) =>
|
||||
export function reconstruct<T extends Interaction>(event: T) {
|
||||
switch (event.type) {
|
||||
case InteractionType.MessageComponent: {
|
||||
let id = event.customId;
|
||||
const data = parseParams(event, id, `_C${event.componentType}`)
|
||||
const data = parseParams(event, event.customId, `_C${event.componentType}`)
|
||||
return [data];
|
||||
}
|
||||
case InteractionType.ApplicationCommand:
|
||||
@@ -27,8 +26,7 @@ export function reconstruct<T extends Interaction>(event: T) {
|
||||
return [{ id: `${event.commandName}_A${event.commandType}` }, { id: `${event.commandName}_B` }];
|
||||
//Modal interactions are classified as components for sern
|
||||
case InteractionType.ModalSubmit: {
|
||||
let id = `${event.customId}`;
|
||||
const data = parseParams(event, id, '_M');
|
||||
const data = parseParams(event, event.customId, '_M');
|
||||
return [data];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import path from 'node:path';
|
||||
import { existsSync } from 'fs';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { readdir } from 'fs/promises';
|
||||
import assert from 'node:assert';
|
||||
import * as Id from './id'
|
||||
|
||||
@@ -86,20 +86,12 @@ export enum PluginType {
|
||||
Control = 2,
|
||||
}
|
||||
/**
|
||||
* @deprecated - Use strings 'success' | 'failure' | 'warning'
|
||||
* @enum { string }
|
||||
*/
|
||||
export enum PayloadType {
|
||||
/**
|
||||
* The PayloadType for a SernEmitter success event
|
||||
*/
|
||||
Success = 'success',
|
||||
/**
|
||||
* The PayloadType for a SernEmitter failure event
|
||||
*/
|
||||
Failure = 'failure',
|
||||
/**
|
||||
* The PayloadType for a SernEmitter warning event
|
||||
*/
|
||||
Warning = 'warning',
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from 'rxjs';
|
||||
import * as Id from '../core/id'
|
||||
import type { Emitter } from '../core/interfaces';
|
||||
import { PayloadType, SernError } from '../core/structures/enums'
|
||||
import { SernError } from '../core/structures/enums'
|
||||
import { Err, Ok, Result } from 'ts-results-es';
|
||||
import type { UnpackedDependencies } from '../types/utility';
|
||||
import type { CommandModule, Module, Processed } from '../types/core-modules';
|
||||
@@ -167,10 +167,10 @@ export function executeModule(
|
||||
return from(Result.wrapAsync(async () => module.execute(...args)))
|
||||
.pipe(concatMap(result => {
|
||||
if (result.isOk()) {
|
||||
emitter.emit('module.activate', resultPayload(PayloadType.Success, module));
|
||||
emitter.emit('module.activate', resultPayload('success', module));
|
||||
return EMPTY;
|
||||
}
|
||||
return throwError(() => resultPayload(PayloadType.Failure, module, result.error));
|
||||
return throwError(() => resultPayload('failure', module, result.error));
|
||||
}))
|
||||
};
|
||||
|
||||
@@ -211,8 +211,7 @@ export async function callInitPlugins(module: Module, deps: Dependencies, emit?:
|
||||
});
|
||||
if(res.isErr()) {
|
||||
if(emit) {
|
||||
deps['@sern/emitter']
|
||||
?.emit('module.register', resultPayload(PayloadType.Failure, module, SernError.PluginFailure));
|
||||
deps['@sern/emitter']?.emit('module.register', resultPayload('failure', module, SernError.PluginFailure));
|
||||
}
|
||||
throw Error("Plugin failed with controller.stop()");
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import type { Interaction } from 'discord.js';
|
||||
import { mergeMap, merge, concatMap, EMPTY } from 'rxjs';
|
||||
import { PayloadType } from '../core/structures/enums';
|
||||
import { filterTap, sharedEventStream } from '../core/operators'
|
||||
import { createInteractionHandler, executeModule, intoTask, } from './event-utils';
|
||||
import { createInteractionHandler, executeModule, intoTask } from './event-utils';
|
||||
import { SernError } from '../core/structures/enums'
|
||||
import { isAutocomplete, isCommand, isMessageComponent, isModal, resultPayload, } from '../core/functions'
|
||||
import { isAutocomplete, isCommand, isMessageComponent, isModal, resultPayload } from '../core/functions'
|
||||
import { UnpackedDependencies } from '../types/utility';
|
||||
import { Emitter } from '../core/interfaces';
|
||||
|
||||
@@ -20,9 +19,9 @@ export default function interactionHandler(deps: UnpackedDependencies, defaultPr
|
||||
handle(isCommand),
|
||||
handle(isModal));
|
||||
return interactionHandler$
|
||||
.pipe(filterTap(e => emitter.emit('warning', resultPayload(PayloadType.Warning, undefined, e))),
|
||||
.pipe(filterTap(e => emitter.emit('warning', resultPayload('warning', undefined, e))),
|
||||
concatMap(intoTask(module => {
|
||||
emitter.emit('module.activate', resultPayload(PayloadType.Failure, module, SernError.PluginFailure))
|
||||
emitter.emit('module.activate', resultPayload('failure', module, SernError.PluginFailure))
|
||||
})),
|
||||
mergeMap(payload => {
|
||||
if(payload)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EMPTY, mergeMap, concatMap } from 'rxjs';
|
||||
import type { Message } from 'discord.js';
|
||||
import { createMessageHandler, executeModule, intoTask } from './event-utils';
|
||||
import { createMessageHandler, executeModule, intoTask } from './event-utils';
|
||||
import { PayloadType, SernError } from '../core/structures/enums'
|
||||
import { resultPayload } from '../core/functions'
|
||||
import { filterTap, sharedEventStream } from '../core/operators'
|
||||
|
||||
@@ -27,7 +27,7 @@ export default async function(dir: string, deps : UnpackedDependencies) {
|
||||
const resultModule = await callInitPlugins(module, deps, true);
|
||||
// FREEZE! no more writing!!
|
||||
commands.set(resultModule.meta.id, Object.freeze(resultModule));
|
||||
sEmitter.emit('module.register', resultPayload(PayloadType.Success, resultModule));
|
||||
sEmitter.emit('module.register', resultPayload('success', resultModule));
|
||||
}
|
||||
sEmitter.emit('modulesLoaded');
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
import type { Err, Ok, Result } from 'ts-results-es';
|
||||
import type {
|
||||
CommandModuleDefs,
|
||||
Module,
|
||||
Processed,
|
||||
SDT,
|
||||
|
||||
@@ -11,7 +11,7 @@ export type AnyFunction = (...args: any[]) => unknown;
|
||||
export interface SernEventsMapping {
|
||||
'module.register': [Payload];
|
||||
'module.activate': [Payload];
|
||||
error: [{ type: PayloadType.Failure; module?: Module; reason: string | Error }];
|
||||
error: [{ type: 'failure'; module?: Module; reason: string | Error }];
|
||||
warning: [Payload];
|
||||
modulesLoaded: [never?];
|
||||
}
|
||||
|
||||
@@ -47,56 +47,45 @@ vi.mock('discord.js', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
test('id -> Text', () => {
|
||||
const bothCmdId = Id.create("ping", CommandType.Text)
|
||||
expect(bothCmdId).toBe("ping_T")
|
||||
expect(Id.create("ping", CommandType.Text)).toBe("ping_T")
|
||||
})
|
||||
|
||||
test('id -> Both', () => {
|
||||
const bothCmdId = Id.create("ping", CommandType.Both)
|
||||
expect(bothCmdId).toBe("ping_B")
|
||||
expect(Id.create("ping", CommandType.Both)).toBe("ping_B")
|
||||
})
|
||||
|
||||
test('id -> CtxMsg', () => {
|
||||
const bothCmdId = Id.create("ping", CommandType.CtxMsg)
|
||||
expect(bothCmdId).toBe("ping_A3")
|
||||
expect(Id.create("ping", CommandType.CtxMsg)).toBe("ping_A3")
|
||||
})
|
||||
test('id -> CtxUsr', () => {
|
||||
const bothCmdId = Id.create("ping", CommandType.CtxUser)
|
||||
expect(bothCmdId).toBe("ping_A2")
|
||||
expect(Id.create("ping", CommandType.CtxUser)).toBe("ping_A2")
|
||||
})
|
||||
test('id -> Modal', () => {
|
||||
const modal = Id.create("my-modal", CommandType.Modal)
|
||||
expect(modal).toBe("my-modal_M");
|
||||
expect(Id.create("my-modal", CommandType.Modal)).toBe("my-modal_M");
|
||||
})
|
||||
|
||||
test('id -> Button', () => {
|
||||
const modal = Id.create("my-button", CommandType.Button)
|
||||
expect(modal).toBe("my-button_C2");
|
||||
expect(Id.create("my-button", CommandType.Button)).toBe("my-button_C2");
|
||||
})
|
||||
|
||||
test('id -> Slash', () => {
|
||||
const modal = Id.create("myslash", CommandType.Slash)
|
||||
expect(modal).toBe("myslash_A1");
|
||||
expect(Id.create("myslash", CommandType.Slash)).toBe("myslash_A1");
|
||||
})
|
||||
|
||||
test('id -> StringSelect', () => {
|
||||
const modal = Id.create("mystringselect", CommandType.StringSelect)
|
||||
expect(modal).toBe("mystringselect_C3");
|
||||
expect(Id.create("mystringselect", CommandType.StringSelect)).toBe("mystringselect_C3");
|
||||
})
|
||||
|
||||
test('id -> UserSelect', () => {
|
||||
const modal = Id.create("myuserselect", CommandType.UserSelect)
|
||||
expect(modal).toBe("myuserselect_C5");
|
||||
expect(Id.create("myuserselect", CommandType.UserSelect)).toBe("myuserselect_C5");
|
||||
})
|
||||
|
||||
test('id -> RoleSelect', () => {
|
||||
const modal = Id.create("myroleselect", CommandType.RoleSelect)
|
||||
expect(modal).toBe("myroleselect_C6");
|
||||
expect(Id.create("myroleselect", CommandType.RoleSelect)).toBe("myroleselect_C6");
|
||||
})
|
||||
|
||||
test('id -> MentionSelect', () => {
|
||||
const modal = Id.create("mymentionselect", CommandType.MentionableSelect)
|
||||
expect(modal).toBe("mymentionselect_C7");
|
||||
expect(Id.create("mymentionselect", CommandType.MentionableSelect)).toBe("mymentionselect_C7");
|
||||
})
|
||||
|
||||
test('id -> ChannelSelect', () => {
|
||||
@@ -129,6 +118,12 @@ test('id reconstruct button with empty params', () => {
|
||||
expect(idload[0].id).toBe("btn_C2")
|
||||
expect(idload[0].params).toBe("")
|
||||
})
|
||||
test('id reconstruct with multiple slashes', () => {
|
||||
const idload = Id.reconstruct(new ButtonInteraction("btn//"))
|
||||
expect(idload[0].id).toBe("btn_C2")
|
||||
expect(idload[0].params).toBe("/")
|
||||
})
|
||||
|
||||
|
||||
test('id reconstruct button', () => {
|
||||
const idload = Id.reconstruct(new ButtonInteraction("btn"))
|
||||
|
||||
@@ -3,6 +3,7 @@ import path from 'node:path'
|
||||
import * as Files from '../../src/core/module-loading'
|
||||
import { Module } from '../../src/types/core-modules'
|
||||
import { AssertionError } from 'node:assert'
|
||||
//TODO: mock fs?
|
||||
describe('module-loading', () => {
|
||||
it('should get the filename of the commandmodule (linux, esm)', () => {
|
||||
const fname = "///home/pooba/Projects/sern/halibu/dist/commands/ping.js"
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
//@ts-nocheck
|
||||
import { beforeEach, describe, expect, vi, it } from 'vitest';
|
||||
import { beforeEach, describe, expect, vi, it, test } from 'vitest';
|
||||
import { callInitPlugins, eventDispatcher } from '../../src/handlers/event-utils';
|
||||
|
||||
import { Client } from 'discord.js'
|
||||
import { Client, ChatInputCommandInteraction } from 'discord.js'
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { Module } from '../../src/types/core-modules';
|
||||
import { Processed } from '../../src/types/core-modules';
|
||||
import { EventEmitter } from 'events';
|
||||
import { EventType } from '../../dist/core/structures/enums';
|
||||
import { CommandInitPlugin, controller } from '../../src';
|
||||
import { CommandControlPlugin, CommandInitPlugin, CommandType, controller } from '../../src';
|
||||
|
||||
vi.mock('discord.js', () => {
|
||||
const Client = vi.fn()
|
||||
Client.prototype.login= vi.fn()
|
||||
const Collection = Map;
|
||||
vi.mock('discord.js', async (importOriginal) => {
|
||||
const mod = await importOriginal()
|
||||
const ModalSubmitInteraction = class {
|
||||
customId;
|
||||
type = 5;
|
||||
@@ -44,41 +42,19 @@ vi.mock('discord.js', () => {
|
||||
};
|
||||
|
||||
return {
|
||||
Client,
|
||||
Collection,
|
||||
ComponentType: {
|
||||
Button: 2,
|
||||
},
|
||||
InteractionType: {
|
||||
Ping: 1,
|
||||
ApplicationCommand: 2,
|
||||
MessageComponent: 3,
|
||||
ApplicationCommandAutocomplete: 4,
|
||||
ModalSubmit: 5,
|
||||
},
|
||||
ApplicationCommandOptionType: {
|
||||
Subcommand: 1,
|
||||
SubcommandGroup: 2,
|
||||
String: 3,
|
||||
Integer: 4,
|
||||
Boolean: 5,
|
||||
User: 6,
|
||||
Channel: 7,
|
||||
Role: 8,
|
||||
Mentionable: 9,
|
||||
Number: 10,
|
||||
Attachment: 11,
|
||||
},
|
||||
ApplicationCommandType: {
|
||||
ChatInput: 1,
|
||||
User: 2,
|
||||
Message: 3,
|
||||
},
|
||||
Client : vi.fn(),
|
||||
Collection: mod.Collection,
|
||||
ComponentType: mod.ComponentType,
|
||||
InteractionType: mod.InteractionType,
|
||||
ApplicationCommandOptionType: mod.ApplicationCommandOptionType,
|
||||
ApplicationCommandType: mod.ApplicationCommandType,
|
||||
ModalSubmitInteraction,
|
||||
ButtonInteraction,
|
||||
AutocompleteInteraction,
|
||||
ChatInputCommandInteraction: vi.fn()
|
||||
};
|
||||
})
|
||||
});
|
||||
|
||||
function createRandomPlugin (s: 'go', mut?: Partial<Module>) {
|
||||
return CommandInitPlugin(({ module, updateModule }) => {
|
||||
if(mut) {
|
||||
@@ -123,14 +99,43 @@ describe('eventDispatcher standard', () => {
|
||||
it("Shouldn't throw", () => {
|
||||
expect(() => eventDispatcher(mockDeps(), m, ee)).not.toThrowError();
|
||||
});
|
||||
it('mutate with init plugins', async () => {
|
||||
const deps = mockDeps()
|
||||
const plugins = createRandomPlugin('go', { name: "abc" })
|
||||
const mod = createRandomModule([plugins])
|
||||
const s = await callInitPlugins(mod, deps, false)
|
||||
expect(s.name).not.equal(mod.name)
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
test ('mutate with init plugins', async () => {
|
||||
const deps = mockDeps()
|
||||
const plugins = createRandomPlugin('go', { name: "abc" })
|
||||
const mod = createRandomModule([plugins])
|
||||
const s = await callInitPlugins(mod, deps, false)
|
||||
expect(s.name).not.equal(mod.name)
|
||||
})
|
||||
|
||||
|
||||
test('call control plugin ', async () => {
|
||||
const plugin = CommandControlPlugin<CommandType.Slash>((ctx,sdt) => {
|
||||
return controller.next();
|
||||
});
|
||||
const res = await plugin.execute(new ChatInputCommandInteraction(), {})
|
||||
expect(res.isOk()).toBe(true)
|
||||
})
|
||||
|
||||
test('form sdt', async () => {
|
||||
|
||||
const expectedObject = {
|
||||
"plugin/abc": faker.person.jobArea(),
|
||||
"plugin2/abc": faker.git.branch(),
|
||||
"plugin3/cheese": faker.person.jobArea()
|
||||
}
|
||||
|
||||
// const plugin = CommandControlPlugin<CommandType.Slash>((ctx,sdt) => {
|
||||
// return controller.next({ "plugin/abc": expectedObject['plugin/abc'] });
|
||||
// });
|
||||
// const plugin2 = CommandControlPlugin<CommandType.Slash>((ctx,sdt) => {
|
||||
// return controller.next({ "plugin2/abc": expectedObject['plugin2/abc'] });
|
||||
// });
|
||||
// const plugin3 = CommandControlPlugin<CommandType.Slash>((ctx,sdt) => {
|
||||
// return controller.next({ "plugin3/cheese": expectedObject['plugin3/cheese'] });
|
||||
// });
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user