@neurodevs/node-tdd 1.0.5 → 1.0.7
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/package.json +1 -1
- package/.nvmrc +0 -1
- package/.vscode/launch.json +0 -53
- package/.vscode/settings.json +0 -62
- package/.vscode/tasks.json +0 -99
- package/build/__tests__/MockFetch.d.ts +0 -18
- package/build/__tests__/MockFetch.js +0 -55
- package/build/__tests__/MockFetch.js.map +0 -1
- package/build/__tests__/behavioral/AbstractModuleTest.test.d.ts +0 -5
- package/build/__tests__/behavioral/AbstractModuleTest.test.js +0 -22
- package/build/__tests__/behavioral/AbstractModuleTest.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/AllHooksCalledEvenIfNotDefined.test.d.ts +0 -5
- package/build/__tests__/behavioral/utilities/AllHooksCalledEvenIfNotDefined.test.js +0 -34
- package/build/__tests__/behavioral/utilities/AllHooksCalledEvenIfNotDefined.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/Assert.test.d.ts +0 -45
- package/build/__tests__/behavioral/utilities/Assert.test.js +0 -645
- package/build/__tests__/behavioral/utilities/Assert.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/InstanceParentTestCanAccessParentMethods.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/InstanceParentTestCanAccessParentMethods.test.js +0 -23
- package/build/__tests__/behavioral/utilities/InstanceParentTestCanAccessParentMethods.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/MockFetch.test.d.ts +0 -28
- package/build/__tests__/behavioral/utilities/MockFetch.test.js +0 -211
- package/build/__tests__/behavioral/utilities/MockFetch.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/StackCleaner.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/StackCleaner.test.js +0 -46
- package/build/__tests__/behavioral/utilities/StackCleaner.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/StaticParentTestCanAccessParentMethods.test.d.ts +0 -7
- package/build/__tests__/behavioral/utilities/StaticParentTestCanAccessParentMethods.test.js +0 -32
- package/build/__tests__/behavioral/utilities/StaticParentTestCanAccessParentMethods.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/StaticTestInheritsAbstractSpruceTestProperly.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/StaticTestInheritsAbstractSpruceTestProperly.test.js +0 -19
- package/build/__tests__/behavioral/utilities/StaticTestInheritsAbstractSpruceTestProperly.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/Stringify.test.d.ts +0 -5
- package/build/__tests__/behavioral/utilities/Stringify.test.js +0 -127
- package/build/__tests__/behavioral/utilities/Stringify.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestDecoratorResolver.test.d.ts +0 -7
- package/build/__tests__/behavioral/utilities/TestDecoratorResolver.test.js +0 -38
- package/build/__tests__/behavioral/utilities/TestDecoratorResolver.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnBasic.test.d.ts +0 -12
- package/build/__tests__/behavioral/utilities/TestOnBasic.test.js +0 -68
- package/build/__tests__/behavioral/utilities/TestOnBasic.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnInstance.test.d.ts +0 -28
- package/build/__tests__/behavioral/utilities/TestOnInstance.test.js +0 -289
- package/build/__tests__/behavioral/utilities/TestOnInstance.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTest.test.d.ts +0 -9
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTest.test.js +0 -118
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTest.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTestWithHooks.test.d.ts +0 -5
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTestWithHooks.test.js +0 -78
- package/build/__tests__/behavioral/utilities/TestOnInstanceExtendsTestWithHooks.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithParentBeforeAll.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithParentBeforeAll.test.js +0 -23
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithParentBeforeAll.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithTwoLevelsOfInheritence.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithTwoLevelsOfInheritence.test.js +0 -24
- package/build/__tests__/behavioral/utilities/TestOnInstanceWithTwoLevelsOfInheritence.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestResolver.test.d.ts +0 -7
- package/build/__tests__/behavioral/utilities/TestResolver.test.js +0 -38
- package/build/__tests__/behavioral/utilities/TestResolver.test.js.map +0 -1
- package/build/__tests__/behavioral/utilities/TestResolverOnStatic.test.d.ts +0 -4
- package/build/__tests__/behavioral/utilities/TestResolverOnStatic.test.js +0 -20
- package/build/__tests__/behavioral/utilities/TestResolverOnStatic.test.js.map +0 -1
- package/build/__tests__/behavioral/workspace/JestJsonParser.test.d.ts +0 -18
- package/build/__tests__/behavioral/workspace/JestJsonParser.test.js +0 -267
- package/build/__tests__/behavioral/workspace/JestJsonParser.test.js.map +0 -1
- package/build/__tests__/behavioral/workspace/TestReporter.test.d.ts +0 -27
- package/build/__tests__/behavioral/workspace/TestReporter.test.js +0 -508
- package/build/__tests__/behavioral/workspace/TestReporter.test.js.map +0 -1
- package/build/__tests__/behavioral/workspace/TestRunner.test.d.ts +0 -15
- package/build/__tests__/behavioral/workspace/TestRunner.test.js +0 -99
- package/build/__tests__/behavioral/workspace/TestRunner.test.js.map +0 -1
- package/build/__tests__/behavioral/workspace/Widgets.test.d.ts +0 -16
- package/build/__tests__/behavioral/workspace/Widgets.test.js +0 -134
- package/build/__tests__/behavioral/workspace/Widgets.test.js.map +0 -1
- package/build/__tests__/mock-terminal-kit.d.ts +0 -79
- package/build/__tests__/mock-terminal-kit.js +0 -103
- package/build/__tests__/mock-terminal-kit.js.map +0 -1
- package/build/__tests__/support/AbstractForInstanceTest.d.ts +0 -4
- package/build/__tests__/support/AbstractForInstanceTest.js +0 -9
- package/build/__tests__/support/AbstractForInstanceTest.js.map +0 -1
- package/build/__tests__/support/AbstractLevelOneTest.d.ts +0 -3
- package/build/__tests__/support/AbstractLevelOneTest.js +0 -4
- package/build/__tests__/support/AbstractLevelOneTest.js.map +0 -1
- package/build/__tests__/support/AbstractLevelTwoTest.d.ts +0 -7
- package/build/__tests__/support/AbstractLevelTwoTest.js +0 -14
- package/build/__tests__/support/AbstractLevelTwoTest.js.map +0 -1
- package/build/__tests__/support/AbstractStaticTest.d.ts +0 -7
- package/build/__tests__/support/AbstractStaticTest.js +0 -14
- package/build/__tests__/support/AbstractStaticTest.js.map +0 -1
- package/build/__tests__/support/AbstractTestOnInstanceTest.d.ts +0 -22
- package/build/__tests__/support/AbstractTestOnInstanceTest.js +0 -23
- package/build/__tests__/support/AbstractTestOnInstanceTest.js.map +0 -1
- package/build/__tests__/support/AbstractTestOnInstanceWithHooks.d.ts +0 -26
- package/build/__tests__/support/AbstractTestOnInstanceWithHooks.js +0 -59
- package/build/__tests__/support/AbstractTestOnInstanceWithHooks.js.map +0 -1
- package/build/__tests__/support/jest.setup.d.ts +0 -1
- package/build/__tests__/support/jest.setup.js +0 -4
- package/build/__tests__/support/jest.setup.js.map +0 -1
- package/build/__tests__/support/onTestFileResult.d.ts +0 -244
- package/build/__tests__/support/onTestFileResult.js +0 -980
- package/build/__tests__/support/onTestFileResult.js.map +0 -1
- package/eslint.config.js +0 -3
- package/prettier.config.js +0 -3
- package/src/.spruce/settings.json +0 -4
- package/src/__tests__/MockFetch.ts +0 -100
- package/src/__tests__/behavioral/AbstractModuleTest.test.ts +0 -15
- package/src/__tests__/behavioral/utilities/AllHooksCalledEvenIfNotDefined.test.ts +0 -31
- package/src/__tests__/behavioral/utilities/Assert.test.ts +0 -826
- package/src/__tests__/behavioral/utilities/InstanceParentTestCanAccessParentMethods.test.ts +0 -14
- package/src/__tests__/behavioral/utilities/MockFetch.test.ts +0 -240
- package/src/__tests__/behavioral/utilities/StackCleaner.test.ts +0 -46
- package/src/__tests__/behavioral/utilities/StaticParentTestCanAccessParentMethods.test.ts +0 -34
- package/src/__tests__/behavioral/utilities/StaticTestInheritsAbstractSpruceTestProperly.test.ts +0 -11
- package/src/__tests__/behavioral/utilities/Stringify.test.ts +0 -169
- package/src/__tests__/behavioral/utilities/TestDecoratorResolver.test.ts +0 -51
- package/src/__tests__/behavioral/utilities/TestOnBasic.test.ts +0 -62
- package/src/__tests__/behavioral/utilities/TestOnInstance.test.ts +0 -439
- package/src/__tests__/behavioral/utilities/TestOnInstanceExtendsTest.test.ts +0 -237
- package/src/__tests__/behavioral/utilities/TestOnInstanceExtendsTestWithHooks.test.ts +0 -85
- package/src/__tests__/behavioral/utilities/TestOnInstanceWithParentBeforeAll.test.ts +0 -14
- package/src/__tests__/behavioral/utilities/TestOnInstanceWithTwoLevelsOfInheritence.test.ts +0 -16
- package/src/__tests__/behavioral/utilities/TestResolver.test.ts +0 -48
- package/src/__tests__/behavioral/utilities/TestResolverOnStatic.test.ts +0 -12
- package/src/__tests__/behavioral/workspace/JestJsonParser.test.ts +0 -357
- package/src/__tests__/behavioral/workspace/TestReporter.test.ts +0 -584
- package/src/__tests__/behavioral/workspace/TestRunner.test.ts +0 -87
- package/src/__tests__/behavioral/workspace/Widgets.test.ts +0 -131
- package/src/__tests__/mock-terminal-kit.ts +0 -115
- package/src/__tests__/support/AbstractForInstanceTest.ts +0 -12
- package/src/__tests__/support/AbstractLevelOneTest.ts +0 -3
- package/src/__tests__/support/AbstractLevelTwoTest.ts +0 -16
- package/src/__tests__/support/AbstractStaticTest.ts +0 -16
- package/src/__tests__/support/AbstractTestOnInstanceTest.ts +0 -30
- package/src/__tests__/support/AbstractTestOnInstanceWithHooks.ts +0 -138
- package/src/__tests__/support/jest.setup.ts +0 -2
- package/src/__tests__/support/onTestFileResult.ts +0 -1008
- package/src/impl/AbstractModuleTest.ts +0 -67
- package/src/index.ts +0 -12
- package/src/utilities/AssertionError.ts +0 -14
- package/src/utilities/StackCleaner.ts +0 -14
- package/src/utilities/TestDecoratorResolver.ts +0 -118
- package/src/utilities/assert.ts +0 -583
- package/src/utilities/assert.utility.ts +0 -295
- package/src/utilities/decorators.ts +0 -167
- package/src/workspace/CommandService.ts +0 -256
- package/src/workspace/JestJsonParser.ts +0 -255
- package/src/workspace/TKButtonWidget.ts +0 -54
- package/src/workspace/TestLogItemGenerator.ts +0 -184
- package/src/workspace/TestReporter.ts +0 -880
- package/src/workspace/TestRunner.ts +0 -128
- package/src/workspace/TkBaseWidget.ts +0 -249
- package/src/workspace/TkInputWidget.ts +0 -83
- package/src/workspace/TkLayoutCellWidget.ts +0 -46
- package/src/workspace/TkLayoutWidget.ts +0 -181
- package/src/workspace/TkMenuBarWidget.ts +0 -95
- package/src/workspace/TkPopupWidget.ts +0 -47
- package/src/workspace/TkProgressBarWidget.ts +0 -54
- package/src/workspace/TkTextWidget.ts +0 -167
- package/src/workspace/TkWindowWidget.ts +0 -122
- package/src/workspace/WidgetFactory.ts +0 -33
- package/src/workspace/button.types.ts +0 -19
- package/src/workspace/duration.utility.ts +0 -34
- package/src/workspace/factory.types.ts +0 -101
- package/src/workspace/input.types.ts +0 -22
- package/src/workspace/keySelectChoices.ts +0 -134
- package/src/workspace/layout.types.ts +0 -40
- package/src/workspace/menuBar.types.ts +0 -24
- package/src/workspace/popup.types.ts +0 -17
- package/src/workspace/progressBar.types.ts +0 -13
- package/src/workspace/table.types.ts +0 -9
- package/src/workspace/termKit.utility.ts +0 -130
- package/src/workspace/terminal-kit.d.ts +0 -28
- package/src/workspace/test.types.ts +0 -34
- package/src/workspace/testRunner.cli.ts +0 -166
- package/src/workspace/text.types.ts +0 -27
- package/src/workspace/widget.utilities.ts +0 -35
- package/src/workspace/widgets.types.ts +0 -102
- package/src/workspace/window.types.ts +0 -22
- package/tsconfig.json +0 -24
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
import { escapeRegExp, get, includes, isObject, isObjectLike } from 'lodash-es'
|
|
3
|
-
import AssertionError from './AssertionError.js'
|
|
4
|
-
import { Assert } from './assert.js'
|
|
5
|
-
|
|
6
|
-
export const UNDEFINED_PLACEHOLDER = '_____________undefined_____________'
|
|
7
|
-
export const FUNCTION_PLACEHOLDER = '_____________function_____________'
|
|
8
|
-
export const CIRCULAR_PLACEHOLDER = '_____________circular_____________'
|
|
9
|
-
export const NULL_PLACEHOLDER = '_____________null_____________'
|
|
10
|
-
|
|
11
|
-
const assertUtil = {
|
|
12
|
-
fail(message?: string, stack?: string) {
|
|
13
|
-
throw new AssertionError(message ?? 'Fail!', stack)
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
stringify(object: any): string {
|
|
17
|
-
let stringified
|
|
18
|
-
|
|
19
|
-
if (Array.isArray(object)) {
|
|
20
|
-
stringified = `[\n ${object.map((o) =>
|
|
21
|
-
this.stringify(o).split('\n').join('\n ')
|
|
22
|
-
)}\n]`
|
|
23
|
-
} else if (typeof object === 'number') {
|
|
24
|
-
// this hack allows the Test Reporter to render number errors (they got eaten by terminal-kit's style regex)
|
|
25
|
-
stringified = chalk.bgBlack.white(` ${object} `)
|
|
26
|
-
} else if (object instanceof Error) {
|
|
27
|
-
stringified = `${object.stack ?? object.message}`
|
|
28
|
-
} else if (object instanceof RegExp) {
|
|
29
|
-
stringified = `${object.toString()}`
|
|
30
|
-
} else if (typeof object === 'undefined') {
|
|
31
|
-
stringified = 'undefined'
|
|
32
|
-
} else if (typeof object === 'string') {
|
|
33
|
-
stringified = `"${object}"`
|
|
34
|
-
} else {
|
|
35
|
-
stringified = JSON.stringify(
|
|
36
|
-
assertUtil.dropInPlaceholders(object),
|
|
37
|
-
undefined,
|
|
38
|
-
2
|
|
39
|
-
).replace(/\\/g, '')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (stringified.length > 5000) {
|
|
43
|
-
stringified =
|
|
44
|
-
stringified.substr(0, 1000) +
|
|
45
|
-
'\n\n... big object ...\n\n' +
|
|
46
|
-
stringified.substr(stringified.length - 1000)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
stringified = assertUtil.replacePlaceholders(stringified)
|
|
50
|
-
|
|
51
|
-
return `${chalk.bold(stringified)}`
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
replacePlaceholders(str: string) {
|
|
55
|
-
return str
|
|
56
|
-
.replace(
|
|
57
|
-
new RegExp(`"${UNDEFINED_PLACEHOLDER}"`, 'g'),
|
|
58
|
-
chalk.italic('undefined')
|
|
59
|
-
)
|
|
60
|
-
.replace(
|
|
61
|
-
new RegExp(`"${FUNCTION_PLACEHOLDER}"`, 'g'),
|
|
62
|
-
chalk.italic('Function')
|
|
63
|
-
)
|
|
64
|
-
.replace(
|
|
65
|
-
new RegExp(`"${NULL_PLACEHOLDER}"`, 'g'),
|
|
66
|
-
chalk.italic('NULL')
|
|
67
|
-
)
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
dropInPlaceholders(obj: Record<string, any>) {
|
|
71
|
-
const checkedObjects: { obj: any; depth: number }[] = [
|
|
72
|
-
{ obj, depth: 0 },
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
let updated = this.dropInPlaceholder(
|
|
76
|
-
obj,
|
|
77
|
-
(obj, depth) => {
|
|
78
|
-
if (
|
|
79
|
-
isObject(obj) &&
|
|
80
|
-
checkedObjects.some((checked) => {
|
|
81
|
-
return checked.obj === obj && checked.depth < depth
|
|
82
|
-
})
|
|
83
|
-
) {
|
|
84
|
-
return true
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
checkedObjects.push({ obj, depth })
|
|
88
|
-
|
|
89
|
-
return false
|
|
90
|
-
},
|
|
91
|
-
CIRCULAR_PLACEHOLDER
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
updated = this.dropInPlaceholder(
|
|
95
|
-
updated,
|
|
96
|
-
(obj) => typeof obj === 'undefined',
|
|
97
|
-
UNDEFINED_PLACEHOLDER
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
updated = this.dropInPlaceholder(
|
|
101
|
-
updated,
|
|
102
|
-
(obj) => typeof obj === 'function',
|
|
103
|
-
FUNCTION_PLACEHOLDER
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
updated = this.dropInPlaceholder(
|
|
107
|
-
updated,
|
|
108
|
-
(obj) => obj === null,
|
|
109
|
-
NULL_PLACEHOLDER
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
return updated
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
dropInPlaceholder(
|
|
116
|
-
obj: Record<string, any>,
|
|
117
|
-
checker: (obj: any, depth: number) => boolean,
|
|
118
|
-
placeholder: string,
|
|
119
|
-
depth = 1
|
|
120
|
-
) {
|
|
121
|
-
if (!isObject(obj)) {
|
|
122
|
-
return obj
|
|
123
|
-
}
|
|
124
|
-
const updated: Record<string, any> | any[] = Array.isArray(obj)
|
|
125
|
-
? []
|
|
126
|
-
: {}
|
|
127
|
-
|
|
128
|
-
Object.keys(obj).forEach((key) => {
|
|
129
|
-
//@ts-ignore
|
|
130
|
-
updated[key] =
|
|
131
|
-
// @ts-ignore
|
|
132
|
-
checker(obj[key], depth) ? placeholder : obj[key]
|
|
133
|
-
|
|
134
|
-
//@ts-ignore
|
|
135
|
-
if (typeof updated[key] !== 'function' && isObject(updated[key])) {
|
|
136
|
-
//@ts-ignore
|
|
137
|
-
updated[key] = this.dropInPlaceholder(
|
|
138
|
-
//@ts-ignore
|
|
139
|
-
updated[key],
|
|
140
|
-
checker,
|
|
141
|
-
placeholder,
|
|
142
|
-
depth + 1
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
return updated
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
doHaystacksPassCheck(
|
|
151
|
-
haystacks: any[],
|
|
152
|
-
needle: any,
|
|
153
|
-
check: Assert['doesInclude']
|
|
154
|
-
) {
|
|
155
|
-
return !!haystacks.find((haystack) => {
|
|
156
|
-
try {
|
|
157
|
-
check(haystack, needle)
|
|
158
|
-
return true
|
|
159
|
-
} catch {
|
|
160
|
-
return false
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
assertTypeof(actual: any, type: string, message: string | undefined) {
|
|
166
|
-
if (typeof actual !== type) {
|
|
167
|
-
this.fail(message ?? `${JSON.stringify(actual)} is not a ${type}`)
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
assertErrorIncludes(
|
|
172
|
-
matcher: string | RegExp | undefined,
|
|
173
|
-
err: Error,
|
|
174
|
-
msg?: string | undefined
|
|
175
|
-
) {
|
|
176
|
-
const originalErrorMessage = err.message ?? ''
|
|
177
|
-
const errorMessage = originalErrorMessage.toLowerCase()
|
|
178
|
-
const needle =
|
|
179
|
-
typeof matcher === 'string' ? matcher.toLowerCase() : matcher
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
typeof needle === 'string' &&
|
|
183
|
-
errorMessage.search(needle) === -1 &&
|
|
184
|
-
!errorMessage.includes(needle)
|
|
185
|
-
) {
|
|
186
|
-
this.fail(
|
|
187
|
-
msg ??
|
|
188
|
-
`Expected thrown error whose message contains: \n\n${chalk.bold(
|
|
189
|
-
matcher
|
|
190
|
-
)}\n\nbut got back:\n\n\`${chalk.bold(originalErrorMessage)}\`.`,
|
|
191
|
-
'\n\nStack: ' + err.stack
|
|
192
|
-
)
|
|
193
|
-
} else if (
|
|
194
|
-
needle instanceof RegExp &&
|
|
195
|
-
errorMessage.search(needle) === -1 &&
|
|
196
|
-
originalErrorMessage.search(needle) === -1
|
|
197
|
-
) {
|
|
198
|
-
this.fail(
|
|
199
|
-
msg ??
|
|
200
|
-
`Expected thrown error whose message matches the regex: \n\n${chalk.bold(
|
|
201
|
-
matcher
|
|
202
|
-
)}\n\nbut got back:\n\n\`${chalk.bold(originalErrorMessage)}\`.`,
|
|
203
|
-
'\n\nStack: ' + err.stack
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
partialContains(object: any, subObject: any) {
|
|
209
|
-
const objProps = object ? Object.getOwnPropertyNames(object) : []
|
|
210
|
-
const subProps = subObject ? Object.getOwnPropertyNames(subObject) : []
|
|
211
|
-
|
|
212
|
-
if (objProps.length == 0 || subProps.length === 0) {
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (subProps.length > objProps.length) {
|
|
217
|
-
return false
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
for (const subProp of subProps) {
|
|
221
|
-
if (!Object.prototype.hasOwnProperty.call(object, subProp)) {
|
|
222
|
-
return false
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
(!isObjectLike(object[subProp]) ||
|
|
227
|
-
!isObjectLike(subObject[subProp])) &&
|
|
228
|
-
object[subProp] !== subObject[subProp]
|
|
229
|
-
) {
|
|
230
|
-
return false
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
isObjectLike(object[subProp]) &&
|
|
235
|
-
isObjectLike(subObject[subProp]) &&
|
|
236
|
-
!this.partialContains(object[subProp], subObject[subProp])
|
|
237
|
-
) {
|
|
238
|
-
return false
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return true
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
valueAtPath(object: Record<string, any>, path: string) {
|
|
246
|
-
return get(object, path)
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
parseIncludeNeedle(needle: any): {
|
|
250
|
-
needleHasArrayNotation: boolean
|
|
251
|
-
path?: string
|
|
252
|
-
expected?: any
|
|
253
|
-
} {
|
|
254
|
-
const path = Object.keys(needle)[0]
|
|
255
|
-
const expected = path && needle[path]
|
|
256
|
-
const needleHasArrayNotation = !!(path && path.search(/\[\]\./) > -1)
|
|
257
|
-
return { needleHasArrayNotation, path, expected }
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
splitPathBasedOnArrayNotation(path: string, haystack: any) {
|
|
261
|
-
const pathParts = path.split('[].')
|
|
262
|
-
const pathToFirstArray = pathParts.shift() ?? ''
|
|
263
|
-
const pathAfterFirstArray = pathParts.join('[].')
|
|
264
|
-
const actualBeforeArray = this.valueAtPath(haystack, pathToFirstArray)
|
|
265
|
-
return { actualBeforeArray, pathAfterFirstArray }
|
|
266
|
-
},
|
|
267
|
-
|
|
268
|
-
foundUsing3rdPartyIncludes(
|
|
269
|
-
haystack: any,
|
|
270
|
-
needle: any,
|
|
271
|
-
isHaystackObject: boolean
|
|
272
|
-
) {
|
|
273
|
-
let passed = false
|
|
274
|
-
const escapedNeedle =
|
|
275
|
-
typeof needle === 'string' ? escapeRegExp(needle) : needle
|
|
276
|
-
if (
|
|
277
|
-
typeof haystack === 'string' &&
|
|
278
|
-
typeof needle === 'string' &&
|
|
279
|
-
haystack.search(escapedNeedle) > -1
|
|
280
|
-
) {
|
|
281
|
-
passed = true
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (isHaystackObject && includes(haystack, escapedNeedle)) {
|
|
285
|
-
passed = true
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (isHaystackObject && this.partialContains(haystack, escapedNeedle)) {
|
|
289
|
-
passed = true
|
|
290
|
-
}
|
|
291
|
-
return passed
|
|
292
|
-
},
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
export default assertUtil
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import TestDecoratorResolver, {
|
|
2
|
-
TestLifecycleListeners,
|
|
3
|
-
} from './TestDecoratorResolver.js'
|
|
4
|
-
|
|
5
|
-
if (typeof it === 'undefined') {
|
|
6
|
-
//@ts-ignore
|
|
7
|
-
global.it = () => {}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let areLifecycleHooksInPlace = false
|
|
11
|
-
|
|
12
|
-
/** Hooks up before, after, etc. */
|
|
13
|
-
function hookupTestClassToJestLifecycle(Target: any) {
|
|
14
|
-
if (areLifecycleHooksInPlace) {
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
areLifecycleHooksInPlace = true
|
|
19
|
-
const hooks = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach']
|
|
20
|
-
hooks.forEach((hook) => {
|
|
21
|
-
// @ts-ignore
|
|
22
|
-
if (global[hook]) {
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
global[hook](async () => {
|
|
25
|
-
TestDecoratorResolver.resolveTestClass(Target)
|
|
26
|
-
if (hook === 'beforeEach') {
|
|
27
|
-
await TestLifecycleListeners.emitWillRunBeforeEach()
|
|
28
|
-
await runBeforeEach(Target)
|
|
29
|
-
await TestLifecycleListeners.emitDidRunBeforeEach()
|
|
30
|
-
} else if (hook === 'afterEach') {
|
|
31
|
-
await TestLifecycleListeners.emitWillRunAfterEach()
|
|
32
|
-
await runAfterEach(Target)
|
|
33
|
-
await TestLifecycleListeners.emitDidRunAfterEach()
|
|
34
|
-
TestDecoratorResolver.reset()
|
|
35
|
-
} else if (hook === 'beforeAll') {
|
|
36
|
-
await TestLifecycleListeners.emitWillRunBeforeAll()
|
|
37
|
-
await runBeforeAll(Target)
|
|
38
|
-
await TestLifecycleListeners.emitDidRunBeforeAll()
|
|
39
|
-
TestDecoratorResolver.reset()
|
|
40
|
-
} else if (hook === 'afterAll') {
|
|
41
|
-
await TestLifecycleListeners.emitWillRunAfterAll()
|
|
42
|
-
await runAfterAll(Target)
|
|
43
|
-
await TestLifecycleListeners.emitDidRunAfterAll()
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function runBeforeAll(Target: any) {
|
|
51
|
-
await callStaticHook(Target, 'beforeAll')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function runAfterAll(Target: any) {
|
|
55
|
-
await callStaticHook(Target, 'afterAll')
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function callStaticHook(Target: any, hook: 'beforeAll' | 'afterAll') {
|
|
59
|
-
const Class =
|
|
60
|
-
TestDecoratorResolver.ActiveTestClass ??
|
|
61
|
-
(typeof Target === 'function' ? Target : Target.constructor)
|
|
62
|
-
const cb = Class?.[hook]
|
|
63
|
-
await cb?.call(Class)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function runAfterEach(Target: any) {
|
|
67
|
-
if (TestDecoratorResolver.ActiveTestClass) {
|
|
68
|
-
const Resolved = TestDecoratorResolver.resolveTestClass(Target)
|
|
69
|
-
await Resolved.afterEach?.apply(Resolved)
|
|
70
|
-
} else if (Target.afterEach) {
|
|
71
|
-
await Target.afterEach?.apply?.(Target)
|
|
72
|
-
} else {
|
|
73
|
-
await Target?.constructor.afterEach?.apply?.(Target.constructor)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async function runBeforeEach(Target: any) {
|
|
78
|
-
if (TestDecoratorResolver.ActiveTestClass) {
|
|
79
|
-
const Resolved = TestDecoratorResolver.resolveTestClass(Target)
|
|
80
|
-
await Resolved.beforeEach?.apply(Resolved)
|
|
81
|
-
} else if (Target.beforeEach) {
|
|
82
|
-
await Target.beforeEach?.apply?.(Target)
|
|
83
|
-
} else {
|
|
84
|
-
await Target?.constructor.beforeEach?.apply?.(Target.constructor)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Test decorator */
|
|
89
|
-
export default function test(description?: string, ...args: any[]) {
|
|
90
|
-
return function (
|
|
91
|
-
Target: any,
|
|
92
|
-
propertyKey: string,
|
|
93
|
-
descriptor: PropertyDescriptor
|
|
94
|
-
) {
|
|
95
|
-
hookupTestClassToJestLifecycle(Target)
|
|
96
|
-
|
|
97
|
-
it(description ?? propertyKey, async () => {
|
|
98
|
-
const Resolved = TestDecoratorResolver.resolveTestClass(Target)
|
|
99
|
-
|
|
100
|
-
if (!Resolved[propertyKey]) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`The test '${propertyKey}()' should NOT be static when tests run with suite(). Or, if you are not using suite(), you MUST make your test static.`
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const bound = descriptor.value.bind(Resolved)
|
|
107
|
-
|
|
108
|
-
//@ts-ignore
|
|
109
|
-
global.activeTest = {
|
|
110
|
-
file: Target.name,
|
|
111
|
-
test: propertyKey,
|
|
112
|
-
}
|
|
113
|
-
return bound(...args)
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function suite() {
|
|
119
|
-
return function (Target: any) {
|
|
120
|
-
TestDecoratorResolver.ActiveTestClass = Target
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Only decorator */
|
|
125
|
-
test.only = (description?: string, ...args: any[]) => {
|
|
126
|
-
return function (
|
|
127
|
-
target: any,
|
|
128
|
-
propertyKey: string,
|
|
129
|
-
descriptor: PropertyDescriptor
|
|
130
|
-
) {
|
|
131
|
-
hookupTestClassToJestLifecycle(target)
|
|
132
|
-
|
|
133
|
-
it.only(description ?? propertyKey, async () => {
|
|
134
|
-
const bound = descriptor.value.bind(
|
|
135
|
-
TestDecoratorResolver.resolveTestClass(target)
|
|
136
|
-
)
|
|
137
|
-
return bound(...args)
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** Todo decorator */
|
|
143
|
-
test.todo = (description?: string, ..._args: any[]) => {
|
|
144
|
-
return function (target: any, propertyKey: string) {
|
|
145
|
-
hookupTestClassToJestLifecycle(target)
|
|
146
|
-
|
|
147
|
-
it.todo(description ?? propertyKey)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** Skip decorator */
|
|
152
|
-
test.skip = (description?: string, ...args: any[]) => {
|
|
153
|
-
return function (
|
|
154
|
-
target: any,
|
|
155
|
-
propertyKey: string,
|
|
156
|
-
descriptor: PropertyDescriptor
|
|
157
|
-
) {
|
|
158
|
-
hookupTestClassToJestLifecycle(target)
|
|
159
|
-
|
|
160
|
-
it.skip(description ?? propertyKey, async () => {
|
|
161
|
-
const bound = descriptor.value.bind(
|
|
162
|
-
TestDecoratorResolver.resolveTestClass(target)
|
|
163
|
-
)
|
|
164
|
-
return bound(...args)
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
}
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import { spawn, SpawnOptions, ChildProcess } from 'child_process'
|
|
2
|
-
import { Writable } from 'stream'
|
|
3
|
-
|
|
4
|
-
process.setMaxListeners(100)
|
|
5
|
-
|
|
6
|
-
export default class CommandServiceImpl implements CommandService {
|
|
7
|
-
private cwd: string
|
|
8
|
-
private activeChildProcess: ChildProcess | undefined
|
|
9
|
-
private ignoreCloseErrors = false
|
|
10
|
-
private static fakeResponses: {
|
|
11
|
-
command: string | RegExp
|
|
12
|
-
response: FakedCommandResponse
|
|
13
|
-
}[] = []
|
|
14
|
-
private static commandsRunCapturedByMockResponses: string[] = []
|
|
15
|
-
|
|
16
|
-
public constructor(cwd: string) {
|
|
17
|
-
this.cwd = cwd
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public getCwd() {
|
|
21
|
-
return this.cwd
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public setCwd(cwd: string) {
|
|
25
|
-
this.cwd = cwd
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public async execute(
|
|
29
|
-
cmd: string,
|
|
30
|
-
options?: ExecuteCommandOptions
|
|
31
|
-
): Promise<{
|
|
32
|
-
stdout: string
|
|
33
|
-
}> {
|
|
34
|
-
const cwd = this.cwd
|
|
35
|
-
const args = options?.args || this.parseArgv(cmd)
|
|
36
|
-
const executable = options?.args ? cmd : args.shift()
|
|
37
|
-
const boundKill = this.kill.bind(this)
|
|
38
|
-
|
|
39
|
-
if (!executable) {
|
|
40
|
-
throw new Error('Bad params sent to command service')
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { mockResponse, mockKey } = this.getMockResponse(executable, args)
|
|
44
|
-
|
|
45
|
-
if (mockResponse) {
|
|
46
|
-
CommandServiceImpl.commandsRunCapturedByMockResponses.push(mockKey)
|
|
47
|
-
mockResponse.callback?.(executable, args)
|
|
48
|
-
|
|
49
|
-
if (mockResponse.code !== 0) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`Command failed: ${executable} ${args.join(' ')}`
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return { stdout: mockResponse.stdout ?? '' }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
process.on('exit', boundKill)
|
|
59
|
-
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
let stdout = ''
|
|
62
|
-
let stderr = ''
|
|
63
|
-
const spawnOptions: SpawnOptions = options?.shouldStream
|
|
64
|
-
? {
|
|
65
|
-
stdio: 'inherit',
|
|
66
|
-
cwd,
|
|
67
|
-
env: {
|
|
68
|
-
PATH: process.env.PATH,
|
|
69
|
-
IS_CLI: 'true',
|
|
70
|
-
FORCE_COLOR: options?.forceColor ? '1' : '0',
|
|
71
|
-
...options?.env,
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
: {
|
|
75
|
-
cwd,
|
|
76
|
-
env: {
|
|
77
|
-
PATH: process.env.PATH,
|
|
78
|
-
IS_CLI: 'true',
|
|
79
|
-
FORCE_COLOR: options?.forceColor ? '1' : '0',
|
|
80
|
-
...options?.env,
|
|
81
|
-
},
|
|
82
|
-
shell: true,
|
|
83
|
-
...options?.spawnOptions,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let child: ChildProcess
|
|
87
|
-
if (spawnOptions.shell) {
|
|
88
|
-
const commandStr = options?.args
|
|
89
|
-
? [executable, ...args].join(' ')
|
|
90
|
-
: cmd
|
|
91
|
-
child = spawn(commandStr, spawnOptions)
|
|
92
|
-
} else {
|
|
93
|
-
child = spawn(executable, args, spawnOptions)
|
|
94
|
-
}
|
|
95
|
-
this.activeChildProcess = child
|
|
96
|
-
|
|
97
|
-
if (options?.outStream) {
|
|
98
|
-
child.stdout?.pipe(options.outStream)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
child.stdout?.addListener('data', (data) => {
|
|
102
|
-
options?.onData?.(data.toString())
|
|
103
|
-
stdout += data
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
child.stderr?.addListener('data', (data) => {
|
|
107
|
-
options?.onError?.(data.toString())
|
|
108
|
-
stderr += data
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
const closeHandler = (code: number) => {
|
|
112
|
-
process.off('exit', boundKill)
|
|
113
|
-
|
|
114
|
-
if (!this.activeChildProcess) {
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
this.activeChildProcess = undefined
|
|
118
|
-
|
|
119
|
-
setTimeout(() => {
|
|
120
|
-
child.stdout?.removeAllListeners()
|
|
121
|
-
child.stderr?.removeAllListeners()
|
|
122
|
-
child.removeAllListeners()
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
code === 0 ||
|
|
126
|
-
this.ignoreCloseErrors ||
|
|
127
|
-
options?.ignoreErrors
|
|
128
|
-
) {
|
|
129
|
-
resolve({ stdout })
|
|
130
|
-
this.ignoreCloseErrors = false
|
|
131
|
-
} else {
|
|
132
|
-
reject(
|
|
133
|
-
new Error(
|
|
134
|
-
`Command failed (exit ${code}): ${executable} ${args.join(' ')}\n${stderr}`
|
|
135
|
-
)
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
}, 0)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
child.addListener('close', closeHandler)
|
|
142
|
-
child.addListener('exit', closeHandler)
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private parseArgv(cmd: string): string[] {
|
|
147
|
-
const result: string[] = []
|
|
148
|
-
let current = ''
|
|
149
|
-
let inQuote = false
|
|
150
|
-
let quoteChar = ''
|
|
151
|
-
|
|
152
|
-
for (let i = 0; i < cmd.length; i++) {
|
|
153
|
-
const ch = cmd[i]
|
|
154
|
-
if (inQuote) {
|
|
155
|
-
if (ch === quoteChar) {
|
|
156
|
-
inQuote = false
|
|
157
|
-
} else {
|
|
158
|
-
current += ch
|
|
159
|
-
}
|
|
160
|
-
} else if (ch === '"' || ch === "'") {
|
|
161
|
-
inQuote = true
|
|
162
|
-
quoteChar = ch
|
|
163
|
-
} else if (ch === ' ') {
|
|
164
|
-
if (current.length > 0) {
|
|
165
|
-
result.push(current)
|
|
166
|
-
current = ''
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
current += ch
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (current.length > 0) {
|
|
173
|
-
result.push(current)
|
|
174
|
-
}
|
|
175
|
-
return result
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
public kill = () => {
|
|
179
|
-
const child = this.activeChildProcess
|
|
180
|
-
if (child?.pid) {
|
|
181
|
-
this.ignoreCloseErrors = true
|
|
182
|
-
try {
|
|
183
|
-
process.kill(-child.pid, 'SIGTERM')
|
|
184
|
-
} catch {
|
|
185
|
-
try {
|
|
186
|
-
child.kill('SIGTERM')
|
|
187
|
-
} catch {}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
public pid = () => {
|
|
193
|
-
return this.activeChildProcess?.pid
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private getMockResponse(executable: string, args: string[]) {
|
|
197
|
-
const mockKey = `${executable} ${args.join(' ')}`.trim()
|
|
198
|
-
const commands = CommandServiceImpl.fakeResponses
|
|
199
|
-
const match = commands.find((r) =>
|
|
200
|
-
r.command instanceof RegExp
|
|
201
|
-
? mockKey.search(r.command) > -1
|
|
202
|
-
: r.command.replace(/ +/gis, '') ===
|
|
203
|
-
mockKey.replace(/ +/gis, '')
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
return { mockResponse: match?.response, mockKey }
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
public static fakeCommand(
|
|
210
|
-
command: string | RegExp,
|
|
211
|
-
response: FakedCommandResponse
|
|
212
|
-
) {
|
|
213
|
-
this.fakeResponses.unshift({
|
|
214
|
-
command,
|
|
215
|
-
response,
|
|
216
|
-
})
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
public static clearFakedResponses() {
|
|
220
|
-
this.fakeResponses = []
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export type FakedCommandCallback = (executable: string, args: any[]) => void
|
|
225
|
-
|
|
226
|
-
interface FakedCommandResponse {
|
|
227
|
-
code: number
|
|
228
|
-
stdout?: string
|
|
229
|
-
stderr?: string
|
|
230
|
-
callback?: FakedCommandCallback
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export interface CommandService {
|
|
234
|
-
execute(
|
|
235
|
-
cmd: string,
|
|
236
|
-
options?: ExecuteCommandOptions
|
|
237
|
-
): Promise<{
|
|
238
|
-
stdout: string
|
|
239
|
-
}>
|
|
240
|
-
getCwd(): string
|
|
241
|
-
setCwd(cwd: string): void
|
|
242
|
-
kill(): void
|
|
243
|
-
pid(): number | undefined
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export interface ExecuteCommandOptions {
|
|
247
|
-
ignoreErrors?: boolean
|
|
248
|
-
args?: string[]
|
|
249
|
-
shouldStream?: boolean
|
|
250
|
-
outStream?: Writable
|
|
251
|
-
onError?: (error: string) => void
|
|
252
|
-
onData?: (data: string) => void
|
|
253
|
-
spawnOptions?: SpawnOptions
|
|
254
|
-
forceColor?: boolean
|
|
255
|
-
env?: Record<string, any>
|
|
256
|
-
}
|