@takaro/module-test 0.0.0-dev.2f94734
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 +260 -0
- package/dist/.source-hash +1 -0
- package/dist/config.d.ts +49 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/currencyLedger.d.ts +13 -0
- package/dist/currencyLedger.d.ts.map +1 -0
- package/dist/currencyLedger.js +39 -0
- package/dist/currencyLedger.js.map +1 -0
- package/dist/fakeClient.d.ts +48 -0
- package/dist/fakeClient.d.ts.map +1 -0
- package/dist/fakeClient.js +335 -0
- package/dist/fakeClient.js.map +1 -0
- package/dist/fixtureQuery.d.ts +33 -0
- package/dist/fixtureQuery.d.ts.map +1 -0
- package/dist/fixtureQuery.js +120 -0
- package/dist/fixtureQuery.js.map +1 -0
- package/dist/fixtures.d.ts +49 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +152 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/installation.d.ts +23 -0
- package/dist/installation.d.ts.map +1 -0
- package/dist/installation.js +170 -0
- package/dist/installation.js.map +1 -0
- package/dist/intrinsics.d.ts +9 -0
- package/dist/intrinsics.d.ts.map +1 -0
- package/dist/intrinsics.js +33 -0
- package/dist/intrinsics.js.map +1 -0
- package/dist/loadModule.d.ts +11 -0
- package/dist/loadModule.d.ts.map +1 -0
- package/dist/loadModule.js +173 -0
- package/dist/loadModule.js.map +1 -0
- package/dist/main.d.ts +22 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -0
- package/dist/moduleExport.d.ts +74 -0
- package/dist/moduleExport.d.ts.map +1 -0
- package/dist/moduleExport.js +2 -0
- package/dist/moduleExport.js.map +1 -0
- package/dist/moduleTest.d.ts +100 -0
- package/dist/moduleTest.d.ts.map +1 -0
- package/dist/moduleTest.js +195 -0
- package/dist/moduleTest.js.map +1 -0
- package/dist/query.d.ts +8 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +51 -0
- package/dist/query.js.map +1 -0
- package/dist/stubbedClient.d.ts +20 -0
- package/dist/stubbedClient.d.ts.map +1 -0
- package/dist/stubbedClient.js +44 -0
- package/dist/stubbedClient.js.map +1 -0
- package/dist/systemConfig.d.ts +19 -0
- package/dist/systemConfig.d.ts.map +1 -0
- package/dist/systemConfig.js +199 -0
- package/dist/systemConfig.js.map +1 -0
- package/dist/triggers.d.ts +53 -0
- package/dist/triggers.d.ts.map +1 -0
- package/dist/triggers.js +116 -0
- package/dist/triggers.js.map +1 -0
- package/dist/variableStore.d.ts +51 -0
- package/dist/variableStore.d.ts.map +1 -0
- package/dist/variableStore.js +201 -0
- package/dist/variableStore.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAErH,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEhG,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjG,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnF,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEjF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvE,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvH,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhG,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createModuleTest, ModuleTest } from './moduleTest.js';
|
|
2
|
+
export { createFakeClient, ok, paginated, single, MissingFixtureError, UnsupportedQueryError } from './fakeClient.js';
|
|
3
|
+
export { UnstubbedMethodError } from './stubbedClient.js';
|
|
4
|
+
export { VariableStore, VariableConflictError, VariableNotFoundError } from './variableStore.js';
|
|
5
|
+
export { CurrencyLedger, InsufficientFundsError } from './currencyLedger.js';
|
|
6
|
+
export { createPlayerFixture, createUserFixture } from './fixtures.js';
|
|
7
|
+
export { installModule, latestVersionOf, systemConfigOf } from './installation.js';
|
|
8
|
+
export { loadModuleDirectory, ModuleLoadError } from './loadModule.js';
|
|
9
|
+
export { InvalidSystemConfigError, InvalidUserConfigError, resolveSystemConfig, resolveUserConfig } from './config.js';
|
|
10
|
+
export { applyArgumentDefaults, buildCommandData, buildCronJobData, buildHookData, buildShopActionData, classifyTriggerData, matchingTriggerKinds, toJobPayload, } from './triggers.js';
|
|
11
|
+
export { buildContextOverride } from './intrinsics.js';
|
|
12
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG/D,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAI1D,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGjG,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAUvE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAcvE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGvH,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export interface ModuleExportCommandArgument {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
helpText?: string;
|
|
5
|
+
/** `null` and absent both mean the argument is required. */
|
|
6
|
+
defaultValue?: string | null;
|
|
7
|
+
position?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ModuleExportCommand {
|
|
10
|
+
name: string;
|
|
11
|
+
trigger: string;
|
|
12
|
+
/** The command's JavaScript source. */
|
|
13
|
+
function: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
helpText?: string;
|
|
16
|
+
arguments?: ModuleExportCommandArgument[];
|
|
17
|
+
requiredPermissions?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ModuleExportHook {
|
|
20
|
+
name: string;
|
|
21
|
+
eventType: string;
|
|
22
|
+
function: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
regex?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ModuleExportCronJob {
|
|
27
|
+
name: string;
|
|
28
|
+
temporalValue: string;
|
|
29
|
+
function: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
}
|
|
32
|
+
/** A named function other components import as `./<name>.js`. */
|
|
33
|
+
export interface ModuleExportFunction {
|
|
34
|
+
name: string;
|
|
35
|
+
function: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ModuleExportShopAction {
|
|
39
|
+
name: string;
|
|
40
|
+
function: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface ModuleExportPermission {
|
|
44
|
+
permission: string;
|
|
45
|
+
friendlyName: string;
|
|
46
|
+
description: string;
|
|
47
|
+
canHaveCount?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface ModuleExportVersion {
|
|
50
|
+
tag: string;
|
|
51
|
+
description: string;
|
|
52
|
+
/** A JSON Schema, serialised. */
|
|
53
|
+
configSchema: string;
|
|
54
|
+
uiSchema?: string;
|
|
55
|
+
/** A serialised partial system config merged under the test's `systemConfig`. */
|
|
56
|
+
defaultSystemConfig?: string;
|
|
57
|
+
commands?: ModuleExportCommand[];
|
|
58
|
+
hooks?: ModuleExportHook[];
|
|
59
|
+
cronJobs?: ModuleExportCronJob[];
|
|
60
|
+
functions?: ModuleExportFunction[];
|
|
61
|
+
permissions?: ModuleExportPermission[];
|
|
62
|
+
shopActions?: ModuleExportShopAction[];
|
|
63
|
+
}
|
|
64
|
+
/** Takaro's module export format, the same shape as a registry's `<module>/<version>.json`. */
|
|
65
|
+
export interface ModuleExport {
|
|
66
|
+
name: string;
|
|
67
|
+
author?: string;
|
|
68
|
+
supportedGames?: string[];
|
|
69
|
+
takaroVersion?: string;
|
|
70
|
+
versions: ModuleExportVersion[];
|
|
71
|
+
}
|
|
72
|
+
/** A module directory (path or `file:` URL) in the registry source layout, or an export object. */
|
|
73
|
+
export type ModuleSource = string | URL | ModuleExport;
|
|
74
|
+
//# sourceMappingURL=moduleExport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moduleExport.d.ts","sourceRoot":"","sources":["../src/moduleExport.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,2BAA2B,EAAE,CAAC;IAC1C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACvC,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACxC;AAED,+FAA+F;AAC/F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,mGAAmG;AACnG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,GAAG,GAAG,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moduleExport.js","sourceRoot":"","sources":["../src/moduleExport.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { VMExecutionResult } from '@takaro/helpers';
|
|
2
|
+
import type { HookOutputDTOEventTypeEnum, ModuleInstallationOutputDTO } from '@takaro/apiclient';
|
|
3
|
+
import type { SystemConfigOverrides } from './config.js';
|
|
4
|
+
import type { FakeClient } from './fakeClient.js';
|
|
5
|
+
import type { PermissionFixture, PlayerFixture, PlayerFixtureOptions, UserFixtureOptions } from './fixtures.js';
|
|
6
|
+
import type { ModuleSource } from './moduleExport.js';
|
|
7
|
+
import { CurrencyLedger } from './currencyLedger.js';
|
|
8
|
+
import { VariableStore } from './variableStore.js';
|
|
9
|
+
import type { VariableSeed } from './variableStore.js';
|
|
10
|
+
import { type CommandArguments, type ShopActionTriggerOptions } from './triggers.js';
|
|
11
|
+
export interface ModuleInstallSpec {
|
|
12
|
+
module: ModuleSource;
|
|
13
|
+
userConfig?: Record<string, unknown>;
|
|
14
|
+
systemConfig?: SystemConfigOverrides;
|
|
15
|
+
}
|
|
16
|
+
export type PlayerSpec = Omit<PlayerFixtureOptions, 'gameServerId'>;
|
|
17
|
+
export interface IModuleTest {
|
|
18
|
+
name: string;
|
|
19
|
+
/** The module under test: a directory in the registry source layout, or a module export object. */
|
|
20
|
+
module: ModuleSource;
|
|
21
|
+
/** Install this version instead of the latest. */
|
|
22
|
+
versionTag?: string;
|
|
23
|
+
userConfig?: Record<string, unknown>;
|
|
24
|
+
systemConfig?: SystemConfigOverrides;
|
|
25
|
+
/** Further modules on the same game server, for module code that lists or calls its neighbours. */
|
|
26
|
+
alsoInstalled?: ModuleInstallSpec[];
|
|
27
|
+
/** Defaults to ROOT, matching `modulesTestSetup`. Read the note in `fixtures.ts` first. */
|
|
28
|
+
permissions?: PermissionFixture;
|
|
29
|
+
/** The rest of the acting player's fixture — ping, ip, position, name, platform ids. */
|
|
30
|
+
player?: PlayerSpec;
|
|
31
|
+
user?: UserFixtureOptions;
|
|
32
|
+
/** Further players on the same game server, reachable as `this.otherPlayers`. */
|
|
33
|
+
otherPlayers?: PlayerSpec[];
|
|
34
|
+
settings?: Record<string, string>;
|
|
35
|
+
variables?: VariableSeed[];
|
|
36
|
+
/** Starting balance for the acting player. */
|
|
37
|
+
currency?: number;
|
|
38
|
+
/** Freeze the VM's clock. */
|
|
39
|
+
now?: Date;
|
|
40
|
+
/** Script `Math.random()` inside the VM. */
|
|
41
|
+
random?: number | number[];
|
|
42
|
+
timeout?: number;
|
|
43
|
+
/** Skip the test with this reason. */
|
|
44
|
+
quarantine?: string;
|
|
45
|
+
setup?: (this: ModuleTest) => Promise<void> | void;
|
|
46
|
+
test: (this: ModuleTest) => Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export interface CommandRunOptions {
|
|
49
|
+
/** The raw chat line, for module code that reads it instead of parsed `arguments`. Defaults to `/<trigger>`. */
|
|
50
|
+
chatMessage?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface HookRunOptions {
|
|
53
|
+
eventData?: Record<string, unknown>;
|
|
54
|
+
eventType?: HookOutputDTOEventTypeEnum;
|
|
55
|
+
withPlayer?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export declare class ModuleTest {
|
|
58
|
+
readonly spec: IModuleTest;
|
|
59
|
+
readonly domainId: `${string}-${string}-${string}-${string}-${string}`;
|
|
60
|
+
readonly gameServerId: `${string}-${string}-${string}-${string}-${string}`;
|
|
61
|
+
client: FakeClient;
|
|
62
|
+
installation: ModuleInstallationOutputDTO;
|
|
63
|
+
/** The fixtures declared via `otherPlayers`, in order. */
|
|
64
|
+
otherPlayers: PlayerFixture[];
|
|
65
|
+
private primary;
|
|
66
|
+
private context;
|
|
67
|
+
private contextOverride;
|
|
68
|
+
constructor(spec: IModuleTest);
|
|
69
|
+
get variables(): VariableStore;
|
|
70
|
+
get currency(): CurrencyLedger;
|
|
71
|
+
private get moduleName();
|
|
72
|
+
get moduleId(): string;
|
|
73
|
+
get player(): import("@takaro/apiclient").PlayerOutputWithRolesDTO;
|
|
74
|
+
get pog(): import("@takaro/apiclient").PlayerOnGameserverOutputWithRolesDTO;
|
|
75
|
+
/** The linked Takaro user, when the spec declared one. */
|
|
76
|
+
get user(): import("@takaro/apiclient").UserOutputWithRolesDTO | undefined;
|
|
77
|
+
/** Messages sent privately to the acting player, in order — what `data.player.pm()` produces. */
|
|
78
|
+
pms(): string[];
|
|
79
|
+
/** Every `gameServerControllerSendMessage` call, private or broadcast. */
|
|
80
|
+
get messages(): import("./fakeClient.js").RecordedMessage[];
|
|
81
|
+
runCommand(name: string, args?: CommandArguments, options?: CommandRunOptions): Promise<VMExecutionResult>;
|
|
82
|
+
runHook(name: string, options?: HookRunOptions): Promise<VMExecutionResult>;
|
|
83
|
+
runCronJob(name: string): Promise<VMExecutionResult>;
|
|
84
|
+
runShopAction(name: string, options: ShopActionTriggerOptions): Promise<VMExecutionResult>;
|
|
85
|
+
userError(result: VMExecutionResult): string | undefined;
|
|
86
|
+
private execute;
|
|
87
|
+
private build;
|
|
88
|
+
/** The options to hand to a test runner's `it`: `timeout`, and `skip` when the spec is quarantined. */
|
|
89
|
+
testOptions(): {
|
|
90
|
+
timeout?: number;
|
|
91
|
+
skip?: string;
|
|
92
|
+
};
|
|
93
|
+
/** Builds the installation, then runs `setup` and `test`. Call it from any runner's test body. */
|
|
94
|
+
runBody(): Promise<void>;
|
|
95
|
+
/** Registers the test with `node:test`. */
|
|
96
|
+
run(): void;
|
|
97
|
+
}
|
|
98
|
+
/** Declare one module-VM test; call `.run()` to register it with `node:test`. */
|
|
99
|
+
export declare function createModuleTest(spec: IModuleTest): ModuleTest;
|
|
100
|
+
//# sourceMappingURL=moduleTest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moduleTest.d.ts","sourceRoot":"","sources":["../src/moduleTest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import vm from 'node:vm';
|
|
3
|
+
import { it } from 'node:test';
|
|
4
|
+
import { executeVM } from '@takaro/helpers';
|
|
5
|
+
import { createFakeClient } from './fakeClient.js';
|
|
6
|
+
import { createPlayerFixture, createUserFixture } from './fixtures.js';
|
|
7
|
+
import { installModule } from './installation.js';
|
|
8
|
+
import { buildContextOverride } from './intrinsics.js';
|
|
9
|
+
import { CurrencyLedger } from './currencyLedger.js';
|
|
10
|
+
import { VariableStore } from './variableStore.js';
|
|
11
|
+
import { buildCommandData, buildCronJobData, buildHookData, buildShopActionData, toJobPayload, } from './triggers.js';
|
|
12
|
+
// Runs one module's function code in the real Node VM executor against an in-memory
|
|
13
|
+
// client (no Postgres/Redis/BullMQ/gameserver/HTTP). Everything outside `executeVM` — including
|
|
14
|
+
// user-error delivery to chat — is NOT covered here; use {@link ModuleTest.userError} instead.
|
|
15
|
+
export class ModuleTest {
|
|
16
|
+
constructor(spec) {
|
|
17
|
+
this.spec = spec;
|
|
18
|
+
this.domainId = randomUUID();
|
|
19
|
+
this.gameServerId = randomUUID();
|
|
20
|
+
/** The fixtures declared via `otherPlayers`, in order. */
|
|
21
|
+
this.otherPlayers = [];
|
|
22
|
+
this.contextOverride = buildContextOverride({ now: spec.now, random: spec.random });
|
|
23
|
+
}
|
|
24
|
+
get variables() {
|
|
25
|
+
return this.client.variables;
|
|
26
|
+
}
|
|
27
|
+
get currency() {
|
|
28
|
+
return this.client.currency;
|
|
29
|
+
}
|
|
30
|
+
get moduleName() {
|
|
31
|
+
return this.installation.module.name;
|
|
32
|
+
}
|
|
33
|
+
get moduleId() {
|
|
34
|
+
return this.installation.moduleId;
|
|
35
|
+
}
|
|
36
|
+
get player() {
|
|
37
|
+
return this.context.player;
|
|
38
|
+
}
|
|
39
|
+
get pog() {
|
|
40
|
+
return this.context.pog;
|
|
41
|
+
}
|
|
42
|
+
/** The linked Takaro user, when the spec declared one. */
|
|
43
|
+
get user() {
|
|
44
|
+
return this.context.user;
|
|
45
|
+
}
|
|
46
|
+
/** Messages sent privately to the acting player, in order — what `data.player.pm()` produces. */
|
|
47
|
+
pms() {
|
|
48
|
+
return this.client.pmsTo(this.context.pog.gameId);
|
|
49
|
+
}
|
|
50
|
+
/** Every `gameServerControllerSendMessage` call, private or broadcast. */
|
|
51
|
+
get messages() {
|
|
52
|
+
return this.client.messages;
|
|
53
|
+
}
|
|
54
|
+
async runCommand(name, args = {}, options = {}) {
|
|
55
|
+
const command = this.primary.installation.version.commands.find((candidate) => candidate.name === name);
|
|
56
|
+
if (!command) {
|
|
57
|
+
const available = this.primary.installation.version.commands.map((c) => c.name).join(', ');
|
|
58
|
+
throw new Error(`Module '${this.moduleName}' has no command '${name}'. Available: ${available}`);
|
|
59
|
+
}
|
|
60
|
+
return this.execute(command.function.code, buildCommandData(this.context, { command, arguments: args, chatMessage: options.chatMessage }));
|
|
61
|
+
}
|
|
62
|
+
async runHook(name, options = {}) {
|
|
63
|
+
const hook = this.primary.installation.version.hooks.find((candidate) => candidate.name === name);
|
|
64
|
+
if (!hook) {
|
|
65
|
+
const available = this.primary.installation.version.hooks.map((h) => h.name).join(', ');
|
|
66
|
+
throw new Error(`Module '${this.moduleName}' has no hook '${name}'. Available: ${available}`);
|
|
67
|
+
}
|
|
68
|
+
return this.execute(hook.function.code, buildHookData(this.context, {
|
|
69
|
+
eventType: options.eventType ?? hook.eventType,
|
|
70
|
+
eventData: options.eventData ?? {},
|
|
71
|
+
withPlayer: options.withPlayer,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
async runCronJob(name) {
|
|
75
|
+
const cronJob = this.primary.installation.version.cronJobs.find((candidate) => candidate.name === name);
|
|
76
|
+
if (!cronJob) {
|
|
77
|
+
const available = this.primary.installation.version.cronJobs.map((c) => c.name).join(', ');
|
|
78
|
+
throw new Error(`Module '${this.moduleName}' has no cron job '${name}'. Available: ${available}`);
|
|
79
|
+
}
|
|
80
|
+
return this.execute(cronJob.function.code, buildCronJobData(this.context));
|
|
81
|
+
}
|
|
82
|
+
async runShopAction(name, options) {
|
|
83
|
+
const action = this.primary.installation.version.shopActions.find((candidate) => candidate.name === name);
|
|
84
|
+
if (!action) {
|
|
85
|
+
const available = this.primary.installation.version.shopActions.map((a) => a.name).join(', ');
|
|
86
|
+
throw new Error(`Module '${this.moduleName}' has no shop action '${name}'. Available: ${available}`);
|
|
87
|
+
}
|
|
88
|
+
return this.execute(action.function.code, buildShopActionData(this.context, options));
|
|
89
|
+
}
|
|
90
|
+
// The `TakaroUserError` message, or `undefined` if the run failed some other way. Mirrors
|
|
91
|
+
// `executeFunction.ts`'s detection (last log entry's `details`), so this matches what the player
|
|
92
|
+
// would have received.
|
|
93
|
+
userError(result) {
|
|
94
|
+
const last = result.logs.at(-1);
|
|
95
|
+
if (!last) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
const details = typeof last.details === 'string' ? last.details : JSON.stringify(last.details ?? '');
|
|
99
|
+
return details.includes('TakaroUserError') ? last.msg : undefined;
|
|
100
|
+
}
|
|
101
|
+
async execute(code, data) {
|
|
102
|
+
return executeVM({
|
|
103
|
+
fn: code,
|
|
104
|
+
data: toJobPayload(data),
|
|
105
|
+
userModules: this.primary.userModules,
|
|
106
|
+
clientOverride: this.client.asClient,
|
|
107
|
+
contextOverride: this.contextOverride,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
build() {
|
|
111
|
+
this.primary = installModule(this.spec.module, {
|
|
112
|
+
versionTag: this.spec.versionTag,
|
|
113
|
+
gameServerId: this.gameServerId,
|
|
114
|
+
userConfig: this.spec.userConfig,
|
|
115
|
+
systemConfig: this.spec.systemConfig,
|
|
116
|
+
});
|
|
117
|
+
this.installation = this.primary.installation;
|
|
118
|
+
const others = (this.spec.alsoInstalled ?? []).map((other) => installModule(other.module, {
|
|
119
|
+
gameServerId: this.gameServerId,
|
|
120
|
+
userConfig: other.userConfig,
|
|
121
|
+
systemConfig: other.systemConfig,
|
|
122
|
+
}));
|
|
123
|
+
const installed = [this.primary, ...others].map(({ installation }) => installation);
|
|
124
|
+
const resolveModule = (moduleName) => {
|
|
125
|
+
const installation = moduleName
|
|
126
|
+
? installed.find((candidate) => candidate.module.name === moduleName)
|
|
127
|
+
: this.primary.installation;
|
|
128
|
+
if (!installation) {
|
|
129
|
+
throw new Error(`Fixture grant names module '${moduleName}', which this test does not install`);
|
|
130
|
+
}
|
|
131
|
+
return { id: installation.moduleId, name: installation.module.name };
|
|
132
|
+
};
|
|
133
|
+
const acting = createPlayerFixture({
|
|
134
|
+
gameServerId: this.gameServerId,
|
|
135
|
+
permissions: this.spec.permissions,
|
|
136
|
+
currency: this.spec.currency,
|
|
137
|
+
...this.spec.player,
|
|
138
|
+
}, resolveModule);
|
|
139
|
+
this.otherPlayers = (this.spec.otherPlayers ?? []).map((spec) => createPlayerFixture({ gameServerId: this.gameServerId, ...spec }, resolveModule));
|
|
140
|
+
const fixtures = [acting, ...this.otherPlayers];
|
|
141
|
+
const { player, pog } = acting;
|
|
142
|
+
const balances = {};
|
|
143
|
+
for (const fixture of fixtures) {
|
|
144
|
+
if (fixture.pog.currency) {
|
|
145
|
+
balances[fixture.player.id] = fixture.pog.currency;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.client = createFakeClient({
|
|
149
|
+
gameServerId: this.gameServerId,
|
|
150
|
+
installations: installed,
|
|
151
|
+
players: fixtures.map((fixture) => fixture.player),
|
|
152
|
+
pogs: fixtures.map((fixture) => fixture.pog),
|
|
153
|
+
variables: new VariableStore(this.spec.variables),
|
|
154
|
+
currency: new CurrencyLedger(balances),
|
|
155
|
+
settings: this.spec.settings,
|
|
156
|
+
now: this.spec.now ? () => this.spec.now : undefined,
|
|
157
|
+
});
|
|
158
|
+
this.context = {
|
|
159
|
+
domainId: this.domainId,
|
|
160
|
+
gameServerId: this.gameServerId,
|
|
161
|
+
installation: this.primary.installation,
|
|
162
|
+
player,
|
|
163
|
+
pog,
|
|
164
|
+
...(this.spec.user ? { user: createUserFixture(player, this.spec.user) } : {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** The options to hand to a test runner's `it`: `timeout`, and `skip` when the spec is quarantined. */
|
|
168
|
+
testOptions() {
|
|
169
|
+
return {
|
|
170
|
+
...(this.spec.timeout === undefined ? {} : { timeout: this.spec.timeout }),
|
|
171
|
+
...(this.spec.quarantine ? { skip: this.spec.quarantine } : {}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** Builds the installation, then runs `setup` and `test`. Call it from any runner's test body. */
|
|
175
|
+
async runBody() {
|
|
176
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- absent at runtime unless Node runs with --experimental-vm-modules
|
|
177
|
+
if (vm.SourceTextModule === undefined) {
|
|
178
|
+
throw new Error('The module VM needs Node to run with --experimental-vm-modules.');
|
|
179
|
+
}
|
|
180
|
+
this.build();
|
|
181
|
+
if (this.spec.setup) {
|
|
182
|
+
await this.spec.setup.bind(this)();
|
|
183
|
+
}
|
|
184
|
+
await this.spec.test.bind(this)();
|
|
185
|
+
}
|
|
186
|
+
/** Registers the test with `node:test`. */
|
|
187
|
+
run() {
|
|
188
|
+
it(this.spec.name, this.testOptions(), () => this.runBody());
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/** Declare one module-VM test; call `.run()` to register it with `node:test`. */
|
|
192
|
+
export function createModuleTest(spec) {
|
|
193
|
+
return new ModuleTest(spec);
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=moduleTest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moduleTest.js","sourceRoot":"","sources":["../src/moduleTest.ts"],"names":[],"mappings":"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"}
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function toDisplayString(value: unknown): string;
|
|
2
|
+
export declare class UnsupportedQueryError extends Error {
|
|
3
|
+
constructor(method: string, problem: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function unimplementedKey(kind: string, key: string, supported: readonly string[]): string;
|
|
6
|
+
export declare function compareForSort(left: unknown, right: unknown, direction: number): number;
|
|
7
|
+
export declare function nonArrayFilter(key: string, value: unknown): string;
|
|
8
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAStD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAO1C;CACF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAKhG;AAKD,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAevF;AAID,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAKlE"}
|
package/dist/query.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Shared by both in-memory stores (fake client's fixtures and the variable store), so the two
|
|
2
|
+
// answer the same query language identically rather than ignoring different parts of it.
|
|
3
|
+
// `String(value)` on an object renders "[object Object]"; anything non-primitive is JSON instead.
|
|
4
|
+
export function toDisplayString(value) {
|
|
5
|
+
if (typeof value === 'string') {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
9
|
+
return String(value);
|
|
10
|
+
}
|
|
11
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- JSON.stringify returns undefined for undefined/function/symbol input despite the `string` lib type
|
|
12
|
+
return JSON.stringify(value) ?? 'undefined';
|
|
13
|
+
}
|
|
14
|
+
export class UnsupportedQueryError extends Error {
|
|
15
|
+
constructor(method, problem) {
|
|
16
|
+
super(`${method}() ${problem} The fake refuses a query it cannot answer faithfully rather than ` +
|
|
17
|
+
'returning a result that quietly ignored part of it. Stub the method yourself, or open an issue ' +
|
|
18
|
+
'on gettakaro/takaro to add support.');
|
|
19
|
+
this.name = 'UnsupportedQueryError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function unimplementedKey(kind, key, supported) {
|
|
23
|
+
return (`was given a ${kind} on '${key}', which the module test fake does not implement. ` +
|
|
24
|
+
`Supported ${kind} keys: ${supported.length ? supported.join(', ') : 'none'}.`);
|
|
25
|
+
}
|
|
26
|
+
// Postgres orders NULLs last ascending, first descending — nulls sort as the largest value.
|
|
27
|
+
// Coercing null to `''` would instead sort it smallest, the opposite order.
|
|
28
|
+
// oxlint-disable-next-line sonarjs/cognitive-complexity -- GH #4103
|
|
29
|
+
export function compareForSort(left, right, direction) {
|
|
30
|
+
const leftNull = left === null || left === undefined;
|
|
31
|
+
const rightNull = right === null || right === undefined;
|
|
32
|
+
if (leftNull || rightNull) {
|
|
33
|
+
if (leftNull && rightNull) {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
return (leftNull ? 1 : -1) * direction;
|
|
37
|
+
}
|
|
38
|
+
if (typeof left === 'number' && typeof right === 'number') {
|
|
39
|
+
return (left === right ? 0 : left < right ? -1 : 1) * direction;
|
|
40
|
+
}
|
|
41
|
+
const a = toDisplayString(left);
|
|
42
|
+
const b = toDisplayString(right);
|
|
43
|
+
return (a === b ? 0 : a < b ? -1 : 1) * direction;
|
|
44
|
+
}
|
|
45
|
+
// `QueryBuilder` honours a bare boolean as an equality test and nothing else; every other scalar
|
|
46
|
+
// falls through its `Array.isArray` branch and filters nothing.
|
|
47
|
+
export function nonArrayFilter(key, value) {
|
|
48
|
+
return (`was given filter '${key}' as a bare ${typeof value} rather than an array. ` +
|
|
49
|
+
'Production QueryBuilder silently ignores non-array, non-boolean filter values.');
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,yFAAyF;AAEzF,kGAAkG;AAClG,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACzF,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,qKAAqK;IACrK,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC;AAC9C,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,MAAc,EAAE,OAAe;QACzC,KAAK,CACH,GAAG,MAAM,MAAM,OAAO,oEAAoE;YACxF,iGAAiG;YACjG,qCAAqC,CACxC,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAW,EAAE,SAA4B;IACtF,OAAO,CACL,eAAe,IAAI,QAAQ,GAAG,oDAAoD;QAClF,aAAa,IAAI,UAAU,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAC/E,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,4EAA4E;AAC5E,oEAAoE;AACpE,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,KAAc,EAAE,SAAiB;IAC7E,MAAM,QAAQ,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,CAAC;IACrD,MAAM,SAAS,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;IACxD,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC1B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACzC,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC1D,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAClE,CAAC;IACD,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AACpD,CAAC;AAED,iGAAiG;AACjG,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,KAAc;IACxD,OAAO,CACL,qBAAqB,GAAG,eAAe,OAAO,KAAK,yBAAyB;QAC5E,gFAAgF,CACjF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type sinon from 'sinon';
|
|
2
|
+
import type { Client } from '@takaro/apiclient';
|
|
3
|
+
/** The controllers module code actually reaches for; using an untyped fourteenth fails via `UnstubbedMethodError`, not `.data.data`. */
|
|
4
|
+
export type ControllerKey = 'command' | 'discord' | 'event' | 'gameserver' | 'item' | 'itemSet' | 'module' | 'player' | 'playerOnGameserver' | 'settings' | 'shopListing' | 'shopOrder' | 'variable';
|
|
5
|
+
type MethodNames<K extends ControllerKey> = {
|
|
6
|
+
[M in keyof Client[K]]: Client[K][M] extends (...args: never[]) => unknown ? M : never;
|
|
7
|
+
}[keyof Client[K]];
|
|
8
|
+
type MethodStub<K extends ControllerKey, M extends keyof Client[K]> = Client[K][M] extends (...args: infer A) => infer R ? sinon.SinonStub<A, R> : never;
|
|
9
|
+
export type ControllerStubs<K extends ControllerKey> = {
|
|
10
|
+
[M in MethodNames<K>]?: MethodStub<K, M>;
|
|
11
|
+
};
|
|
12
|
+
export type ClientStubs = {
|
|
13
|
+
[K in ControllerKey]: ControllerStubs<K>;
|
|
14
|
+
};
|
|
15
|
+
export declare class UnstubbedMethodError extends Error {
|
|
16
|
+
constructor(method: string);
|
|
17
|
+
}
|
|
18
|
+
export declare function buildClientProxy(stubs: ClientStubs): Client;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=stubbedClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stubbedClient.d.ts","sourceRoot":"","sources":["../src/stubbedClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,wIAAwI;AACxI,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,SAAS,GACT,OAAO,GACP,YAAY,GACZ,MAAM,GACN,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,oBAAoB,GACpB,UAAU,GACV,aAAa,GACb,WAAW,GACX,UAAU,CAAC;AAEf,KAAK,WAAW,CAAC,CAAC,SAAS,aAAa,IAAI;KACzC,CAAC,IAAI,MAAM,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GAAG,CAAC,GAAG,KAAK;CACvF,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnB,KAAK,UAAU,CAAC,CAAC,SAAS,aAAa,EAAE,CAAC,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GACpH,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GACrB,KAAK,CAAC;AAIV,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,aAAa,IAAI;KAAG,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;CAAE,CAAC;AAEpG,MAAM,MAAM,WAAW,GAAG;KAAG,CAAC,IAAI,aAAa,GAAG,eAAe,CAAC,CAAC,CAAC;CAAE,CAAC;AAEvE,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAM,EAAE,MAAM,EAMzB;CACF;AAID,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAqC3D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export class UnstubbedMethodError extends Error {
|
|
2
|
+
constructor(method) {
|
|
3
|
+
super(`${method}() is not covered by the module test fake. Module code called it, so either the ` +
|
|
4
|
+
'fake needs it (open an issue on gettakaro/takaro) or the test should stub it.');
|
|
5
|
+
this.name = 'UnstubbedMethodError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
// Two layers of proxy so an unknown controller AND an unknown method on a known one fail by
|
|
9
|
+
// name, instead of `undefined` surfacing later as an unrelated `TypeError` on `.data.data`.
|
|
10
|
+
export function buildClientProxy(stubs) {
|
|
11
|
+
const controllers = new Map(Object.entries(stubs).map(([name, methods]) => [
|
|
12
|
+
name,
|
|
13
|
+
new Proxy(methods, {
|
|
14
|
+
get(target, property) {
|
|
15
|
+
if (typeof property !== 'string' || property in target) {
|
|
16
|
+
return Reflect.get(target, property);
|
|
17
|
+
}
|
|
18
|
+
return () => {
|
|
19
|
+
throw new UnstubbedMethodError(`takaro.${name}.${property}`);
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
]));
|
|
24
|
+
// `getTakaro` sets the module header on every client it is handed, override or not — keeping
|
|
25
|
+
// that call unconditional is what makes the production path the one under test.
|
|
26
|
+
const base = { setHeader: () => { } };
|
|
27
|
+
return new Proxy(base, {
|
|
28
|
+
get(target, property) {
|
|
29
|
+
if (typeof property !== 'string') {
|
|
30
|
+
return Reflect.get(target, property);
|
|
31
|
+
}
|
|
32
|
+
if (controllers.has(property)) {
|
|
33
|
+
return controllers.get(property);
|
|
34
|
+
}
|
|
35
|
+
if (property in target) {
|
|
36
|
+
return Reflect.get(target, property);
|
|
37
|
+
}
|
|
38
|
+
return () => {
|
|
39
|
+
throw new UnstubbedMethodError(`takaro.${property}`);
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=stubbedClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stubbedClient.js","sourceRoot":"","sources":["../src/stubbedClient.ts"],"names":[],"mappings":"AAkCA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAc;QACxB,KAAK,CACH,GAAG,MAAM,kFAAkF;YACzF,+EAA+E,CAClF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,4FAA4F;AAC5F,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;QAC7C,IAAI;QACJ,IAAI,KAAK,CAAC,OAAkC,EAAE;YAC5C,GAAG,CAAC,MAAM,EAAE,QAAQ;gBAClB,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;oBACvD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBACvC,CAAC;gBACD,OAAO,GAAG,EAAE;oBACV,MAAM,IAAI,oBAAoB,CAAC,UAAU,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;gBAC/D,CAAC,CAAC;YACJ,CAAC;SACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,6FAA6F;IAC7F,gFAAgF;IAChF,MAAM,IAAI,GAA4B,EAAE,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IAE9D,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE;QACrB,GAAG,CAAC,MAAM,EAAE,QAAQ;YAClB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjC,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;YACD,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;YACD,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;gBACvB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,GAAG,EAAE;gBACV,MAAM,IAAI,oBAAoB,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;YACvD,CAAC,CAAC;QACJ,CAAC;KACF,CAAsB,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface SystemConfigVersion {
|
|
2
|
+
cronJobs?: ReadonlyArray<{
|
|
3
|
+
name: string;
|
|
4
|
+
temporalValue: string;
|
|
5
|
+
}>;
|
|
6
|
+
hooks?: ReadonlyArray<{
|
|
7
|
+
name: string;
|
|
8
|
+
eventType: string;
|
|
9
|
+
}>;
|
|
10
|
+
commands?: ReadonlyArray<{
|
|
11
|
+
name: string;
|
|
12
|
+
}>;
|
|
13
|
+
shopActions?: ReadonlyArray<{
|
|
14
|
+
name: string;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
export declare function getSystemConfigSchema(mod: SystemConfigVersion): string;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=systemConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systemConfig.d.ts","sourceRoot":"","sources":["../src/systemConfig.ts"],"names":[],"mappings":"AAKA,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,KAAK,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C;AAyBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAgMtE"}
|