@sprucelabs/test-utils 3.1.83 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ export default class AbstractSpruceTest {
2
+ protected static cwd: string;
3
+ protected static beforeAll(): Promise<void>;
4
+ protected static afterAll(): Promise<void>;
5
+ protected static beforeEach(): Promise<void>;
6
+ protected static afterEach(): Promise<void>;
7
+ protected static resolvePath(...filePath: string[]): string;
8
+ protected static wait(ms?: number): Promise<unknown>;
9
+ protected static log(...args: any[]): void;
10
+ }
@@ -0,0 +1,38 @@
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
+ const path_1 = __importDefault(require("path"));
7
+ class AbstractSpruceTest {
8
+ static async beforeAll() {
9
+ this.cwd = process.cwd();
10
+ }
11
+ static async afterAll() { }
12
+ static async beforeEach() { }
13
+ static async afterEach() { }
14
+ static resolvePath(...filePath) {
15
+ const cwd = this.cwd;
16
+ let builtPath = path_1.default.join(...filePath);
17
+ if (!cwd) {
18
+ throw new Error('You must call super.beforeAll().');
19
+ }
20
+ if (builtPath[0] !== '/') {
21
+ if (builtPath.substr(0, 2) === './') {
22
+ builtPath = builtPath.substr(1);
23
+ }
24
+ builtPath = path_1.default.join(cwd, builtPath);
25
+ }
26
+ return builtPath;
27
+ }
28
+ static async wait(ms = 1000) {
29
+ return new Promise((resolve) => {
30
+ setTimeout(() => resolve(true), ms);
31
+ });
32
+ }
33
+ static log(...args) {
34
+ const str = args.map((a) => `${a}`).join(' ');
35
+ process.stderr.write(str);
36
+ }
37
+ }
38
+ exports.default = AbstractSpruceTest;
@@ -0,0 +1,3 @@
1
+ export default class AssertionError extends Error {
2
+ constructor(message: string, stack?: string);
3
+ }
@@ -0,0 +1,15 @@
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
+ const StackCleaner_1 = __importDefault(require("./StackCleaner"));
7
+ class AssertionError extends Error {
8
+ constructor(message, stack) {
9
+ var _a;
10
+ super(message);
11
+ this.message = StackCleaner_1.default.clean(message ? `${message}\n` : '');
12
+ this.stack = StackCleaner_1.default.clean(`${this.message}${((_a = stack !== null && stack !== void 0 ? stack : this.stack) !== null && _a !== void 0 ? _a : '').replace(message, '')}`);
13
+ }
14
+ }
15
+ exports.default = AssertionError;
@@ -0,0 +1,4 @@
1
+ export default class StackCleaner {
2
+ private static matchPattern;
3
+ static clean(stack: string): string;
4
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class StackCleaner {
4
+ static clean(stack) {
5
+ const lines = stack.split(/\r?\n/);
6
+ const filtered = lines.filter((line) => line.search(this.matchPattern) === -1);
7
+ const newStack = filtered.join('\n');
8
+ return newStack;
9
+ }
10
+ }
11
+ exports.default = StackCleaner;
12
+ StackCleaner.matchPattern = /spruce-test\/(?!src\/__tests__)|node_modules|internal\/process\/task_queues|@babel|regenerator-runtime\/runtime/gi;
@@ -0,0 +1,44 @@
1
+ import { expectType } from 'ts-expect';
2
+ declare type RecursivePartial<T> = {
3
+ [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object ? RecursivePartial<T[P]> : T[P];
4
+ };
5
+ declare type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
6
+ declare type IsAny<T> = IfAny<T, true, never>;
7
+ declare type TypeEqual<T, U> = IsAny<T> extends never ? Exclude<T, U> extends never ? Exclude<U, T> extends never ? true : false : false : false;
8
+ declare function isExactType<T, E, Pass = TypeEqual<T, E>>(_: Pass): void;
9
+ export interface ISpruceAssert {
10
+ isNumber(actual: any, message?: string): asserts actual is number;
11
+ isType: typeof expectType;
12
+ isExactType: typeof isExactType;
13
+ isArray<T extends any[]>(actual: any, message?: string): asserts actual is T;
14
+ areSameType<T>(actual: T, expected: T): asserts actual is T;
15
+ isEqual<T>(actual: T, expected: T, message?: string): asserts actual is T;
16
+ isNotEqual<T>(actual: T, expected: T, message?: string): asserts actual is T;
17
+ isEqualDeep<T>(actual: T, expected: T, message?: string, shouldAppendDelta?: boolean): asserts actual is T;
18
+ isAbove<T>(actual: T, floor: T, message?: string): void;
19
+ isBelow<T>(actual: T, ceiling: T, message?: string): void;
20
+ isUndefined<T>(actual: T, message?: string): void;
21
+ isTruthy<T = any>(value: T, message?: string): asserts value is NonNullable<T>;
22
+ isFalsy(value: any, message?: string): void;
23
+ isTrue(actual: boolean | undefined | null, message?: string): asserts actual is true;
24
+ isFalse(actual: boolean | undefined | null, message?: string): asserts actual is false;
25
+ isObject<T>(actual: T, message?: string): void;
26
+ isLength(actual: any[] | undefined | null, expected: number, message?: string): void;
27
+ isNull(actual: any, message?: string): void;
28
+ doesNotInclude<T>(haystack: T, needle: RecursivePartial<T>, message?: string): void;
29
+ doesNotInclude(haystack: string, needle: string, message?: string): void;
30
+ doesNotInclude(haystack: any, needle: string, message?: string): void;
31
+ doesNotInclude(haystack: any, needle: any, message?: string): void;
32
+ doesInclude<T>(haystack: T, needle: RecursivePartial<T>, message?: string): void;
33
+ doesInclude(haystack: string, needle: string, message?: string): void;
34
+ doesInclude(haystack: any, needle: string, message?: string): void;
35
+ doesInclude(haystack: any, needle: any, message?: string): void;
36
+ isString(actual: any, message?: string): asserts actual is string;
37
+ isFunction(actual: any, message?: string): asserts actual is Function;
38
+ hasAllFunctions(obj: any, functionNames: string[]): void;
39
+ doesThrow(cb: () => any, matcher?: string | RegExp | undefined, msg?: string | undefined): Error;
40
+ doesThrowAsync(cb: () => any | Promise<any>, matcher?: string | RegExp | undefined, msg?: string | undefined): Promise<Error>;
41
+ fail(message?: string): void;
42
+ }
43
+ declare const assert: ISpruceAssert;
44
+ export default assert;
@@ -0,0 +1,227 @@
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
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const deep_equal_1 = __importDefault(require("deep-equal"));
8
+ const escapeRegExp_1 = __importDefault(require("lodash/escapeRegExp"));
9
+ const isObjectLike_1 = __importDefault(require("lodash/isObjectLike"));
10
+ const ts_expect_1 = require("ts-expect");
11
+ const variable_diff_1 = __importDefault(require("variable-diff"));
12
+ const assert_utility_1 = __importDefault(require("./assert.utility"));
13
+ const stringify = assert_utility_1.default.stringify.bind(assert_utility_1.default);
14
+ function isExactType(_) { }
15
+ const assert = {
16
+ areSameType() { },
17
+ isType: ts_expect_1.expectType,
18
+ isExactType,
19
+ isNumber(actual, message) {
20
+ if (typeof actual !== 'number') {
21
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not a number!`);
22
+ }
23
+ },
24
+ isEqual(actual, expected, message) {
25
+ if (actual !== expected) {
26
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} does not equal ${stringify(expected)}`);
27
+ }
28
+ },
29
+ isNotEqual(actual, expected, message) {
30
+ if (actual === expected) {
31
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} should not equal ${stringify(expected)}`);
32
+ }
33
+ },
34
+ isEqualDeep(actual, expected, message, shouldAppendDelta = true) {
35
+ if (!(0, deep_equal_1.default)(actual, expected, { strict: true })) {
36
+ let result = (0, variable_diff_1.default)(actual, expected);
37
+ this.fail(`${message !== null && message !== void 0 ? message : `Deep equal failed.\n\nActual would need the following changes to match expected:`}${shouldAppendDelta ? `\n\n${result.text}` : ``}`);
38
+ }
39
+ },
40
+ isAbove(actual, floor, message) {
41
+ if (typeof actual !== 'number') {
42
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not a number!`);
43
+ }
44
+ if (actual <= floor) {
45
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not above ${stringify(floor)}`);
46
+ }
47
+ },
48
+ isBelow(actual, ceiling, message) {
49
+ if (typeof actual !== 'number') {
50
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not a number!`);
51
+ }
52
+ if (actual >= ceiling) {
53
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not below ${stringify(ceiling)}`);
54
+ }
55
+ },
56
+ isUndefined(actual, message) {
57
+ if (typeof actual !== 'undefined') {
58
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not undefined`);
59
+ }
60
+ },
61
+ isTruthy(actual, message) {
62
+ if (actual === false ||
63
+ actual === null ||
64
+ typeof actual === 'undefined' ||
65
+ actual === 0) {
66
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not truthy`);
67
+ }
68
+ },
69
+ isFalsy(actual, message) {
70
+ if (actual) {
71
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not falsy`);
72
+ }
73
+ },
74
+ isNull(actual, message) {
75
+ if (actual !== null) {
76
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not null`);
77
+ }
78
+ },
79
+ isString(actual, message) {
80
+ assert_utility_1.default.assertTypeof(actual, 'string', message);
81
+ },
82
+ isFunction(actual, message) {
83
+ assert_utility_1.default.assertTypeof(actual, 'function', message);
84
+ },
85
+ isTrue(actual, message) {
86
+ //@ts-ignore
87
+ this.isEqual(actual, true, message);
88
+ },
89
+ isFalse(actual, message) {
90
+ //@ts-ignore
91
+ this.isEqual(actual, false, message);
92
+ },
93
+ isObject(actual, message) {
94
+ if (!(0, isObjectLike_1.default)(actual)) {
95
+ throw this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not an object`);
96
+ }
97
+ },
98
+ isArray(actual, message) {
99
+ if (!Array.isArray(actual)) {
100
+ throw this.fail(message !== null && message !== void 0 ? message : `${stringify(actual)} is not an array`);
101
+ }
102
+ },
103
+ isLength(actual, expected, message) {
104
+ if (!actual) {
105
+ throw this.fail(message !== null && message !== void 0 ? message : `Expected array of length ${expected}, but got ${stringify(actual)}`);
106
+ }
107
+ //@ts-ignore
108
+ this.isEqual(actual.length, expected, message !== null && message !== void 0 ? message : `Expected length of ${stringify(expected)}, but got a length of ${stringify(actual.length)}`);
109
+ },
110
+ doesNotInclude(haystack, needle, message) {
111
+ let doesInclude = false;
112
+ try {
113
+ this.doesInclude(haystack, needle);
114
+ doesInclude = true;
115
+ }
116
+ catch (_a) {
117
+ doesInclude = false;
118
+ }
119
+ if (doesInclude) {
120
+ this.fail(message !== null && message !== void 0 ? message : `${stringify(haystack)} should not include ${stringify(needle)}, but it does`);
121
+ }
122
+ },
123
+ doesInclude(haystack, needle, message) {
124
+ let msg = message !== null && message !== void 0 ? message : `Could not find ${stringify(needle)} in ${stringify(haystack)}`;
125
+ const isNeedleString = typeof needle === 'string';
126
+ const isNeedleRegex = needle instanceof RegExp;
127
+ if (typeof haystack === 'string' &&
128
+ (isNeedleString || isNeedleRegex) &&
129
+ haystack.search(isNeedleString ? (0, escapeRegExp_1.default)(needle) : needle) > -1) {
130
+ return;
131
+ }
132
+ const isHaystackObject = (0, isObjectLike_1.default)(haystack);
133
+ const { needleHasArrayNotation, path, expected } = assert_utility_1.default.parseIncludeNeedle(needle);
134
+ if (Array.isArray(haystack)) {
135
+ let cleanedNeedle = needle;
136
+ if (path && path.substr(0, 3) === '[].') {
137
+ cleanedNeedle = { [path.substr(3)]: expected };
138
+ }
139
+ const found = assert_utility_1.default.doHaystacksPassCheck(haystack, cleanedNeedle, this.doesInclude.bind(this));
140
+ if (found) {
141
+ return;
142
+ }
143
+ }
144
+ if (isHaystackObject && (0, isObjectLike_1.default)(needle)) {
145
+ try {
146
+ //@ts-ignore
147
+ this.isEqualDeep(haystack, needle);
148
+ return;
149
+ // eslint-disable-next-line no-empty
150
+ }
151
+ catch (_a) { }
152
+ }
153
+ if (assert_utility_1.default.foundUsing3rdPartyIncludes(haystack, needle, isHaystackObject)) {
154
+ return;
155
+ }
156
+ if (!Array.isArray(haystack) &&
157
+ isHaystackObject &&
158
+ (0, isObjectLike_1.default)(needle) &&
159
+ Object.keys(needle).length === 1 &&
160
+ !needleHasArrayNotation &&
161
+ path) {
162
+ const actual = assert_utility_1.default.valueAtPath(haystack, path);
163
+ if (typeof actual === 'undefined') {
164
+ msg = `The path ${stringify(path)} was not found in ${stringify(haystack)}`;
165
+ }
166
+ else {
167
+ msg = `Expected ${chalk_1.default.green(stringify(needle[path]))} but found ${chalk_1.default.red(stringify(actual))} at ${stringify(path)} in ${stringify(haystack)}`;
168
+ }
169
+ if (typeof expected === 'string' &&
170
+ typeof actual === 'string' &&
171
+ actual.search(expected) > -1) {
172
+ return;
173
+ }
174
+ else if (expected instanceof RegExp && expected.exec(actual)) {
175
+ return;
176
+ }
177
+ else {
178
+ //@ts-ignore
179
+ this.isEqualDeep(expected, actual, msg, false);
180
+ }
181
+ return;
182
+ }
183
+ if (isHaystackObject && (0, isObjectLike_1.default)(needle) && path) {
184
+ const { actualBeforeArray, pathAfterFirstArray } = assert_utility_1.default.splitPathBasedOnArrayNotation(path, haystack);
185
+ if (!Array.isArray(actualBeforeArray)) {
186
+ this.fail(msg);
187
+ }
188
+ const found = assert_utility_1.default.doHaystacksPassCheck(actualBeforeArray, {
189
+ [pathAfterFirstArray]: expected,
190
+ }, this.doesInclude.bind(this));
191
+ if (found) {
192
+ return;
193
+ }
194
+ msg = `Could not find match ${stringify(expected)} at ${stringify(pathAfterFirstArray)} in ${stringify(actualBeforeArray)}.`;
195
+ }
196
+ this.fail(msg);
197
+ },
198
+ hasAllFunctions(obj, functionNames) {
199
+ functionNames.forEach((name) => {
200
+ if (typeof obj[name] !== 'function') {
201
+ this.fail(`A function named "${name}" does not exist on ${stringify(obj)}`);
202
+ }
203
+ });
204
+ },
205
+ doesThrow(cb, matcher, msg) {
206
+ try {
207
+ cb();
208
+ }
209
+ catch (err) {
210
+ assert_utility_1.default.checkDoesThrowError(matcher, err, msg);
211
+ return err;
212
+ }
213
+ this.fail('Expected a thrown error, but never got one!');
214
+ },
215
+ async doesThrowAsync(cb, matcher, msg) {
216
+ try {
217
+ await cb();
218
+ }
219
+ catch (err) {
220
+ assert_utility_1.default.checkDoesThrowError(matcher, err, msg);
221
+ return err;
222
+ }
223
+ this.fail('Expected a thrown error, but never got one!');
224
+ },
225
+ fail: assert_utility_1.default.fail,
226
+ };
227
+ exports.default = assert;
@@ -0,0 +1,28 @@
1
+ import { ISpruceAssert } from './assert';
2
+ export declare const UNDEFINED_PLACEHOLDER = "_____________undefined_____________";
3
+ export declare const FUNCTION_PLACEHOLDER = "_____________function_____________";
4
+ export declare const CIRCULAR_PLACEHOLDER = "_____________circular_____________";
5
+ export declare const NULL_PLACEHOLDER = "_____________null_____________";
6
+ declare const assertUtil: {
7
+ fail(message?: string, stack?: string): never;
8
+ stringify(object: any): string;
9
+ replacePlaceholders(str: string): string;
10
+ dropInPlaceholders(obj: Record<string, any>): Record<string, any>;
11
+ dropInPlaceholder(obj: Record<string, any>, checker: (obj: any, depth: number) => boolean, placeholder: string, depth?: number): Record<string, any>;
12
+ doHaystacksPassCheck(haystacks: any[], needle: any, check: ISpruceAssert['doesInclude']): boolean;
13
+ assertTypeof(actual: any, type: string, message: string | undefined): void;
14
+ checkDoesThrowError(matcher: string | RegExp | undefined, err: Error, msg?: string | undefined): void;
15
+ partialContains(object: any, subObject: any): boolean | undefined;
16
+ valueAtPath(object: Record<string, any>, path: string): any;
17
+ parseIncludeNeedle(needle: any): {
18
+ needleHasArrayNotation: boolean;
19
+ path?: string | undefined;
20
+ expected?: any;
21
+ };
22
+ splitPathBasedOnArrayNotation(path: string, haystack: any): {
23
+ actualBeforeArray: any;
24
+ pathAfterFirstArray: string;
25
+ };
26
+ foundUsing3rdPartyIncludes(haystack: any, needle: any, isHaystackObject: boolean): boolean;
27
+ };
28
+ export default assertUtil;
@@ -0,0 +1,182 @@
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.NULL_PLACEHOLDER = exports.CIRCULAR_PLACEHOLDER = exports.FUNCTION_PLACEHOLDER = exports.UNDEFINED_PLACEHOLDER = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const get_1 = __importDefault(require("lodash/get"));
9
+ const includes_1 = __importDefault(require("lodash/includes"));
10
+ const isObject_1 = __importDefault(require("lodash/isObject"));
11
+ const isObjectLike_1 = __importDefault(require("lodash/isObjectLike"));
12
+ const AssertionError_1 = __importDefault(require("../AssertionError"));
13
+ exports.UNDEFINED_PLACEHOLDER = '_____________undefined_____________';
14
+ exports.FUNCTION_PLACEHOLDER = '_____________function_____________';
15
+ exports.CIRCULAR_PLACEHOLDER = '_____________circular_____________';
16
+ exports.NULL_PLACEHOLDER = '_____________null_____________';
17
+ const assertUtil = {
18
+ fail(message, stack) {
19
+ throw new AssertionError_1.default(message !== null && message !== void 0 ? message : 'Fail!', stack);
20
+ },
21
+ stringify(object) {
22
+ var _a;
23
+ let stringified;
24
+ if (Array.isArray(object)) {
25
+ stringified = `[\n${object.map((o) => this.stringify(o).split('\n').join('\n\t'))}\n]`;
26
+ }
27
+ else if (typeof object === 'number') {
28
+ // this hack allows the Spruce Test Reporter to render number errors (they got eaten by terminal-kit's style regex)
29
+ stringified = chalk_1.default.bgBlack.white(` ${object} `);
30
+ }
31
+ else if (object instanceof Error) {
32
+ stringified = `${(_a = object.stack) !== null && _a !== void 0 ? _a : object.message}`;
33
+ }
34
+ else if (object instanceof RegExp) {
35
+ stringified = `${object.toString()}`;
36
+ }
37
+ else if (typeof object === 'undefined') {
38
+ stringified = 'undefined';
39
+ }
40
+ else if (typeof object === 'string') {
41
+ stringified = `"${object}"`;
42
+ }
43
+ else {
44
+ stringified = JSON.stringify(assertUtil.dropInPlaceholders(object), undefined, 2).replace(/\\/g, '');
45
+ }
46
+ if (stringified.length > 5000) {
47
+ stringified =
48
+ stringified.substr(0, 1000) +
49
+ '\n\n... big object ...\n\n' +
50
+ stringified.substr(stringified.length - 1000);
51
+ }
52
+ stringified = assertUtil.replacePlaceholders(stringified);
53
+ return `\n\n${chalk_1.default.bold(stringified)}\n\n`;
54
+ },
55
+ replacePlaceholders(str) {
56
+ return str
57
+ .replace(new RegExp(`"${exports.UNDEFINED_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('undefined'))
58
+ .replace(new RegExp(`"${exports.FUNCTION_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('Function'))
59
+ .replace(new RegExp(`"${exports.NULL_PLACEHOLDER}"`, 'g'), chalk_1.default.italic('NULL'));
60
+ },
61
+ dropInPlaceholders(obj) {
62
+ const checkedObjects = [{ obj, depth: 0 }];
63
+ let updated = this.dropInPlaceholder(obj, (obj, depth) => {
64
+ if ((0, isObject_1.default)(obj) &&
65
+ checkedObjects.some((checked) => {
66
+ return checked.obj === obj && checked.depth < depth;
67
+ })) {
68
+ return true;
69
+ }
70
+ checkedObjects.push({ obj, depth });
71
+ return false;
72
+ }, exports.CIRCULAR_PLACEHOLDER);
73
+ updated = this.dropInPlaceholder(updated, (obj) => typeof obj === 'undefined', exports.UNDEFINED_PLACEHOLDER);
74
+ updated = this.dropInPlaceholder(updated, (obj) => typeof obj === 'function', exports.FUNCTION_PLACEHOLDER);
75
+ updated = this.dropInPlaceholder(updated, (obj) => obj === null, exports.NULL_PLACEHOLDER);
76
+ return updated;
77
+ },
78
+ dropInPlaceholder(obj, checker, placeholder, depth = 1) {
79
+ if (!(0, isObject_1.default)(obj)) {
80
+ return obj;
81
+ }
82
+ const updated = Array.isArray(obj) ? [] : {};
83
+ Object.keys(obj).forEach((key) => {
84
+ //@ts-ignore
85
+ updated[key] =
86
+ // @ts-ignore
87
+ checker(obj[key], depth) ? placeholder : obj[key];
88
+ //@ts-ignore
89
+ if (typeof updated[key] !== 'function' && (0, isObject_1.default)(updated[key])) {
90
+ //@ts-ignore
91
+ updated[key] = this.dropInPlaceholder(
92
+ //@ts-ignore
93
+ updated[key], checker, placeholder, depth + 1);
94
+ }
95
+ });
96
+ return updated;
97
+ },
98
+ doHaystacksPassCheck(haystacks, needle, check) {
99
+ return !!haystacks.find((haystack) => {
100
+ try {
101
+ check(haystack, needle);
102
+ return true;
103
+ }
104
+ catch (_a) {
105
+ return false;
106
+ }
107
+ });
108
+ },
109
+ assertTypeof(actual, type, message) {
110
+ if (typeof actual !== type) {
111
+ this.fail(message !== null && message !== void 0 ? message : `${JSON.stringify(actual)} is not a ${type}`);
112
+ }
113
+ },
114
+ checkDoesThrowError(matcher, err, msg) {
115
+ var _a, _b;
116
+ const message = (_b = (_a = err.stack) !== null && _a !== void 0 ? _a : err.message) !== null && _b !== void 0 ? _b : '**MISSING ERROR MESSAGE**';
117
+ if (typeof matcher === 'string' && message.search(matcher) === -1) {
118
+ this.fail(msg !== null && msg !== void 0 ? msg : `Expected thrown error whose message contains: \n\n${chalk_1.default.bold(matcher)}\n\nbut got back:\n\n\`${chalk_1.default.bold(message)}\`.`, '\n\nStack: ' + err.stack);
119
+ }
120
+ else if (matcher instanceof RegExp && message.search(matcher) === -1) {
121
+ this.fail(msg !== null && msg !== void 0 ? msg : `Expected thrown error whose message matches the regex: \n\n${chalk_1.default.bold(matcher)}\n\nbut got back:\n\n\`${chalk_1.default.bold(message)}\`.`, '\n\nStack: ' + err.stack);
122
+ }
123
+ },
124
+ partialContains(object, subObject) {
125
+ const objProps = object ? Object.getOwnPropertyNames(object) : [];
126
+ const subProps = subObject ? Object.getOwnPropertyNames(subObject) : [];
127
+ if (objProps.length == 0 || subProps.length === 0) {
128
+ return;
129
+ }
130
+ if (subProps.length > objProps.length) {
131
+ return false;
132
+ }
133
+ for (const subProp of subProps) {
134
+ if (!Object.prototype.hasOwnProperty.call(object, subProp)) {
135
+ return false;
136
+ }
137
+ if ((!(0, isObjectLike_1.default)(object[subProp]) || !(0, isObjectLike_1.default)(subObject[subProp])) &&
138
+ object[subProp] !== subObject[subProp]) {
139
+ return false;
140
+ }
141
+ if ((0, isObjectLike_1.default)(object[subProp]) &&
142
+ (0, isObjectLike_1.default)(subObject[subProp]) &&
143
+ !this.partialContains(object[subProp], subObject[subProp])) {
144
+ return false;
145
+ }
146
+ }
147
+ return true;
148
+ },
149
+ valueAtPath(object, path) {
150
+ return (0, get_1.default)(object, path);
151
+ },
152
+ parseIncludeNeedle(needle) {
153
+ const path = Object.keys(needle)[0];
154
+ const expected = path && needle[path];
155
+ const needleHasArrayNotation = !!(path && path.search(/\[\]\./) > -1);
156
+ return { needleHasArrayNotation, path, expected };
157
+ },
158
+ splitPathBasedOnArrayNotation(path, haystack) {
159
+ var _a;
160
+ const pathParts = path.split('[].');
161
+ const pathToFirstArray = (_a = pathParts.shift()) !== null && _a !== void 0 ? _a : '';
162
+ const pathAfterFirstArray = pathParts.join('[].');
163
+ const actualBeforeArray = this.valueAtPath(haystack, pathToFirstArray);
164
+ return { actualBeforeArray, pathAfterFirstArray };
165
+ },
166
+ foundUsing3rdPartyIncludes(haystack, needle, isHaystackObject) {
167
+ let passed = false;
168
+ if (typeof haystack === 'string' &&
169
+ typeof needle === 'string' &&
170
+ haystack.search(needle) > -1) {
171
+ passed = true;
172
+ }
173
+ if (isHaystackObject && (0, includes_1.default)(haystack, needle)) {
174
+ passed = true;
175
+ }
176
+ if (isHaystackObject && this.partialContains(haystack, needle)) {
177
+ passed = true;
178
+ }
179
+ return passed;
180
+ },
181
+ };
182
+ exports.default = assertUtil;
@@ -0,0 +1,8 @@
1
+ /** Test decorator */
2
+ declare function test(description?: string, ...args: any[]): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
3
+ declare namespace test {
4
+ var only: (description?: string | undefined, ...args: any[]) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
5
+ var todo: (description?: string | undefined, ..._args: any[]) => (target: any, propertyKey: string) => void;
6
+ var skip: (description?: string | undefined, ...args: any[]) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
7
+ }
8
+ export default test;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /** Hooks up before, after, etc. */
4
+ function hookupTestClass(target) {
5
+ if (target.__isTestingHookedUp) {
6
+ return;
7
+ }
8
+ target.__isTestingHookedUp = true;
9
+ const hooks = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'];
10
+ hooks.forEach((hook) => {
11
+ // Have they defined a hook
12
+ if (!target[hook]) {
13
+ return;
14
+ }
15
+ // @ts-ignore
16
+ if (global[hook]) {
17
+ // @ts-ignore
18
+ global[hook](async () => {
19
+ return target[hook]();
20
+ });
21
+ }
22
+ });
23
+ }
24
+ /** Test decorator */
25
+ function test(description, ...args) {
26
+ return function (target, propertyKey, descriptor) {
27
+ // Lets attach before/after
28
+ hookupTestClass(target);
29
+ const bound = descriptor.value.bind(target);
30
+ // Make sure each test gets the spruce
31
+ it(description !== null && description !== void 0 ? description : propertyKey, async () => {
32
+ //@ts-ignore
33
+ global.activeTest = {
34
+ file: target.name,
35
+ test: propertyKey,
36
+ };
37
+ return bound(...args);
38
+ });
39
+ };
40
+ }
41
+ exports.default = test;
42
+ /** Only decorator */
43
+ test.only = (description, ...args) => {
44
+ return function (target, propertyKey, descriptor) {
45
+ // Lets attach before/after
46
+ hookupTestClass(target);
47
+ const bound = descriptor.value.bind(target);
48
+ // Make sure each test gets the spruce
49
+ it.only(description !== null && description !== void 0 ? description : propertyKey, async () => {
50
+ return bound(...args);
51
+ });
52
+ };
53
+ };
54
+ /** Todo decorator */
55
+ test.todo = (description, ..._args) => {
56
+ return function (target, propertyKey) {
57
+ // Lets attach before/after
58
+ hookupTestClass(target);
59
+ // Make sure each test gets the spruce
60
+ it.todo(description !== null && description !== void 0 ? description : propertyKey);
61
+ };
62
+ };
63
+ /** Skip decorator */
64
+ test.skip = (description, ...args) => {
65
+ return function (target, propertyKey, descriptor) {
66
+ // Lets attach before/after
67
+ hookupTestClass(target);
68
+ const bound = descriptor.value.bind(target);
69
+ // Make sure each test gets the spruce
70
+ it.skip(description !== null && description !== void 0 ? description : propertyKey, async () => {
71
+ return bound(...args);
72
+ });
73
+ };
74
+ };
@@ -0,0 +1,10 @@
1
+ export default class AbstractSpruceTest {
2
+ protected static cwd: string;
3
+ protected static beforeAll(): Promise<void>;
4
+ protected static afterAll(): Promise<void>;
5
+ protected static beforeEach(): Promise<void>;
6
+ protected static afterEach(): Promise<void>;
7
+ protected static resolvePath(...filePath: string[]): string;
8
+ protected static wait(ms?: number): Promise<unknown>;
9
+ protected static log(...args: any[]): void;
10
+ }