@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
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MushConnection = void 0;
|
|
37
|
+
const net = __importStar(require("net"));
|
|
38
|
+
const events_1 = require("events");
|
|
39
|
+
/**
|
|
40
|
+
* Async FIFO queue for lines received from the server.
|
|
41
|
+
* Delivers directly to waiting consumers; buffers when none are waiting.
|
|
42
|
+
*/
|
|
43
|
+
class AsyncLineQueue {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.buffer = [];
|
|
46
|
+
this.waiters = [];
|
|
47
|
+
}
|
|
48
|
+
push(line) {
|
|
49
|
+
if (this.waiters.length > 0) {
|
|
50
|
+
this.waiters.shift().resolve(line);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.buffer.push(line);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
next(timeoutMs) {
|
|
57
|
+
if (this.buffer.length > 0) {
|
|
58
|
+
return Promise.resolve(this.buffer.shift());
|
|
59
|
+
}
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const entry = { resolve, reject };
|
|
62
|
+
this.waiters.push(entry);
|
|
63
|
+
const timer = setTimeout(() => {
|
|
64
|
+
const idx = this.waiters.indexOf(entry);
|
|
65
|
+
if (idx !== -1) {
|
|
66
|
+
this.waiters.splice(idx, 1);
|
|
67
|
+
reject(new Error(`Timed out after ${timeoutMs}ms waiting for next line`));
|
|
68
|
+
}
|
|
69
|
+
}, timeoutMs);
|
|
70
|
+
const origResolve = entry.resolve;
|
|
71
|
+
entry.resolve = (line) => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
origResolve(line);
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
drainSync() {
|
|
78
|
+
const lines = [...this.buffer];
|
|
79
|
+
this.buffer = [];
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
cancelAll(reason) {
|
|
83
|
+
const err = new Error(reason);
|
|
84
|
+
for (const w of this.waiters.splice(0))
|
|
85
|
+
w.reject(err);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class MushConnection extends events_1.EventEmitter {
|
|
89
|
+
constructor(host, port) {
|
|
90
|
+
super();
|
|
91
|
+
this.host = host;
|
|
92
|
+
this.port = port;
|
|
93
|
+
this.socket = null;
|
|
94
|
+
this.rawBuffer = '';
|
|
95
|
+
this.lines = new AsyncLineQueue();
|
|
96
|
+
}
|
|
97
|
+
connect(connectTimeoutMs = 10000) {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
this.socket = new net.Socket();
|
|
100
|
+
this.socket.setEncoding('utf8');
|
|
101
|
+
this.socket.once('error', (err) => { reject(err); });
|
|
102
|
+
this.socket.setTimeout(connectTimeoutMs);
|
|
103
|
+
this.socket.once('timeout', () => {
|
|
104
|
+
this.socket.destroy();
|
|
105
|
+
reject(new Error(`connect() timed out after ${connectTimeoutMs}ms`));
|
|
106
|
+
});
|
|
107
|
+
this.socket.connect(this.port, this.host, () => {
|
|
108
|
+
this.socket.setTimeout(0); // disable timeout after connection established
|
|
109
|
+
this.socket.removeAllListeners('error');
|
|
110
|
+
this.socket.removeAllListeners('timeout');
|
|
111
|
+
this.socket.on('error', (err) => this.emit('error', err));
|
|
112
|
+
this.socket.on('close', () => {
|
|
113
|
+
this.lines.cancelAll('Connection closed');
|
|
114
|
+
this.emit('close');
|
|
115
|
+
});
|
|
116
|
+
this.socket.on('data', (chunk) => this.onData(chunk));
|
|
117
|
+
resolve();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
onData(chunk) {
|
|
122
|
+
this.rawBuffer += chunk;
|
|
123
|
+
let newlineIdx;
|
|
124
|
+
while ((newlineIdx = this.rawBuffer.indexOf('\n')) !== -1) {
|
|
125
|
+
const line = this.rawBuffer.slice(0, newlineIdx).replace(/\r$/, '');
|
|
126
|
+
this.rawBuffer = this.rawBuffer.slice(newlineIdx + 1);
|
|
127
|
+
this.emit('line', line);
|
|
128
|
+
this.lines.push(line);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
send(command) {
|
|
132
|
+
if (!this.socket || this.socket.destroyed) {
|
|
133
|
+
throw new Error('Not connected');
|
|
134
|
+
}
|
|
135
|
+
this.socket.write(command + '\r\n');
|
|
136
|
+
}
|
|
137
|
+
close() {
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
if (!this.socket || this.socket.destroyed) {
|
|
140
|
+
resolve();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.socket.once('close', () => resolve());
|
|
144
|
+
this.socket.end();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.MushConnection = MushConnection;
|
|
149
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAA2B;AAC3B,mCAAsC;AAEtC;;;GAGG;AACH,MAAM,cAAc;IAApB;QACY,WAAM,GAAa,EAAE,CAAC;QACtB,YAAO,GAA6E,EAAE,CAAC;IA0CnG,CAAC;IAxCG,IAAI,CAAC,IAAY;QACb,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IAED,IAAI,CAAC,SAAiB;QAClB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAG,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACxC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;oBACb,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;oBAC5B,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,SAAS,0BAA0B,CAAC,CAAC,CAAC;gBAC9E,CAAC;YACL,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC;YAClC,KAAK,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE;gBACrB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,WAAW,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC;IAED,SAAS;QACL,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,SAAS,CAAC,MAAc;QACpB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;CACJ;AAED,MAAa,cAAe,SAAQ,qBAAY;IAK5C,YAA6B,IAAY,EAAmB,IAAY;QACpE,KAAK,EAAE,CAAC;QADiB,SAAI,GAAJ,IAAI,CAAQ;QAAmB,SAAI,GAAJ,IAAI,CAAQ;QAJhE,WAAM,GAAsB,IAAI,CAAC;QACjC,cAAS,GAAG,EAAE,CAAC;QAKnB,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,EAAE,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,gBAAgB,GAAG,KAAK;QAC5B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;gBAC7B,IAAI,CAAC,MAAO,CAAC,OAAO,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,gBAAgB,IAAI,CAAC,CAAC,CAAC;YACzE,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;gBAC3C,IAAI,CAAC,MAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,+CAA+C;gBAC3E,IAAI,CAAC,MAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,CAAC,MAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;gBAC3C,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC3D,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;oBAC1B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;oBAC1C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACvB,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC/D,OAAO,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,MAAM,CAAC,KAAa;QACxB,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QACxB,IAAI,UAAkB,CAAC;QACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YACtD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACL,CAAC;IAED,IAAI,CAAC,OAAe;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,KAAK;QACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBACxC,OAAO,EAAE,CAAC;gBACV,OAAO;YACX,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AA/DD,wCA+DC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface ContainerConnectionInfo {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class RhostContainer {
|
|
6
|
+
private started;
|
|
7
|
+
private readonly factory;
|
|
8
|
+
private constructor();
|
|
9
|
+
/**
|
|
10
|
+
* Use a pre-built Docker image.
|
|
11
|
+
* Build it first with: `docker build -t rhostmush:latest .`
|
|
12
|
+
* (run from the rhostmush-docker repo root)
|
|
13
|
+
*/
|
|
14
|
+
static fromImage(image?: string): RhostContainer;
|
|
15
|
+
/**
|
|
16
|
+
* Build the image from the Dockerfile in the rhostmush-docker project root.
|
|
17
|
+
*
|
|
18
|
+
* The first build clones and compiles RhostMUSH from source — allow 5-10
|
|
19
|
+
* minutes. Subsequent runs reuse Docker's layer cache.
|
|
20
|
+
*
|
|
21
|
+
* @param projectRoot - Path to the rhostmush-docker directory.
|
|
22
|
+
* Defaults to `../` relative to this file (i.e. the repo root).
|
|
23
|
+
*/
|
|
24
|
+
static fromSource(projectRoot?: string): RhostContainer;
|
|
25
|
+
/**
|
|
26
|
+
* Start the container. Blocks until port 4201 is accepting connections.
|
|
27
|
+
* Returns the host and dynamically-assigned port to pass to `RhostClient`.
|
|
28
|
+
*
|
|
29
|
+
* @param startupTimeout - Max ms to wait for the server to be ready.
|
|
30
|
+
* Default: 120000 (2 min). Increase for slow machines or first builds.
|
|
31
|
+
*/
|
|
32
|
+
start(startupTimeout?: number): Promise<ContainerConnectionInfo>;
|
|
33
|
+
/** Stop and remove the container. Safe to call if never started. */
|
|
34
|
+
stop(): Promise<void>;
|
|
35
|
+
/** Connection details. Throws if the container is not running. */
|
|
36
|
+
getConnectionInfo(): ContainerConnectionInfo;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAE3C,OAAO;IAIP;;;;OAIG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,SAAqB,GAAG,cAAc;IAI5D;;;;;;;;OAQG;IACH,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc;IAUvD;;;;;;OAMG;IACG,KAAK,CAAC,cAAc,SAAU,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAYvE,oEAAoE;IAC9D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,kEAAkE;IAClE,iBAAiB,IAAI,uBAAuB;CAS/C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RhostContainer = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* RhostContainer — wraps testcontainers to spin up a real RhostMUSH server
|
|
39
|
+
* for integration tests without any manual `docker compose up`.
|
|
40
|
+
*
|
|
41
|
+
* Two modes:
|
|
42
|
+
* 1. Pre-built image (fast): RhostContainer.fromImage('rhostmush:latest')
|
|
43
|
+
* 2. Build from source (slow first run, cached thereafter):
|
|
44
|
+
* RhostContainer.fromSource()
|
|
45
|
+
*
|
|
46
|
+
* RhostMUSH takes longer to start than most servers (compiles from source on
|
|
47
|
+
* first build, then initialises a flat-file database). The container waits
|
|
48
|
+
* for port 4201 to be accepting connections before returning.
|
|
49
|
+
*
|
|
50
|
+
* Default wizard credentials for the minimal_db: Wizard / Nyctasia
|
|
51
|
+
*/
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const testcontainers_1 = require("testcontainers");
|
|
54
|
+
class RhostContainer {
|
|
55
|
+
constructor(factory) {
|
|
56
|
+
this.started = null;
|
|
57
|
+
this.factory = factory;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Use a pre-built Docker image.
|
|
61
|
+
* Build it first with: `docker build -t rhostmush:latest .`
|
|
62
|
+
* (run from the rhostmush-docker repo root)
|
|
63
|
+
*/
|
|
64
|
+
static fromImage(image = 'rhostmush:latest') {
|
|
65
|
+
return new RhostContainer(async () => new testcontainers_1.GenericContainer(image));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build the image from the Dockerfile in the rhostmush-docker project root.
|
|
69
|
+
*
|
|
70
|
+
* The first build clones and compiles RhostMUSH from source — allow 5-10
|
|
71
|
+
* minutes. Subsequent runs reuse Docker's layer cache.
|
|
72
|
+
*
|
|
73
|
+
* @param projectRoot - Path to the rhostmush-docker directory.
|
|
74
|
+
* Defaults to `../` relative to this file (i.e. the repo root).
|
|
75
|
+
*/
|
|
76
|
+
static fromSource(projectRoot) {
|
|
77
|
+
const root = projectRoot
|
|
78
|
+
? path.resolve(projectRoot)
|
|
79
|
+
: path.resolve(__dirname, '../');
|
|
80
|
+
return new RhostContainer(async () => {
|
|
81
|
+
return testcontainers_1.GenericContainer.fromDockerfile(root).build();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Start the container. Blocks until port 4201 is accepting connections.
|
|
86
|
+
* Returns the host and dynamically-assigned port to pass to `RhostClient`.
|
|
87
|
+
*
|
|
88
|
+
* @param startupTimeout - Max ms to wait for the server to be ready.
|
|
89
|
+
* Default: 120000 (2 min). Increase for slow machines or first builds.
|
|
90
|
+
*/
|
|
91
|
+
async start(startupTimeout = 120000) {
|
|
92
|
+
const base = await this.factory();
|
|
93
|
+
this.started = await base
|
|
94
|
+
.withExposedPorts(4201)
|
|
95
|
+
.withWaitStrategy(testcontainers_1.Wait.forListeningPorts().withStartupTimeout(startupTimeout))
|
|
96
|
+
.start();
|
|
97
|
+
return this.getConnectionInfo();
|
|
98
|
+
}
|
|
99
|
+
/** Stop and remove the container. Safe to call if never started. */
|
|
100
|
+
async stop() {
|
|
101
|
+
await this.started?.stop();
|
|
102
|
+
this.started = null;
|
|
103
|
+
}
|
|
104
|
+
/** Connection details. Throws if the container is not running. */
|
|
105
|
+
getConnectionInfo() {
|
|
106
|
+
if (!this.started) {
|
|
107
|
+
throw new Error('Container is not running — call start() first.');
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
host: this.started.getHost(),
|
|
111
|
+
port: this.started.getMappedPort(4201),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.RhostContainer = RhostContainer;
|
|
116
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;GAcG;AACH,2CAA6B;AAC7B,mDAIwB;AASxB,MAAa,cAAc;IAIvB,YAAoB,OAAyB;QAHrC,YAAO,GAAgC,IAAI,CAAC;QAIhD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,kBAAkB;QACvC,OAAO,IAAI,cAAc,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,iCAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,UAAU,CAAC,WAAoB;QAClC,MAAM,IAAI,GAAG,WAAW;YACpB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YAC3B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAErC,OAAO,IAAI,cAAc,CAAC,KAAK,IAAI,EAAE;YACjC,OAAO,iCAAgB,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACzD,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CAAC,cAAc,GAAG,MAAO;QAChC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,MAAM,IAAI;aACpB,gBAAgB,CAAC,IAAI,CAAC;aACtB,gBAAgB,CACb,qBAAI,CAAC,iBAAiB,EAAE,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAC9D;aACA,KAAK,EAAE,CAAC;QAEb,OAAO,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACpC,CAAC;IAED,oEAAoE;IACpE,KAAK,CAAC,IAAI;QACN,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,kEAAkE;IAClE,iBAAiB;QACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACtE,CAAC;QACD,OAAO;YACH,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YAC5B,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;SACzC,CAAC;IACN,CAAC;CACJ;AAvED,wCAuEC"}
|
package/dist/expect.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { RhostClient } from './client';
|
|
2
|
+
export { isRhostError } from './assertions';
|
|
3
|
+
export declare class RhostExpectError extends Error {
|
|
4
|
+
readonly expression: string;
|
|
5
|
+
readonly matcherName: string;
|
|
6
|
+
readonly actual: string;
|
|
7
|
+
readonly expectedDesc: string;
|
|
8
|
+
readonly negated: boolean;
|
|
9
|
+
constructor(expression: string, matcherName: string, actual: string, expectedDesc: string, negated: boolean);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Jest-style expect wrapper for RhostMUSH softcode evaluation.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const ex = new RhostExpect(client, 'add(2,3)');
|
|
16
|
+
* await ex.toBe('5');
|
|
17
|
+
* await ex.not.toBe('42');
|
|
18
|
+
*/
|
|
19
|
+
export declare class RhostExpect {
|
|
20
|
+
private readonly client;
|
|
21
|
+
private readonly expression;
|
|
22
|
+
private readonly negated;
|
|
23
|
+
private _cached;
|
|
24
|
+
constructor(client: RhostClient, expression: string, negated?: boolean);
|
|
25
|
+
/** Negation accessor — returns a new RhostExpect with negation flipped. */
|
|
26
|
+
get not(): RhostExpect;
|
|
27
|
+
private resolve;
|
|
28
|
+
private pass;
|
|
29
|
+
/** Exact match (after trim). */
|
|
30
|
+
toBe(expected: string): Promise<void>;
|
|
31
|
+
/** Regex or substring match. */
|
|
32
|
+
toMatch(pattern: RegExp | string): Promise<void>;
|
|
33
|
+
/** String contains substring. */
|
|
34
|
+
toContain(substring: string): Promise<void>;
|
|
35
|
+
/** String starts with prefix. */
|
|
36
|
+
toStartWith(prefix: string): Promise<void>;
|
|
37
|
+
/** String ends with suffix. */
|
|
38
|
+
toEndWith(suffix: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Numeric proximity: |actual - expected| < 10^(-precision).
|
|
41
|
+
* Default precision = 3 (within 0.001).
|
|
42
|
+
*/
|
|
43
|
+
toBeCloseTo(expected: number, precision?: number): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Truthy in MUSH terms: non-empty, not "0", not starting with #-1/#-2/#-3.
|
|
46
|
+
*/
|
|
47
|
+
toBeTruthy(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Falsy in MUSH terms: empty OR "0" OR starts with #-1.
|
|
50
|
+
*/
|
|
51
|
+
toBeFalsy(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Result is a RhostMUSH error (#-1, #-2, #-3).
|
|
54
|
+
*/
|
|
55
|
+
toBeError(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Result is a valid object dbref: matches /^#\d+$/ (positive dbref).
|
|
58
|
+
*/
|
|
59
|
+
toBeDbref(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Result parses as a finite JavaScript number.
|
|
62
|
+
* Empty string is not considered a number.
|
|
63
|
+
*/
|
|
64
|
+
toBeNumber(): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Word is present in the space-delimited (or custom sep) list.
|
|
67
|
+
*/
|
|
68
|
+
toContainWord(word: string, sep?: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* List has exactly n words (space-delimited by default).
|
|
71
|
+
*/
|
|
72
|
+
toHaveWordCount(n: number, sep?: string): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=expect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../src/expect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAO5C,qBAAa,gBAAiB,SAAQ,KAAK;aAEnB,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,MAAM;aACnB,MAAM,EAAE,MAAM;aACd,YAAY,EAAE,MAAM;aACpB,OAAO,EAAE,OAAO;gBAJhB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,OAAO;CAWvC;AAMD;;;;;;;GAOG;AACH,qBAAa,WAAW;IAIhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL5B,OAAO,CAAC,OAAO,CAAiC;gBAG3B,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,UAAQ;IAGpC,2EAA2E;IAC3E,IAAI,GAAG,IAAI,WAAW,CAErB;YAMa,OAAO;IAOrB,OAAO,CAAC,IAAI;IAYZ,gCAAgC;IAC1B,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C,gCAAgC;IAC1B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAStD,iCAAiC;IAC3B,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,iCAAiC;IAC3B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,+BAA+B;IACzB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9C;;;OAGG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAajE;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAMhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAKhC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3D;;OAEG;IACG,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAK7D"}
|
package/dist/expect.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RhostExpect = exports.RhostExpectError = exports.isRhostError = void 0;
|
|
4
|
+
var assertions_1 = require("./assertions");
|
|
5
|
+
Object.defineProperty(exports, "isRhostError", { enumerable: true, get: function () { return assertions_1.isRhostError; } });
|
|
6
|
+
const assertions_2 = require("./assertions");
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Error class
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
class RhostExpectError extends Error {
|
|
11
|
+
constructor(expression, matcherName, actual, expectedDesc, negated) {
|
|
12
|
+
const not = negated ? '.not' : '';
|
|
13
|
+
super(`expect(${JSON.stringify(expression)})\n` +
|
|
14
|
+
` \u25cf ${not}.${matcherName} failed\n` +
|
|
15
|
+
` Expected: ${expectedDesc}\n` +
|
|
16
|
+
` Received: ${JSON.stringify(actual)}`);
|
|
17
|
+
this.expression = expression;
|
|
18
|
+
this.matcherName = matcherName;
|
|
19
|
+
this.actual = actual;
|
|
20
|
+
this.expectedDesc = expectedDesc;
|
|
21
|
+
this.negated = negated;
|
|
22
|
+
this.name = 'RhostExpectError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.RhostExpectError = RhostExpectError;
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// RhostExpect
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Jest-style expect wrapper for RhostMUSH softcode evaluation.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const ex = new RhostExpect(client, 'add(2,3)');
|
|
34
|
+
* await ex.toBe('5');
|
|
35
|
+
* await ex.not.toBe('42');
|
|
36
|
+
*/
|
|
37
|
+
class RhostExpect {
|
|
38
|
+
constructor(client, expression, negated = false) {
|
|
39
|
+
this.client = client;
|
|
40
|
+
this.expression = expression;
|
|
41
|
+
this.negated = negated;
|
|
42
|
+
this._cached = undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Negation accessor — returns a new RhostExpect with negation flipped. */
|
|
45
|
+
get not() {
|
|
46
|
+
return new RhostExpect(this.client, this.expression, !this.negated);
|
|
47
|
+
}
|
|
48
|
+
// -------------------------------------------------------------------------
|
|
49
|
+
// Internal helpers
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
async resolve() {
|
|
52
|
+
if (this._cached === undefined) {
|
|
53
|
+
this._cached = (await this.client.eval(this.expression)).replace(/[\r\n]+$/, '');
|
|
54
|
+
}
|
|
55
|
+
return this._cached;
|
|
56
|
+
}
|
|
57
|
+
pass(condition, matcherName, actual, expectedDesc) {
|
|
58
|
+
const success = this.negated ? !condition : condition;
|
|
59
|
+
if (!success) {
|
|
60
|
+
const desc = this.negated ? `NOT ${expectedDesc}` : expectedDesc;
|
|
61
|
+
throw new RhostExpectError(this.expression, matcherName, actual, desc, this.negated);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// -------------------------------------------------------------------------
|
|
65
|
+
// Matchers
|
|
66
|
+
// -------------------------------------------------------------------------
|
|
67
|
+
/** Exact match (after trim). */
|
|
68
|
+
async toBe(expected) {
|
|
69
|
+
const actual = (await this.resolve()).trim();
|
|
70
|
+
this.pass(actual === expected, 'toBe', actual, JSON.stringify(expected));
|
|
71
|
+
}
|
|
72
|
+
/** Regex or substring match. */
|
|
73
|
+
async toMatch(pattern) {
|
|
74
|
+
const actual = await this.resolve();
|
|
75
|
+
const matched = typeof pattern === 'string'
|
|
76
|
+
? actual.includes(pattern)
|
|
77
|
+
: pattern.test(actual);
|
|
78
|
+
const desc = pattern instanceof RegExp ? pattern.toString() : JSON.stringify(pattern);
|
|
79
|
+
this.pass(matched, 'toMatch', actual, desc);
|
|
80
|
+
}
|
|
81
|
+
/** String contains substring. */
|
|
82
|
+
async toContain(substring) {
|
|
83
|
+
const actual = await this.resolve();
|
|
84
|
+
this.pass(actual.includes(substring), 'toContain', actual, `string containing ${JSON.stringify(substring)}`);
|
|
85
|
+
}
|
|
86
|
+
/** String starts with prefix. */
|
|
87
|
+
async toStartWith(prefix) {
|
|
88
|
+
const actual = await this.resolve();
|
|
89
|
+
this.pass(actual.startsWith(prefix), 'toStartWith', actual, `string starting with ${JSON.stringify(prefix)}`);
|
|
90
|
+
}
|
|
91
|
+
/** String ends with suffix. */
|
|
92
|
+
async toEndWith(suffix) {
|
|
93
|
+
const actual = await this.resolve();
|
|
94
|
+
this.pass(actual.endsWith(suffix), 'toEndWith', actual, `string ending with ${JSON.stringify(suffix)}`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Numeric proximity: |actual - expected| < 10^(-precision).
|
|
98
|
+
* Default precision = 3 (within 0.001).
|
|
99
|
+
*/
|
|
100
|
+
async toBeCloseTo(expected, precision = 3) {
|
|
101
|
+
const actual = await this.resolve();
|
|
102
|
+
const num = Number(actual);
|
|
103
|
+
const diff = Math.abs(num - expected);
|
|
104
|
+
const threshold = Math.pow(10, -precision);
|
|
105
|
+
this.pass(Number.isFinite(num) && diff < threshold, 'toBeCloseTo', actual, `a number close to ${expected} (precision ${precision})`);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Truthy in MUSH terms: non-empty, not "0", not starting with #-1/#-2/#-3.
|
|
109
|
+
*/
|
|
110
|
+
async toBeTruthy() {
|
|
111
|
+
const actual = await this.resolve();
|
|
112
|
+
const truthy = actual !== '' && actual !== '0' && !(0, assertions_2.isRhostError)(actual);
|
|
113
|
+
this.pass(truthy, 'toBeTruthy', actual, '<truthy: non-empty, non-"0", non-error>');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Falsy in MUSH terms: empty OR "0" OR starts with #-1.
|
|
117
|
+
*/
|
|
118
|
+
async toBeFalsy() {
|
|
119
|
+
const actual = await this.resolve();
|
|
120
|
+
const falsy = actual === '' || actual === '0' || (0, assertions_2.isRhostError)(actual);
|
|
121
|
+
this.pass(falsy, 'toBeFalsy', actual, '<falsy: empty, "0", or error dbref>');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Result is a RhostMUSH error (#-1, #-2, #-3).
|
|
125
|
+
*/
|
|
126
|
+
async toBeError() {
|
|
127
|
+
const actual = await this.resolve();
|
|
128
|
+
this.pass((0, assertions_2.isRhostError)(actual), 'toBeError', actual, '<error: starts with #-1, #-2, or #-3>');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Result is a valid object dbref: matches /^#\d+$/ (positive dbref).
|
|
132
|
+
*/
|
|
133
|
+
async toBeDbref() {
|
|
134
|
+
const actual = await this.resolve();
|
|
135
|
+
this.pass(/^#\d+$/.test(actual), 'toBeDbref', actual, '<dbref: /^#\\d+$/>');
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Result parses as a finite JavaScript number.
|
|
139
|
+
* Empty string is not considered a number.
|
|
140
|
+
*/
|
|
141
|
+
async toBeNumber() {
|
|
142
|
+
const actual = await this.resolve();
|
|
143
|
+
const isNum = actual !== '' && Number.isFinite(Number(actual));
|
|
144
|
+
this.pass(isNum, 'toBeNumber', actual, '<finite number>');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Word is present in the space-delimited (or custom sep) list.
|
|
148
|
+
*/
|
|
149
|
+
async toContainWord(word, sep = ' ') {
|
|
150
|
+
const actual = await this.resolve();
|
|
151
|
+
const words = actual.split(sep).map((w) => w.trim()).filter(Boolean);
|
|
152
|
+
this.pass(words.includes(word), 'toContainWord', actual, `list containing word ${JSON.stringify(word)}`);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* List has exactly n words (space-delimited by default).
|
|
156
|
+
*/
|
|
157
|
+
async toHaveWordCount(n, sep = ' ') {
|
|
158
|
+
const actual = await this.resolve();
|
|
159
|
+
const words = actual === '' ? [] : actual.split(sep).map((w) => w.trim()).filter(Boolean);
|
|
160
|
+
this.pass(words.length === n, 'toHaveWordCount', actual, `list with ${n} word(s) (got ${words.length})`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.RhostExpect = RhostExpect;
|
|
164
|
+
//# sourceMappingURL=expect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect.js","sourceRoot":"","sources":["../src/expect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { RhostClient, RhostClientOptions, stripAnsi } from './client';
|
|
2
|
+
export { MushConnection } from './connection';
|
|
3
|
+
export { RhostContainer, ContainerConnectionInfo } from './container';
|
|
4
|
+
export { RhostAssert, RhostAssertionError, AssertionResult, isRhostError } from './assertions';
|
|
5
|
+
export { RhostExpect, RhostExpectError } from './expect';
|
|
6
|
+
export { RhostWorld } from './world';
|
|
7
|
+
export { Reporter } from './reporter';
|
|
8
|
+
export { RhostRunner, RunnerOptions, RunResult, TestContext, TestFn, HookFn, SuiteContext, ItFn, DescribeFn, } from './runner';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGtE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGtE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG/F,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,EACH,WAAW,EACX,aAAa,EACb,SAAS,EACT,WAAW,EACX,MAAM,EACN,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,UAAU,GACb,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RhostRunner = exports.Reporter = exports.RhostWorld = exports.RhostExpectError = exports.RhostExpect = exports.isRhostError = exports.RhostAssertionError = exports.RhostAssert = exports.RhostContainer = exports.MushConnection = exports.stripAnsi = exports.RhostClient = void 0;
|
|
4
|
+
// Core client
|
|
5
|
+
var client_1 = require("./client");
|
|
6
|
+
Object.defineProperty(exports, "RhostClient", { enumerable: true, get: function () { return client_1.RhostClient; } });
|
|
7
|
+
Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return client_1.stripAnsi; } });
|
|
8
|
+
// Connection
|
|
9
|
+
var connection_1 = require("./connection");
|
|
10
|
+
Object.defineProperty(exports, "MushConnection", { enumerable: true, get: function () { return connection_1.MushConnection; } });
|
|
11
|
+
// Container
|
|
12
|
+
var container_1 = require("./container");
|
|
13
|
+
Object.defineProperty(exports, "RhostContainer", { enumerable: true, get: function () { return container_1.RhostContainer; } });
|
|
14
|
+
// Assertions (backward-compat)
|
|
15
|
+
var assertions_1 = require("./assertions");
|
|
16
|
+
Object.defineProperty(exports, "RhostAssert", { enumerable: true, get: function () { return assertions_1.RhostAssert; } });
|
|
17
|
+
Object.defineProperty(exports, "RhostAssertionError", { enumerable: true, get: function () { return assertions_1.RhostAssertionError; } });
|
|
18
|
+
Object.defineProperty(exports, "isRhostError", { enumerable: true, get: function () { return assertions_1.isRhostError; } });
|
|
19
|
+
// New expect API
|
|
20
|
+
var expect_1 = require("./expect");
|
|
21
|
+
Object.defineProperty(exports, "RhostExpect", { enumerable: true, get: function () { return expect_1.RhostExpect; } });
|
|
22
|
+
Object.defineProperty(exports, "RhostExpectError", { enumerable: true, get: function () { return expect_1.RhostExpectError; } });
|
|
23
|
+
// World fixture manager
|
|
24
|
+
var world_1 = require("./world");
|
|
25
|
+
Object.defineProperty(exports, "RhostWorld", { enumerable: true, get: function () { return world_1.RhostWorld; } });
|
|
26
|
+
// Reporter
|
|
27
|
+
var reporter_1 = require("./reporter");
|
|
28
|
+
Object.defineProperty(exports, "Reporter", { enumerable: true, get: function () { return reporter_1.Reporter; } });
|
|
29
|
+
// Runner + types
|
|
30
|
+
var runner_1 = require("./runner");
|
|
31
|
+
Object.defineProperty(exports, "RhostRunner", { enumerable: true, get: function () { return runner_1.RhostRunner; } });
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,cAAc;AACd,mCAAsE;AAA7D,qGAAA,WAAW,OAAA;AAAsB,mGAAA,SAAS,OAAA;AAEnD,aAAa;AACb,2CAA8C;AAArC,4GAAA,cAAc,OAAA;AAEvB,YAAY;AACZ,yCAAsE;AAA7D,2GAAA,cAAc,OAAA;AAEvB,+BAA+B;AAC/B,2CAA+F;AAAtF,yGAAA,WAAW,OAAA;AAAE,iHAAA,mBAAmB,OAAA;AAAmB,0GAAA,YAAY,OAAA;AAExE,iBAAiB;AACjB,mCAAyD;AAAhD,qGAAA,WAAW,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAEtC,wBAAwB;AACxB,iCAAqC;AAA5B,mGAAA,UAAU,OAAA;AAEnB,WAAW;AACX,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AAEjB,iBAAiB;AACjB,mCAUkB;AATd,qGAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RunResult } from './runner';
|
|
2
|
+
export declare class Reporter {
|
|
3
|
+
private readonly verbose;
|
|
4
|
+
constructor(verbose: boolean);
|
|
5
|
+
suiteStart(name: string, depth: number): void;
|
|
6
|
+
testPass(name: string, ms: number, depth: number): void;
|
|
7
|
+
testFail(name: string, ms: number, depth: number, error: Error): void;
|
|
8
|
+
testSkip(name: string, depth: number): void;
|
|
9
|
+
summary(result: RunResult): void;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAsBrC,qBAAa,QAAQ;IACL,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,OAAO;IAE7C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM7C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMvD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAWrE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM3C,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;CASnC"}
|