@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 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
- const _dirname = _path.default.dirname((0, _url.fileURLToPath)(import.meta.url));
10
- const TEST_OUTPUT_DIR = _path.default.join(_dirname, '../../__temp__');
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
- projectRoot
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 _dirname = _path.default.dirname((0, _url.fileURLToPath)(import.meta.url));
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
- const _dirname = _path.default.dirname((0, _url.fileURLToPath)(import.meta.url));
9
- const TEST_OUTPUT_DIR = _path.default.join(_dirname, '../../__temp__');
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
- if (!this._isValidErrorCategory(errorCategory)) {
75
- _logger.Logger.warn(`Invalid error category: ${errorCategory}. Using 'tool' as default.`);
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: errorCategory,
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
- const errorMessage = error instanceof Error ? error.message : String(error);
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.32-experimental",
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
  }