@plugjs/expect5 0.4.2 → 0.4.3
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/dist/cli.mjs +1 -1
- package/dist/expectation/async.cjs +73 -0
- package/dist/expectation/async.cjs.map +6 -0
- package/dist/expectation/async.d.ts +54 -0
- package/dist/expectation/async.mjs +46 -0
- package/dist/expectation/async.mjs.map +6 -0
- package/dist/expectation/basic.cjs +155 -183
- package/dist/expectation/basic.cjs.map +1 -1
- package/dist/expectation/basic.d.ts +90 -47
- package/dist/expectation/basic.mjs +142 -163
- package/dist/expectation/basic.mjs.map +1 -1
- package/dist/expectation/diff.cjs +7 -7
- package/dist/expectation/diff.cjs.map +1 -1
- package/dist/expectation/diff.mjs +7 -7
- package/dist/expectation/diff.mjs.map +1 -1
- package/dist/expectation/expect.cjs +94 -108
- package/dist/expectation/expect.cjs.map +2 -2
- package/dist/expectation/expect.d.ts +103 -130
- package/dist/expectation/expect.mjs +131 -137
- package/dist/expectation/expect.mjs.map +2 -2
- package/dist/expectation/include.cjs +50 -61
- package/dist/expectation/include.cjs.map +1 -1
- package/dist/expectation/include.d.ts +19 -10
- package/dist/expectation/include.mjs +53 -57
- package/dist/expectation/include.mjs.map +1 -1
- package/dist/expectation/throwing.cjs +27 -27
- package/dist/expectation/throwing.cjs.map +1 -1
- package/dist/expectation/throwing.d.ts +36 -8
- package/dist/expectation/throwing.mjs +26 -26
- package/dist/expectation/throwing.mjs.map +1 -1
- package/dist/expectation/trivial.cjs +96 -0
- package/dist/expectation/trivial.cjs.map +6 -0
- package/dist/expectation/trivial.d.ts +13 -0
- package/dist/expectation/trivial.mjs +61 -0
- package/dist/expectation/trivial.mjs.map +6 -0
- package/dist/expectation/types.cjs +9 -12
- package/dist/expectation/types.cjs.map +1 -1
- package/dist/expectation/types.d.ts +52 -10
- package/dist/expectation/types.mjs +8 -10
- package/dist/expectation/types.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/expectation/async.ts +151 -0
- package/src/expectation/basic.ts +356 -156
- package/src/expectation/diff.ts +8 -9
- package/src/expectation/expect.ts +239 -268
- package/src/expectation/include.ts +93 -59
- package/src/expectation/throwing.ts +102 -41
- package/src/expectation/trivial.ts +107 -0
- package/src/expectation/types.ts +82 -25
- package/src/index.ts +2 -0
- package/dist/expectation/void.cjs +0 -111
- package/dist/expectation/void.cjs.map +0 -6
- package/dist/expectation/void.d.ts +0 -39
- package/dist/expectation/void.mjs +0 -77
- package/dist/expectation/void.mjs.map +0 -6
- package/src/expectation/void.ts +0 -80
|
@@ -1,294 +1,274 @@
|
|
|
1
|
-
import { ExpectationError, matcherMarker } from './types'
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
2
|
+
toBeRejected,
|
|
3
|
+
toBeRejectedWithError,
|
|
4
|
+
toBeResolved,
|
|
5
|
+
} from './async'
|
|
6
|
+
import {
|
|
7
|
+
toBeA,
|
|
8
|
+
toBeCloseTo,
|
|
9
|
+
toBeError,
|
|
10
|
+
toBeGreaterThan,
|
|
11
|
+
toBeGreaterThanOrEqual,
|
|
12
|
+
toBeInstanceOf,
|
|
13
|
+
toBeLessThan,
|
|
14
|
+
toBeLessThanOrEqual,
|
|
15
|
+
toBeWithinRange,
|
|
16
|
+
toEqual,
|
|
17
|
+
toHaveLength,
|
|
18
|
+
toHaveProperty,
|
|
19
|
+
toHaveSize,
|
|
20
|
+
toMatch,
|
|
21
|
+
toStrictlyEqual,
|
|
18
22
|
} from './basic'
|
|
19
23
|
import {
|
|
20
|
-
|
|
24
|
+
toInclude,
|
|
25
|
+
toMatchContents,
|
|
21
26
|
} from './include'
|
|
22
27
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
toThrow,
|
|
29
|
+
toThrowError,
|
|
25
30
|
} from './throwing'
|
|
26
31
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
import
|
|
32
|
+
toBeDefined,
|
|
33
|
+
toBeFalse,
|
|
34
|
+
toBeFalsy,
|
|
35
|
+
toBeNaN,
|
|
36
|
+
toBeNegativeInfinity,
|
|
37
|
+
toBeNull,
|
|
38
|
+
toBeNullable,
|
|
39
|
+
toBePositiveInfinity,
|
|
40
|
+
toBeTrue,
|
|
41
|
+
toBeTruthy,
|
|
42
|
+
toBeUndefined,
|
|
43
|
+
} from './trivial'
|
|
44
|
+
import {
|
|
45
|
+
ExpectationError,
|
|
46
|
+
matcherMarker,
|
|
47
|
+
} from './types'
|
|
48
|
+
|
|
49
|
+
import type {
|
|
50
|
+
ExpectationsContext,
|
|
51
|
+
ExpectationsParent,
|
|
52
|
+
} from './types'
|
|
40
53
|
|
|
41
54
|
/* ========================================================================== *
|
|
42
55
|
* IMPORT AND PREPARE EXTERNAL EXPECTATIONS *
|
|
43
56
|
* ========================================================================== */
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
const asyncExpectations = {
|
|
59
|
+
toBeResolved,
|
|
60
|
+
toBeRejected,
|
|
61
|
+
toBeRejectedWithError,
|
|
62
|
+
} as const
|
|
63
|
+
|
|
64
|
+
type AsyncExpectations = typeof asyncExpectations
|
|
65
|
+
|
|
66
|
+
const syncExpectations = {
|
|
67
|
+
// basic
|
|
68
|
+
toBeA,
|
|
69
|
+
toBeCloseTo,
|
|
70
|
+
toBeError,
|
|
71
|
+
toBeGreaterThan,
|
|
72
|
+
toBeGreaterThanOrEqual,
|
|
73
|
+
toBeInstanceOf,
|
|
74
|
+
toBeLessThan,
|
|
75
|
+
toBeLessThanOrEqual,
|
|
76
|
+
toBeWithinRange,
|
|
77
|
+
toEqual,
|
|
78
|
+
toHaveLength,
|
|
79
|
+
toHaveProperty,
|
|
80
|
+
toHaveSize,
|
|
81
|
+
toMatch,
|
|
82
|
+
toStrictlyEqual,
|
|
63
83
|
|
|
64
84
|
// include
|
|
65
|
-
toInclude
|
|
66
|
-
toMatchContents
|
|
85
|
+
toInclude,
|
|
86
|
+
toMatchContents,
|
|
67
87
|
|
|
68
88
|
// throwing
|
|
69
|
-
toThrow
|
|
70
|
-
toThrowError
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
toBeDefined
|
|
74
|
-
toBeFalse
|
|
75
|
-
toBeFalsy
|
|
76
|
-
toBeNaN
|
|
77
|
-
toBeNegativeInfinity
|
|
78
|
-
toBeNull
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
toThrow,
|
|
90
|
+
toThrowError,
|
|
91
|
+
|
|
92
|
+
// trivial
|
|
93
|
+
toBeDefined,
|
|
94
|
+
toBeFalse,
|
|
95
|
+
toBeFalsy,
|
|
96
|
+
toBeNaN,
|
|
97
|
+
toBeNegativeInfinity,
|
|
98
|
+
toBeNull,
|
|
99
|
+
toBeNullable,
|
|
100
|
+
toBePositiveInfinity,
|
|
101
|
+
toBeTrue,
|
|
102
|
+
toBeTruthy,
|
|
103
|
+
toBeUndefined,
|
|
83
104
|
} as const
|
|
84
105
|
|
|
85
|
-
|
|
86
|
-
type ExpectationsByName = typeof expectations
|
|
106
|
+
type SyncExpectations = typeof syncExpectations
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
never
|
|
108
|
+
const allExpectations = {
|
|
109
|
+
...asyncExpectations,
|
|
110
|
+
...syncExpectations,
|
|
111
|
+
}
|
|
93
112
|
|
|
94
|
-
|
|
95
|
-
type ExpectationReturn<E, T> = E extends Expectation ? Expectations<T> : never
|
|
113
|
+
type AllExpectations = SyncExpectations & AsyncExpectations
|
|
96
114
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
/* ========================================================================== *
|
|
116
|
+
* OVERLOADED FUNCTIONS TYPES *
|
|
117
|
+
* ========================================================================== */
|
|
118
|
+
|
|
119
|
+
/** Combine the arguments of a number of overloads (tuples) */
|
|
120
|
+
type OverloadArguments<T> =
|
|
121
|
+
T extends readonly [ infer T, ...infer Rest ] ?
|
|
122
|
+
[ T, ...OverloadArguments<Rest> ] :
|
|
123
|
+
T extends readonly [] ? [] :
|
|
124
|
+
T extends readonly (infer T)[] ?
|
|
125
|
+
unknown extends T ? never :
|
|
126
|
+
T extends undefined ? [] :
|
|
127
|
+
[ T ] :
|
|
128
|
+
never
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Remap `Functions` (a record of functions) inferring arguments and forcing
|
|
132
|
+
* return type to `Result`
|
|
133
|
+
*/
|
|
134
|
+
type OverloadFunctions<Functions, Result> = {
|
|
135
|
+
[ k in keyof Functions ]:
|
|
136
|
+
Functions[k] extends {
|
|
137
|
+
(...args: infer A0): any
|
|
138
|
+
(...args: infer A1): any
|
|
139
|
+
(...args: infer A2): any
|
|
140
|
+
(...args: infer A3): any
|
|
141
|
+
(...args: infer A4): any
|
|
142
|
+
(...args: infer A5): any
|
|
143
|
+
} ? (...args: OverloadArguments<A0 | A1 | A2 | A3 | A4 | A5>) => Result :
|
|
144
|
+
Functions[k] extends {
|
|
145
|
+
(...args: infer A0): any
|
|
146
|
+
(...args: infer A1): any
|
|
147
|
+
(...args: infer A2): any
|
|
148
|
+
(...args: infer A3): any
|
|
149
|
+
(...args: infer A4): any
|
|
150
|
+
} ? (...args: OverloadArguments<A0 | A1 | A2 | A3 | A4>) => Result :
|
|
151
|
+
Functions[k] extends {
|
|
152
|
+
(...args: infer A0): any
|
|
153
|
+
(...args: infer A1): any
|
|
154
|
+
(...args: infer A2): any
|
|
155
|
+
(...args: infer A3): any
|
|
156
|
+
} ? (...args: OverloadArguments<A0 | A1 | A2 | A3>) => Result :
|
|
157
|
+
Functions[k] extends {
|
|
158
|
+
(...args: infer A0): any
|
|
159
|
+
(...args: infer A1): any
|
|
160
|
+
(...args: infer A2): any
|
|
161
|
+
} ? (...args: OverloadArguments<A0 | A1 | A2>) => Result :
|
|
162
|
+
Functions[k] extends {
|
|
163
|
+
(...args: infer A0): any
|
|
164
|
+
(...args: infer A1): any
|
|
165
|
+
} ? (...args: OverloadArguments<A0 | A1>) => Result :
|
|
166
|
+
Functions[k] extends {
|
|
167
|
+
(...args: infer A0): any
|
|
168
|
+
} ? (...args: OverloadArguments<A0>) => Result :
|
|
169
|
+
never
|
|
102
170
|
}
|
|
103
171
|
|
|
104
172
|
/* ========================================================================== *
|
|
105
173
|
* EXPECTATIONS DEFINITION *
|
|
106
174
|
* ========================================================================== */
|
|
107
175
|
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Expectation functions simply check a _value_, but do not alter the type
|
|
178
|
+
* returned by each expectation.
|
|
179
|
+
*/
|
|
180
|
+
export interface ExpectationFunctions<T> extends
|
|
181
|
+
OverloadFunctions<AsyncExpectations, Promise<Expectations<PromiseLike<T>>>>,
|
|
182
|
+
OverloadFunctions<SyncExpectations, Expectations<T>> {
|
|
183
|
+
// empty interface, specifically without `value` or `not` so that
|
|
184
|
+
// in no way this can be confused with the full `Expectations<T>`.
|
|
185
|
+
}
|
|
115
186
|
|
|
187
|
+
/**
|
|
188
|
+
* An interface describing all expectations returned by `expect(...)`.
|
|
189
|
+
*
|
|
190
|
+
* Each function, upon checking, might return an expectation bound to a
|
|
191
|
+
* different _type_ (for example `.toBeNull()` returns always
|
|
192
|
+
* `Expectations<null>`, inferring that `value` is indeed `null`).
|
|
193
|
+
*/
|
|
194
|
+
export interface Expectations<T = unknown> extends AllExpectations {
|
|
116
195
|
/** The value this {@link Expectations} instance operates on */
|
|
117
|
-
value: T
|
|
118
|
-
|
|
196
|
+
readonly value: T
|
|
119
197
|
/** The _negated_ expectations of _this_ {@link Expectations} instance. */
|
|
120
|
-
not:
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Programmatically return _positive_ or _negative_ {@link Expectations}
|
|
124
|
-
* for the value wrapped by this instance.
|
|
125
|
-
*/
|
|
126
|
-
negated(negative: boolean): Expectations<T>
|
|
127
|
-
|
|
128
|
-
/** Create an {@link Expectations} associated with a property of this value */
|
|
129
|
-
forProperty(prop: string | number | symbol): Expectations
|
|
130
|
-
|
|
131
|
-
/** Create a new {@link Expectations} instance for the specified value */
|
|
132
|
-
forValue<T = unknown>(value: T): Expectations<T>
|
|
133
|
-
|
|
134
|
-
/* == ASYNCHRONOUS EXPECTATIONS =========================================== */
|
|
135
|
-
|
|
136
|
-
/** Expect the value to be a _resolved_ {@link Promise} */
|
|
137
|
-
toBeResolved(): Promise<ExpectationsImpl<T>>
|
|
138
|
-
/**
|
|
139
|
-
* Expect the value to be a _resolved_ {@link Promise}, and assert the
|
|
140
|
-
* resolved result with the specified callback
|
|
141
|
-
*/
|
|
142
|
-
toBeResolved(assert: (resultExpectations: Expectations) => void): Promise<ExpectationsImpl<T>>
|
|
143
|
-
|
|
144
|
-
/** Expect the value to be a _rejected_ {@link Promise} */
|
|
145
|
-
toBeRejected(): Promise<ExpectationsImpl<T>>
|
|
146
|
-
/**
|
|
147
|
-
* Expect the value to be a _rejected_ {@link Promise}, and assert the
|
|
148
|
-
* rejected reason with the specified callback
|
|
149
|
-
*/
|
|
150
|
-
toBeRejected(assert?: (rejectionExpectations: Expectations) => void): Promise<ExpectationsImpl<T>>
|
|
151
|
-
|
|
152
|
-
/** Expect the value to be a {@link Promise} _rejected_ by an {@link Error} */
|
|
153
|
-
toBeRejectedWithError(): Promise<Expectations<T>>
|
|
154
|
-
/**
|
|
155
|
-
* Expect the value to be a {@link Promise} _rejected_ by an {@link Error}
|
|
156
|
-
* with the specified _message_
|
|
157
|
-
*/
|
|
158
|
-
toBeRejectedWithError(message: StringMatcher): Promise<Expectations<T>>
|
|
159
|
-
/**
|
|
160
|
-
* Expect the value to be a {@link Promise} _rejected_ by an {@link Error}
|
|
161
|
-
* of the specified _type_
|
|
162
|
-
*/
|
|
163
|
-
toBeRejectedWithError(constructor: Constructor<Error>): Promise<Expectations<T>>
|
|
164
|
-
/**
|
|
165
|
-
* Expect the value to be a {@link Promise} _rejected_ by an {@link Error}
|
|
166
|
-
* of the specified _type_ and with the specified _message_
|
|
167
|
-
*/
|
|
168
|
-
toBeRejectedWithError(constructor: Constructor<Error>, message: StringMatcher): Promise<Expectations<T>>
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/** Parent expectations */
|
|
172
|
-
export interface ExpectationsParent {
|
|
173
|
-
context: Expectations,
|
|
174
|
-
prop: string | number | symbol,
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** Basic definition of an {@link Expectation} as an object */
|
|
178
|
-
export interface Expectation {
|
|
179
|
-
expect(context: Expectations, negative: boolean, ...args: any[]): void
|
|
198
|
+
readonly not: ExpectationFunctions<T>
|
|
180
199
|
}
|
|
181
200
|
|
|
182
201
|
/* ========================================================================== *
|
|
183
202
|
* EXPECTATIONS IMPLEMENTATION *
|
|
184
203
|
* ========================================================================== */
|
|
185
204
|
|
|
186
|
-
|
|
187
|
-
interface ExpectationsImpl<T = unknown> extends Expectations<T> {}
|
|
188
|
-
|
|
189
|
-
/** Implementation of our {@link Expectations} interface */
|
|
190
|
-
class ExpectationsImpl<T = unknown> implements Expectations<T> {
|
|
191
|
-
private readonly _positiveExpectations: ExpectationsImpl<T>
|
|
192
|
-
private readonly _negativeExpectations: ExpectationsImpl<T>
|
|
193
|
-
private readonly _negative: boolean
|
|
194
|
-
|
|
205
|
+
class ExpectationsContextImpl<T = unknown> implements ExpectationsContext<T> {
|
|
195
206
|
constructor(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this._negative = false
|
|
205
|
-
this._positiveExpectations = this
|
|
206
|
-
this._negativeExpectations = new ExpectationsImpl(value, this)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/* == NEW EXPECTATIONS ==================================================== */
|
|
211
|
-
|
|
212
|
-
forProperty(prop: string | number | symbol): ExpectationsImpl {
|
|
213
|
-
this.toBeDefined()
|
|
214
|
-
|
|
215
|
-
const child = new ExpectationsImpl((this.value as any)[prop])
|
|
216
|
-
child.parent = { context: this, prop }
|
|
217
|
-
return child
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
forValue<T = unknown>(value: T): ExpectationsImpl<T> {
|
|
207
|
+
readonly value: T,
|
|
208
|
+
readonly negative: boolean,
|
|
209
|
+
readonly expects: Expectations<T>,
|
|
210
|
+
readonly negated: ExpectationFunctions<T>,
|
|
211
|
+
readonly parent?: ExpectationsParent,
|
|
212
|
+
) {}
|
|
213
|
+
|
|
214
|
+
forValue<V>(value: V): Expectations<V> {
|
|
221
215
|
return new ExpectationsImpl(value)
|
|
222
216
|
}
|
|
223
217
|
|
|
224
|
-
|
|
218
|
+
forProperty(prop: string | number | symbol): Expectations<unknown> {
|
|
219
|
+
this.expects.toBeDefined()
|
|
225
220
|
|
|
226
|
-
|
|
227
|
-
|
|
221
|
+
const value = (this.value as any)[prop]
|
|
222
|
+
const parent = { context: this, prop }
|
|
223
|
+
return new ExpectationsImpl(value, parent)
|
|
228
224
|
}
|
|
225
|
+
}
|
|
229
226
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
227
|
+
/** Empty interface: the `class` below won't complain about missing stuff */
|
|
228
|
+
interface ExpectationsImpl<T = unknown> extends Expectations<T> {}
|
|
233
229
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
return Promise.resolve()
|
|
238
|
-
.then(() => {
|
|
239
|
-
this._positiveExpectations.toHaveProperty('then', (a) => a.toBeA('function'))
|
|
240
|
-
return Promise.allSettled([ Promise.resolve(this.value) ])
|
|
241
|
-
})
|
|
242
|
-
.then(([ settlement ]) => {
|
|
243
|
-
if (settlement.status === 'fulfilled') {
|
|
244
|
-
if (this._negative) throw new ExpectationError(this, true, 'to be resolved')
|
|
245
|
-
if (assert) assert(new ExpectationsImpl(settlement.value))
|
|
246
|
-
} else if (! this._negative) {
|
|
247
|
-
throw new ExpectationError(this, false, 'to be resolved')
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return this._positiveExpectations
|
|
251
|
-
})
|
|
252
|
-
}
|
|
230
|
+
/** Implementation of our {@link Expectations} interface */
|
|
231
|
+
class ExpectationsImpl<T = unknown> implements Expectations<T> {
|
|
232
|
+
private readonly _context: ExpectationsContext<T>
|
|
253
233
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
.then(() => {
|
|
257
|
-
this._positiveExpectations.toHaveProperty('then', (a) => a.toBeA('function'))
|
|
258
|
-
return Promise.allSettled([ Promise.resolve(this.value) ])
|
|
259
|
-
})
|
|
260
|
-
.then(([ settlement ]) => {
|
|
261
|
-
if (settlement.status === 'rejected') {
|
|
262
|
-
if (this._negative) throw new ExpectationError(this, true, 'to be rejected')
|
|
263
|
-
if (assert) assert(new ExpectationsImpl(settlement.reason))
|
|
264
|
-
} else if (! this._negative) {
|
|
265
|
-
throw new ExpectationError(this, false, 'to be rejected')
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return this._positiveExpectations
|
|
269
|
-
})
|
|
270
|
-
}
|
|
234
|
+
readonly value: T
|
|
235
|
+
readonly not: ExpectationFunctions<T>
|
|
271
236
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
237
|
+
constructor(
|
|
238
|
+
value: T,
|
|
239
|
+
parent?: ExpectationsParent,
|
|
240
|
+
positives?: Expectations<T>,
|
|
241
|
+
) {
|
|
242
|
+
this.value = value
|
|
243
|
+
|
|
244
|
+
if (positives) {
|
|
245
|
+
this.not = positives as ExpectationFunctions<any>
|
|
246
|
+
this._context = new ExpectationsContextImpl(
|
|
247
|
+
value,
|
|
248
|
+
true,
|
|
249
|
+
positives,
|
|
250
|
+
this as ExpectationFunctions<any>,
|
|
251
|
+
parent)
|
|
252
|
+
} else {
|
|
253
|
+
this._context = new ExpectationsContextImpl(
|
|
254
|
+
value,
|
|
255
|
+
false,
|
|
256
|
+
this,
|
|
257
|
+
this as ExpectationFunctions<any>,
|
|
258
|
+
parent)
|
|
259
|
+
this.not = new ExpectationsImpl(value, parent, this) as ExpectationFunctions<any>
|
|
260
|
+
}
|
|
280
261
|
}
|
|
281
262
|
|
|
282
263
|
/* == STATIC INITALIZER =================================================== */
|
|
283
264
|
|
|
284
265
|
static {
|
|
285
|
-
for (const [ key, value ] of Object.entries(
|
|
286
|
-
const expectation = value as
|
|
266
|
+
for (const [ key, value ] of Object.entries(allExpectations)) {
|
|
267
|
+
const expectation = value as (this: ExpectationsContext, ...args: any[]) => any
|
|
287
268
|
|
|
288
269
|
const fn = function(this: ExpectationsImpl, ...args: any[]): any {
|
|
289
270
|
try {
|
|
290
|
-
expectation.
|
|
291
|
-
return this._positiveExpectations
|
|
271
|
+
return expectation.call(this._context, ...args)
|
|
292
272
|
} catch (error) {
|
|
293
273
|
if (error instanceof ExpectationError) Error.captureStackTrace(error, fn)
|
|
294
274
|
throw error
|
|
@@ -305,34 +285,24 @@ class ExpectationsImpl<T = unknown> implements Expectations<T> {
|
|
|
305
285
|
* EXPECTATIONS MATCHERS *
|
|
306
286
|
* ========================================================================== */
|
|
307
287
|
|
|
308
|
-
/** Infer return parameter from {@link Expectation} type */
|
|
309
|
-
type MatcherReturn<E> = E extends Expectation ? ExpectationsMatcher : never
|
|
310
|
-
|
|
311
|
-
/** Infer expectation functions from imported {@link Expectation} instances */
|
|
312
|
-
type ImportedMatchers = {
|
|
313
|
-
[ k in keyof ExpectationsByName ]: (
|
|
314
|
-
...args: ExpectationParameters<ExpectationsByName[k]>
|
|
315
|
-
) => MatcherReturn<ExpectationsByName[k]>
|
|
316
|
-
}
|
|
317
|
-
|
|
318
288
|
/** An interface describing all expectations returned by `expect(...)` */
|
|
319
|
-
export interface
|
|
320
|
-
not:
|
|
289
|
+
export interface Matchers extends OverloadFunctions<SyncExpectations, Matchers> {
|
|
290
|
+
not: Matchers
|
|
291
|
+
/* The assertion here will trigger */
|
|
321
292
|
expect(value: unknown): void
|
|
322
293
|
}
|
|
323
294
|
|
|
295
|
+
interface MatcherImpl extends Matchers {}
|
|
324
296
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
class ExpectationsMatcherImpl {
|
|
297
|
+
class MatcherImpl {
|
|
328
298
|
private readonly _matchers: readonly [ string, boolean, any[] ][]
|
|
329
|
-
private readonly _positiveBuilder:
|
|
330
|
-
private readonly _negativeBuilder:
|
|
299
|
+
private readonly _positiveBuilder: MatcherImpl
|
|
300
|
+
private readonly _negativeBuilder: MatcherImpl
|
|
331
301
|
private readonly _negative: boolean
|
|
332
302
|
|
|
333
303
|
constructor(
|
|
334
304
|
_matchers: readonly [ string, boolean, any[] ][],
|
|
335
|
-
_positiveBuilder?:
|
|
305
|
+
_positiveBuilder?: MatcherImpl,
|
|
336
306
|
) {
|
|
337
307
|
this._matchers = _matchers
|
|
338
308
|
if (_positiveBuilder) {
|
|
@@ -342,18 +312,19 @@ class ExpectationsMatcherImpl {
|
|
|
342
312
|
} else {
|
|
343
313
|
this._negative = false
|
|
344
314
|
this._positiveBuilder = this
|
|
345
|
-
this._negativeBuilder = new
|
|
315
|
+
this._negativeBuilder = new MatcherImpl(this._matchers, this)
|
|
346
316
|
}
|
|
347
317
|
}
|
|
348
318
|
|
|
349
|
-
get not():
|
|
319
|
+
get not(): MatcherImpl {
|
|
350
320
|
return this._negative ? this._positiveBuilder : this._negativeBuilder
|
|
351
321
|
}
|
|
352
322
|
|
|
353
323
|
expect(value: unknown): void {
|
|
354
|
-
const expectations =
|
|
324
|
+
const expectations = expect(value)
|
|
355
325
|
for (const [ expectation, negative, args ] of this._matchers) {
|
|
356
|
-
|
|
326
|
+
const expect = negative ? expectations.not as any : expectations as any
|
|
327
|
+
expect[expectation](...args)
|
|
357
328
|
}
|
|
358
329
|
}
|
|
359
330
|
|
|
@@ -364,10 +335,10 @@ class ExpectationsMatcherImpl {
|
|
|
364
335
|
Object.defineProperty(this.prototype, matcherMarker, { value: matcherMarker })
|
|
365
336
|
|
|
366
337
|
// all our matchers
|
|
367
|
-
for (const key in
|
|
338
|
+
for (const key in syncExpectations) {
|
|
368
339
|
Object.defineProperty(this.prototype, key, {
|
|
369
|
-
value: function(this:
|
|
370
|
-
return new
|
|
340
|
+
value: function(this: MatcherImpl, ...args: any[]): any {
|
|
341
|
+
return new MatcherImpl([
|
|
371
342
|
...this._matchers, [ key, this._negative, args ],
|
|
372
343
|
])
|
|
373
344
|
},
|
|
@@ -383,18 +354,18 @@ class ExpectationsMatcherImpl {
|
|
|
383
354
|
/** The `expect` function exposing expectations and matchers */
|
|
384
355
|
export const expect = (<T = unknown>(value: T): Expectations<T> => {
|
|
385
356
|
return new ExpectationsImpl(value)
|
|
386
|
-
}) as
|
|
357
|
+
}) as Matchers & (<T = unknown>(value: T) => Expectations<T>)
|
|
387
358
|
|
|
388
359
|
// Instrument a getter for negative matchers
|
|
389
360
|
Object.defineProperty(expect, 'not', {
|
|
390
|
-
get: () => new
|
|
361
|
+
get: () => new MatcherImpl([]).not,
|
|
391
362
|
})
|
|
392
363
|
|
|
393
|
-
// Create a matcher for each expectation
|
|
394
|
-
for (const name in
|
|
364
|
+
// Create a matcher for each expectation function
|
|
365
|
+
for (const name in syncExpectations) {
|
|
395
366
|
Object.defineProperty(expect, name, {
|
|
396
|
-
value: function(...args: any[]):
|
|
397
|
-
const builder = new
|
|
367
|
+
value: function(...args: any[]): Matchers {
|
|
368
|
+
const builder = new MatcherImpl([])
|
|
398
369
|
return (builder as any)[name](...args)
|
|
399
370
|
},
|
|
400
371
|
})
|