kizu 0.0.0-autorel
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/LICENSE +21 -0
- package/README.md +124 -0
- package/bin/cli.js +3 -0
- package/dist/assertions/AssertionError.d.ts +3 -0
- package/dist/assertions/AssertionError.js +11 -0
- package/dist/assertions/equal.d.ts +2 -0
- package/dist/assertions/equal.js +55 -0
- package/dist/assertions/errorsEquivalent.d.ts +3 -0
- package/dist/assertions/errorsEquivalent.js +49 -0
- package/dist/assertions/fail.d.ts +2 -0
- package/dist/assertions/fail.js +7 -0
- package/dist/assertions/index.d.ts +10 -0
- package/dist/assertions/index.js +22 -0
- package/dist/assertions/isFalse.d.ts +2 -0
- package/dist/assertions/isFalse.js +49 -0
- package/dist/assertions/isTrue.d.ts +2 -0
- package/dist/assertions/isTrue.js +49 -0
- package/dist/assertions/pass.d.ts +2 -0
- package/dist/assertions/pass.js +7 -0
- package/dist/assertions/throws.d.ts +2 -0
- package/dist/assertions/throws.js +16 -0
- package/dist/calculateFinalResults.d.ts +9 -0
- package/dist/calculateFinalResults.js +21 -0
- package/dist/getSpecFiles.d.ts +1 -0
- package/dist/getSpecFiles.js +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/isTestPassing.d.ts +6 -0
- package/dist/isTestPassing.js +15 -0
- package/dist/lib/deepStrictEqual.d.ts +1 -0
- package/dist/lib/deepStrictEqual.js +60 -0
- package/dist/lib/diff.d.ts +2 -0
- package/dist/lib/diff.js +32 -0
- package/dist/lib/toResult.d.ts +4 -0
- package/dist/lib/toResult.js +34 -0
- package/dist/output.d.ts +5 -0
- package/dist/output.js +84 -0
- package/dist/run.d.ts +12 -0
- package/dist/run.js +52 -0
- package/dist/shouldExitWithError.d.ts +2 -0
- package/dist/shouldExitWithError.js +7 -0
- package/dist/sortTestResults.d.ts +3 -0
- package/dist/sortTestResults.js +32 -0
- package/dist/test.d.ts +16 -0
- package/dist/test.js +44 -0
- package/dist/workerPool.d.ts +2 -0
- package/dist/workerPool.js +36 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Marc H. Weiner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source srcset="docs/kitest-logo-light.svg" media="(prefers-color-scheme: light)">
|
|
3
|
+
<source srcset="docs/kitest-logo-dark.svg" media="(prefers-color-scheme: dark)">
|
|
4
|
+
<img src="docs/kitest-logo-light.svg" alt="Logo" style="margin: 0 0 10px" size="250">
|
|
5
|
+
</picture>
|
|
6
|
+
|
|
7
|
+
[](https://github.com/mhweiner/kitest/actions)
|
|
8
|
+
[]()
|
|
9
|
+
[](https://conventionalcommits.org)
|
|
10
|
+
[](https://github.com/mhweiner/autorel)
|
|
11
|
+
|
|
12
|
+
**kitest** is a fast, minimalist test runner for TypeScript and JavaScript, with a small, easy-to-learn API that lets you focus on your tests — not your tooling.
|
|
13
|
+
|
|
14
|
+
Fast, minimal, precise, safe, atomic, and easy to use.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
**🚀 Fast & Reliable**
|
|
19
|
+
- Multi-process parallel test runner. Each test file is run in its own process/runtime for performance and isolation benefits. _Use on a multicore machine for best results._
|
|
20
|
+
- Optimized for speed and simplicity.
|
|
21
|
+
- Minimal dependencies.
|
|
22
|
+
|
|
23
|
+
**😀 Easy to Use**
|
|
24
|
+
- Very simple functional [assertion API](docs/api.md). No need to learn a DSL or framework.
|
|
25
|
+
- Built-in [powerful diff visualization tool](#visual-diff-tool) and clean, organized output.
|
|
26
|
+
- Failed tests are easy to find, grouped at the end of the output.
|
|
27
|
+
- Errors or unhandled promise rejections are buffered and grouped under the test file in the output. This helps you know where they came from.
|
|
28
|
+
- Clean stack traces with no extra noise.
|
|
29
|
+
|
|
30
|
+
**🛡 Defensive**
|
|
31
|
+
- Uncaught errors and unhandled promise rejections will cause the test to fail.
|
|
32
|
+
- Any spec files without tests, or tests without assertions, result in a failed test.
|
|
33
|
+
- Strict and deep equality comparison by default.
|
|
34
|
+
|
|
35
|
+
**🔒 Out-of-the-box Typescript support**
|
|
36
|
+
- No special configuration needed, and no plugins to install.
|
|
37
|
+
- Works great with [c8](https://github.com/bcoe/c8) for code coverage.
|
|
38
|
+
- Handles compilation errors gracefully.
|
|
39
|
+
|
|
40
|
+
# Quick Examples
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import {test} from '@kitest/kitest';
|
|
44
|
+
|
|
45
|
+
// Basic test
|
|
46
|
+
|
|
47
|
+
function greet(name: string): string {
|
|
48
|
+
return `hello, ${name}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test('greet()', (assert) => {
|
|
52
|
+
assert.equal(hello('world'), 'hello, world');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Error handling
|
|
56
|
+
|
|
57
|
+
function throwError(): never {
|
|
58
|
+
throw new Error('oops');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test('throwError()', (assert) => {
|
|
62
|
+
assert.throws(() => throwError(), /oops/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Async test
|
|
66
|
+
|
|
67
|
+
async function fetchData(): Promise<string> {
|
|
68
|
+
return Promise.resolve('data');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
test('fetchData()', async (assert) => {
|
|
72
|
+
const data = await fetchData();
|
|
73
|
+
assert.equal(data, 'data');
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
# Table of Contents
|
|
78
|
+
|
|
79
|
+
- [Getting Started](docs/gettingStarted.md)
|
|
80
|
+
- [Examples](#examples)
|
|
81
|
+
- [API](docs/api.md)
|
|
82
|
+
- [Visual Diff Tool](docs/visualDiff.md)
|
|
83
|
+
- [Best Practices](docs/bestPractices.md)
|
|
84
|
+
- [Inspiration, Philosophy & Attribution](docs/inspiration.md)
|
|
85
|
+
- [FAQ](docs/faq.md)
|
|
86
|
+
- [Support, Feedback, and Contributions](#support-feedback-and-contributions)
|
|
87
|
+
- [Sponsorship](#sponsorship)
|
|
88
|
+
- [License](LICENSE)
|
|
89
|
+
|
|
90
|
+
# Getting Started
|
|
91
|
+
|
|
92
|
+
To install and get started with `kitest`, see our [Getting Started](docs/gettingStarted.md) guide.
|
|
93
|
+
|
|
94
|
+
# Examples
|
|
95
|
+
|
|
96
|
+
See the [examples](examples) and [src](src) folders for more examples.
|
|
97
|
+
|
|
98
|
+
# Support, feedback, and contributions
|
|
99
|
+
|
|
100
|
+
- Star this repo if you like it!
|
|
101
|
+
- Submit an [issue](https://github.com/mhweiner/kitest/issues) with your problem, feature request or bug report
|
|
102
|
+
- Issue a PR against `main` and request review. Make sure all tests pass and coverage is good.
|
|
103
|
+
- Write about this project in your blog, tweet about it, or share it with your friends!
|
|
104
|
+
|
|
105
|
+
# Sponsorship
|
|
106
|
+
<br>
|
|
107
|
+
<picture>
|
|
108
|
+
<source srcset="docs/aeroview-white.svg" media="(prefers-color-scheme: dark)">
|
|
109
|
+
<source srcset="docs/aeroview-black.svg" media="(prefers-color-scheme: light)">
|
|
110
|
+
<img src="docs/aeroview-black.svg" alt="Logo" height="20">
|
|
111
|
+
</picture>
|
|
112
|
+
<br>
|
|
113
|
+
|
|
114
|
+
Aeroview is a lightning-fast, developer-friendly, AI-powered logging IDE. Get started for free at [https://aeroview.io](https://aeroview.io).
|
|
115
|
+
|
|
116
|
+
Want to sponsor this project? [Reach out](mailto:mhweiner234@gmail.com?subject=I%20want%20to%20sponsor%20kitest).
|
|
117
|
+
|
|
118
|
+
# Other useful libraries
|
|
119
|
+
|
|
120
|
+
- [autorel](https://github.com/mhweiner/autorel): Automate semantic releases based on conventional commits. Similar to semantic-release but much simpler.
|
|
121
|
+
- [brek](https://github.com/mhweiner/brek): A powerful yet simple configuration library for Node.js. It’s structured, typed, and designed for dynamic configuration loading, making it perfect for securely managing secrets (e.g., AWS Secrets Manager).
|
|
122
|
+
- [jsout](https://github.com/mhweiner/jsout): A Syslog-compatible, small, and simple logger for Typescript/Javascript projects.
|
|
123
|
+
- [cjs-mock](https://github.com/mhweiner/cjs-mock): NodeJS module mocking for CJS (CommonJS) modules for unit testing purposes.
|
|
124
|
+
- [typura](https://github.com/aeroview/typura): Simple and extensible runtime input validation for TS/JS, written in TS.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssertionError = void 0;
|
|
4
|
+
class AssertionError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = this.constructor.name;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.AssertionError = AssertionError;
|
|
11
|
+
//# sourceMappingURL=AssertionError.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.equal = equal;
|
|
30
|
+
const deepStrictEqual_1 = require("../lib/deepStrictEqual");
|
|
31
|
+
const util = __importStar(require("util"));
|
|
32
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
33
|
+
const AssertionError_1 = require("./AssertionError");
|
|
34
|
+
const diff_1 = require("../lib/diff");
|
|
35
|
+
function equal(assertions, actual, expected, description) {
|
|
36
|
+
const descWithDefault = description || 'equal()';
|
|
37
|
+
if ((0, deepStrictEqual_1.deepStrictEqual)(actual, expected)) {
|
|
38
|
+
assertions.push({ pass: true, description: descWithDefault });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const diagnostic = createDiagnostic(actual, expected);
|
|
42
|
+
const stack = new AssertionError_1.AssertionError('not deeply and strictly equivalent').stack;
|
|
43
|
+
assertions.push({ pass: false, description: descWithDefault, diagnostic, stack });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function createDiagnostic(actual, expected) {
|
|
47
|
+
const diff = (0, diff_1.getDiff)(actual, expected);
|
|
48
|
+
const actualStr = util.inspect(actual, { colors: true, depth: null });
|
|
49
|
+
const expectedStr = util.inspect(expected, { colors: true, depth: null });
|
|
50
|
+
const sectionActual = `${kleur_1.default.grey().bold('Actual:')}\n\n${actualStr}`;
|
|
51
|
+
const sectionExpected = `\n\n${kleur_1.default.grey().bold('Expected:')}\n\n${expectedStr}`;
|
|
52
|
+
const sectionDiff = diff && `\n\n${kleur_1.default.grey().bold('Diff:')}\n\n${diff}`;
|
|
53
|
+
return `${sectionActual}${sectionExpected}${sectionDiff}\n`;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=equal.js.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Assertion } from '../test';
|
|
2
|
+
export declare function errorsEquivalent(assertions: Assertion[], actualErr: Error, expectedErr: Error | RegExp, description?: string): void;
|
|
3
|
+
export declare function createDiagnosticRegexMismatch(actualErrMsg: string, expectedRegEx: RegExp): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.errorsEquivalent = errorsEquivalent;
|
|
7
|
+
exports.createDiagnosticRegexMismatch = createDiagnosticRegexMismatch;
|
|
8
|
+
const serialize_error_1 = require("serialize-error");
|
|
9
|
+
const equal_1 = require("./equal");
|
|
10
|
+
const pass_1 = require("./pass");
|
|
11
|
+
const AssertionError_1 = require("./AssertionError");
|
|
12
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
13
|
+
function errorsEquivalent(assertions, actualErr, expectedErr, description) {
|
|
14
|
+
if (!(actualErr instanceof Error))
|
|
15
|
+
throw new Error('actualErr is not an instance of Error');
|
|
16
|
+
if (!(expectedErr instanceof Error) && !(expectedErr instanceof RegExp))
|
|
17
|
+
throw new Error('expectedErr is not an instance of Error or a RegExp');
|
|
18
|
+
if (expectedErr instanceof RegExp) {
|
|
19
|
+
if (!expectedErr.test(actualErr.message)) {
|
|
20
|
+
const diagnostic = createDiagnosticRegexMismatch(actualErr.message, expectedErr);
|
|
21
|
+
const stack = new AssertionError_1.AssertionError('Expected error message does not match').stack;
|
|
22
|
+
assertions.push({ pass: false, description: description !== null && description !== void 0 ? description : 'errorsEquivalent()', diagnostic, stack });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
(0, pass_1.pass)(assertions, description !== null && description !== void 0 ? description : 'errorsEquivalent()');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
compareErrorObjects(assertions, actualErr, expectedErr, description);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function compareErrorObjects(assertions, actualErr, expectedErr, description) {
|
|
33
|
+
if (!(actualErr instanceof Error))
|
|
34
|
+
throw new Error('actualErr is not an instance of Error');
|
|
35
|
+
if (!(expectedErr instanceof Error) && !(expectedErr instanceof RegExp))
|
|
36
|
+
throw new Error('expectedErr is not an instance of Error or a RegExp');
|
|
37
|
+
const actualErrSerialized = (0, serialize_error_1.serializeError)(actualErr);
|
|
38
|
+
const expectedErrSerialized = (0, serialize_error_1.serializeError)(expectedErr);
|
|
39
|
+
// ignore stack traces
|
|
40
|
+
actualErrSerialized === null || actualErrSerialized === void 0 ? true : delete actualErrSerialized.stack;
|
|
41
|
+
expectedErrSerialized === null || expectedErrSerialized === void 0 ? true : delete expectedErrSerialized.stack;
|
|
42
|
+
(0, equal_1.equal)(assertions, actualErrSerialized, expectedErrSerialized, description || 'errorsEquivalent()');
|
|
43
|
+
}
|
|
44
|
+
function createDiagnosticRegexMismatch(actualErrMsg, expectedRegEx) {
|
|
45
|
+
const actual = `${kleur_1.default.grey().bold('Actual Error Message:')}\n\n${actualErrMsg}`;
|
|
46
|
+
const expected = `\n\n${kleur_1.default.grey().bold('Expected RegEx:')}\n\n${expectedRegEx}`;
|
|
47
|
+
return `${actual}${expected}\n\n`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=errorsEquivalent.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fail = fail;
|
|
4
|
+
function fail(assertions, description) {
|
|
5
|
+
assertions.push({ pass: false, description: description !== null && description !== void 0 ? description : 'fail()' });
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=fail.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Assertion } from '../test';
|
|
2
|
+
export declare function createAssertionPredicates(assertions: Assertion[]): {
|
|
3
|
+
pass: (description?: string) => void;
|
|
4
|
+
fail: (description?: string) => void;
|
|
5
|
+
isTrue: (condition: boolean, description?: string) => void;
|
|
6
|
+
isFalse: (condition: boolean, description?: string) => void;
|
|
7
|
+
equal: (actual: any, expected: any, description?: string) => void;
|
|
8
|
+
errorsEquivalent: (actual: any, expected: any, description?: string) => void;
|
|
9
|
+
throws: (experiment: () => any, expectedErr: Error | RegExp, description?: string) => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAssertionPredicates = createAssertionPredicates;
|
|
4
|
+
const errorsEquivalent_1 = require("./errorsEquivalent");
|
|
5
|
+
const equal_1 = require("./equal");
|
|
6
|
+
const throws_1 = require("./throws");
|
|
7
|
+
const isTrue_1 = require("./isTrue");
|
|
8
|
+
const isFalse_1 = require("./isFalse");
|
|
9
|
+
const fail_1 = require("./fail");
|
|
10
|
+
const pass_1 = require("./pass");
|
|
11
|
+
function createAssertionPredicates(assertions) {
|
|
12
|
+
return {
|
|
13
|
+
pass: (description) => ((0, pass_1.pass)(assertions, description)),
|
|
14
|
+
fail: (description) => ((0, fail_1.fail)(assertions, description)),
|
|
15
|
+
isTrue: (condition, description) => ((0, isTrue_1.isTrue)(assertions, condition, description)),
|
|
16
|
+
isFalse: (condition, description) => ((0, isFalse_1.isFalse)(assertions, condition, description)),
|
|
17
|
+
equal: (actual, expected, description) => ((0, equal_1.equal)(assertions, actual, expected, description)),
|
|
18
|
+
errorsEquivalent: (actual, expected, description) => ((0, errorsEquivalent_1.errorsEquivalent)(assertions, actual, expected, description)),
|
|
19
|
+
throws: (experiment, expectedErr, description) => ((0, throws_1.throws)(assertions, experiment, expectedErr, description)),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.isFalse = isFalse;
|
|
30
|
+
const util = __importStar(require("util"));
|
|
31
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
32
|
+
const AssertionError_1 = require("./AssertionError");
|
|
33
|
+
function isFalse(assertions, condition, description) {
|
|
34
|
+
const descWithDefault = description || 'isFalse()';
|
|
35
|
+
if (!condition) {
|
|
36
|
+
assertions.push({ pass: true, description: descWithDefault });
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const diagnostic = createDiagnostic(condition);
|
|
40
|
+
const stack = new AssertionError_1.AssertionError('is not false').stack;
|
|
41
|
+
assertions.push({ pass: false, description: descWithDefault, diagnostic, stack });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function createDiagnostic(actual) {
|
|
45
|
+
const actualStr = util.inspect(actual, { colors: true, depth: null });
|
|
46
|
+
const sectionActual = `${kleur_1.default.grey().bold('Actual:')}\n\n${actualStr}`;
|
|
47
|
+
return `${sectionActual}\n`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=isFalse.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.isTrue = isTrue;
|
|
30
|
+
const util = __importStar(require("util"));
|
|
31
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
32
|
+
const AssertionError_1 = require("./AssertionError");
|
|
33
|
+
function isTrue(assertions, condition, description) {
|
|
34
|
+
const descWithDefault = description || 'isTrue()';
|
|
35
|
+
if (condition) {
|
|
36
|
+
assertions.push({ pass: true, description: descWithDefault });
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const diagnostic = createDiagnostic(condition);
|
|
40
|
+
const stack = new AssertionError_1.AssertionError('is not true').stack;
|
|
41
|
+
assertions.push({ pass: false, description: descWithDefault, diagnostic, stack });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function createDiagnostic(actual) {
|
|
45
|
+
const actualStr = util.inspect(actual, { colors: true, depth: null });
|
|
46
|
+
const sectionActual = `${kleur_1.default.grey().bold('Actual:')}\n\n${actualStr}`;
|
|
47
|
+
return `${sectionActual}\n`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=isTrue.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pass = pass;
|
|
4
|
+
function pass(assertions, description) {
|
|
5
|
+
assertions.push({ pass: true, description: description !== null && description !== void 0 ? description : 'pass()' });
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=pass.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.throws = throws;
|
|
4
|
+
const toResult_1 = require("../lib/toResult");
|
|
5
|
+
const errorsEquivalent_1 = require("./errorsEquivalent");
|
|
6
|
+
function throws(assertions, experiment, expectedErr, description) {
|
|
7
|
+
if (typeof experiment !== 'function')
|
|
8
|
+
throw new Error('experiment must be a function');
|
|
9
|
+
if (!(expectedErr instanceof Error) && !(expectedErr instanceof RegExp))
|
|
10
|
+
throw new Error('expectedErr is not an instance of Error or a RegExp');
|
|
11
|
+
const [actualErr] = (0, toResult_1.toResult)(experiment);
|
|
12
|
+
if (!actualErr)
|
|
13
|
+
throw new Error('experiment did not throw an error');
|
|
14
|
+
(0, errorsEquivalent_1.errorsEquivalent)(assertions, actualErr, expectedErr, description || 'throws()');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=throws.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TestResultsByFile } from './run';
|
|
2
|
+
export declare function calculateFinalResults(specFiles: string[], testResults: TestResultsByFile): {
|
|
3
|
+
numFiles: number;
|
|
4
|
+
numTests: number;
|
|
5
|
+
numSuccessfulTests: number;
|
|
6
|
+
filesWithNoTests: string[];
|
|
7
|
+
numAssertions: number;
|
|
8
|
+
numSuccessfulAssertions: number;
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateFinalResults = calculateFinalResults;
|
|
4
|
+
const isTestPassing_1 = require("./isTestPassing");
|
|
5
|
+
function calculateFinalResults(specFiles, testResults) {
|
|
6
|
+
const numFiles = Object.keys(testResults).length;
|
|
7
|
+
const filesWithNoTests = specFiles.reduce((files, filename) => (testResults[filename] ? files : files.concat([filename])), []);
|
|
8
|
+
const numTests = Object.values(testResults).reduce((acc, results) => acc + results.length, 0);
|
|
9
|
+
const numSuccessfulTests = Object.values(testResults).reduce((acc, results) => (acc + results.reduce((acc, test) => (acc + ((0, isTestPassing_1.isTestPassing)(test) ? 1 : 0)), 0)), 0);
|
|
10
|
+
const numAssertions = Object.values(testResults).reduce((acc, results) => (acc + results.reduce((acc, test) => acc + test.assertions.length, 0)), 0);
|
|
11
|
+
const numSuccessfulAssertions = Object.values(testResults).reduce((acc, results) => (acc + results.reduce((acc, test) => (acc + test.assertions.reduce((acc, assertion) => acc + (assertion.pass ? 1 : 0), 0)), 0)), 0);
|
|
12
|
+
return {
|
|
13
|
+
numFiles,
|
|
14
|
+
numTests,
|
|
15
|
+
numSuccessfulTests,
|
|
16
|
+
filesWithNoTests,
|
|
17
|
+
numAssertions,
|
|
18
|
+
numSuccessfulAssertions,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=calculateFinalResults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSpecFiles(): Promise<string[]>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getSpecFiles = getSpecFiles;
|
|
16
|
+
const tiny_glob_1 = __importDefault(require("tiny-glob"));
|
|
17
|
+
function getSpecFiles() {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
return (0, tiny_glob_1.default)(process.argv[2]);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=getSpecFiles.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './test';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./test"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTestPassing = isTestPassing;
|
|
4
|
+
/**
|
|
5
|
+
* All assertions must pass, with no errors, and at least one assertion.
|
|
6
|
+
* @param test
|
|
7
|
+
*/
|
|
8
|
+
function isTestPassing(test) {
|
|
9
|
+
if (!test.assertions.length)
|
|
10
|
+
return false;
|
|
11
|
+
if (test.error)
|
|
12
|
+
return false;
|
|
13
|
+
return test.assertions.reduce((pass, assertion) => pass && assertion.pass, true);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=isTestPassing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function deepStrictEqual(obj1: any, obj2: any): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deepStrictEqual = deepStrictEqual;
|
|
4
|
+
/* eslint-disable max-lines-per-function */
|
|
5
|
+
function deepStrictEqual(obj1, obj2) {
|
|
6
|
+
if (obj1 === obj2)
|
|
7
|
+
return true;
|
|
8
|
+
if (isPrimitive(obj1) && isPrimitive(obj2))
|
|
9
|
+
return obj1 === obj2;
|
|
10
|
+
if (Array.isArray(obj1) !== Array.isArray(obj2))
|
|
11
|
+
return false;
|
|
12
|
+
if (typeof obj1 !== typeof obj2)
|
|
13
|
+
return false;
|
|
14
|
+
if (obj1 === null || obj2 === null)
|
|
15
|
+
return false;
|
|
16
|
+
// Handle Map objects
|
|
17
|
+
if (obj1 instanceof Map && obj2 instanceof Map) {
|
|
18
|
+
if (obj1.size !== obj2.size)
|
|
19
|
+
return false;
|
|
20
|
+
for (const [key, value] of obj1) {
|
|
21
|
+
if (!obj2.has(key) || !deepStrictEqual(value, obj2.get(key)))
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
// Handle Set objects
|
|
27
|
+
if (obj1 instanceof Set && obj2 instanceof Set) {
|
|
28
|
+
if (obj1.size !== obj2.size)
|
|
29
|
+
return false;
|
|
30
|
+
for (const item of obj1) {
|
|
31
|
+
let matchFound = false;
|
|
32
|
+
for (const item2 of obj2) {
|
|
33
|
+
if (deepStrictEqual(item, item2)) {
|
|
34
|
+
matchFound = true;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!matchFound)
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
// Handle object comparison
|
|
44
|
+
const keys1 = Object.keys(obj1);
|
|
45
|
+
const keys2 = Object.keys(obj2);
|
|
46
|
+
if (keys1.length !== keys2.length)
|
|
47
|
+
return false;
|
|
48
|
+
for (const key of keys1) {
|
|
49
|
+
if (!Object.prototype.hasOwnProperty.call(obj2, key))
|
|
50
|
+
return false;
|
|
51
|
+
if (!deepStrictEqual(obj1[key], obj2[key]))
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Helper function to check if a value is a primitive
|
|
57
|
+
function isPrimitive(value) {
|
|
58
|
+
return value !== Object(value);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=deepStrictEqual.js.map
|
package/dist/lib/diff.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDiff = getDiff;
|
|
7
|
+
exports.stringVisualDiff = stringVisualDiff;
|
|
8
|
+
const deep_object_diff_1 = require("deep-object-diff");
|
|
9
|
+
const diff_1 = require("diff");
|
|
10
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
11
|
+
const node_util_1 = require("node:util");
|
|
12
|
+
function getDiff(actual, expected) {
|
|
13
|
+
if (actual === expected)
|
|
14
|
+
return '';
|
|
15
|
+
if (typeof actual === 'string' && typeof expected === 'string') {
|
|
16
|
+
return stringVisualDiff(actual, expected);
|
|
17
|
+
}
|
|
18
|
+
else if (typeof actual === 'object' && typeof expected === 'object') {
|
|
19
|
+
return (0, node_util_1.inspect)((0, deep_object_diff_1.diff)(actual, expected), {
|
|
20
|
+
colors: true,
|
|
21
|
+
depth: null,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function stringVisualDiff(actual, expected) {
|
|
29
|
+
return (0, diff_1.diffChars)(actual, expected).reduce((str, part) => str + (part.added ? kleur_1.default.bgGreen().black(part.value) : part.removed
|
|
30
|
+
? kleur_1.default.bgRed().white(part.value) : kleur_1.default.white(part.value)), '');
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type Result<E, T> = [E] | [undefined, T];
|
|
2
|
+
export type PromiseResult<E, T> = Promise<Result<E, T>>;
|
|
3
|
+
export declare function toResult<E extends Error, T>(executable: () => T): Result<E, T>;
|
|
4
|
+
export declare function toResultAsync<E extends Error, T>(p: Promise<T>): PromiseResult<E, T>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.toResult = toResult;
|
|
13
|
+
exports.toResultAsync = toResultAsync;
|
|
14
|
+
function toResult(executable) {
|
|
15
|
+
try {
|
|
16
|
+
const result = executable();
|
|
17
|
+
return [undefined, result];
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return [e];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function toResultAsync(p) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
try {
|
|
26
|
+
const result = yield p;
|
|
27
|
+
return [undefined, result];
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
return [e];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=toResult.js.map
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TestResultsByFile, FinalResults } from './run';
|
|
2
|
+
import { TestResults } from './test';
|
|
3
|
+
export declare function printResultsByFile(resultsByFile: TestResultsByFile): void;
|
|
4
|
+
export declare function printFileResults(filename: string, tests: TestResults[]): void;
|
|
5
|
+
export declare function printSummary(finalResults: FinalResults): void;
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.printResultsByFile = printResultsByFile;
|
|
7
|
+
exports.printFileResults = printFileResults;
|
|
8
|
+
exports.printSummary = printSummary;
|
|
9
|
+
const kleur_1 = __importDefault(require("kleur"));
|
|
10
|
+
const isTestPassing_1 = require("./isTestPassing");
|
|
11
|
+
const serialize_error_1 = require("serialize-error");
|
|
12
|
+
const sortTestResults_1 = require("./sortTestResults");
|
|
13
|
+
const log = console.log;
|
|
14
|
+
const successSymbol = kleur_1.default.green('✔');
|
|
15
|
+
const failureSymbol = kleur_1.default.red('✖');
|
|
16
|
+
const hr = kleur_1.default.gray('\n────────────────────────────────\n');
|
|
17
|
+
const noTestErrorTpl = (files) => kleur_1.default.red().bold(`
|
|
18
|
+
Error: ${files.length} spec file(s) have no tests. This could indicate a compilation error
|
|
19
|
+
(ie. Typescript), or an early runtime error. All spec files must have at least one test.
|
|
20
|
+
The following spec files do not have any attempted or completed tests:
|
|
21
|
+
|
|
22
|
+
${files.join(', ')}
|
|
23
|
+
`);
|
|
24
|
+
function printResultsByFile(resultsByFile) {
|
|
25
|
+
const sortedResults = (0, sortTestResults_1.sortTestResults)(resultsByFile);
|
|
26
|
+
for (const [filename, tests] of sortedResults) {
|
|
27
|
+
printFileResults(filename, tests);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function printFileResults(filename, tests) {
|
|
31
|
+
const doesFileHaveFailures = tests.some((test) => !(0, isTestPassing_1.isTestPassing)(test));
|
|
32
|
+
const header = `${kleur_1.default.underline().blue(filename)} ${doesFileHaveFailures ? failureSymbol : successSymbol}\n`;
|
|
33
|
+
log(header);
|
|
34
|
+
tests.forEach(((test) => {
|
|
35
|
+
log(`${test.description} ${(0, isTestPassing_1.isTestPassing)(test) ? successSymbol : failureSymbol}`);
|
|
36
|
+
test.assertions.forEach((assertion) => {
|
|
37
|
+
log(kleur_1.default.gray(` ${assertion.description} ${assertion.pass ? successSymbol : failureSymbol}`));
|
|
38
|
+
!assertion.pass && printFailedAssertionDiag(assertion);
|
|
39
|
+
});
|
|
40
|
+
test.error && printError(test.error);
|
|
41
|
+
log('');
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
function printError(serializedError) {
|
|
45
|
+
log(hr);
|
|
46
|
+
log((0, serialize_error_1.deserializeError)(serializedError));
|
|
47
|
+
log(hr);
|
|
48
|
+
}
|
|
49
|
+
function printFailedAssertionDiag(assertion) {
|
|
50
|
+
if (!assertion.diagnostic && !assertion.stack)
|
|
51
|
+
return;
|
|
52
|
+
log(hr);
|
|
53
|
+
assertion.diagnostic && log(assertion.diagnostic);
|
|
54
|
+
assertion.stack && log(kleur_1.default.grey(filterStackTrace(assertion.stack)));
|
|
55
|
+
log(hr);
|
|
56
|
+
}
|
|
57
|
+
function printSummary(finalResults) {
|
|
58
|
+
const successRate = finalResults.numSuccessfulTests / finalResults.numTests;
|
|
59
|
+
const assertionSuccessRate = finalResults.numSuccessfulAssertions / finalResults.numAssertions;
|
|
60
|
+
const numFilesWithNoTests = finalResults.filesWithNoTests.length;
|
|
61
|
+
if (assertionSuccessRate === 1) {
|
|
62
|
+
log(kleur_1.default.bold().green(`${successSymbol} ${finalResults.numSuccessfulAssertions}/${finalResults.numAssertions} assertions passed`));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
log(kleur_1.default.bold().red(`${failureSymbol} ${finalResults.numSuccessfulAssertions}/${finalResults.numAssertions} assertions passed`));
|
|
66
|
+
}
|
|
67
|
+
if (successRate === 1) {
|
|
68
|
+
log(kleur_1.default.bold().green(`${successSymbol} ${finalResults.numSuccessfulTests}/${finalResults.numTests} tests passed`));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
log(kleur_1.default.bold().red(`${failureSymbol} ${finalResults.numSuccessfulTests}/${finalResults.numTests} tests passed`));
|
|
72
|
+
}
|
|
73
|
+
numFilesWithNoTests && log(noTestErrorTpl(finalResults.filesWithNoTests));
|
|
74
|
+
}
|
|
75
|
+
function filterStackTrace(stack) {
|
|
76
|
+
const ignoreRegex = [
|
|
77
|
+
/at Generator.next \(<anonymous>\)/,
|
|
78
|
+
/at new Promise \(<anonymous>\)/,
|
|
79
|
+
/assertions\/index.[ts|js]{2}/,
|
|
80
|
+
/\/kitest\/[src|dist]{3,4}\/test.[ts|js]{2}/,
|
|
81
|
+
].reduce((combined, exp) => (new RegExp(`${combined.source}|${exp.source}`)), new RegExp('a^'));
|
|
82
|
+
return stack.split('\n').reduce((acc, line) => (!ignoreRegex.test(line) ? acc.concat([line]) : acc), []).join('\n');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=output.js.map
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TestResults } from './test';
|
|
2
|
+
export type TestResultsByFile = {
|
|
3
|
+
[file: string]: TestResults[];
|
|
4
|
+
};
|
|
5
|
+
export type FinalResults = {
|
|
6
|
+
numFiles: number;
|
|
7
|
+
numTests: number;
|
|
8
|
+
numSuccessfulTests: number;
|
|
9
|
+
filesWithNoTests: string[];
|
|
10
|
+
numAssertions: number;
|
|
11
|
+
numSuccessfulAssertions: number;
|
|
12
|
+
};
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const ora_1 = __importDefault(require("ora"));
|
|
16
|
+
const output_1 = require("./output");
|
|
17
|
+
const calculateFinalResults_1 = require("./calculateFinalResults");
|
|
18
|
+
const workerPool_1 = require("./workerPool");
|
|
19
|
+
const shouldExitWithError_1 = require("./shouldExitWithError");
|
|
20
|
+
const getSpecFiles_1 = require("./getSpecFiles");
|
|
21
|
+
const testResultsByFile = {};
|
|
22
|
+
let numCompletedTests = 0;
|
|
23
|
+
const status = (0, ora_1.default)();
|
|
24
|
+
function start() {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
const specFiles = yield (0, getSpecFiles_1.getSpecFiles)();
|
|
27
|
+
console.log(`Found ${specFiles.length} spec files.\n`);
|
|
28
|
+
status.start('Running tests...');
|
|
29
|
+
yield (0, workerPool_1.workerPool)(specFiles, addTestResults);
|
|
30
|
+
finish(specFiles);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Add TestResults and update status.
|
|
35
|
+
* @param file
|
|
36
|
+
* @param results
|
|
37
|
+
*/
|
|
38
|
+
function addTestResults(file, results) {
|
|
39
|
+
numCompletedTests = numCompletedTests + 1;
|
|
40
|
+
testResultsByFile[file] = (testResultsByFile[file] || []).concat([results]);
|
|
41
|
+
status.text = `${numCompletedTests} tests completed.`;
|
|
42
|
+
}
|
|
43
|
+
function finish(specFiles) {
|
|
44
|
+
status.stop();
|
|
45
|
+
const finalResults = (0, calculateFinalResults_1.calculateFinalResults)(specFiles, testResultsByFile);
|
|
46
|
+
(0, output_1.printResultsByFile)(testResultsByFile);
|
|
47
|
+
(0, output_1.printSummary)(finalResults);
|
|
48
|
+
if ((0, shouldExitWithError_1.shouldExitWithError)(finalResults))
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
start().catch(console.log.bind(console));
|
|
52
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shouldExitWithError = shouldExitWithError;
|
|
4
|
+
function shouldExitWithError(finalResults) {
|
|
5
|
+
return !!finalResults.filesWithNoTests.length || finalResults.numSuccessfulTests / finalResults.numTests !== 1;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=shouldExitWithError.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sortTestResults = sortTestResults;
|
|
4
|
+
const isTestPassing_1 = require("./isTestPassing");
|
|
5
|
+
function sortTestResults(resultsByFile) {
|
|
6
|
+
const sortedResults = new Map();
|
|
7
|
+
const passingFiles = [];
|
|
8
|
+
const failingFiles = [];
|
|
9
|
+
// Separate passing and failing files
|
|
10
|
+
for (const [file, tests] of Object.entries(resultsByFile)) {
|
|
11
|
+
const hasFailingTests = tests.some((test) => !(0, isTestPassing_1.isTestPassing)(test));
|
|
12
|
+
if (hasFailingTests) {
|
|
13
|
+
failingFiles.push([file, tests]);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
passingFiles.push([file, tests]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Sort passing files first, failing files last
|
|
20
|
+
const sortedFiles = [...passingFiles, ...failingFiles];
|
|
21
|
+
for (const [file, tests] of sortedFiles) {
|
|
22
|
+
// Sort tests: passing tests first, failing tests last
|
|
23
|
+
const sortedTests = [...tests].sort((a, b) => Number((0, isTestPassing_1.isTestPassing)(b)) - Number((0, isTestPassing_1.isTestPassing)(a)));
|
|
24
|
+
// Sort assertions inside each test: passing assertions first
|
|
25
|
+
for (const test of sortedTests) {
|
|
26
|
+
test.assertions.sort((a, b) => Number(b.pass) - Number(a.pass));
|
|
27
|
+
}
|
|
28
|
+
sortedResults.set(file, sortedTests);
|
|
29
|
+
}
|
|
30
|
+
return sortedResults;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=sortTestResults.js.map
|
package/dist/test.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createAssertionPredicates } from './assertions';
|
|
2
|
+
import { ErrorObject } from 'serialize-error';
|
|
3
|
+
export type TestResults = {
|
|
4
|
+
description: string;
|
|
5
|
+
assertions: Assertion[];
|
|
6
|
+
error?: ErrorObject;
|
|
7
|
+
};
|
|
8
|
+
export type Assertion = {
|
|
9
|
+
pass: boolean;
|
|
10
|
+
description: string;
|
|
11
|
+
diagnostic?: string;
|
|
12
|
+
stack?: string;
|
|
13
|
+
};
|
|
14
|
+
type AssertionAPI = ReturnType<typeof createAssertionPredicates>;
|
|
15
|
+
export declare function test(description: string, experiment: (assert: AssertionAPI) => void): Promise<void>;
|
|
16
|
+
export {};
|
package/dist/test.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.test = test;
|
|
13
|
+
const assertions_1 = require("./assertions");
|
|
14
|
+
const serialize_error_1 = require("serialize-error");
|
|
15
|
+
const toResult_1 = require("./lib/toResult");
|
|
16
|
+
process.on('unhandledRejection', (err) => {
|
|
17
|
+
sendTestResults({
|
|
18
|
+
description: 'Unhandled Promise Rejection',
|
|
19
|
+
assertions: [],
|
|
20
|
+
error: (0, serialize_error_1.serializeError)(err),
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
function test(description, experiment) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const assertions = [];
|
|
26
|
+
const expAsync = () => __awaiter(this, void 0, void 0, function* () { return experiment((0, assertions_1.createAssertionPredicates)(assertions)); });
|
|
27
|
+
const [err] = yield (0, toResult_1.toResultAsync)(expAsync());
|
|
28
|
+
if (err) {
|
|
29
|
+
sendTestResults({
|
|
30
|
+
description,
|
|
31
|
+
assertions: [],
|
|
32
|
+
error: (0, serialize_error_1.serializeError)(err),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
sendTestResults({ description, assertions });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function sendTestResults(results) {
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
process.send(results);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.workerPool = workerPool;
|
|
4
|
+
const os_1 = require("os");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const toResult_1 = require("./lib/toResult");
|
|
7
|
+
const numCores = (0, os_1.cpus)().length; // will be the size of our worker pool
|
|
8
|
+
let numWorkers = 0;
|
|
9
|
+
let currentSpecFileIndex = 0;
|
|
10
|
+
function workerPool(specFiles, addTestResults) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
function next() {
|
|
13
|
+
if (currentSpecFileIndex >= specFiles.length && numWorkers === 0)
|
|
14
|
+
resolve();
|
|
15
|
+
if (currentSpecFileIndex >= specFiles.length)
|
|
16
|
+
return;
|
|
17
|
+
if (numWorkers >= numCores)
|
|
18
|
+
return;
|
|
19
|
+
const file = specFiles[currentSpecFileIndex];
|
|
20
|
+
const [err, worker] = (0, toResult_1.toResult)(() => (0, child_process_1.fork)(file));
|
|
21
|
+
if (err) {
|
|
22
|
+
return reject(new Error(`failed to create worker for ${file}`));
|
|
23
|
+
}
|
|
24
|
+
numWorkers++;
|
|
25
|
+
currentSpecFileIndex++;
|
|
26
|
+
worker.on('close', () => {
|
|
27
|
+
numWorkers--;
|
|
28
|
+
next();
|
|
29
|
+
});
|
|
30
|
+
worker.on('message', (msg) => addTestResults(file, msg));
|
|
31
|
+
next();
|
|
32
|
+
}
|
|
33
|
+
next();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=workerPool.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kizu",
|
|
3
|
+
"version": "0.0.0-autorel",
|
|
4
|
+
"description": "An easy-to-use, fast, and defensive Typescript/Javascript test runner designed to help you to write simple, readable, and maintainable tests.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kitest": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"bin",
|
|
13
|
+
"dist",
|
|
14
|
+
"!dist/**/*.map",
|
|
15
|
+
"!dist/**/*.spec.*",
|
|
16
|
+
"package.json",
|
|
17
|
+
"package-lock.json"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/mhweiner/hoare.git"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"prepare": "npm run build",
|
|
25
|
+
"test": "npm run build && c8 ./bin/cli.js '@(examples|src)/**/*.spec.@(ts|js)' && c8 report -r text -r html",
|
|
26
|
+
"lint": "eslint ./ --ext .js,.ts",
|
|
27
|
+
"build": "rm -rf ./dist && tsc"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/mhweiner/hoare",
|
|
30
|
+
"keywords": [
|
|
31
|
+
"unit test",
|
|
32
|
+
"ts unit test",
|
|
33
|
+
"typescript unit test",
|
|
34
|
+
"unit-test",
|
|
35
|
+
"mocha",
|
|
36
|
+
"jasmine",
|
|
37
|
+
"jest",
|
|
38
|
+
"tape",
|
|
39
|
+
"ava",
|
|
40
|
+
"node-tap"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"deep-object-diff": "^1.1.0",
|
|
44
|
+
"diff": "^5.0.0",
|
|
45
|
+
"kleur": "^4.1.4",
|
|
46
|
+
"ora": "^5.4.1",
|
|
47
|
+
"serialize-error": "^8.1.0",
|
|
48
|
+
"tiny-glob": "^0.2.9"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/diff": "^5.0.1",
|
|
52
|
+
"@types/node": "^16.11.6",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
|
54
|
+
"@typescript-eslint/parser": "^5.2.0",
|
|
55
|
+
"c8": "^7.10.0",
|
|
56
|
+
"cjs-mock": "^0.1.0",
|
|
57
|
+
"eslint": "^8.1.0",
|
|
58
|
+
"ts-node": "^10.9.2",
|
|
59
|
+
"typescript": "^5.5.2"
|
|
60
|
+
}
|
|
61
|
+
}
|