@effect/vitest 4.0.0-beta.1 → 4.0.0-beta.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +43 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -23
- package/dist/index.js.map +1 -1
- package/dist/internal/internal.d.ts +1 -1
- package/dist/internal/internal.js +65 -14
- package/dist/internal/internal.js.map +1 -1
- package/dist/utils.d.ts +40 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +35 -12
- package/dist/utils.js.map +1 -1
- package/package.json +9 -9
- package/src/index.ts +41 -33
- package/src/internal/internal.ts +95 -23
- package/src/utils.ts +46 -15
package/src/internal/internal.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since
|
|
2
|
+
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { getCurrentSuite } from "@vitest/runner"
|
|
5
6
|
import * as Cause from "effect/Cause"
|
|
6
7
|
import * as Duration from "effect/Duration"
|
|
7
8
|
import * as Effect from "effect/Effect"
|
|
@@ -48,6 +49,44 @@ export const addEqualityTesters = () => {
|
|
|
48
49
|
/** @internal */
|
|
49
50
|
const testOptions = (timeout?: number | V.TestOptions) => typeof timeout === "number" ? { timeout } : timeout ?? {}
|
|
50
51
|
|
|
52
|
+
const hookTimeout = (timeout?: Duration.Input) =>
|
|
53
|
+
timeout === undefined ? undefined : Duration.toMillis(Duration.fromInputUnsafe(timeout))
|
|
54
|
+
|
|
55
|
+
const makeItProxy = <Methods extends object>(
|
|
56
|
+
it: V.TestAPI,
|
|
57
|
+
overrides: Methods
|
|
58
|
+
): Methods & V.TestAPI =>
|
|
59
|
+
new Proxy(it as Methods & V.TestAPI, {
|
|
60
|
+
apply(target, thisArg, argArray) {
|
|
61
|
+
return Reflect.apply(target, thisArg, argArray)
|
|
62
|
+
},
|
|
63
|
+
get(target, property, receiver) {
|
|
64
|
+
if (property in overrides) {
|
|
65
|
+
return Reflect.get(overrides, property)
|
|
66
|
+
}
|
|
67
|
+
// do not bind: binding would strip vitest's static helpers (e.g. `describe.each`)
|
|
68
|
+
return Reflect.get(target, property, receiver)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
type CollectedTask = {
|
|
73
|
+
readonly type: string
|
|
74
|
+
readonly mode?: string
|
|
75
|
+
readonly tasks?: ReadonlyArray<CollectedTask>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const collectTasks = (tasks: ReadonlyArray<CollectedTask>, acc: Array<V.TestContext["task"]> = []) => {
|
|
79
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
80
|
+
const task = tasks[i]
|
|
81
|
+
if (task.type === "test" && task.mode !== "skip" && task.mode !== "todo") {
|
|
82
|
+
acc.push(task as V.TestContext["task"])
|
|
83
|
+
} else if (task.tasks !== undefined) {
|
|
84
|
+
collectTasks(task.tasks, acc)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return acc
|
|
88
|
+
}
|
|
89
|
+
|
|
51
90
|
/** @internal */
|
|
52
91
|
const makeTester = <R>(
|
|
53
92
|
mapEffect: <A, E>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, never>,
|
|
@@ -109,10 +148,7 @@ const makeTester = <R>(
|
|
|
109
148
|
const arbs = fc.record(
|
|
110
149
|
Object.keys(arbitraries).reduce(function(result, key) {
|
|
111
150
|
const arb: any = arbitraries[key]
|
|
112
|
-
|
|
113
|
-
result[key] = Schema.toArbitrary(arb)
|
|
114
|
-
}
|
|
115
|
-
result[key] = arb
|
|
151
|
+
result[key] = Schema.isSchema(arb) ? Schema.toArbitrary(arb) : arb
|
|
116
152
|
return result
|
|
117
153
|
}, {} as Record<string, fc.Arbitrary<any>>)
|
|
118
154
|
)
|
|
@@ -176,7 +212,7 @@ export const layer = <R, E>(
|
|
|
176
212
|
layer_: Layer.Layer<R, E>,
|
|
177
213
|
options?: {
|
|
178
214
|
readonly memoMap?: Layer.MemoMap
|
|
179
|
-
readonly timeout?: Duration.
|
|
215
|
+
readonly timeout?: Duration.Input
|
|
180
216
|
readonly excludeTestServices?: boolean
|
|
181
217
|
}
|
|
182
218
|
): {
|
|
@@ -207,9 +243,17 @@ export const layer = <R, E>(
|
|
|
207
243
|
Effect.cached,
|
|
208
244
|
Effect.runSync
|
|
209
245
|
)
|
|
246
|
+
let closed = false
|
|
247
|
+
const closeScope = (ctx?: Vitest.TestContext) => {
|
|
248
|
+
if (closed) {
|
|
249
|
+
return Promise.resolve()
|
|
250
|
+
}
|
|
251
|
+
closed = true
|
|
252
|
+
return runPromise(Scope.close(scope, Exit.void), ctx)
|
|
253
|
+
}
|
|
210
254
|
|
|
211
255
|
const makeIt = (it: V.TestAPI): Vitest.Vitest.MethodsNonLive<R> =>
|
|
212
|
-
|
|
256
|
+
makeItProxy(it, {
|
|
213
257
|
effect: makeTester<R | Scope.Scope>(
|
|
214
258
|
(effect) =>
|
|
215
259
|
Effect.flatMap(contextEffect, (context) =>
|
|
@@ -222,32 +266,60 @@ export const layer = <R, E>(
|
|
|
222
266
|
prop,
|
|
223
267
|
flakyTest,
|
|
224
268
|
layer<R2, E2>(nestedLayer: Layer.Layer<R2, E2, R>, options?: {
|
|
225
|
-
readonly timeout?: Duration.
|
|
269
|
+
readonly timeout?: Duration.Input
|
|
226
270
|
}) {
|
|
227
|
-
return layer(Layer.provideMerge(nestedLayer, withTestEnv), {
|
|
271
|
+
return layer(Layer.provideMerge(nestedLayer, withTestEnv), {
|
|
272
|
+
...options,
|
|
273
|
+
memoMap: Layer.forkMemoMapUnsafe(memoMap),
|
|
274
|
+
excludeTestServices
|
|
275
|
+
})
|
|
228
276
|
}
|
|
229
277
|
})
|
|
230
278
|
|
|
231
279
|
if (args.length === 1) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
280
|
+
const currentSuite = getCurrentSuite()
|
|
281
|
+
const previousTasks = new Set(currentSuite.tasks)
|
|
282
|
+
|
|
283
|
+
args[0](makeIt(V.it))
|
|
284
|
+
|
|
285
|
+
const blockTasks = collectTasks(
|
|
286
|
+
currentSuite.tasks.filter((task) => !previousTasks.has(task)) as ReadonlyArray<CollectedTask>
|
|
235
287
|
)
|
|
236
|
-
|
|
237
|
-
() =>
|
|
238
|
-
|
|
288
|
+
if (blockTasks.length === 0) {
|
|
289
|
+
V.afterAll(() => closeScope(), hookTimeout(options?.timeout))
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const blockTaskSet = new Set(blockTasks)
|
|
294
|
+
let remaining = blockTasks.length
|
|
295
|
+
|
|
296
|
+
V.beforeEach(
|
|
297
|
+
(ctx) => {
|
|
298
|
+
if (!blockTaskSet.has(ctx.task)) {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
ctx.onTestFinished(() => {
|
|
302
|
+
remaining--
|
|
303
|
+
if (remaining === 0) {
|
|
304
|
+
return closeScope(ctx)
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
return runPromise(Effect.asVoid(contextEffect), ctx)
|
|
308
|
+
},
|
|
309
|
+
hookTimeout(options?.timeout)
|
|
239
310
|
)
|
|
240
|
-
|
|
311
|
+
V.afterAll(() => closeScope(), hookTimeout(options?.timeout))
|
|
312
|
+
return
|
|
241
313
|
}
|
|
242
314
|
|
|
243
315
|
return V.describe(args[0], () => {
|
|
244
316
|
V.beforeAll(
|
|
245
317
|
() => runPromise(Effect.asVoid(contextEffect)),
|
|
246
|
-
options?.timeout
|
|
318
|
+
hookTimeout(options?.timeout)
|
|
247
319
|
)
|
|
248
320
|
V.afterAll(
|
|
249
|
-
() =>
|
|
250
|
-
options?.timeout
|
|
321
|
+
() => closeScope(),
|
|
322
|
+
hookTimeout(options?.timeout)
|
|
251
323
|
)
|
|
252
324
|
return args[1](makeIt(V.it))
|
|
253
325
|
})
|
|
@@ -256,7 +328,7 @@ export const layer = <R, E>(
|
|
|
256
328
|
/** @internal */
|
|
257
329
|
export const flakyTest = <A, E, R>(
|
|
258
330
|
self: Effect.Effect<A, E, R | Scope.Scope>,
|
|
259
|
-
timeout: Duration.
|
|
331
|
+
timeout: Duration.Input = Duration.seconds(30)
|
|
260
332
|
) =>
|
|
261
333
|
pipe(
|
|
262
334
|
self,
|
|
@@ -267,8 +339,8 @@ export const flakyTest = <A, E, R>(
|
|
|
267
339
|
Schedule.recurs(10),
|
|
268
340
|
Schedule.while((_) =>
|
|
269
341
|
Effect.succeed(Duration.isLessThanOrEqualTo(
|
|
270
|
-
Duration.
|
|
271
|
-
Duration.
|
|
342
|
+
Duration.fromInputUnsafe(_.elapsed),
|
|
343
|
+
Duration.fromInputUnsafe(timeout)
|
|
272
344
|
))
|
|
273
345
|
)
|
|
274
346
|
)
|
|
@@ -278,7 +350,7 @@ export const flakyTest = <A, E, R>(
|
|
|
278
350
|
|
|
279
351
|
/** @internal */
|
|
280
352
|
export const makeMethods = (it: V.TestAPI): Vitest.Vitest.Methods =>
|
|
281
|
-
|
|
353
|
+
makeItProxy(it, {
|
|
282
354
|
effect: makeTester<Scope.Scope>(flow(Effect.scoped, Effect.provide(TestEnv)), it),
|
|
283
355
|
live: makeTester<Scope.Scope>(Effect.scoped, it),
|
|
284
356
|
flakyTest,
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Provides assertion helpers used by `@effect/vitest` tests.
|
|
3
|
+
*
|
|
4
|
+
* This module defines small assertion functions built on Node's `assert`,
|
|
5
|
+
* Vitest's instance checks, and Effect's equality support. The helpers cover
|
|
6
|
+
* basic equality, thrown errors, defined and undefined values, strings, regular
|
|
7
|
+
* expressions, class instances, `Option`, `Result`, and `Exit`. Most helpers are
|
|
8
|
+
* synchronous; `throwsAsync` handles rejected promises.
|
|
9
|
+
*
|
|
2
10
|
* @since 4.0.0
|
|
3
11
|
*/
|
|
4
12
|
import type * as Cause from "effect/Cause"
|
|
@@ -15,8 +23,9 @@ import { assert as vassert } from "vitest"
|
|
|
15
23
|
// ----------------------------
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
|
-
*
|
|
26
|
+
* Fails the current test with the provided error message.
|
|
19
27
|
*
|
|
28
|
+
* @category testing
|
|
20
29
|
* @since 4.0.0
|
|
21
30
|
*/
|
|
22
31
|
export function fail(message: string) {
|
|
@@ -24,35 +33,39 @@ export function fail(message: string) {
|
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
/**
|
|
27
|
-
* Asserts that `actual` is equal to `expected` using
|
|
36
|
+
* Asserts that `actual` is deeply strictly equal to `expected` using Node's `assert.deepStrictEqual`.
|
|
28
37
|
*
|
|
38
|
+
* @category testing
|
|
29
39
|
* @since 4.0.0
|
|
30
40
|
*/
|
|
31
41
|
export function deepStrictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
|
|
32
|
-
assert.deepStrictEqual(actual, expected, message)
|
|
42
|
+
assert.deepStrictEqual(actual, expected, message as string)
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
/**
|
|
36
|
-
* Asserts that `actual` is not equal to `expected` using
|
|
46
|
+
* Asserts that `actual` is not deeply strictly equal to `expected` using Node's `assert.notDeepStrictEqual`.
|
|
37
47
|
*
|
|
48
|
+
* @category testing
|
|
38
49
|
* @since 4.0.0
|
|
39
50
|
*/
|
|
40
51
|
export function notDeepStrictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
|
|
41
|
-
assert.notDeepStrictEqual(actual, expected, message)
|
|
52
|
+
assert.notDeepStrictEqual(actual, expected, message as string)
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
/**
|
|
45
|
-
* Asserts that `actual` is equal to `expected` using
|
|
56
|
+
* Asserts that `actual` is strictly equal to `expected` using Node's `assert.strictEqual`.
|
|
46
57
|
*
|
|
58
|
+
* @category testing
|
|
47
59
|
* @since 4.0.0
|
|
48
60
|
*/
|
|
49
61
|
export function strictEqual<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
|
|
50
|
-
assert.strictEqual(actual, expected, message)
|
|
62
|
+
assert.strictEqual(actual, expected, message as string)
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
/**
|
|
54
66
|
* Asserts that `actual` is equal to `expected` using the `Equal.equals` trait.
|
|
55
67
|
*
|
|
68
|
+
* @category testing
|
|
56
69
|
* @since 4.0.0
|
|
57
70
|
*/
|
|
58
71
|
export function assertEquals<A>(actual: A, expected: A, message?: string, ..._: Array<never>) {
|
|
@@ -65,6 +78,7 @@ export function assertEquals<A>(actual: A, expected: A, message?: string, ..._:
|
|
|
65
78
|
/**
|
|
66
79
|
* Asserts that `thunk` does not throw an error.
|
|
67
80
|
*
|
|
81
|
+
* @category testing
|
|
68
82
|
* @since 4.0.0
|
|
69
83
|
*/
|
|
70
84
|
export function doesNotThrow(thunk: () => void, message?: string, ..._: Array<never>) {
|
|
@@ -78,6 +92,7 @@ export function doesNotThrow(thunk: () => void, message?: string, ..._: Array<ne
|
|
|
78
92
|
/**
|
|
79
93
|
* Asserts that `value` is an instance of `constructor`.
|
|
80
94
|
*
|
|
95
|
+
* @category testing
|
|
81
96
|
* @since 4.0.0
|
|
82
97
|
*/
|
|
83
98
|
export function assertInstanceOf<C extends abstract new(...args: any) => any>(
|
|
@@ -92,6 +107,7 @@ export function assertInstanceOf<C extends abstract new(...args: any) => any>(
|
|
|
92
107
|
/**
|
|
93
108
|
* Asserts that `self` is `true`.
|
|
94
109
|
*
|
|
110
|
+
* @category testing
|
|
95
111
|
* @since 4.0.0
|
|
96
112
|
*/
|
|
97
113
|
export function assertTrue(self: unknown, message?: string, ..._: Array<never>): asserts self {
|
|
@@ -101,6 +117,7 @@ export function assertTrue(self: unknown, message?: string, ..._: Array<never>):
|
|
|
101
117
|
/**
|
|
102
118
|
* Asserts that `self` is `false`.
|
|
103
119
|
*
|
|
120
|
+
* @category testing
|
|
104
121
|
* @since 4.0.0
|
|
105
122
|
*/
|
|
106
123
|
export function assertFalse(self: boolean, message?: string, ..._: Array<never>) {
|
|
@@ -110,6 +127,7 @@ export function assertFalse(self: boolean, message?: string, ..._: Array<never>)
|
|
|
110
127
|
/**
|
|
111
128
|
* Asserts that `actual` includes `expected`.
|
|
112
129
|
*
|
|
130
|
+
* @category testing
|
|
113
131
|
* @since 4.0.0
|
|
114
132
|
*/
|
|
115
133
|
export function assertInclude(actual: string | undefined, expected: string, ..._: Array<never>) {
|
|
@@ -123,6 +141,7 @@ export function assertInclude(actual: string | undefined, expected: string, ..._
|
|
|
123
141
|
/**
|
|
124
142
|
* Asserts that `actual` matches `regExp`.
|
|
125
143
|
*
|
|
144
|
+
* @category testing
|
|
126
145
|
* @since 4.0.0
|
|
127
146
|
*/
|
|
128
147
|
export function assertMatch(actual: string, regExp: RegExp, ..._: Array<never>) {
|
|
@@ -132,8 +151,9 @@ export function assertMatch(actual: string, regExp: RegExp, ..._: Array<never>)
|
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
/**
|
|
135
|
-
* Asserts that `thunk` throws an
|
|
154
|
+
* Asserts that `thunk` throws, optionally checking the thrown value against an expected `Error` or validation function.
|
|
136
155
|
*
|
|
156
|
+
* @category testing
|
|
137
157
|
* @since 4.0.0
|
|
138
158
|
*/
|
|
139
159
|
export function throws(thunk: () => void, error?: Error | ((u: unknown) => undefined), ..._: Array<never>) {
|
|
@@ -144,16 +164,19 @@ export function throws(thunk: () => void, error?: Error | ((u: unknown) => undef
|
|
|
144
164
|
if (error !== undefined) {
|
|
145
165
|
if (Predicate.isFunction(error)) {
|
|
146
166
|
error(e)
|
|
147
|
-
} else {
|
|
167
|
+
} else if (error) {
|
|
148
168
|
deepStrictEqual(e, error)
|
|
169
|
+
} else {
|
|
170
|
+
throw e
|
|
149
171
|
}
|
|
150
172
|
}
|
|
151
173
|
}
|
|
152
174
|
}
|
|
153
175
|
|
|
154
176
|
/**
|
|
155
|
-
* Asserts that `thunk` throws an
|
|
177
|
+
* Asserts that `thunk` throws or returns a rejected promise, optionally checking the failure value against an expected `Error` or validation function.
|
|
156
178
|
*
|
|
179
|
+
* @category testing
|
|
157
180
|
* @since 4.0.0
|
|
158
181
|
*/
|
|
159
182
|
export async function throwsAsync(
|
|
@@ -182,6 +205,7 @@ export async function throwsAsync(
|
|
|
182
205
|
/**
|
|
183
206
|
* Asserts that `option` is `None`.
|
|
184
207
|
*
|
|
208
|
+
* @category testing
|
|
185
209
|
* @since 4.0.0
|
|
186
210
|
*/
|
|
187
211
|
export function assertNone<A>(option: Option.Option<A>, ..._: Array<never>): asserts option is Option.None<never> {
|
|
@@ -191,6 +215,7 @@ export function assertNone<A>(option: Option.Option<A>, ..._: Array<never>): ass
|
|
|
191
215
|
/**
|
|
192
216
|
* Asserts that `a` is not `undefined`.
|
|
193
217
|
*
|
|
218
|
+
* @category testing
|
|
194
219
|
* @since 4.0.0
|
|
195
220
|
*/
|
|
196
221
|
export function assertDefined<A>(
|
|
@@ -205,6 +230,7 @@ export function assertDefined<A>(
|
|
|
205
230
|
/**
|
|
206
231
|
* Asserts that `a` is `undefined`.
|
|
207
232
|
*
|
|
233
|
+
* @category testing
|
|
208
234
|
* @since 4.0.0
|
|
209
235
|
*/
|
|
210
236
|
export function assertUndefined<A>(
|
|
@@ -217,8 +243,9 @@ export function assertUndefined<A>(
|
|
|
217
243
|
}
|
|
218
244
|
|
|
219
245
|
/**
|
|
220
|
-
* Asserts that `option` is `Some`.
|
|
246
|
+
* Asserts that `option` is `Some` and contains a value equal to `expected`.
|
|
221
247
|
*
|
|
248
|
+
* @category testing
|
|
222
249
|
* @since 4.0.0
|
|
223
250
|
*/
|
|
224
251
|
export function assertSome<A>(
|
|
@@ -234,8 +261,9 @@ export function assertSome<A>(
|
|
|
234
261
|
// ----------------------------
|
|
235
262
|
|
|
236
263
|
/**
|
|
237
|
-
* Asserts that `result` is `Success`.
|
|
264
|
+
* Asserts that `result` is `Success` and contains a value equal to `expected`.
|
|
238
265
|
*
|
|
266
|
+
* @category testing
|
|
239
267
|
* @since 4.0.0
|
|
240
268
|
*/
|
|
241
269
|
export function assertSuccess<A, E>(
|
|
@@ -247,8 +275,9 @@ export function assertSuccess<A, E>(
|
|
|
247
275
|
}
|
|
248
276
|
|
|
249
277
|
/**
|
|
250
|
-
* Asserts that `result` is `Failure`.
|
|
278
|
+
* Asserts that `result` is `Failure` and contains an error equal to `expected`.
|
|
251
279
|
*
|
|
280
|
+
* @category testing
|
|
252
281
|
* @since 4.0.0
|
|
253
282
|
*/
|
|
254
283
|
export function assertFailure<A, E>(
|
|
@@ -264,8 +293,9 @@ export function assertFailure<A, E>(
|
|
|
264
293
|
// ----------------------------
|
|
265
294
|
|
|
266
295
|
/**
|
|
267
|
-
* Asserts that `exit` is a failure
|
|
296
|
+
* Asserts that `exit` is a failure with a cause equal to `expected`.
|
|
268
297
|
*
|
|
298
|
+
* @category testing
|
|
269
299
|
* @since 4.0.0
|
|
270
300
|
*/
|
|
271
301
|
export function assertExitFailure<A, E>(
|
|
@@ -277,8 +307,9 @@ export function assertExitFailure<A, E>(
|
|
|
277
307
|
}
|
|
278
308
|
|
|
279
309
|
/**
|
|
280
|
-
* Asserts that `exit` is a success
|
|
310
|
+
* Asserts that `exit` is a success with a value equal to `expected`.
|
|
281
311
|
*
|
|
312
|
+
* @category testing
|
|
282
313
|
* @since 4.0.0
|
|
283
314
|
*/
|
|
284
315
|
export function assertExitSuccess<A, E>(
|