@zohodesk/unit-testing-framework 0.0.1-experimental → 0.0.2-experimental
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/index.js +47 -0
- package/{src → dist/src}/config/config-loader.js +31 -49
- package/{src → dist/src}/config/default-config.js +22 -31
- package/{src → dist/src}/environment/globals-inject.js +4 -3
- package/{src → dist/src}/environment/setup.js +8 -3
- package/{src → dist/src}/environment/teardown.js +8 -3
- package/{src → dist/src}/reporters/default-reporter.js +19 -11
- package/{src → dist/src}/reporters/reporter-handler.js +15 -10
- package/{src → dist/src}/runner/jest-runner.js +34 -23
- package/package.json +14 -10
- package/index.js +0 -20
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "createJestRunner", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _jestRunner.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "default", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _jestRunner.default;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "globalSetup", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _setup.default;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "globalTeardown", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _teardown.default;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "loadConfig", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _configLoader.loadConfig;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "resolveReporters", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _reporterHandler.resolveReporters;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var _jestRunner = _interopRequireDefault(require("./src/runner/jest-runner.js"));
|
|
43
|
+
var _configLoader = require("./src/config/config-loader.js");
|
|
44
|
+
var _reporterHandler = require("./src/reporters/reporter-handler.js");
|
|
45
|
+
var _setup = _interopRequireDefault(require("./src/environment/setup.js"));
|
|
46
|
+
var _teardown = _interopRequireDefault(require("./src/environment/teardown.js"));
|
|
47
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.loadConfig = loadConfig;
|
|
7
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
8
|
+
var _path = _interopRequireDefault(require("path"));
|
|
9
|
+
var _url = require("url");
|
|
10
|
+
var _defaultConfig = require("./default-config.js");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
|
|
2
13
|
* config-loader.js
|
|
3
14
|
*
|
|
4
15
|
* Responsible for:
|
|
@@ -9,42 +20,27 @@
|
|
|
9
20
|
* Merge priority (highest → lowest):
|
|
10
21
|
* inline options > consumer config file > framework defaults
|
|
11
22
|
*/
|
|
12
|
-
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import { pathToFileURL } from 'url';
|
|
16
|
-
import { getDefaultConfig } from './default-config.js';
|
|
17
|
-
|
|
18
23
|
/**
|
|
19
24
|
* Deep-merge two plain objects. Arrays are concatenated & de-duped.
|
|
20
25
|
* `source` values override `target` values.
|
|
21
26
|
*/
|
|
22
27
|
function deepMerge(target, source) {
|
|
23
|
-
const output = {
|
|
24
|
-
|
|
28
|
+
const output = {
|
|
29
|
+
...target
|
|
30
|
+
};
|
|
25
31
|
for (const key of Object.keys(source)) {
|
|
26
32
|
const srcVal = source[key];
|
|
27
33
|
const tgtVal = target[key];
|
|
28
|
-
|
|
29
34
|
if (srcVal === undefined) continue;
|
|
30
|
-
|
|
31
35
|
if (Array.isArray(srcVal) && Array.isArray(tgtVal)) {
|
|
32
36
|
// Concatenate and de-duplicate
|
|
33
37
|
output[key] = [...new Set([...tgtVal, ...srcVal])];
|
|
34
|
-
} else if (
|
|
35
|
-
srcVal !== null &&
|
|
36
|
-
typeof srcVal === 'object' &&
|
|
37
|
-
!Array.isArray(srcVal) &&
|
|
38
|
-
tgtVal !== null &&
|
|
39
|
-
typeof tgtVal === 'object' &&
|
|
40
|
-
!Array.isArray(tgtVal)
|
|
41
|
-
) {
|
|
38
|
+
} else if (srcVal !== null && typeof srcVal === 'object' && !Array.isArray(srcVal) && tgtVal !== null && typeof tgtVal === 'object' && !Array.isArray(tgtVal)) {
|
|
42
39
|
output[key] = deepMerge(tgtVal, srcVal);
|
|
43
40
|
} else {
|
|
44
41
|
output[key] = srcVal;
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
|
-
|
|
48
44
|
return output;
|
|
49
45
|
}
|
|
50
46
|
|
|
@@ -56,20 +52,18 @@ function deepMerge(target, source) {
|
|
|
56
52
|
* @returns {Promise<object>} Loaded configuration or empty object.
|
|
57
53
|
*/
|
|
58
54
|
async function loadConfigFile(configPath) {
|
|
59
|
-
if (!
|
|
55
|
+
if (!_fs.default.existsSync(configPath)) {
|
|
60
56
|
return {};
|
|
61
57
|
}
|
|
62
|
-
|
|
63
|
-
const ext = path.extname(configPath).toLowerCase();
|
|
64
|
-
|
|
58
|
+
const ext = _path.default.extname(configPath).toLowerCase();
|
|
65
59
|
if (ext === '.json') {
|
|
66
|
-
const raw =
|
|
60
|
+
const raw = _fs.default.readFileSync(configPath, 'utf-8');
|
|
67
61
|
return JSON.parse(raw);
|
|
68
62
|
}
|
|
69
63
|
|
|
70
64
|
// ESM dynamic import works for .js / .mjs
|
|
71
|
-
const fileUrl = pathToFileURL(configPath).href;
|
|
72
|
-
const mod = await
|
|
65
|
+
const fileUrl = (0, _url.pathToFileURL)(configPath).href;
|
|
66
|
+
const mod = await (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(fileUrl);
|
|
73
67
|
return mod.default ?? mod;
|
|
74
68
|
}
|
|
75
69
|
|
|
@@ -87,23 +81,14 @@ async function loadConfigFile(configPath) {
|
|
|
87
81
|
*/
|
|
88
82
|
function resolveConfigFilePath(projectRoot, explicitPath) {
|
|
89
83
|
if (explicitPath) {
|
|
90
|
-
const abs =
|
|
91
|
-
|
|
92
|
-
: path.resolve(projectRoot, explicitPath);
|
|
93
|
-
return fs.existsSync(abs) ? abs : null;
|
|
84
|
+
const abs = _path.default.isAbsolute(explicitPath) ? explicitPath : _path.default.resolve(projectRoot, explicitPath);
|
|
85
|
+
return _fs.default.existsSync(abs) ? abs : null;
|
|
94
86
|
}
|
|
95
|
-
|
|
96
|
-
const candidates = [
|
|
97
|
-
'jest.unit.config.js',
|
|
98
|
-
'jest.unit.config.mjs',
|
|
99
|
-
'jest.unit.config.json',
|
|
100
|
-
];
|
|
101
|
-
|
|
87
|
+
const candidates = ['jest.unit.config.js', 'jest.unit.config.mjs', 'jest.unit.config.json'];
|
|
102
88
|
for (const name of candidates) {
|
|
103
|
-
const full =
|
|
104
|
-
if (
|
|
89
|
+
const full = _path.default.resolve(projectRoot, name);
|
|
90
|
+
if (_fs.default.existsSync(full)) return full;
|
|
105
91
|
}
|
|
106
|
-
|
|
107
92
|
return null;
|
|
108
93
|
}
|
|
109
94
|
|
|
@@ -116,22 +101,19 @@ function resolveConfigFilePath(projectRoot, explicitPath) {
|
|
|
116
101
|
* @param {object} [options.inlineConfig] - Inline overrides (highest priority).
|
|
117
102
|
* @returns {Promise<import('@jest/types').Config.InitialOptions>}
|
|
118
103
|
*/
|
|
119
|
-
|
|
104
|
+
async function loadConfig({
|
|
120
105
|
projectRoot = process.cwd(),
|
|
121
106
|
configPath,
|
|
122
|
-
inlineConfig = {}
|
|
107
|
+
inlineConfig = {}
|
|
123
108
|
} = {}) {
|
|
124
109
|
// 1. Framework defaults
|
|
125
|
-
const defaults = getDefaultConfig(projectRoot);
|
|
110
|
+
const defaults = (0, _defaultConfig.getDefaultConfig)(projectRoot);
|
|
126
111
|
|
|
127
112
|
// 2. Consumer config file
|
|
128
113
|
const resolvedPath = resolveConfigFilePath(projectRoot, configPath);
|
|
129
|
-
const consumerFileConfig = resolvedPath
|
|
130
|
-
? await loadConfigFile(resolvedPath)
|
|
131
|
-
: {};
|
|
114
|
+
const consumerFileConfig = resolvedPath ? await loadConfigFile(resolvedPath) : {};
|
|
132
115
|
|
|
133
116
|
// 3. Merge: defaults ← consumer file ← inline
|
|
134
117
|
const merged = deepMerge(deepMerge(defaults, consumerFileConfig), inlineConfig);
|
|
135
|
-
|
|
136
118
|
return merged;
|
|
137
|
-
}
|
|
119
|
+
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getDefaultConfig = getDefaultConfig;
|
|
7
|
+
var _path = _interopRequireDefault(require("path"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
1
9
|
/**
|
|
2
10
|
* default-config.js
|
|
3
11
|
*
|
|
@@ -6,11 +14,8 @@
|
|
|
6
14
|
* via their own config file or inline options.
|
|
7
15
|
*/
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = path.dirname(__filename);
|
|
17
|
+
// NOTE: __dirname is available after Babel transpiles ESM → CJS.
|
|
18
|
+
// Do not add import.meta.url workarounds here.
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Returns the default Jest configuration object.
|
|
@@ -20,61 +25,47 @@ const __dirname = path.dirname(__filename);
|
|
|
20
25
|
* @param {string} projectRoot - Absolute path to the consumer project root.
|
|
21
26
|
* @returns {import('@jest/types').Config.InitialOptions}
|
|
22
27
|
*/
|
|
23
|
-
|
|
28
|
+
function getDefaultConfig(projectRoot) {
|
|
24
29
|
return {
|
|
25
30
|
// --------------- Roots & File Discovery ---------------
|
|
26
31
|
// __tests__ folders can be nested anywhere under the project,
|
|
27
32
|
// so we root Jest at the project itself and rely on testMatch
|
|
28
33
|
// to locate **/__tests__/**/* files at any depth.
|
|
29
34
|
roots: [projectRoot],
|
|
30
|
-
testMatch: [
|
|
31
|
-
'**/__tests__/**/*.test.js',
|
|
32
|
-
'**/__tests__/**/*.test.mjs',
|
|
33
|
-
'**/__tests__/**/*.test.ts',
|
|
34
|
-
'**/__tests__/**/*.spec.js',
|
|
35
|
-
'**/__tests__/**/*.spec.mjs',
|
|
36
|
-
'**/__tests__/**/*.spec.ts',
|
|
37
|
-
],
|
|
35
|
+
testMatch: ['**/__tests__/**/*.test.js', '**/__tests__/**/*.test.mjs', '**/__tests__/**/*.test.ts', '**/__tests__/**/*.spec.js', '**/__tests__/**/*.spec.mjs', '**/__tests__/**/*.spec.ts'],
|
|
38
36
|
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/build/'],
|
|
39
|
-
|
|
40
37
|
// --------------- Environment ---------------
|
|
41
38
|
testEnvironment: 'node',
|
|
42
|
-
|
|
43
39
|
// --------------- Transform ---------------
|
|
44
40
|
// ESM-native – no transform needed for plain JS.
|
|
45
41
|
// Consumer can add ts-jest / babel-jest as needed.
|
|
46
42
|
transform: {},
|
|
47
|
-
|
|
48
43
|
// --------------- Coverage ---------------
|
|
49
44
|
collectCoverage: false,
|
|
50
|
-
coverageDirectory:
|
|
45
|
+
coverageDirectory: _path.default.resolve(projectRoot, 'coverage'),
|
|
51
46
|
coverageReporters: ['text', 'lcov', 'clover'],
|
|
52
47
|
coveragePathIgnorePatterns: ['/node_modules/', '/tests/'],
|
|
53
|
-
|
|
54
48
|
// --------------- Reporters ---------------
|
|
55
49
|
reporters: ['default'],
|
|
56
|
-
|
|
57
50
|
// --------------- Parallelism & Performance ---------------
|
|
58
|
-
maxWorkers: '50%',
|
|
51
|
+
maxWorkers: '50%',
|
|
52
|
+
// Use half of available CPUs
|
|
59
53
|
maxConcurrency: 5,
|
|
60
|
-
|
|
61
54
|
// --------------- Timeouts ---------------
|
|
62
|
-
testTimeout: 30_000,
|
|
55
|
+
testTimeout: 30_000,
|
|
56
|
+
// 30 seconds per test
|
|
63
57
|
|
|
64
58
|
// --------------- Setup Files ---------------
|
|
65
59
|
// Injects `jest` into globalThis so ESM test files don't need
|
|
66
60
|
// `import { jest } from '@jest/globals'` manually.
|
|
67
|
-
setupFiles: [
|
|
68
|
-
|
|
61
|
+
setupFiles: [_path.default.resolve(__dirname, '..', 'environment', 'globals-inject.js')],
|
|
69
62
|
// --------------- Global Setup / Teardown ---------------
|
|
70
|
-
globalSetup:
|
|
71
|
-
globalTeardown:
|
|
72
|
-
|
|
63
|
+
globalSetup: _path.default.resolve(__dirname, '..', 'environment', 'setup.js'),
|
|
64
|
+
globalTeardown: _path.default.resolve(__dirname, '..', 'environment', 'teardown.js'),
|
|
73
65
|
// --------------- Module Resolution ---------------
|
|
74
66
|
moduleFileExtensions: ['js', 'mjs', 'ts', 'json', 'node'],
|
|
75
|
-
|
|
76
67
|
// --------------- Misc ---------------
|
|
77
68
|
verbose: true,
|
|
78
|
-
passWithNoTests: true
|
|
69
|
+
passWithNoTests: true
|
|
79
70
|
};
|
|
80
|
-
}
|
|
71
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _globals = require("@jest/globals");
|
|
1
4
|
/**
|
|
2
5
|
* globals-inject.js
|
|
3
6
|
*
|
|
@@ -10,6 +13,4 @@
|
|
|
10
13
|
* installed, making `@jest/globals` available.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
globalThis.jest = jest;
|
|
16
|
+
globalThis.jest = _globals.jest;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = globalSetup;
|
|
1
7
|
/**
|
|
2
8
|
* Global Setup
|
|
3
9
|
*
|
|
@@ -8,9 +14,8 @@
|
|
|
8
14
|
* in their jest.unit.config.js to their own setup file.
|
|
9
15
|
*/
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
async function globalSetup(_globalConfig) {
|
|
12
18
|
// Store start timestamp for reporting
|
|
13
19
|
process.env.__UTL_START_TIME__ = Date.now().toString();
|
|
14
|
-
|
|
15
20
|
console.log('[unit-testing-framework] Global setup complete.');
|
|
16
|
-
}
|
|
21
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = globalTeardown;
|
|
1
7
|
/**
|
|
2
8
|
* Global Teardown
|
|
3
9
|
*
|
|
@@ -8,12 +14,11 @@
|
|
|
8
14
|
* in their jest.unit.config.js to their own teardown file.
|
|
9
15
|
*/
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
async function globalTeardown(_globalConfig) {
|
|
12
18
|
const startTime = Number(process.env.__UTL_START_TIME__ || Date.now());
|
|
13
19
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
14
|
-
|
|
15
20
|
console.log(`[unit-testing-framework] Global teardown complete. Total time: ${elapsed}s`);
|
|
16
21
|
|
|
17
22
|
// Cleanup environment variable
|
|
18
23
|
delete process.env.__UTL_START_TIME__;
|
|
19
|
-
}
|
|
24
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
1
7
|
/**
|
|
2
8
|
* default-reporter.js
|
|
3
9
|
*
|
|
@@ -11,35 +17,36 @@
|
|
|
11
17
|
* - onRunComplete(contexts, results)
|
|
12
18
|
*/
|
|
13
19
|
|
|
14
|
-
|
|
20
|
+
class DefaultReporter {
|
|
15
21
|
constructor(globalConfig, _reporterOptions) {
|
|
16
22
|
this.globalConfig = globalConfig;
|
|
17
23
|
this._startTime = 0;
|
|
18
24
|
}
|
|
19
|
-
|
|
20
25
|
onRunStart(_results, _options) {
|
|
21
26
|
this._startTime = Date.now();
|
|
22
27
|
console.log('\n╔══════════════════════════════════════════╗');
|
|
23
28
|
console.log('║ Unit Testing Framework – Test Run ║');
|
|
24
29
|
console.log('╚══════════════════════════════════════════╝\n');
|
|
25
30
|
}
|
|
26
|
-
|
|
27
31
|
onTestStart(test) {
|
|
28
32
|
console.log(` ▶ Running: ${test.path}`);
|
|
29
33
|
}
|
|
30
|
-
|
|
31
34
|
onTestResult(_test, testResult, _aggregatedResults) {
|
|
32
|
-
const {
|
|
35
|
+
const {
|
|
36
|
+
numPassingTests,
|
|
37
|
+
numFailingTests,
|
|
38
|
+
numPendingTests
|
|
39
|
+
} = testResult;
|
|
33
40
|
const icon = numFailingTests > 0 ? '✖' : '✔';
|
|
34
|
-
console.log(
|
|
35
|
-
` ${icon} Passed: ${numPassingTests} Failed: ${numFailingTests} Skipped: ${numPendingTests}`
|
|
36
|
-
);
|
|
41
|
+
console.log(` ${icon} Passed: ${numPassingTests} Failed: ${numFailingTests} Skipped: ${numPendingTests}`);
|
|
37
42
|
}
|
|
38
|
-
|
|
39
43
|
onRunComplete(_contexts, results) {
|
|
40
44
|
const elapsed = ((Date.now() - this._startTime) / 1000).toFixed(2);
|
|
41
|
-
const {
|
|
42
|
-
|
|
45
|
+
const {
|
|
46
|
+
numPassedTests,
|
|
47
|
+
numFailedTests,
|
|
48
|
+
numTotalTests
|
|
49
|
+
} = results;
|
|
43
50
|
console.log('\n──────────────────────────────────────────');
|
|
44
51
|
console.log(` Total: ${numTotalTests}`);
|
|
45
52
|
console.log(` Passed: ${numPassedTests}`);
|
|
@@ -48,3 +55,4 @@ export default class DefaultReporter {
|
|
|
48
55
|
console.log('──────────────────────────────────────────\n');
|
|
49
56
|
}
|
|
50
57
|
}
|
|
58
|
+
exports.default = DefaultReporter;
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.resolveReporters = resolveReporters;
|
|
7
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
1
9
|
/**
|
|
2
10
|
* reporter-handler.js
|
|
3
11
|
*
|
|
@@ -10,14 +18,11 @@
|
|
|
10
18
|
* - [reporterPath, options] tuples
|
|
11
19
|
*/
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = path.dirname(__filename);
|
|
21
|
+
// NOTE: __dirname is available after Babel transpiles ESM → CJS.
|
|
22
|
+
// Do not add import.meta.url workarounds here.
|
|
18
23
|
|
|
19
24
|
const BUILTIN_ALIASES = {
|
|
20
|
-
'framework-default':
|
|
25
|
+
'framework-default': _nodePath.default.resolve(__dirname, 'default-reporter.js')
|
|
21
26
|
};
|
|
22
27
|
|
|
23
28
|
/**
|
|
@@ -44,7 +49,7 @@ function resolveEntry(entry, projectRoot) {
|
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
// Relative paths → resolve from consumer project root
|
|
47
|
-
const abs =
|
|
52
|
+
const abs = _nodePath.default.resolve(projectRoot, name);
|
|
48
53
|
return opts ? [abs, opts] : abs;
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -55,6 +60,6 @@ function resolveEntry(entry, projectRoot) {
|
|
|
55
60
|
* @param {string} projectRoot - Consumer project root.
|
|
56
61
|
* @returns {Array<string | [string, object]>}
|
|
57
62
|
*/
|
|
58
|
-
|
|
59
|
-
return reporters.map(
|
|
60
|
-
}
|
|
63
|
+
function resolveReporters(reporters = ['default'], projectRoot = process.cwd()) {
|
|
64
|
+
return reporters.map(entry => resolveEntry(entry, projectRoot));
|
|
65
|
+
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = createJestRunner;
|
|
7
|
+
var _path = _interopRequireDefault(require("path"));
|
|
8
|
+
var _configLoader = require("../config/config-loader.js");
|
|
9
|
+
var _reporterHandler = require("../reporters/reporter-handler.js");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
|
|
2
12
|
* jest-runner.js
|
|
3
13
|
*
|
|
4
14
|
* Core module that runs Jest programmatically via @jest/core's runCLI.
|
|
@@ -7,11 +17,6 @@
|
|
|
7
17
|
* import createJestRunner from 'unit-testing-framework';
|
|
8
18
|
* await createJestRunner({ projectRoot: process.cwd() });
|
|
9
19
|
*/
|
|
10
|
-
|
|
11
|
-
import path from 'path';
|
|
12
|
-
import { loadConfig } from '../config/config-loader.js';
|
|
13
|
-
import { resolveReporters } from '../reporters/reporter-handler.js';
|
|
14
|
-
|
|
15
20
|
/**
|
|
16
21
|
* @typedef {object} RunnerOptions
|
|
17
22
|
* @property {string} [projectRoot] - Absolute path to the consumer project (default: cwd).
|
|
@@ -31,7 +36,7 @@ import { resolveReporters } from '../reporters/reporter-handler.js';
|
|
|
31
36
|
* @param {RunnerOptions} [options={}]
|
|
32
37
|
* @returns {Promise<import('@jest/core').AggregatedResult>} Jest aggregated results.
|
|
33
38
|
*/
|
|
34
|
-
|
|
39
|
+
async function createJestRunner(options = {}) {
|
|
35
40
|
const {
|
|
36
41
|
projectRoot = process.cwd(),
|
|
37
42
|
configPath,
|
|
@@ -41,14 +46,14 @@ export default async function createJestRunner(options = {}) {
|
|
|
41
46
|
verbose,
|
|
42
47
|
maxWorkers,
|
|
43
48
|
silent,
|
|
44
|
-
watch = false
|
|
49
|
+
watch = false
|
|
45
50
|
} = options;
|
|
46
51
|
|
|
47
52
|
// ── 1. Load & merge configuration ──────────────────────────
|
|
48
|
-
const mergedConfig = await loadConfig({
|
|
53
|
+
const mergedConfig = await (0, _configLoader.loadConfig)({
|
|
49
54
|
projectRoot,
|
|
50
55
|
configPath,
|
|
51
|
-
inlineConfig
|
|
56
|
+
inlineConfig
|
|
52
57
|
});
|
|
53
58
|
|
|
54
59
|
// ── 2. Apply CLI-level overrides ───────────────────────────
|
|
@@ -58,17 +63,24 @@ export default async function createJestRunner(options = {}) {
|
|
|
58
63
|
if (silent !== undefined) mergedConfig.silent = silent;
|
|
59
64
|
|
|
60
65
|
// ── 3. Resolve reporters ───────────────────────────────────
|
|
61
|
-
mergedConfig.reporters = resolveReporters(mergedConfig.reporters, projectRoot);
|
|
66
|
+
mergedConfig.reporters = (0, _reporterHandler.resolveReporters)(mergedConfig.reporters, projectRoot);
|
|
62
67
|
|
|
63
68
|
// ── 4. Build argv for runCLI ───────────────────────────────
|
|
64
69
|
// runCLI expects a yargs-like argv object.
|
|
65
|
-
const argv = buildArgv(mergedConfig, {
|
|
70
|
+
const argv = buildArgv(mergedConfig, {
|
|
71
|
+
testFiles,
|
|
72
|
+
watch,
|
|
73
|
+
projectRoot
|
|
74
|
+
});
|
|
66
75
|
|
|
67
76
|
// ── 5. Run Jest programmatically ───────────────────────────
|
|
68
77
|
// Lazy-import to keep startup fast; @jest/core is heavy.
|
|
69
|
-
const {
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
const {
|
|
79
|
+
runCLI
|
|
80
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('@jest/core')));
|
|
81
|
+
const {
|
|
82
|
+
results
|
|
83
|
+
} = await runCLI(argv, [projectRoot]);
|
|
72
84
|
|
|
73
85
|
// ── 6. Return results for the caller to inspect ────────────
|
|
74
86
|
return results;
|
|
@@ -84,31 +96,30 @@ export default async function createJestRunner(options = {}) {
|
|
|
84
96
|
* @param {string} extra.projectRoot
|
|
85
97
|
* @returns {object}
|
|
86
98
|
*/
|
|
87
|
-
function buildArgv(config, {
|
|
99
|
+
function buildArgv(config, {
|
|
100
|
+
testFiles,
|
|
101
|
+
watch,
|
|
102
|
+
projectRoot
|
|
103
|
+
}) {
|
|
88
104
|
const argv = {
|
|
89
105
|
// Serialise the config so Jest uses our merged config
|
|
90
106
|
// instead of searching for jest.config.* files.
|
|
91
107
|
config: JSON.stringify(config),
|
|
92
|
-
|
|
93
108
|
// Project root for resolution
|
|
94
109
|
rootDir: projectRoot,
|
|
95
|
-
|
|
96
110
|
// Flags
|
|
97
111
|
watch: watch,
|
|
98
112
|
watchAll: false,
|
|
99
113
|
ci: process.env.CI === 'true',
|
|
100
|
-
|
|
101
114
|
// Pass-through values that CLI users might expect
|
|
102
115
|
verbose: config.verbose ?? true,
|
|
103
116
|
collectCoverage: config.collectCoverage ?? false,
|
|
104
117
|
passWithNoTests: config.passWithNoTests ?? true,
|
|
105
118
|
maxWorkers: config.maxWorkers ?? '50%',
|
|
106
119
|
silent: config.silent ?? false,
|
|
107
|
-
|
|
108
120
|
// Do not search for config files automatically
|
|
109
121
|
_: testFiles ?? [],
|
|
110
|
-
$0: 'unit-testing-framework'
|
|
122
|
+
$0: 'unit-testing-framework'
|
|
111
123
|
};
|
|
112
|
-
|
|
113
124
|
return argv;
|
|
114
|
-
}
|
|
125
|
+
}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zohodesk/unit-testing-framework",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2-experimental",
|
|
4
4
|
"description": "A modular Jest-based unit testing framework",
|
|
5
|
-
"
|
|
6
|
-
"main": "./index.js",
|
|
5
|
+
"main": "./dist/index.js",
|
|
7
6
|
"exports": {
|
|
8
|
-
".": "./index.js",
|
|
9
|
-
"./config": "./src/config/config-loader.js",
|
|
10
|
-
"./reporters": "./src/reporters/reporter-handler.js",
|
|
11
|
-
"./runner": "./src/runner/jest-runner.js"
|
|
7
|
+
".": "./dist/index.js",
|
|
8
|
+
"./config": "./dist/src/config/config-loader.js",
|
|
9
|
+
"./reporters": "./dist/src/reporters/reporter-handler.js",
|
|
10
|
+
"./runner": "./dist/src/runner/jest-runner.js"
|
|
12
11
|
},
|
|
13
12
|
"files": [
|
|
14
|
-
"
|
|
15
|
-
"src/**/*.js"
|
|
13
|
+
"dist/"
|
|
16
14
|
],
|
|
17
15
|
"scripts": {
|
|
18
16
|
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
|
19
|
-
"lint": "eslint src/ index.js"
|
|
17
|
+
"lint": "eslint src/ index.js",
|
|
18
|
+
"build": "babel src -d dist/src && babel index.js --out-file dist/index.js",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [],
|
|
22
22
|
"author": "",
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
"jest": "30.2.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"@babel/cli": "^7.28.6",
|
|
34
|
+
"@babel/core": "^7.29.0",
|
|
35
|
+
"@babel/plugin-transform-modules-commonjs": "^7.28.6",
|
|
36
|
+
"@babel/preset-env": "^7.29.0",
|
|
33
37
|
"jest": "30.2.0"
|
|
34
38
|
}
|
|
35
39
|
}
|
package/index.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* unit-testing-framework
|
|
3
|
-
*
|
|
4
|
-
* A modular Jest-based unit testing framework that plugs into
|
|
5
|
-
* existing CLI pipelines via a single exported function.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* import createJestRunner from 'unit-testing-framework';
|
|
9
|
-
* const results = await createJestRunner({ configPath: './jest.config.js' });
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export { default as createJestRunner } from './src/runner/jest-runner.js';
|
|
13
|
-
export { loadConfig } from './src/config/config-loader.js';
|
|
14
|
-
export { resolveReporters } from './src/reporters/reporter-handler.js';
|
|
15
|
-
export { default as globalSetup } from './src/environment/setup.js';
|
|
16
|
-
export { default as globalTeardown } from './src/environment/teardown.js';
|
|
17
|
-
|
|
18
|
-
// Default export for simple consumer usage:
|
|
19
|
-
// import createJestRunner from 'unit-testing-framework';
|
|
20
|
-
export { default } from './src/runner/jest-runner.js';
|