@memberjunction/testing-cli 5.36.0 → 5.38.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/dist/commands/compare.d.ts +36 -11
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +464 -29
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +137 -7
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/suite.d.ts +10 -0
- package/dist/commands/suite.d.ts.map +1 -1
- package/dist/commands/suite.js +94 -6
- package/dist/commands/suite.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +5 -3
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/oracle-module-loader.d.ts +25 -0
- package/dist/utils/oracle-module-loader.d.ts.map +1 -0
- package/dist/utils/oracle-module-loader.js +135 -0
- package/dist/utils/oracle-module-loader.js.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Custom-oracle plugin loader for `--oracles-module=path/to/module.cjs`.
|
|
3
|
+
* @module @memberjunction/testing-cli
|
|
4
|
+
*
|
|
5
|
+
* Lets non-MJ users plug app-specific oracles into the regression suite without
|
|
6
|
+
* modifying TestingFramework itself. The module path is resolved relative to the
|
|
7
|
+
* caller's cwd, dynamically imported (Node resolves CJS + ESM automatically),
|
|
8
|
+
* and every exported `IOracle` is registered on the engine.
|
|
9
|
+
*/
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
/**
|
|
14
|
+
* Duck-type check: an `IOracle` has a string `type` and an async `evaluate`
|
|
15
|
+
* function. We don't `instanceof` against a class because the user's module
|
|
16
|
+
* may import its own copy of the interface (different package version, etc.).
|
|
17
|
+
*/
|
|
18
|
+
function isOracleInstance(value) {
|
|
19
|
+
if (!value || typeof value !== 'object')
|
|
20
|
+
return false;
|
|
21
|
+
const candidate = value;
|
|
22
|
+
return (typeof candidate.type === 'string' &&
|
|
23
|
+
candidate.type.length > 0 &&
|
|
24
|
+
typeof candidate.evaluate === 'function');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Heuristic class-vs-instance check. Classes are functions whose prototype
|
|
28
|
+
* defines `evaluate`. We instantiate them with no args — Oracle implementations
|
|
29
|
+
* shouldn't need constructor arguments since their config flows through `evaluate()`.
|
|
30
|
+
*/
|
|
31
|
+
function isOracleClass(value) {
|
|
32
|
+
if (typeof value !== 'function')
|
|
33
|
+
return false;
|
|
34
|
+
const proto = value.prototype;
|
|
35
|
+
if (!proto)
|
|
36
|
+
return false;
|
|
37
|
+
return typeof proto.evaluate === 'function';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load a user-supplied oracle module and register every `IOracle` export
|
|
41
|
+
* onto the provided TestEngine instance. Returns a summary so the caller
|
|
42
|
+
* can log what happened.
|
|
43
|
+
*
|
|
44
|
+
* Exports recognized:
|
|
45
|
+
* - A class implementing `IOracle` — instantiated with no args.
|
|
46
|
+
* - An object instance with `{ type: string, evaluate: fn }` — used as-is.
|
|
47
|
+
*
|
|
48
|
+
* Anything else (constants, helper functions, unrelated exports) is silently
|
|
49
|
+
* skipped — callers like the CLI surface this as a warning, not an error.
|
|
50
|
+
*
|
|
51
|
+
* @throws if the module file doesn't exist or the import itself fails.
|
|
52
|
+
*/
|
|
53
|
+
export async function loadOraclesModule(modulePath, engine) {
|
|
54
|
+
const absPath = path.resolve(modulePath);
|
|
55
|
+
if (!existsSync(absPath)) {
|
|
56
|
+
throw new Error(`Oracle module not found: ${absPath}`);
|
|
57
|
+
}
|
|
58
|
+
// Dynamic import: this is plugin discovery from a path that's only known
|
|
59
|
+
// at runtime (per CLI flag). Static import isn't possible here. Node's
|
|
60
|
+
// ESM resolver handles both .cjs and .mjs/.js targets when given a
|
|
61
|
+
// file:// URL.
|
|
62
|
+
const fileUrl = pathToFileURL(absPath).href;
|
|
63
|
+
const mod = await import(fileUrl);
|
|
64
|
+
// Walk both the namespace exports (named exports + a synthetic `default`)
|
|
65
|
+
// and any CJS `module.exports = {...}` shape that landed under `.default`.
|
|
66
|
+
// Node's CJS interop exposes the same value at BOTH `mod.A` and
|
|
67
|
+
// `mod.default.A` for a `module.exports = { A }`, so dedupe by reference
|
|
68
|
+
// to avoid double-registering.
|
|
69
|
+
const seen = new Set();
|
|
70
|
+
const candidates = [];
|
|
71
|
+
const consider = (name, value) => {
|
|
72
|
+
if (value === undefined || value === null)
|
|
73
|
+
return;
|
|
74
|
+
if (seen.has(value))
|
|
75
|
+
return;
|
|
76
|
+
seen.add(value);
|
|
77
|
+
candidates.push([name, value]);
|
|
78
|
+
};
|
|
79
|
+
// Walk top-level names first so they win the dedupe "first seen" slot —
|
|
80
|
+
// those are the names the author actually wrote. Then walk into a CJS
|
|
81
|
+
// `module.exports = { … }` namespace if present (it lands under
|
|
82
|
+
// `mod.default` when imported via ESM `import()`). Skip the `default`
|
|
83
|
+
// key itself when it's the CJS wrapper so we don't surface it as a
|
|
84
|
+
// bogus "skipped" candidate.
|
|
85
|
+
const defaultExport = mod.default;
|
|
86
|
+
const defaultIsCjsNamespace = defaultExport &&
|
|
87
|
+
typeof defaultExport === 'object' &&
|
|
88
|
+
defaultExport !== null &&
|
|
89
|
+
!isOracleInstance(defaultExport) &&
|
|
90
|
+
!isOracleClass(defaultExport);
|
|
91
|
+
// CJS-interop synthetic keys Node exposes on imported CJS modules — these
|
|
92
|
+
// aren't real user exports and shouldn't show up in summary.skipped.
|
|
93
|
+
const CJS_NOISE_KEYS = new Set(['module.exports', '__esModule']);
|
|
94
|
+
for (const [name, value] of Object.entries(mod)) {
|
|
95
|
+
if (name === 'default' && defaultIsCjsNamespace)
|
|
96
|
+
continue;
|
|
97
|
+
if (CJS_NOISE_KEYS.has(name))
|
|
98
|
+
continue;
|
|
99
|
+
consider(name, value);
|
|
100
|
+
}
|
|
101
|
+
if (defaultIsCjsNamespace) {
|
|
102
|
+
for (const [name, value] of Object.entries(defaultExport)) {
|
|
103
|
+
consider(`default.${name}`, value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const registered = [];
|
|
107
|
+
const skipped = [];
|
|
108
|
+
for (const [name, value] of candidates) {
|
|
109
|
+
let oracle;
|
|
110
|
+
if (isOracleInstance(value)) {
|
|
111
|
+
oracle = value;
|
|
112
|
+
}
|
|
113
|
+
else if (isOracleClass(value)) {
|
|
114
|
+
try {
|
|
115
|
+
oracle = new value();
|
|
116
|
+
if (!isOracleInstance(oracle)) {
|
|
117
|
+
skipped.push(`${name} (instantiated but missing 'type' or 'evaluate')`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
skipped.push(`${name} (instantiation threw: ${err.message})`);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
skipped.push(name);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
engine.RegisterOracle(oracle);
|
|
131
|
+
registered.push(oracle.type);
|
|
132
|
+
}
|
|
133
|
+
return { modulePath: absPath, registered, skipped };
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=oracle-module-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracle-module-loader.js","sourceRoot":"","sources":["../../src/utils/oracle-module-loader.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/testing-cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.38.0",
|
|
5
5
|
"description": "MemberJunction Testing Framework CLI - Command-line interface for test execution and management",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"@types/debug": "^4.1.12"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@memberjunction/global": "5.
|
|
25
|
-
"@memberjunction/core": "5.
|
|
26
|
-
"@memberjunction/core-entities": "5.
|
|
27
|
-
"@memberjunction/testing-engine": "5.
|
|
28
|
-
"@memberjunction/testing-engine-base": "5.
|
|
29
|
-
"@memberjunction/sqlserver-dataprovider": "5.
|
|
24
|
+
"@memberjunction/global": "5.38.0",
|
|
25
|
+
"@memberjunction/core": "5.38.0",
|
|
26
|
+
"@memberjunction/core-entities": "5.38.0",
|
|
27
|
+
"@memberjunction/testing-engine": "5.38.0",
|
|
28
|
+
"@memberjunction/testing-engine-base": "5.38.0",
|
|
29
|
+
"@memberjunction/sqlserver-dataprovider": "5.38.0",
|
|
30
30
|
"@oclif/core": "^3.27.0",
|
|
31
31
|
"ora-classic": "^5.4.2",
|
|
32
32
|
"chalk": "^5.6.2",
|