testing n shi

This commit is contained in:
Jacob Nguyen
2024-05-23 01:02:02 -05:00
parent 1de21b8b37
commit 86dd0cd842
14 changed files with 86 additions and 98 deletions

View File

@@ -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

View File

@@ -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 };
}

View File

@@ -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];
}
}

View File

@@ -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'

View File

@@ -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',
}

View File

@@ -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()");
}

View File

@@ -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)

View File

@@ -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'

View File

@@ -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');
}

View File

@@ -13,7 +13,6 @@
import type { Err, Ok, Result } from 'ts-results-es';
import type {
CommandModuleDefs,
Module,
Processed,
SDT,

View File

@@ -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?];
}

View File

@@ -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"))

View File

@@ -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"

View File

@@ -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'] });
// });
})