@rhost/testkit 1.4.0 → 1.5.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.
Files changed (73) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/index.js +15 -4
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/init.d.ts.map +1 -1
  5. package/dist/cli/init.js +107 -19
  6. package/dist/cli/init.js.map +1 -1
  7. package/dist/cli/lint.d.ts +2 -0
  8. package/dist/cli/lint.d.ts.map +1 -0
  9. package/dist/cli/lint.js +163 -0
  10. package/dist/cli/lint.js.map +1 -0
  11. package/dist/cli/mush-format.d.ts +2 -0
  12. package/dist/cli/mush-format.d.ts.map +1 -0
  13. package/dist/cli/mush-format.js +232 -0
  14. package/dist/cli/mush-format.js.map +1 -0
  15. package/dist/client.d.ts +43 -1
  16. package/dist/client.d.ts.map +1 -1
  17. package/dist/client.js +78 -5
  18. package/dist/client.js.map +1 -1
  19. package/dist/index.d.ts +3 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +10 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/offline/document.d.ts +8 -0
  24. package/dist/offline/document.d.ts.map +1 -0
  25. package/dist/offline/document.js +124 -0
  26. package/dist/offline/document.js.map +1 -0
  27. package/dist/offline/expect.d.ts +27 -0
  28. package/dist/offline/expect.d.ts.map +1 -0
  29. package/dist/offline/expect.js +90 -0
  30. package/dist/offline/expect.js.map +1 -0
  31. package/dist/offline/index.d.ts +5 -0
  32. package/dist/offline/index.d.ts.map +1 -0
  33. package/dist/offline/index.js +14 -0
  34. package/dist/offline/index.js.map +1 -0
  35. package/dist/offline/mock-client.d.ts +19 -0
  36. package/dist/offline/mock-client.d.ts.map +1 -0
  37. package/dist/offline/mock-client.js +36 -0
  38. package/dist/offline/mock-client.js.map +1 -0
  39. package/dist/offline/mock-world.d.ts +30 -0
  40. package/dist/offline/mock-world.d.ts.map +1 -0
  41. package/dist/offline/mock-world.js +64 -0
  42. package/dist/offline/mock-world.js.map +1 -0
  43. package/dist/offline/reduced-expect.d.ts +38 -0
  44. package/dist/offline/reduced-expect.d.ts.map +1 -0
  45. package/dist/offline/reduced-expect.js +61 -0
  46. package/dist/offline/reduced-expect.js.map +1 -0
  47. package/dist/offline/runner.d.ts +13 -0
  48. package/dist/offline/runner.d.ts.map +1 -0
  49. package/dist/offline/runner.js +174 -0
  50. package/dist/offline/runner.js.map +1 -0
  51. package/dist/offline/types.d.ts +78 -0
  52. package/dist/offline/types.d.ts.map +1 -0
  53. package/dist/offline/types.js +3 -0
  54. package/dist/offline/types.js.map +1 -0
  55. package/dist/reporter.d.ts +3 -1
  56. package/dist/reporter.d.ts.map +1 -1
  57. package/dist/reporter.js +20 -0
  58. package/dist/reporter.js.map +1 -1
  59. package/dist/runner.d.ts +39 -0
  60. package/dist/runner.d.ts.map +1 -1
  61. package/dist/runner.js +82 -15
  62. package/dist/runner.js.map +1 -1
  63. package/dist/validator/formatter.js +13 -2
  64. package/dist/validator/formatter.js.map +1 -1
  65. package/dist/validator/mush-format.d.ts +43 -0
  66. package/dist/validator/mush-format.d.ts.map +1 -0
  67. package/dist/validator/mush-format.js +484 -0
  68. package/dist/validator/mush-format.js.map +1 -0
  69. package/dist/validator/mush-lint.d.ts +22 -0
  70. package/dist/validator/mush-lint.d.ts.map +1 -0
  71. package/dist/validator/mush-lint.js +590 -0
  72. package/dist/validator/mush-lint.js.map +1 -0
  73. package/package.json +10 -2
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OfflineRunner = void 0;
4
+ const document_1 = require("./document");
5
+ const expect_1 = require("./expect");
6
+ // ---------------------------------------------------------------------------
7
+ // Context builder
8
+ // ---------------------------------------------------------------------------
9
+ function makeTestContext() {
10
+ return {
11
+ parse: (source, filename) => (0, document_1.parseDocument)(source, filename),
12
+ expect: (doc) => new expect_1.OfflineExpect(doc),
13
+ loadFile: (filePath) => (0, document_1.parseDocumentFile)(filePath),
14
+ loadGlob: (pattern, cwd) => (0, document_1.loadGlob)(pattern, cwd),
15
+ };
16
+ }
17
+ function makeSuiteContext(suite) {
18
+ function makeIt(mode) {
19
+ return (name, fn) => suite.children.push({ kind: 'test', name, fn, mode });
20
+ }
21
+ function makeDescribe(mode) {
22
+ return (name, fn) => {
23
+ const child = { kind: 'suite', name, children: [], beforeAll: [], afterAll: [], beforeEach: [], afterEach: [], mode };
24
+ suite.children.push(child);
25
+ fn(makeSuiteContext(child));
26
+ };
27
+ }
28
+ const it = makeIt('normal');
29
+ it.skip = makeIt('skip');
30
+ it.only = makeIt('only');
31
+ const test = makeIt('normal');
32
+ test.skip = makeIt('skip');
33
+ test.only = makeIt('only');
34
+ const describe = makeDescribe('normal');
35
+ describe.skip = makeDescribe('skip');
36
+ describe.only = makeDescribe('only');
37
+ return {
38
+ it,
39
+ test,
40
+ describe,
41
+ beforeAll: fn => suite.beforeAll.push(fn),
42
+ afterAll: fn => suite.afterAll.push(fn),
43
+ beforeEach: fn => suite.beforeEach.push(fn),
44
+ afterEach: fn => suite.afterEach.push(fn),
45
+ };
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // OfflineRunner
49
+ // ---------------------------------------------------------------------------
50
+ class OfflineRunner {
51
+ constructor() {
52
+ this.root = {
53
+ kind: 'suite', name: '<root>', children: [],
54
+ beforeAll: [], afterAll: [], beforeEach: [], afterEach: [], mode: 'normal',
55
+ };
56
+ }
57
+ describe(name, fn) {
58
+ const suite = { kind: 'suite', name, children: [], beforeAll: [], afterAll: [], beforeEach: [], afterEach: [], mode: 'normal' };
59
+ this.root.children.push(suite);
60
+ fn(makeSuiteContext(suite));
61
+ return this;
62
+ }
63
+ run(options = {}) {
64
+ const useJest = options.useJest ?? (typeof describe !== 'undefined' && typeof it !== 'undefined');
65
+ if (useJest) {
66
+ return this._runJest(this.root, options);
67
+ }
68
+ return this._runStandalone(this.root, options);
69
+ }
70
+ // -------------------------------------------------------------------------
71
+ // Jest delegation
72
+ // -------------------------------------------------------------------------
73
+ _runJest(root, _opts) {
74
+ // When Jest globals are present we register describe/it blocks and let
75
+ // Jest drive execution. Return a placeholder result — Jest owns reporting.
76
+ for (const child of root.children) {
77
+ this._registerJestNode(child);
78
+ }
79
+ return { passed: 0, failed: 0, skipped: 0, total: 0, duration: 0, failures: [] };
80
+ }
81
+ _registerJestNode(node) {
82
+ if (node.kind === 'test') {
83
+ const jestIt = node.mode === 'skip' ? it.skip : node.mode === 'only' ? it.only : it;
84
+ jestIt(node.name, async () => {
85
+ await node.fn(makeTestContext());
86
+ });
87
+ }
88
+ else {
89
+ const jestDescribe = node.mode === 'skip' ? describe.skip : node.mode === 'only' ? describe.only : describe;
90
+ jestDescribe(node.name, () => {
91
+ if (node.beforeAll.length)
92
+ beforeAll(async () => { for (const h of node.beforeAll)
93
+ await h(); });
94
+ if (node.afterAll.length)
95
+ afterAll(async () => { for (const h of node.afterAll)
96
+ await h(); });
97
+ if (node.beforeEach.length)
98
+ beforeEach(async () => { for (const h of node.beforeEach)
99
+ await h(); });
100
+ if (node.afterEach.length)
101
+ afterEach(async () => { for (const h of node.afterEach)
102
+ await h(); });
103
+ for (const child of node.children)
104
+ this._registerJestNode(child);
105
+ });
106
+ }
107
+ }
108
+ // -------------------------------------------------------------------------
109
+ // Standalone executor
110
+ // -------------------------------------------------------------------------
111
+ _runStandalone(root, opts) {
112
+ const result = { passed: 0, failed: 0, skipped: 0, total: 0, duration: 0, failures: [] };
113
+ const start = Date.now();
114
+ this._execSuite(root, [], result, opts);
115
+ result.duration = Date.now() - start;
116
+ return result;
117
+ }
118
+ async _execSuite(suite, ancestors, result, opts) {
119
+ if (suite.mode === 'skip') {
120
+ const count = this._countTests(suite);
121
+ result.skipped += count;
122
+ result.total += count;
123
+ return;
124
+ }
125
+ const path = suite.name === '<root>' ? ancestors : [...ancestors, suite.name];
126
+ for (const h of suite.beforeAll)
127
+ await h();
128
+ for (const child of suite.children) {
129
+ if (child.kind === 'suite') {
130
+ await this._execSuite(child, path, result, opts);
131
+ }
132
+ else {
133
+ await this._execTest(child, path, suite, result, opts);
134
+ }
135
+ }
136
+ for (const h of suite.afterAll)
137
+ await h();
138
+ }
139
+ async _execTest(node, suitePath, suite, result, opts) {
140
+ result.total++;
141
+ if (node.mode === 'skip') {
142
+ result.skipped++;
143
+ if (opts.verbose)
144
+ console.log(` SKIP ${[...suitePath, node.name].join(' > ')}`);
145
+ return;
146
+ }
147
+ for (const h of suite.beforeEach)
148
+ await h();
149
+ try {
150
+ await node.fn(makeTestContext());
151
+ result.passed++;
152
+ if (opts.verbose)
153
+ console.log(` PASS ${[...suitePath, node.name].join(' > ')}`);
154
+ }
155
+ catch (err) {
156
+ result.failed++;
157
+ const error = err instanceof Error ? err : new Error(String(err));
158
+ result.failures.push({ suite: suitePath.join(' > '), test: node.name, error });
159
+ if (opts.verbose)
160
+ console.error(` FAIL ${[...suitePath, node.name].join(' > ')}\n ${error.message}`);
161
+ }
162
+ for (const h of suite.afterEach)
163
+ await h();
164
+ }
165
+ _countTests(suite) {
166
+ let n = 0;
167
+ for (const child of suite.children) {
168
+ n += child.kind === 'test' ? 1 : this._countTests(child);
169
+ }
170
+ return n;
171
+ }
172
+ }
173
+ exports.OfflineRunner = OfflineRunner;
174
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/offline/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import type { ValidationResult, Diagnostic } from '../validator/types';
2
+ import type { LintResult, LintDiag } from '../validator/mush-lint';
3
+ export type { ValidationResult, Diagnostic, LintResult, LintDiag };
4
+ export interface OfflineAttr {
5
+ name: string;
6
+ object: string;
7
+ value: string;
8
+ line: number;
9
+ }
10
+ export interface OfflineDocument {
11
+ source: string;
12
+ filename: string;
13
+ attrs: OfflineAttr[];
14
+ validationResult: ValidationResult;
15
+ lintResult: LintResult;
16
+ /** Shorthand: start an assertion chain directly on this document. */
17
+ readonly expect: OfflineExpectChain;
18
+ }
19
+ export interface OfflineExpectChain {
20
+ not: OfflineExpectChain;
21
+ noSyntaxErrors(): OfflineExpectChain;
22
+ noLintErrors(): OfflineExpectChain;
23
+ noLintWarnings(): OfflineExpectChain;
24
+ hasFunction(name: string): OfflineExpectChain;
25
+ hasAttribute(name: string): OfflineExpectChain;
26
+ attributeCount(n: number): OfflineExpectChain;
27
+ noUndefinedFunctions(): OfflineExpectChain;
28
+ noClobber(): OfflineExpectChain;
29
+ isPortable(): OfflineExpectChain;
30
+ hasDiagnostic(code: string): OfflineExpectChain;
31
+ maxAttributeLength(chars?: number): OfflineExpectChain;
32
+ }
33
+ export interface OfflineTestContext {
34
+ parse(source: string, filename?: string): OfflineDocument;
35
+ expect(doc: OfflineDocument): OfflineExpectChain;
36
+ loadFile(filePath: string): OfflineDocument;
37
+ loadGlob(pattern: string, cwd?: string): OfflineDocument[];
38
+ }
39
+ export interface OfflineSuiteContext {
40
+ it: OfflineItFn & {
41
+ skip: OfflineItFn;
42
+ only: OfflineItFn;
43
+ };
44
+ test: OfflineItFn & {
45
+ skip: OfflineItFn;
46
+ only: OfflineItFn;
47
+ };
48
+ describe: OfflineDescribeFn & {
49
+ skip: OfflineDescribeFn;
50
+ only: OfflineDescribeFn;
51
+ };
52
+ beforeAll(fn: OfflineHookFn): void;
53
+ afterAll(fn: OfflineHookFn): void;
54
+ beforeEach(fn: OfflineHookFn): void;
55
+ afterEach(fn: OfflineHookFn): void;
56
+ }
57
+ export type OfflineItFn = (name: string, fn: OfflineTestFn) => void;
58
+ export type OfflineDescribeFn = (name: string, fn: (ctx: OfflineSuiteContext) => void) => void;
59
+ export type OfflineTestFn = (ctx: OfflineTestContext) => void | Promise<void>;
60
+ export type OfflineHookFn = () => void | Promise<void>;
61
+ export interface OfflineRunOptions {
62
+ verbose?: boolean;
63
+ /** Delegate to Jest's describe/it when Jest globals are detected */
64
+ useJest?: boolean;
65
+ }
66
+ export interface OfflineRunResult {
67
+ passed: number;
68
+ failed: number;
69
+ skipped: number;
70
+ total: number;
71
+ duration: number;
72
+ failures: Array<{
73
+ suite: string;
74
+ test: string;
75
+ error: Error;
76
+ }>;
77
+ }
78
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/offline/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/offline/types.ts"],"names":[],"mappings":""}
@@ -1,4 +1,4 @@
1
- import { RunResult } from './runner';
1
+ import type { RunResult } from './runner';
2
2
  import { SnapshotStats } from './snapshots';
3
3
  export declare class Reporter {
4
4
  private readonly verbose;
@@ -7,6 +7,8 @@ export declare class Reporter {
7
7
  testPass(name: string, ms: number, depth: number): void;
8
8
  testFail(name: string, ms: number, depth: number, error: Error): void;
9
9
  testSkip(name: string, depth: number): void;
10
+ testOfflineSkip(name: string, depth: number, behavioralSkips: number): void;
11
+ offlineBanner(reason?: string): void;
10
12
  summary(result: RunResult): void;
11
13
  snapshotSummary(stats: SnapshotStats): void;
12
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuB5C,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;IAWhC,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;CAoB9C"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuB5C,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,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI;IAO3E,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAOpC,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAgBhC,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;CAoB9C"}
package/dist/reporter.js CHANGED
@@ -50,6 +50,20 @@ class Reporter {
50
50
  const indent = ' '.repeat(depth + 1);
51
51
  process.stdout.write(`${indent}${yellow('○')} ${gray(name)}\n`);
52
52
  }
53
+ testOfflineSkip(name, depth, behavioralSkips) {
54
+ if (!this.verbose)
55
+ return;
56
+ const indent = ' '.repeat(depth + 1);
57
+ const skipped = behavioralSkips > 0 ? gray(` (${behavioralSkips} behavioral skipped)`) : '';
58
+ process.stdout.write(`${indent}${cyan('⊘')} ${name}${skipped}\n`);
59
+ }
60
+ offlineBanner(reason) {
61
+ if (!this.verbose)
62
+ return;
63
+ const msg = reason ? ` — ${reason}` : '';
64
+ process.stdout.write(`\n${cyan('⚡')} ${bold('Offline mode')}${gray(msg)}\n`);
65
+ process.stdout.write(`${gray(' Syntax and lint checks run. Behavioral assertions skipped.')}\n`);
66
+ }
53
67
  summary(result) {
54
68
  if (!this.verbose)
55
69
  return;
@@ -60,8 +74,14 @@ class Reporter {
60
74
  parts.push(red(`${result.failed} failed`));
61
75
  if (result.skipped > 0)
62
76
  parts.push(yellow(`${result.skipped} skipped`));
77
+ if (result.offlineSkipped > 0)
78
+ parts.push(cyan(`${result.offlineSkipped} syntax-checked`));
63
79
  parts.push(`${result.total} total`);
64
80
  process.stdout.write(`\nTests: ${parts.join(', ')} ${gray(`(${result.duration}ms)`)}\n`);
81
+ if (result.mode === 'offline') {
82
+ const skipped = result.behavioralSkipped ?? 0;
83
+ process.stdout.write(`${cyan('⚡')} ${gray(`Offline — ${skipped} behavioral assertion${skipped !== 1 ? 's' : ''} skipped (needs server)`)}\n`);
84
+ }
65
85
  this.snapshotSummary(result.snapshots);
66
86
  }
67
87
  snapshotSummary(stats) {
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
package/dist/runner.d.ts CHANGED
@@ -7,6 +7,12 @@ export interface RunResult {
7
7
  passed: number;
8
8
  failed: number;
9
9
  skipped: number;
10
+ /** Tests that ran in offline mode (syntax-checked but behavioral assertions skipped). */
11
+ offlineSkipped: number;
12
+ /** Total behavioral assertions skipped across all offline tests. */
13
+ behavioralSkipped: number;
14
+ /** Whether this run connected to a server or ran entirely offline. */
15
+ mode: 'online' | 'offline';
10
16
  total: number;
11
17
  duration: number;
12
18
  failures: Array<{
@@ -18,6 +24,23 @@ export interface RunResult {
18
24
  }
19
25
  export interface TestContext {
20
26
  expect(expression: string): RhostExpect;
27
+ /**
28
+ * Evaluate N expressions in one pipelined batch and assert on each result.
29
+ *
30
+ * Pass `[expression, expected]` pairs. A string `expected` uses exact
31
+ * match (`.toBe`); a RegExp uses `.test()` (equivalent to `.toMatch`).
32
+ * All failures are collected before throwing, so you see every broken
33
+ * assertion at once rather than stopping at the first.
34
+ *
35
+ * @example
36
+ * await expectAll([
37
+ * [`u(${cg}/F.IS.STAT,int)`, '1'],
38
+ * [`u(${cg}/F.IS.STAT,INT)`, '1'],
39
+ * [`u(${cg}/F.IS.STAT,foo)`, '0'],
40
+ * [`u(${cg}/F.VALIDATE,${p},int,0)`, /minimum/],
41
+ * ]);
42
+ */
43
+ expectAll(cases: Array<[string, string | RegExp]>): Promise<void>;
21
44
  client: RhostClient;
22
45
  world: RhostWorld;
23
46
  /**
@@ -122,6 +145,22 @@ export interface RunnerOptions extends RhostClientOptions {
122
145
  * Default: false
123
146
  */
124
147
  updateSnapshots?: boolean;
148
+ /**
149
+ * Run tests in offline mode — no server connection required.
150
+ *
151
+ * In offline mode:
152
+ * - `world.set()` validates softcode syntax and lint rules immediately,
153
+ * failing the test if errors are found.
154
+ * - `expect(expr).toBe(...)` and all other behavioral matchers are silently
155
+ * skipped — they can't run without a live server.
156
+ * - Syntax errors in `expect()` expressions still fail the test.
157
+ *
158
+ * Also activated by the `RHOST_OFFLINE=1` environment variable.
159
+ *
160
+ * Set to `'auto'` to try connecting first and silently fall back to
161
+ * offline mode if the server is unreachable.
162
+ */
163
+ offline?: boolean | 'auto';
125
164
  }
126
165
  /**
127
166
  * Jest-style test runner for RhostMUSH softcode.
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAmB,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAM7D,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAC/D,SAAS,EAAE,aAAa,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrE;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAChE,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAC/F,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE7F,MAAM,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,KAAK,IAAI,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1G,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IACtC,IAAI,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IACxC,QAAQ,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9D,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACrD,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC9C;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AA+BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAmC;IACnD,iFAAiF;IACjF,OAAO,CAAC,QAAQ,CAA4B;IAM5C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IASvD,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IAgDrD,OAAO,CAAC,WAAW;YAwEL,SAAS;YAqET,QAAQ;IAgFtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,yBAAyB;IAmBjC,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,YAAY;IAoBpB,OAAO,CAAC,mBAAmB;IAa3B;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAmBxB;AAKD,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
package/dist/runner.js CHANGED
@@ -42,6 +42,9 @@ const expect_1 = require("./expect");
42
42
  const world_1 = require("./world");
43
43
  const reporter_1 = require("./reporter");
44
44
  const snapshots_1 = require("./snapshots");
45
+ const mock_client_1 = require("./offline/mock-client");
46
+ const mock_world_1 = require("./offline/mock-world");
47
+ const reduced_expect_1 = require("./offline/reduced-expect");
45
48
  // ---------------------------------------------------------------------------
46
49
  // RhostRunner
47
50
  // ---------------------------------------------------------------------------
@@ -85,12 +88,38 @@ class RhostRunner {
85
88
  process.env['RHOST_UPDATE_SNAPSHOTS'] === '1';
86
89
  const snapshotFile = this.resolveSnapshotFile(options);
87
90
  const snapshots = new snapshots_1.SnapshotManager(snapshotFile, updateMode);
88
- const client = new client_1.RhostClient(options);
89
- await client.connect();
90
- await client.login(options.username, options.password);
91
+ const offlineOpt = options.offline ?? (process.env['RHOST_OFFLINE'] === '1' ? true : undefined);
91
92
  const reporter = new reporter_1.Reporter(verbose);
93
+ let isOffline = offlineOpt === true;
94
+ let client;
95
+ if (offlineOpt === 'auto') {
96
+ try {
97
+ client = new client_1.RhostClient(options);
98
+ await client.connect();
99
+ await client.login(options.username, options.password);
100
+ isOffline = false;
101
+ }
102
+ catch (err) {
103
+ isOffline = true;
104
+ client = new mock_client_1.MockRhostClient();
105
+ const reason = err instanceof Error ? err.message : String(err);
106
+ reporter.offlineBanner(`server unreachable — ${reason}`);
107
+ }
108
+ }
109
+ else if (isOffline) {
110
+ client = new mock_client_1.MockRhostClient();
111
+ reporter.offlineBanner();
112
+ }
113
+ else {
114
+ client = new client_1.RhostClient(options);
115
+ await client.connect();
116
+ await client.login(options.username, options.password);
117
+ }
92
118
  const result = {
93
- passed: 0, failed: 0, skipped: 0, total: 0, duration: 0,
119
+ passed: 0, failed: 0, skipped: 0,
120
+ offlineSkipped: 0, behavioralSkipped: 0,
121
+ mode: isOffline ? 'offline' : 'online',
122
+ total: 0, duration: 0,
94
123
  failures: [],
95
124
  snapshots: { matched: 0, written: 0, updated: 0, obsolete: 0 },
96
125
  };
@@ -103,12 +132,13 @@ class RhostRunner {
103
132
  children: this.topLevel,
104
133
  beforeAll: [], afterAll: [], beforeEach: [], afterEach: [],
105
134
  };
106
- await this._runSuite(root, client, reporter, result, [], 0, [], snapshots);
135
+ await this._runSuite(root, client, reporter, result, [], 0, [], snapshots, isOffline);
107
136
  result.duration = Date.now() - start;
108
137
  snapshots.save();
109
138
  result.snapshots = snapshots.stats();
110
139
  reporter.summary(result);
111
- await client.disconnect();
140
+ if (!isOffline)
141
+ await client.disconnect();
112
142
  return result;
113
143
  }
114
144
  // -------------------------------------------------------------------------
@@ -179,7 +209,7 @@ class RhostRunner {
179
209
  // -------------------------------------------------------------------------
180
210
  // Internal: executing the tree
181
211
  // -------------------------------------------------------------------------
182
- async _runSuite(suite, client, reporter, result, inheritedBeforeEach, depth, suitePath, snapshots) {
212
+ async _runSuite(suite, client, reporter, result, inheritedBeforeEach, depth, suitePath, snapshots, isOffline = false) {
183
213
  // Skip entire suite if marked skip
184
214
  if (suite.mode === 'skip') {
185
215
  this._countSkipped(suite, result, reporter, depth);
@@ -194,7 +224,7 @@ class RhostRunner {
194
224
  // Build the path for this suite's children
195
225
  const childPath = suite.name ? [...suitePath, suite.name] : suitePath;
196
226
  // Run suite-level beforeAll hooks — if one throws, count all suite tests as failures
197
- const hookCtx = { client, world: new world_1.RhostWorld(client) };
227
+ const hookCtx = { client, world: isOffline ? new mock_world_1.OfflineWorldProxy(client) : new world_1.RhostWorld(client) };
198
228
  for (const hook of suite.beforeAll) {
199
229
  try {
200
230
  await hook(hookCtx);
@@ -211,11 +241,11 @@ class RhostRunner {
211
241
  const childWithMode = effectiveMode !== child.mode
212
242
  ? { ...child, mode: effectiveMode }
213
243
  : child;
214
- await this._runSuite(childWithMode, client, reporter, result, combinedBeforeEach, depth + (suite.name ? 1 : 0), childPath, snapshots);
244
+ await this._runSuite(childWithMode, client, reporter, result, combinedBeforeEach, depth + (suite.name ? 1 : 0), childPath, snapshots, isOffline);
215
245
  }
216
246
  else {
217
247
  const skip = !activeChildren.includes(child) || child.mode === 'skip';
218
- await this._runTest(child, skip, client, reporter, result, combinedBeforeEach, suite.afterEach, childPath, depth + (suite.name ? 1 : 0), snapshots);
248
+ await this._runTest(child, skip, client, reporter, result, combinedBeforeEach, suite.afterEach, childPath, depth + (suite.name ? 1 : 0), snapshots, isOffline);
219
249
  }
220
250
  }
221
251
  // Run suite-level afterAll hooks
@@ -223,7 +253,7 @@ class RhostRunner {
223
253
  await hook(hookCtx);
224
254
  }
225
255
  }
226
- async _runTest(test, skip, client, reporter, result, beforeEachHooks, afterEachHooks, suitePath, depth, snapshots) {
256
+ async _runTest(test, skip, client, reporter, result, beforeEachHooks, afterEachHooks, suitePath, depth, snapshots, isOffline = false) {
227
257
  result.total++;
228
258
  if (skip || test.mode === 'skip') {
229
259
  result.skipped++;
@@ -235,16 +265,46 @@ class RhostRunner {
235
265
  const suiteName = suitePath[suitePath.length - 1] ?? '';
236
266
  // Reset snapshot counter for this test
237
267
  snapshots.resetCounter(testKey);
238
- const world = new world_1.RhostWorld(client);
268
+ const world = isOffline
269
+ ? new mock_world_1.OfflineWorldProxy(client)
270
+ : new world_1.RhostWorld(client);
239
271
  const hookCtx = { client, world };
240
272
  const snapshotCtx = {
241
273
  manager: snapshots,
242
274
  testName: testKey,
243
275
  };
276
+ const counter = { behavioralSkips: 0 };
244
277
  const testCtx = {
245
278
  client,
246
279
  world,
247
- expect: (expr) => new expect_1.RhostExpect(client, expr, false, snapshotCtx),
280
+ expect: (expr) => isOffline
281
+ ? new reduced_expect_1.ReducedExpect(expr, false, snapshotCtx, counter)
282
+ : new expect_1.RhostExpect(client, expr, false, snapshotCtx),
283
+ expectAll: async (cases) => {
284
+ if (isOffline) {
285
+ for (const [expr] of cases) {
286
+ await new reduced_expect_1.ReducedExpect(expr, false, snapshotCtx, counter).toBe('');
287
+ }
288
+ return;
289
+ }
290
+ const results = await client.evalAll(cases.map(c => c[0]));
291
+ const failures = [];
292
+ for (let i = 0; i < cases.length; i++) {
293
+ const actual = results[i].replace(/[\r\n]+$/, '');
294
+ const expected = cases[i][1];
295
+ const pass = typeof expected === 'string'
296
+ ? actual === expected
297
+ : expected.test(actual);
298
+ if (!pass) {
299
+ failures.push(` [${i}] expect(${JSON.stringify(cases[i][0])})\n` +
300
+ ` Expected: ${expected instanceof RegExp ? expected : JSON.stringify(expected)}\n` +
301
+ ` Received: ${JSON.stringify(actual)}`);
302
+ }
303
+ }
304
+ if (failures.length > 0) {
305
+ throw new Error(`expectAll: ${failures.length} of ${cases.length} failed:\n${failures.join('\n')}`);
306
+ }
307
+ },
248
308
  preview: (input, opts) => client.preview(input, opts),
249
309
  };
250
310
  // Run inherited + suite beforeEach — if one throws, count as a test failure
@@ -269,8 +329,15 @@ class RhostRunner {
269
329
  const timeoutMs = test.timeout ?? 15000;
270
330
  await this._withTimeout(test.fn(testCtx), timeoutMs, test.name);
271
331
  const ms = Date.now() - t0;
272
- result.passed++;
273
- reporter.testPass(test.name, ms, depth);
332
+ if (isOffline) {
333
+ result.offlineSkipped++;
334
+ result.behavioralSkipped += counter.behavioralSkips;
335
+ reporter.testOfflineSkip(test.name, depth, counter.behavioralSkips);
336
+ }
337
+ else {
338
+ result.passed++;
339
+ reporter.testPass(test.name, ms, depth);
340
+ }
274
341
  }
275
342
  catch (err) {
276
343
  const ms = Date.now() - t0;