@rhost/testkit 0.1.0
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/LICENSE +21 -0
- package/README.md +861 -0
- package/SECURITY.md +130 -0
- package/dist/assertions.d.ts +67 -0
- package/dist/assertions.d.ts.map +1 -0
- package/dist/assertions.js +142 -0
- package/dist/assertions.js.map +1 -0
- package/dist/client.d.ts +91 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +157 -0
- package/dist/client.js.map +1 -0
- package/dist/connection.d.ts +27 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +149 -0
- package/dist/connection.js.map +1 -0
- package/dist/container.d.ts +38 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +116 -0
- package/dist/container.js.map +1 -0
- package/dist/expect.d.ts +74 -0
- package/dist/expect.d.ts.map +1 -0
- package/dist/expect.js +164 -0
- package/dist/expect.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +11 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +67 -0
- package/dist/reporter.js.map +1 -0
- package/dist/runner.d.ts +90 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +257 -0
- package/dist/runner.js.map +1 -0
- package/dist/world.d.ts +62 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +130 -0
- package/dist/world.js.map +1 -0
- package/package.json +76 -0
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Reporter = void 0;
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// ANSI color helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
const USE_COLOR = process.stdout.isTTY === true;
|
|
8
|
+
function colorize(code, text) {
|
|
9
|
+
return USE_COLOR ? `\x1b[${code}m${text}\x1b[0m` : text;
|
|
10
|
+
}
|
|
11
|
+
const green = (s) => colorize('32', s);
|
|
12
|
+
const red = (s) => colorize('31', s);
|
|
13
|
+
const yellow = (s) => colorize('33', s);
|
|
14
|
+
const gray = (s) => colorize('90', s);
|
|
15
|
+
const bold = (s) => colorize('1', s);
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Reporter
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
class Reporter {
|
|
20
|
+
constructor(verbose) {
|
|
21
|
+
this.verbose = verbose;
|
|
22
|
+
}
|
|
23
|
+
suiteStart(name, depth) {
|
|
24
|
+
if (!this.verbose)
|
|
25
|
+
return;
|
|
26
|
+
const indent = ' '.repeat(depth);
|
|
27
|
+
process.stdout.write(`\n${indent}${bold(name)}\n`);
|
|
28
|
+
}
|
|
29
|
+
testPass(name, ms, depth) {
|
|
30
|
+
if (!this.verbose)
|
|
31
|
+
return;
|
|
32
|
+
const indent = ' '.repeat(depth + 1);
|
|
33
|
+
process.stdout.write(`${indent}${green('✓')} ${name} ${gray(`(${ms}ms)`)}\n`);
|
|
34
|
+
}
|
|
35
|
+
testFail(name, ms, depth, error) {
|
|
36
|
+
if (!this.verbose)
|
|
37
|
+
return;
|
|
38
|
+
const indent = ' '.repeat(depth + 1);
|
|
39
|
+
const errIndent = ' '.repeat(depth + 3);
|
|
40
|
+
process.stdout.write(`${indent}${red('✗')} ${name} ${gray(`(${ms}ms)`)}\n`);
|
|
41
|
+
const lines = error.message.split('\n');
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
process.stdout.write(`${errIndent}${line}\n`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
testSkip(name, depth) {
|
|
47
|
+
if (!this.verbose)
|
|
48
|
+
return;
|
|
49
|
+
const indent = ' '.repeat(depth + 1);
|
|
50
|
+
process.stdout.write(`${indent}${yellow('○')} ${gray(name)}\n`);
|
|
51
|
+
}
|
|
52
|
+
summary(result) {
|
|
53
|
+
if (!this.verbose)
|
|
54
|
+
return;
|
|
55
|
+
const parts = [];
|
|
56
|
+
if (result.passed > 0)
|
|
57
|
+
parts.push(green(`${result.passed} passed`));
|
|
58
|
+
if (result.failed > 0)
|
|
59
|
+
parts.push(red(`${result.failed} failed`));
|
|
60
|
+
if (result.skipped > 0)
|
|
61
|
+
parts.push(yellow(`${result.skipped} skipped`));
|
|
62
|
+
parts.push(`${result.total} total`);
|
|
63
|
+
process.stdout.write(`\nTests: ${parts.join(', ')} (${result.duration}ms)\n`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.Reporter = Reporter;
|
|
67
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { RhostClient, RhostClientOptions } from './client';
|
|
2
|
+
import { RhostAssert } from './assertions';
|
|
3
|
+
import { RhostExpect } from './expect';
|
|
4
|
+
import { RhostWorld } from './world';
|
|
5
|
+
export interface RunResult {
|
|
6
|
+
passed: number;
|
|
7
|
+
failed: number;
|
|
8
|
+
skipped: number;
|
|
9
|
+
total: number;
|
|
10
|
+
duration: number;
|
|
11
|
+
failures: Array<{
|
|
12
|
+
suite: string;
|
|
13
|
+
test: string;
|
|
14
|
+
error: Error;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
export interface TestContext {
|
|
18
|
+
expect(expression: string): RhostExpect;
|
|
19
|
+
client: RhostClient;
|
|
20
|
+
world: RhostWorld;
|
|
21
|
+
}
|
|
22
|
+
export type TestFn = (ctx: TestContext) => Promise<void> | void;
|
|
23
|
+
export type HookFn = (ctx: {
|
|
24
|
+
client: RhostClient;
|
|
25
|
+
world: RhostWorld;
|
|
26
|
+
}) => Promise<void> | void;
|
|
27
|
+
export type ItFn = (name: string, fn: TestFn, timeout?: number) => void;
|
|
28
|
+
export type DescribeFn = (name: string, fn: (ctx: SuiteContext) => void) => void;
|
|
29
|
+
export interface SuiteContext {
|
|
30
|
+
it: ItFn & {
|
|
31
|
+
skip: ItFn;
|
|
32
|
+
only: ItFn;
|
|
33
|
+
};
|
|
34
|
+
test: ItFn & {
|
|
35
|
+
skip: ItFn;
|
|
36
|
+
only: ItFn;
|
|
37
|
+
};
|
|
38
|
+
describe: DescribeFn & {
|
|
39
|
+
skip: DescribeFn;
|
|
40
|
+
only: DescribeFn;
|
|
41
|
+
};
|
|
42
|
+
beforeAll(fn: HookFn): void;
|
|
43
|
+
afterAll(fn: HookFn): void;
|
|
44
|
+
beforeEach(fn: HookFn): void;
|
|
45
|
+
afterEach(fn: HookFn): void;
|
|
46
|
+
}
|
|
47
|
+
export interface RunnerOptions extends RhostClientOptions {
|
|
48
|
+
/** Character name. Required. */
|
|
49
|
+
username: string;
|
|
50
|
+
/** Character password. Required. */
|
|
51
|
+
password: string;
|
|
52
|
+
/** Print results to stdout while running. Default: true */
|
|
53
|
+
verbose?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Jest-style test runner for RhostMUSH softcode.
|
|
57
|
+
*
|
|
58
|
+
* Supports nested describes, it.skip/it.only, describe.skip/describe.only,
|
|
59
|
+
* per-test timeouts, lifecycle hooks, and automatic world cleanup.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const runner = new RhostRunner();
|
|
63
|
+
*
|
|
64
|
+
* runner.describe('Math', ({ it }) => {
|
|
65
|
+
* it('add(2,3)', async ({ expect }) => {
|
|
66
|
+
* await expect('add(2,3)').toBe('5');
|
|
67
|
+
* });
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* const result = await runner.run({ username: 'Wizard', password: 'Nyctasia' });
|
|
71
|
+
* process.exit(result.failed > 0 ? 1 : 0);
|
|
72
|
+
*/
|
|
73
|
+
export declare class RhostRunner {
|
|
74
|
+
private topLevel;
|
|
75
|
+
describe(name: string, fn: (ctx: SuiteContext) => void): this;
|
|
76
|
+
run(options: RunnerOptions): Promise<RunResult>;
|
|
77
|
+
private _buildSuite;
|
|
78
|
+
private _runSuite;
|
|
79
|
+
private _runTest;
|
|
80
|
+
/**
|
|
81
|
+
* Apply `only` semantics: if ANY direct child has mode 'only', only run
|
|
82
|
+
* those. Otherwise run all non-skip children.
|
|
83
|
+
*/
|
|
84
|
+
private _resolveOnly;
|
|
85
|
+
private _countFailedFromBeforeAll;
|
|
86
|
+
private _countSkipped;
|
|
87
|
+
private _withTimeout;
|
|
88
|
+
}
|
|
89
|
+
export { RhostAssert };
|
|
90
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RhostAssert = exports.RhostRunner = void 0;
|
|
4
|
+
const client_1 = require("./client");
|
|
5
|
+
const assertions_1 = require("./assertions");
|
|
6
|
+
Object.defineProperty(exports, "RhostAssert", { enumerable: true, get: function () { return assertions_1.RhostAssert; } });
|
|
7
|
+
const expect_1 = require("./expect");
|
|
8
|
+
const world_1 = require("./world");
|
|
9
|
+
const reporter_1 = require("./reporter");
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// RhostRunner
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Jest-style test runner for RhostMUSH softcode.
|
|
15
|
+
*
|
|
16
|
+
* Supports nested describes, it.skip/it.only, describe.skip/describe.only,
|
|
17
|
+
* per-test timeouts, lifecycle hooks, and automatic world cleanup.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const runner = new RhostRunner();
|
|
21
|
+
*
|
|
22
|
+
* runner.describe('Math', ({ it }) => {
|
|
23
|
+
* it('add(2,3)', async ({ expect }) => {
|
|
24
|
+
* await expect('add(2,3)').toBe('5');
|
|
25
|
+
* });
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* const result = await runner.run({ username: 'Wizard', password: 'Nyctasia' });
|
|
29
|
+
* process.exit(result.failed > 0 ? 1 : 0);
|
|
30
|
+
*/
|
|
31
|
+
class RhostRunner {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.topLevel = [];
|
|
34
|
+
}
|
|
35
|
+
// -------------------------------------------------------------------------
|
|
36
|
+
// Collection-phase API
|
|
37
|
+
// -------------------------------------------------------------------------
|
|
38
|
+
describe(name, fn) {
|
|
39
|
+
this.topLevel.push(this._buildSuite(name, fn, 'normal'));
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
// -------------------------------------------------------------------------
|
|
43
|
+
// Execution phase
|
|
44
|
+
// -------------------------------------------------------------------------
|
|
45
|
+
async run(options) {
|
|
46
|
+
const verbose = options.verbose !== false;
|
|
47
|
+
const client = new client_1.RhostClient(options);
|
|
48
|
+
await client.connect();
|
|
49
|
+
await client.login(options.username, options.password);
|
|
50
|
+
const reporter = new reporter_1.Reporter(verbose);
|
|
51
|
+
const result = {
|
|
52
|
+
passed: 0, failed: 0, skipped: 0, total: 0, duration: 0, failures: [],
|
|
53
|
+
};
|
|
54
|
+
const start = Date.now();
|
|
55
|
+
// Wrap top-level nodes in a root suite for uniform execution
|
|
56
|
+
const root = {
|
|
57
|
+
kind: 'suite',
|
|
58
|
+
name: '',
|
|
59
|
+
mode: 'normal',
|
|
60
|
+
children: this.topLevel,
|
|
61
|
+
beforeAll: [], afterAll: [], beforeEach: [], afterEach: [],
|
|
62
|
+
};
|
|
63
|
+
await this._runSuite(root, client, reporter, result, [], 0);
|
|
64
|
+
result.duration = Date.now() - start;
|
|
65
|
+
reporter.summary(result);
|
|
66
|
+
await client.disconnect();
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
// -------------------------------------------------------------------------
|
|
70
|
+
// Internal: building the tree
|
|
71
|
+
// -------------------------------------------------------------------------
|
|
72
|
+
_buildSuite(name, fn, mode) {
|
|
73
|
+
const node = {
|
|
74
|
+
kind: 'suite', name, mode,
|
|
75
|
+
children: [], beforeAll: [], afterAll: [], beforeEach: [], afterEach: [],
|
|
76
|
+
};
|
|
77
|
+
const makeItFn = (itMode) => (testName, testFn, timeout) => {
|
|
78
|
+
node.children.push({ kind: 'test', name: testName, fn: testFn, mode: itMode, timeout });
|
|
79
|
+
};
|
|
80
|
+
const makeDescribeFn = (descMode) => (descName, descFn) => {
|
|
81
|
+
node.children.push(this._buildSuite(descName, descFn, descMode));
|
|
82
|
+
};
|
|
83
|
+
const itFn = makeItFn('normal');
|
|
84
|
+
itFn.skip = makeItFn('skip');
|
|
85
|
+
itFn.only = makeItFn('only');
|
|
86
|
+
const describeFn = makeDescribeFn('normal');
|
|
87
|
+
describeFn.skip = makeDescribeFn('skip');
|
|
88
|
+
describeFn.only = makeDescribeFn('only');
|
|
89
|
+
fn({
|
|
90
|
+
it: itFn,
|
|
91
|
+
test: itFn,
|
|
92
|
+
describe: describeFn,
|
|
93
|
+
beforeAll: (h) => node.beforeAll.push(h),
|
|
94
|
+
afterAll: (h) => node.afterAll.push(h),
|
|
95
|
+
beforeEach: (h) => node.beforeEach.push(h),
|
|
96
|
+
afterEach: (h) => node.afterEach.push(h),
|
|
97
|
+
});
|
|
98
|
+
return node;
|
|
99
|
+
}
|
|
100
|
+
// -------------------------------------------------------------------------
|
|
101
|
+
// Internal: executing the tree
|
|
102
|
+
// -------------------------------------------------------------------------
|
|
103
|
+
async _runSuite(suite, client, reporter, result, inheritedBeforeEach, depth) {
|
|
104
|
+
// Skip entire suite if marked skip
|
|
105
|
+
if (suite.mode === 'skip') {
|
|
106
|
+
this._countSkipped(suite, result, reporter, depth);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (suite.name)
|
|
110
|
+
reporter.suiteStart(suite.name, depth);
|
|
111
|
+
// Resolve which children are active given `only` semantics
|
|
112
|
+
const activeChildren = this._resolveOnly(suite.children);
|
|
113
|
+
// Build the cumulative beforeEach/afterEach stack (inherited + suite-level)
|
|
114
|
+
const combinedBeforeEach = [...inheritedBeforeEach, ...suite.beforeEach];
|
|
115
|
+
// Run suite-level beforeAll hooks — if one throws, count all suite tests as failures
|
|
116
|
+
const hookCtx = { client, world: new world_1.RhostWorld(client) };
|
|
117
|
+
for (const hook of suite.beforeAll) {
|
|
118
|
+
try {
|
|
119
|
+
await hook(hookCtx);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
123
|
+
this._countFailedFromBeforeAll(suite, result, reporter, depth, error);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const child of suite.children) {
|
|
128
|
+
if (child.kind === 'suite') {
|
|
129
|
+
const effectiveMode = activeChildren.includes(child) ? child.mode : 'skip';
|
|
130
|
+
const childWithMode = effectiveMode !== child.mode
|
|
131
|
+
? { ...child, mode: effectiveMode }
|
|
132
|
+
: child;
|
|
133
|
+
await this._runSuite(childWithMode, client, reporter, result, combinedBeforeEach, depth + (suite.name ? 1 : 0));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const skip = !activeChildren.includes(child) || child.mode === 'skip';
|
|
137
|
+
await this._runTest(child, skip, client, reporter, result, combinedBeforeEach, suite.afterEach, suite.name, depth + (suite.name ? 1 : 0));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Run suite-level afterAll hooks
|
|
141
|
+
for (const hook of suite.afterAll) {
|
|
142
|
+
await hook(hookCtx);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async _runTest(test, skip, client, reporter, result, beforeEachHooks, afterEachHooks, suiteName, depth) {
|
|
146
|
+
result.total++;
|
|
147
|
+
if (skip || test.mode === 'skip') {
|
|
148
|
+
result.skipped++;
|
|
149
|
+
reporter.testSkip(test.name, depth);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const world = new world_1.RhostWorld(client);
|
|
153
|
+
const hookCtx = { client, world };
|
|
154
|
+
const testCtx = {
|
|
155
|
+
client,
|
|
156
|
+
world,
|
|
157
|
+
expect: (expr) => new expect_1.RhostExpect(client, expr),
|
|
158
|
+
};
|
|
159
|
+
// Run inherited + suite beforeEach — if one throws, count as a test failure
|
|
160
|
+
for (const hook of beforeEachHooks) {
|
|
161
|
+
try {
|
|
162
|
+
await hook(hookCtx);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
166
|
+
result.failed++;
|
|
167
|
+
result.failures.push({ suite: suiteName, test: test.name, error });
|
|
168
|
+
reporter.testFail(test.name, 0, depth, error);
|
|
169
|
+
try {
|
|
170
|
+
await world.cleanup();
|
|
171
|
+
}
|
|
172
|
+
catch { /* ignore */ }
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const t0 = Date.now();
|
|
177
|
+
try {
|
|
178
|
+
const timeoutMs = test.timeout ?? 15000;
|
|
179
|
+
await this._withTimeout(test.fn(testCtx), timeoutMs, test.name);
|
|
180
|
+
const ms = Date.now() - t0;
|
|
181
|
+
result.passed++;
|
|
182
|
+
reporter.testPass(test.name, ms, depth);
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
const ms = Date.now() - t0;
|
|
186
|
+
result.failed++;
|
|
187
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
188
|
+
result.failures.push({ suite: suiteName, test: test.name, error });
|
|
189
|
+
reporter.testFail(test.name, ms, depth, error);
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
// Auto-cleanup world (ignore errors)
|
|
193
|
+
try {
|
|
194
|
+
await world.cleanup();
|
|
195
|
+
}
|
|
196
|
+
catch { /* ignore */ }
|
|
197
|
+
}
|
|
198
|
+
// Run suite afterEach
|
|
199
|
+
for (const hook of afterEachHooks) {
|
|
200
|
+
try {
|
|
201
|
+
await hook(hookCtx);
|
|
202
|
+
}
|
|
203
|
+
catch { /* ignore */ }
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Apply `only` semantics: if ANY direct child has mode 'only', only run
|
|
208
|
+
* those. Otherwise run all non-skip children.
|
|
209
|
+
*/
|
|
210
|
+
_resolveOnly(children) {
|
|
211
|
+
const hasOnly = children.some((c) => c.mode === 'only');
|
|
212
|
+
if (hasOnly) {
|
|
213
|
+
return children.filter((c) => c.mode === 'only');
|
|
214
|
+
}
|
|
215
|
+
return children.filter((c) => c.mode !== 'skip');
|
|
216
|
+
}
|
|
217
|
+
_countFailedFromBeforeAll(suite, result, reporter, depth, error) {
|
|
218
|
+
for (const child of suite.children) {
|
|
219
|
+
if (child.kind === 'suite') {
|
|
220
|
+
this._countFailedFromBeforeAll(child, result, reporter, depth + 1, error);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
result.total++;
|
|
224
|
+
result.failed++;
|
|
225
|
+
result.failures.push({ suite: suite.name, test: child.name, error });
|
|
226
|
+
reporter.testFail(child.name, 0, depth + 1, error);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
_countSkipped(suite, result, reporter, depth) {
|
|
231
|
+
if (suite.name)
|
|
232
|
+
reporter.suiteStart(suite.name, depth);
|
|
233
|
+
for (const child of suite.children) {
|
|
234
|
+
if (child.kind === 'suite') {
|
|
235
|
+
this._countSkipped(child, result, reporter, depth + 1);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
result.total++;
|
|
239
|
+
result.skipped++;
|
|
240
|
+
reporter.testSkip(child.name, depth + 1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
_withTimeout(p, ms, name) {
|
|
245
|
+
if (!(p instanceof Promise))
|
|
246
|
+
return Promise.resolve();
|
|
247
|
+
return new Promise((resolve, reject) => {
|
|
248
|
+
const timer = setTimeout(() => reject(new Error(`Test "${name}" timed out after ${ms}ms`)), ms);
|
|
249
|
+
// Unref so Node won't keep the process alive if the test hangs
|
|
250
|
+
if (typeof timer.unref === 'function')
|
|
251
|
+
timer.unref();
|
|
252
|
+
p.then(() => { clearTimeout(timer); resolve(); }, (err) => { clearTimeout(timer); reject(err); });
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
exports.RhostRunner = RhostRunner;
|
|
257
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/world.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RhostClient } from './client';
|
|
2
|
+
/**
|
|
3
|
+
* RhostWorld — fixture manager for creating and cleaning up in-game objects
|
|
4
|
+
* during test runs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const world = new RhostWorld(client);
|
|
8
|
+
* const obj = await world.create('TestThing');
|
|
9
|
+
* await world.set(obj, 'MYATTR', 'hello');
|
|
10
|
+
* const val = await world.get(obj, 'MYATTR'); // => 'hello'
|
|
11
|
+
* await world.cleanup(); // auto-nukes everything
|
|
12
|
+
*/
|
|
13
|
+
export declare class RhostWorld {
|
|
14
|
+
private readonly client;
|
|
15
|
+
private dbrefs;
|
|
16
|
+
constructor(client: RhostClient);
|
|
17
|
+
private guardInput;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a THING via `@create name`.
|
|
20
|
+
* Parses the dbref from the command output (e.g. "name created as object #42").
|
|
21
|
+
* Registers the dbref for automatic cleanup.
|
|
22
|
+
* Returns the dbref string like '#42'.
|
|
23
|
+
*/
|
|
24
|
+
create(name: string, cost?: number): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a ROOM via `@dig name`.
|
|
27
|
+
* Parses the output for the dbref (e.g. "name created as room #NN.").
|
|
28
|
+
* Registers the dbref for automatic cleanup.
|
|
29
|
+
*/
|
|
30
|
+
dig(name: string): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Destroys an object with `@nuke dbref`.
|
|
33
|
+
*/
|
|
34
|
+
destroy(dbref: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Sets an attribute: `&ATTR dbref=value`.
|
|
37
|
+
*/
|
|
38
|
+
set(dbref: string, attr: string, value: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Gets an attribute by evaluating `get(dbref/ATTR)`.
|
|
41
|
+
*/
|
|
42
|
+
get(dbref: string, attr: string): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Locks an object: `@lock dbref=<lockstring>`.
|
|
45
|
+
*/
|
|
46
|
+
lock(dbref: string, lockstring: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Sets a flag: `@set dbref=FLAG` or `@set dbref=!FLAG` to clear.
|
|
49
|
+
*/
|
|
50
|
+
flag(dbref: string, flag: string, clear?: boolean): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Triggers `@trigger dbref/ATTR=args`. Returns captured output lines.
|
|
53
|
+
*/
|
|
54
|
+
trigger(dbref: string, attr: string, args?: string): Promise<string[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Destroys all objects created by this world instance (in reverse order).
|
|
57
|
+
*/
|
|
58
|
+
cleanup(): Promise<void>;
|
|
59
|
+
/** How many objects are tracked for cleanup. */
|
|
60
|
+
get size(): number;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=world.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IAGP,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,MAAM,CAAgB;gBAED,MAAM,EAAE,WAAW;IAEhD,OAAO,CAAC,UAAU;IAQlB;;;;;OAKG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa1D;;;;OAIG;IACG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAexC;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C;;OAEG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE;;OAEG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKvD;;OAEG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;OAEG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrE;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAS5E;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B,gDAAgD;IAChD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACJ"}
|
package/dist/world.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RhostWorld = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* RhostWorld — fixture manager for creating and cleaning up in-game objects
|
|
6
|
+
* during test runs.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* const world = new RhostWorld(client);
|
|
10
|
+
* const obj = await world.create('TestThing');
|
|
11
|
+
* await world.set(obj, 'MYATTR', 'hello');
|
|
12
|
+
* const val = await world.get(obj, 'MYATTR'); // => 'hello'
|
|
13
|
+
* await world.cleanup(); // auto-nukes everything
|
|
14
|
+
*/
|
|
15
|
+
class RhostWorld {
|
|
16
|
+
constructor(client) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.dbrefs = [];
|
|
19
|
+
}
|
|
20
|
+
guardInput(field, value) {
|
|
21
|
+
if (/[\n\r]/.test(value)) {
|
|
22
|
+
throw new RangeError(`world: invalid ${field} — value must not contain newline or carriage return characters`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a THING via `@create name`.
|
|
27
|
+
* Parses the dbref from the command output (e.g. "name created as object #42").
|
|
28
|
+
* Registers the dbref for automatic cleanup.
|
|
29
|
+
* Returns the dbref string like '#42'.
|
|
30
|
+
*/
|
|
31
|
+
async create(name, cost) {
|
|
32
|
+
this.guardInput('name', name);
|
|
33
|
+
const expr = cost !== undefined ? `create(${name},${cost})` : `create(${name})`;
|
|
34
|
+
const result = (await this.client.eval(expr)).trim();
|
|
35
|
+
const m = result.match(/^#(\d+)$/);
|
|
36
|
+
if (m) {
|
|
37
|
+
const dbref = `#${m[1]}`;
|
|
38
|
+
this.dbrefs.push(dbref);
|
|
39
|
+
return dbref;
|
|
40
|
+
}
|
|
41
|
+
throw new Error(`world.create(${JSON.stringify(name)}) returned unexpected value: ${JSON.stringify(result)}`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a ROOM via `@dig name`.
|
|
45
|
+
* Parses the output for the dbref (e.g. "name created as room #NN.").
|
|
46
|
+
* Registers the dbref for automatic cleanup.
|
|
47
|
+
*/
|
|
48
|
+
async dig(name) {
|
|
49
|
+
this.guardInput('name', name);
|
|
50
|
+
const lines = await this.client.command(`@dig ${name}`);
|
|
51
|
+
// Match "#42" or "room number 42" or "room number #42"
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
const m = line.match(/(?:room number\s+#?|#)(\d+)/i);
|
|
54
|
+
if (m) {
|
|
55
|
+
const dbref = `#${m[1]}`;
|
|
56
|
+
this.dbrefs.push(dbref);
|
|
57
|
+
return dbref;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`world.dig(${JSON.stringify(name)}) could not parse dbref from output: ${JSON.stringify(lines)}`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Destroys an object with `@nuke dbref`.
|
|
64
|
+
*/
|
|
65
|
+
async destroy(dbref) {
|
|
66
|
+
await this.client.command(`@nuke ${dbref}`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Sets an attribute: `&ATTR dbref=value`.
|
|
70
|
+
*/
|
|
71
|
+
async set(dbref, attr, value) {
|
|
72
|
+
this.guardInput('attr', attr);
|
|
73
|
+
this.guardInput('value', value);
|
|
74
|
+
await this.client.command(`&${attr} ${dbref}=${value}`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Gets an attribute by evaluating `get(dbref/ATTR)`.
|
|
78
|
+
*/
|
|
79
|
+
async get(dbref, attr) {
|
|
80
|
+
// Strip the '#' for the get() call — Rhost expects get(#42/ATTR)
|
|
81
|
+
return (await this.client.eval(`get(${dbref}/${attr})`)).trim();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Locks an object: `@lock dbref=<lockstring>`.
|
|
85
|
+
*/
|
|
86
|
+
async lock(dbref, lockstring) {
|
|
87
|
+
this.guardInput('lockstring', lockstring);
|
|
88
|
+
await this.client.command(`@lock ${dbref}=${lockstring}`);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Sets a flag: `@set dbref=FLAG` or `@set dbref=!FLAG` to clear.
|
|
92
|
+
*/
|
|
93
|
+
async flag(dbref, flag, clear = false) {
|
|
94
|
+
this.guardInput('flag', flag);
|
|
95
|
+
const flagStr = clear ? `!${flag}` : flag;
|
|
96
|
+
await this.client.command(`@set ${dbref}=${flagStr}`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Triggers `@trigger dbref/ATTR=args`. Returns captured output lines.
|
|
100
|
+
*/
|
|
101
|
+
async trigger(dbref, attr, args) {
|
|
102
|
+
this.guardInput('attr', attr);
|
|
103
|
+
if (args !== undefined)
|
|
104
|
+
this.guardInput('args', args);
|
|
105
|
+
const cmd = args
|
|
106
|
+
? `@trigger ${dbref}/${attr}=${args}`
|
|
107
|
+
: `@trigger ${dbref}/${attr}`;
|
|
108
|
+
return this.client.command(cmd);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Destroys all objects created by this world instance (in reverse order).
|
|
112
|
+
*/
|
|
113
|
+
async cleanup() {
|
|
114
|
+
const toDestroy = this.dbrefs.splice(0).reverse();
|
|
115
|
+
for (const dbref of toDestroy) {
|
|
116
|
+
try {
|
|
117
|
+
await this.destroy(dbref);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Ignore cleanup errors — object may already be gone
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** How many objects are tracked for cleanup. */
|
|
125
|
+
get size() {
|
|
126
|
+
return this.dbrefs.length;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.RhostWorld = RhostWorld;
|
|
130
|
+
//# sourceMappingURL=world.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world.js","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"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"}
|