@zohodesk/unit-testing-framework 0.0.32-experimental → 0.0.35-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/README.md +37 -0
- package/build/index.js +14 -0
- package/build/src/cli/__tests__/parse-args.test.js +45 -0
- package/build/src/cli/bin.js +11 -0
- package/build/src/cli/parse-args.js +56 -0
- package/build/src/cli/run.js +19 -0
- package/build/src/runner/__tests__/jest-runner.test.js +18 -3
- package/build/src/runner/__tests__/runner-base.test.js +53 -0
- package/build/src/runner/jest-runner.js +22 -2
- package/build/src/runner/runner-base.js +4 -1
- package/build/src/utils/__tests__/pipeline-summary-directory.test.js +1 -3
- package/build/src/utils/__tests__/pipeline-summary.test.js +3 -3
- package/build/src/utils/logger.js +4 -0
- package/build/src/utils/pipeline-summary.js +13 -4
- package/package.json +17 -1
package/README.md
CHANGED
|
@@ -17,6 +17,10 @@ unit-testing-framework/
|
|
|
17
17
|
│ ├── runner/
|
|
18
18
|
│ │ ├── jest-runner.js # createJestRunner() – main orchestrator
|
|
19
19
|
│ │ └── runner-base.js # buildArgv() & executeJest() via @jest/core
|
|
20
|
+
│ ├── cli/
|
|
21
|
+
│ │ ├── bin.js # zd-unit-test executable (shebang)
|
|
22
|
+
│ │ ├── run.js # runUnitTestCli() – parse argv + run
|
|
23
|
+
│ │ └── parse-args.js # parseUnitTestArgs() – Jest argv parsing
|
|
20
24
|
│ ├── config/
|
|
21
25
|
│ │ └── default-config.js # getDefaultConfig() – framework defaults
|
|
22
26
|
│ ├── environment/
|
|
@@ -39,6 +43,26 @@ npm install @zohodesk/unit-testing-framework
|
|
|
39
43
|
|
|
40
44
|
All Jest dependencies (`@jest/core`, `jest-environment-jsdom`, `babel-jest`) are bundled — consumers don't need to install Jest separately.
|
|
41
45
|
|
|
46
|
+
Installing the package also provides the `zd-unit-test` CLI command.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## CLI
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Full suite
|
|
54
|
+
npx zd-unit-test
|
|
55
|
+
|
|
56
|
+
# A file, a directory, or related tests — plus any Jest flag
|
|
57
|
+
npx zd-unit-test src/foo/Bar.test.js -u
|
|
58
|
+
npx zd-unit-test src/foo/__tests__ --coverage
|
|
59
|
+
npx zd-unit-test --findRelatedTests src/foo/Bar.js
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
CLI references:
|
|
63
|
+
- [docs/UNIT_TEST_CLI.md](./docs/UNIT_TEST_CLI.md) — standalone `zd-unit-test` command (commands, flags, exit codes, output files).
|
|
64
|
+
- [docs/UNIT_TEST_VIA_TESTING_FRAMEWORK.md](./docs/UNIT_TEST_VIA_TESTING_FRAMEWORK.md) — running unit tests through `ZDTestingFramework test-ut`.
|
|
65
|
+
|
|
42
66
|
---
|
|
43
67
|
|
|
44
68
|
## Quick Start
|
|
@@ -66,6 +90,12 @@ Enable watch mode:
|
|
|
66
90
|
await createJestRunner({ watch: true });
|
|
67
91
|
```
|
|
68
92
|
|
|
93
|
+
Update snapshots (Jest `-u` / `--updateSnapshot`):
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
await createJestRunner({ updateSnapshot: true });
|
|
97
|
+
```
|
|
98
|
+
|
|
69
99
|
---
|
|
70
100
|
|
|
71
101
|
## API
|
|
@@ -77,9 +107,16 @@ await createJestRunner({ watch: true });
|
|
|
77
107
|
| `projectRoot` | `string` | `process.cwd()` | Consumer project root directory |
|
|
78
108
|
| `testPathPattern` | `string` | — | Filter tests by file path pattern |
|
|
79
109
|
| `watch` | `boolean` | `false` | Enable Jest watch mode |
|
|
110
|
+
| ...any Jest CLI option | — | — | All remaining options are forwarded to Jest's `runCLI` as camelCase CLI options, e.g. `updateSnapshot`, `coverage`, `bail`, `testNamePattern`, `runInBand`, `ci`, `verbose`, `maxWorkers` |
|
|
111
|
+
|
|
112
|
+
> Note: `config` cannot be overridden via pass-through — it is managed by the framework (use `configPath` / `ut.config.*` instead).
|
|
113
|
+
|
|
114
|
+
> Fail fast: if `testFiles`/`testPathPattern` resolves to no existing files, the runner throws `No test files matched pattern: <pattern>` (surfaced as `JEST_EXECUTION_ERROR` in the summary) instead of silently running the full suite.
|
|
80
115
|
|
|
81
116
|
Returns: `Promise<AggregatedResult>` — Jest's aggregated results object.
|
|
82
117
|
|
|
118
|
+
See [docs/UNIT_TEST_CLI.md](./docs/UNIT_TEST_CLI.md) for the `ZDTestingFramework unit-test` CLI commands and usage.
|
|
119
|
+
|
|
83
120
|
---
|
|
84
121
|
|
|
85
122
|
## Default Configuration
|
package/build/index.js
CHANGED
|
@@ -9,5 +9,19 @@ Object.defineProperty(exports, "createJestRunner", {
|
|
|
9
9
|
return _jestRunner.default;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
+
Object.defineProperty(exports, "parseUnitTestArgs", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _parseArgs.parseUnitTestArgs;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "runUnitTestCli", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _run.runUnitTestCli;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
12
24
|
var _jestRunner = _interopRequireDefault(require("./src/runner/jest-runner.js"));
|
|
25
|
+
var _run = require("./src/cli/run.js");
|
|
26
|
+
var _parseArgs = require("./src/cli/parse-args.js");
|
|
13
27
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _parseArgs = require("../parse-args.js");
|
|
4
|
+
describe('parseUnitTestArgs', () => {
|
|
5
|
+
test('returns empty options for no args (full suite)', async () => {
|
|
6
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)([]);
|
|
7
|
+
expect(options.testPathPattern).toBeUndefined();
|
|
8
|
+
expect(options.configPath).toBeUndefined();
|
|
9
|
+
});
|
|
10
|
+
test('expands -u alias to updateSnapshot and drops the short alias', async () => {
|
|
11
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['-u']);
|
|
12
|
+
expect(options.updateSnapshot).toBe(true);
|
|
13
|
+
expect(options.u).toBeUndefined();
|
|
14
|
+
});
|
|
15
|
+
test('treats a single positional as testPathPattern', async () => {
|
|
16
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['src/foo/Bar.test.js']);
|
|
17
|
+
expect(options.testPathPattern).toBe('src/foo/Bar.test.js');
|
|
18
|
+
});
|
|
19
|
+
test('joins multiple positionals with commas', async () => {
|
|
20
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['src/a.test.js', 'src/b.test.js']);
|
|
21
|
+
expect(options.testPathPattern).toBe('src/a.test.js,src/b.test.js');
|
|
22
|
+
});
|
|
23
|
+
test('maps --config to configPath (not config)', async () => {
|
|
24
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['--config', './ut.config.js']);
|
|
25
|
+
expect(options.configPath).toBe('./ut.config.js');
|
|
26
|
+
expect(options.config).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
test('drops a leading unit-test subcommand token', async () => {
|
|
29
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['unit-test', 'src/a.test.js', '-u']);
|
|
30
|
+
expect(options.testPathPattern).toBe('src/a.test.js');
|
|
31
|
+
expect(options.updateSnapshot).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
test('forwards arbitrary Jest flags as camelCase options', async () => {
|
|
34
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['--coverage', '-t', 'login', '--runInBand']);
|
|
35
|
+
expect(options.coverage).toBe(true);
|
|
36
|
+
expect(options.testNamePattern).toBe('login');
|
|
37
|
+
expect(options.runInBand).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
test('combines paths and flags', async () => {
|
|
40
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(['src/foo/Bar.test.js', '-u', '-t', 'edge cases']);
|
|
41
|
+
expect(options.testPathPattern).toBe('src/foo/Bar.test.js');
|
|
42
|
+
expect(options.updateSnapshot).toBe(true);
|
|
43
|
+
expect(options.testNamePattern).toBe('edge cases');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var _run = require("./run.js");
|
|
5
|
+
(0, _run.runUnitTestCli)(process.argv.slice(2)).then(result => {
|
|
6
|
+
process.exitCode = result && result.success ? 0 : 1;
|
|
7
|
+
}).catch(error => {
|
|
8
|
+
const message = error && error.stack ? error.stack : String(error);
|
|
9
|
+
process.stderr.write(`${message}\n`);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.parseUnitTestArgs = parseUnitTestArgs;
|
|
7
|
+
var _jestCli = require("jest-cli");
|
|
8
|
+
// Short alias names from Jest's own option table (e.g. 'u', 't', 'c').
|
|
9
|
+
// buildArgv emits both the alias and the canonical camelCase name; we keep
|
|
10
|
+
// only the canonical one so the options object forwarded to the runner is clean.
|
|
11
|
+
const SHORT_ALIASES = new Set();
|
|
12
|
+
for (const def of Object.values(_jestCli.yargsOptions)) {
|
|
13
|
+
const alias = def && def.alias;
|
|
14
|
+
if (!alias) continue;
|
|
15
|
+
(Array.isArray(alias) ? alias : [alias]).forEach(name => SHORT_ALIASES.add(name));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parse raw CLI argv into options for `createJestRunner`.
|
|
20
|
+
*
|
|
21
|
+
* Uses Jest's own argv parser (`jest-cli`), so every Jest flag is supported
|
|
22
|
+
* with full fidelity and the parsing stays in sync when Jest is upgraded —
|
|
23
|
+
* there is no hand-maintained flag list.
|
|
24
|
+
*
|
|
25
|
+
* - A leading `unit-test` subcommand token is dropped if present.
|
|
26
|
+
* - Positional args (files / directories) become `testPathPattern`.
|
|
27
|
+
* - `--config <file>` maps to the runner's own `configPath` param.
|
|
28
|
+
* - All other flags pass through as camelCase Jest CLI options.
|
|
29
|
+
*
|
|
30
|
+
* @param {string[]} rawArgv - argv after `node <script>` (e.g. process.argv.slice(2)).
|
|
31
|
+
* @returns {Promise<Object>} options object for createJestRunner.
|
|
32
|
+
*/
|
|
33
|
+
async function parseUnitTestArgs(rawArgv = []) {
|
|
34
|
+
const args = rawArgv[0] === 'unit-test' ? rawArgv.slice(1) : rawArgv;
|
|
35
|
+
const argv = await (0, _jestCli.buildArgv)(args);
|
|
36
|
+
const {
|
|
37
|
+
_: positionals = [],
|
|
38
|
+
$0,
|
|
39
|
+
config,
|
|
40
|
+
...rest
|
|
41
|
+
} = argv;
|
|
42
|
+
const options = {};
|
|
43
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
44
|
+
if (value === undefined) continue; // unset flags
|
|
45
|
+
if (SHORT_ALIASES.has(key)) continue; // drop short-alias duplicates
|
|
46
|
+
options[key] = value;
|
|
47
|
+
}
|
|
48
|
+
if (config) {
|
|
49
|
+
// Jest `--config <file>` is a config file path → runner's configPath.
|
|
50
|
+
options.configPath = config;
|
|
51
|
+
}
|
|
52
|
+
if (positionals.length) {
|
|
53
|
+
options.testPathPattern = positionals.join(',');
|
|
54
|
+
}
|
|
55
|
+
return options;
|
|
56
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.runUnitTestCli = runUnitTestCli;
|
|
7
|
+
var _jestRunner = _interopRequireDefault(require("../runner/jest-runner.js"));
|
|
8
|
+
var _parseArgs = require("./parse-args.js");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/**
|
|
11
|
+
* Run the unit-test CLI: parse argv, then delegate to createJestRunner.
|
|
12
|
+
*
|
|
13
|
+
* @param {string[]} rawArgv - argv after `node <script>` (e.g. process.argv.slice(2)).
|
|
14
|
+
* @returns {Promise<{ testResults, summary, success }>} runner result.
|
|
15
|
+
*/
|
|
16
|
+
async function runUnitTestCli(rawArgv = []) {
|
|
17
|
+
const options = await (0, _parseArgs.parseUnitTestArgs)(rawArgv);
|
|
18
|
+
return (0, _jestRunner.default)(options);
|
|
19
|
+
}
|
|
@@ -4,10 +4,10 @@ var _jestRunner = _interopRequireDefault(require("../jest-runner.js"));
|
|
|
4
4
|
var _pipelineSummary = require("../../utils/pipeline-summary.js");
|
|
5
5
|
var _fs = _interopRequireDefault(require("fs"));
|
|
6
6
|
var _path = _interopRequireDefault(require("path"));
|
|
7
|
-
var _url = require("url");
|
|
8
7
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// Tests are transpiled to CommonJS (babel `modules: "commonjs"`), so
|
|
9
|
+
// __dirname is available directly; import.meta would be a syntax error.
|
|
10
|
+
const TEST_OUTPUT_DIR = _path.default.join(__dirname, '../../__temp__');
|
|
11
11
|
describe('createJestRunner with Pipeline Summary', () => {
|
|
12
12
|
let tempDir;
|
|
13
13
|
beforeEach(() => {
|
|
@@ -83,6 +83,21 @@ describe('createJestRunner with Pipeline Summary', () => {
|
|
|
83
83
|
const content = JSON.parse(_fs.default.readFileSync(summaryPath, 'utf-8'));
|
|
84
84
|
expect(content.status).toBe('FAILURE');
|
|
85
85
|
});
|
|
86
|
+
test('should fail fast when pattern matches no files (not run full suite)', async () => {
|
|
87
|
+
const summaryPath = _path.default.join(tempDir, 'no-match-summary.json');
|
|
88
|
+
const result = await (0, _jestRunner.default)({
|
|
89
|
+
projectRoot: process.cwd(),
|
|
90
|
+
summaryPath,
|
|
91
|
+
testFiles: 'totally-bogus-path.test.js'
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Must not fall through to running the full suite.
|
|
95
|
+
expect(result.success).toBe(false);
|
|
96
|
+
expect(result.testResults).toBeNull();
|
|
97
|
+
expect(result.summary.status).toBe('FAILURE');
|
|
98
|
+
expect(result.summary.error.code).toBe('JEST_EXECUTION_ERROR');
|
|
99
|
+
expect(result.summary.error.message).toContain('No test files matched pattern: totally-bogus-path.test.js');
|
|
100
|
+
});
|
|
86
101
|
test('should use default summary path if not provided', async () => {
|
|
87
102
|
const result = await (0, _jestRunner.default)({
|
|
88
103
|
projectRoot: process.cwd(),
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _runnerBase = require("../runner-base.js");
|
|
4
|
+
describe('buildArgv', () => {
|
|
5
|
+
const config = {
|
|
6
|
+
testEnvironment: 'jsdom'
|
|
7
|
+
};
|
|
8
|
+
test('should include serialized config and watch flag', () => {
|
|
9
|
+
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
10
|
+
watch: true
|
|
11
|
+
});
|
|
12
|
+
expect(argv.config).toBe(JSON.stringify(config));
|
|
13
|
+
expect(argv.watch).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
test('should append test paths to positional args', () => {
|
|
16
|
+
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
17
|
+
testPathPattern: ['/abs/path/a.test.js', '/abs/path/b.test.js']
|
|
18
|
+
});
|
|
19
|
+
expect(argv._).toEqual(['/abs/path/a.test.js', '/abs/path/b.test.js']);
|
|
20
|
+
});
|
|
21
|
+
test('should forward updateSnapshot to Jest argv', () => {
|
|
22
|
+
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
23
|
+
jestOptions: {
|
|
24
|
+
updateSnapshot: true
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
expect(argv.updateSnapshot).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
test('should forward arbitrary Jest CLI options', () => {
|
|
30
|
+
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
31
|
+
jestOptions: {
|
|
32
|
+
coverage: true,
|
|
33
|
+
bail: 1,
|
|
34
|
+
testNamePattern: 'login',
|
|
35
|
+
runInBand: true,
|
|
36
|
+
ci: true
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
expect(argv.coverage).toBe(true);
|
|
40
|
+
expect(argv.bail).toBe(1);
|
|
41
|
+
expect(argv.testNamePattern).toBe('login');
|
|
42
|
+
expect(argv.runInBand).toBe(true);
|
|
43
|
+
expect(argv.ci).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
test('should not allow jestOptions to override framework-managed config', () => {
|
|
46
|
+
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
47
|
+
jestOptions: {
|
|
48
|
+
config: 'malicious.json'
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
expect(argv.config).toBe(JSON.stringify(config));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -35,7 +35,10 @@ async function createJestRunner(options = {}) {
|
|
|
35
35
|
configPath,
|
|
36
36
|
watch = false,
|
|
37
37
|
summaryPath = _path.default.join(projectRoot, 'test-slices', 'unit-test', 'unit_reports', 'ut-test-summary.json'),
|
|
38
|
-
webUrl = process.env.CI_BUILD_URL || ''
|
|
38
|
+
webUrl = process.env.CI_BUILD_URL || '',
|
|
39
|
+
// Any remaining options are forwarded to Jest as CLI options
|
|
40
|
+
// (e.g. updateSnapshot, coverage, bail, testNamePattern, runInBand).
|
|
41
|
+
...jestOptions
|
|
39
42
|
} = options;
|
|
40
43
|
|
|
41
44
|
// ── 0. Setup pipeline summary (mandatory) ──────────────────────
|
|
@@ -54,14 +57,31 @@ async function createJestRunner(options = {}) {
|
|
|
54
57
|
if (rawPattern) {
|
|
55
58
|
// Normalize: split on comma, resolve each to absolute, keep only files that exist.
|
|
56
59
|
resolvedPaths = resolveTestFiles(rawPattern, projectRoot);
|
|
60
|
+
if (!resolvedPaths) {
|
|
61
|
+
// Fail fast: a pattern that matches nothing must not silently
|
|
62
|
+
// fall through to running the full suite. The throw surfaces
|
|
63
|
+
// through the catch below as JEST_EXECUTION_ERROR in the summary.
|
|
64
|
+
throw new Error(`No test files matched pattern: ${rawPattern}`);
|
|
65
|
+
}
|
|
57
66
|
}
|
|
58
67
|
|
|
68
|
+
// ── Workaround: force HTML report output path ────────────────
|
|
69
|
+
// Overrides any reporters from resolved config so the pipeline
|
|
70
|
+
// always finds the report at a fixed location.
|
|
71
|
+
config.reporters = ['default', ['jest-html-reporter', {
|
|
72
|
+
outputPath: _path.default.join(projectRoot, 'test-slices', 'unit-test', 'unit_reports', 'ut-test-report.html'),
|
|
73
|
+
pageTitle: 'Unit Test Report',
|
|
74
|
+
includeFailureMsg: true,
|
|
75
|
+
includeSuiteFailure: true,
|
|
76
|
+
theme: 'darkTheme'
|
|
77
|
+
}]];
|
|
78
|
+
|
|
59
79
|
// ── 3. Build argv & run Jest ──────────────────────────────────
|
|
60
80
|
const argv = (0, _runnerBase.buildArgv)(config, {
|
|
61
81
|
// Pass explicit files to Jest positional args to avoid testMatch glob filtering.
|
|
62
82
|
testPathPattern: resolvedPaths,
|
|
63
83
|
watch,
|
|
64
|
-
|
|
84
|
+
jestOptions
|
|
65
85
|
});
|
|
66
86
|
const testResults = await (0, _runnerBase.executeJest)(argv, projectRoot);
|
|
67
87
|
|
|
@@ -8,9 +8,12 @@ exports.executeJest = executeJest;
|
|
|
8
8
|
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); }
|
|
9
9
|
function buildArgv(config, {
|
|
10
10
|
testPathPattern,
|
|
11
|
-
watch = false
|
|
11
|
+
watch = false,
|
|
12
|
+
jestOptions = {}
|
|
12
13
|
}) {
|
|
13
14
|
const argv = {
|
|
15
|
+
// Pass through any Jest CLI option (updateSnapshot, coverage, bail, testNamePattern, ...).
|
|
16
|
+
...jestOptions,
|
|
14
17
|
config: JSON.stringify(config),
|
|
15
18
|
watch
|
|
16
19
|
};
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var _fs = _interopRequireDefault(require("fs"));
|
|
4
4
|
var _path = _interopRequireDefault(require("path"));
|
|
5
|
-
var _url = require("url");
|
|
6
5
|
var _pipelineSummary = require("../pipeline-summary.js");
|
|
7
6
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
const
|
|
9
|
-
const TEST_ROOT = _path.default.join(_dirname, '../../__temp__/dir-tests');
|
|
7
|
+
const TEST_ROOT = _path.default.join(__dirname, '../../__temp__/dir-tests');
|
|
10
8
|
describe('Pipeline Summary - Directory Creation Edge Cases', () => {
|
|
11
9
|
afterEach(() => {
|
|
12
10
|
// Cleanup
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var _fs = _interopRequireDefault(require("fs"));
|
|
4
4
|
var _path = _interopRequireDefault(require("path"));
|
|
5
|
-
var _url = require("url");
|
|
6
5
|
var _pipelineSummary = require("../pipeline-summary.js");
|
|
7
6
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
// Own isolated subdir — suites run in parallel and each cleans up its own
|
|
8
|
+
// directory; never the shared __temp__ root, or it races with sibling suites.
|
|
9
|
+
const TEST_OUTPUT_DIR = _path.default.join(__dirname, '../../__temp__/pipeline-summary');
|
|
10
10
|
describe('PipelineSummaryGenerator', () => {
|
|
11
11
|
let summary;
|
|
12
12
|
beforeEach(() => {
|
|
@@ -8,6 +8,7 @@ const COLORS = {
|
|
|
8
8
|
success: '\x1b[36m',
|
|
9
9
|
failure: '\x1b[31m',
|
|
10
10
|
info: '\x1b[33m',
|
|
11
|
+
warn: '\x1b[33m',
|
|
11
12
|
reset: '\x1b[0m'
|
|
12
13
|
};
|
|
13
14
|
|
|
@@ -24,6 +25,9 @@ const Logger = exports.Logger = {
|
|
|
24
25
|
info(message) {
|
|
25
26
|
consoleLogger.log(`${COLORS.info}${message}${COLORS.reset}`);
|
|
26
27
|
},
|
|
28
|
+
warn(message) {
|
|
29
|
+
consoleLogger.warn(`${COLORS.warn}${message}${COLORS.reset}`);
|
|
30
|
+
},
|
|
27
31
|
success(message) {
|
|
28
32
|
consoleLogger.log(`${COLORS.success}${message}${COLORS.reset}`);
|
|
29
33
|
}
|
|
@@ -71,8 +71,10 @@ class PipelineSummaryGenerator {
|
|
|
71
71
|
errors = [],
|
|
72
72
|
result = []
|
|
73
73
|
} = params;
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
let category = errorCategory;
|
|
75
|
+
if (!this._isValidErrorCategory(category)) {
|
|
76
|
+
_logger.Logger.warn(`Invalid error category: ${category}. Using 'tool' as default.`);
|
|
77
|
+
category = ERROR_CATEGORIES.TOOL;
|
|
76
78
|
}
|
|
77
79
|
const response = {
|
|
78
80
|
status: 'FAILURE',
|
|
@@ -80,7 +82,7 @@ class PipelineSummaryGenerator {
|
|
|
80
82
|
web_url: this.webUrl || '',
|
|
81
83
|
error: {
|
|
82
84
|
code: errorCode,
|
|
83
|
-
category
|
|
85
|
+
category,
|
|
84
86
|
message: errorMessage,
|
|
85
87
|
errors: Array.isArray(errors) ? errors : [errors]
|
|
86
88
|
}
|
|
@@ -155,7 +157,14 @@ class PipelineSummaryGenerator {
|
|
|
155
157
|
error,
|
|
156
158
|
exitCode
|
|
157
159
|
} = params;
|
|
158
|
-
|
|
160
|
+
let errorMessage;
|
|
161
|
+
if (error instanceof Error) {
|
|
162
|
+
errorMessage = error.message;
|
|
163
|
+
} else if (error === undefined || error === null) {
|
|
164
|
+
errorMessage = '';
|
|
165
|
+
} else {
|
|
166
|
+
errorMessage = String(error);
|
|
167
|
+
}
|
|
159
168
|
const errorStack = error instanceof Error ? error.stack : null;
|
|
160
169
|
const errors = [{
|
|
161
170
|
tool: toolName,
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zohodesk/unit-testing-framework",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35-experimental",
|
|
4
4
|
"description": "A modular Jest-based unit testing framework",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./build/index.js"
|
|
8
8
|
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"zd-unit-test": "./build/src/cli/bin.js"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"build/"
|
|
11
14
|
],
|
|
@@ -23,13 +26,26 @@
|
|
|
23
26
|
"@babel/preset-env": "7.29.0",
|
|
24
27
|
"@jest/core": "30.2.0",
|
|
25
28
|
"@jest/types": "30.2.0",
|
|
29
|
+
"@testing-library/react": "12.1.5",
|
|
30
|
+
"@types/jest": "29.5.12",
|
|
31
|
+
"@types/react": "16.14.70",
|
|
32
|
+
"@types/react-dom": "16.9.25",
|
|
26
33
|
"babel-jest": "30.2.0",
|
|
34
|
+
"identity-obj-proxy": "3.0.0",
|
|
27
35
|
"jest-environment-jsdom": "30.2.0",
|
|
36
|
+
"jest-transform-stub": "2.0.0",
|
|
28
37
|
"jest-html-reporter": "4.3.0",
|
|
38
|
+
"jest-cli": "30.2.0",
|
|
29
39
|
"jest": "30.2.0"
|
|
30
40
|
},
|
|
31
41
|
"devDependencies": {
|
|
32
42
|
"@babel/cli": "7.28.6",
|
|
33
43
|
"@babel/plugin-transform-modules-commonjs": "7.28.6"
|
|
44
|
+
},
|
|
45
|
+
"jest": {
|
|
46
|
+
"testPathIgnorePatterns": [
|
|
47
|
+
"/node_modules/",
|
|
48
|
+
"/build/"
|
|
49
|
+
]
|
|
34
50
|
}
|
|
35
51
|
}
|