@effect-app/vue 2.52.0 → 2.52.1
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/CHANGELOG.md +6 -0
- package/dist/experimental/makeExperimental.d.ts +13 -52
- package/dist/experimental/makeExperimental.d.ts.map +1 -1
- package/dist/experimental/makeExperimental.js +2 -2
- package/dist/experimental/useCommand.d.ts +17 -51
- package/dist/experimental/useCommand.d.ts.map +1 -1
- package/dist/experimental/useCommand.js +84 -47
- package/dist/mutate.js +1 -1
- package/package.json +1 -1
- package/src/experimental/makeExperimental.ts +1 -1
- package/src/experimental/useCommand.ts +120 -72
- package/src/mutate.ts +1 -1
- package/test/Mutation.test.ts +324 -2
- package/test/dist/stubs.d.ts +12 -51
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +3 -3
- package/test/stubs.ts +2 -2
|
@@ -43,6 +43,12 @@ export class CommandContext extends Context.Tag("CommandContext")<
|
|
|
43
43
|
{ action: string }
|
|
44
44
|
>() {}
|
|
45
45
|
|
|
46
|
+
export interface CommandProps<A, E> {
|
|
47
|
+
action: string
|
|
48
|
+
result: Result<A, E>
|
|
49
|
+
waiting: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
export const makeUseCommand = <Locale extends string, RT>(
|
|
47
53
|
// NOTE: underscores to not collide with auto exports in nuxt apps
|
|
48
54
|
_useIntl: MakeIntlReturn<Locale>["useIntl"],
|
|
@@ -58,11 +64,7 @@ export const makeUseCommand = <Locale extends string, RT>(
|
|
|
58
64
|
const runFork = Runtime.runFork(runtime)
|
|
59
65
|
|
|
60
66
|
type CommandOut<Args extends Array<any>, A, E> = ComputedRef<
|
|
61
|
-
((...a: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) &
|
|
62
|
-
action: string
|
|
63
|
-
result: Result<A, E>
|
|
64
|
-
waiting: boolean
|
|
65
|
-
}
|
|
67
|
+
((...a: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) & CommandProps<A, E>
|
|
66
68
|
>
|
|
67
69
|
|
|
68
70
|
type CommandOutHelper<Args extends Array<any>, Eff extends Effect.Effect<any, any, any>> = CommandOut<
|
|
@@ -71,6 +73,108 @@ export const makeUseCommand = <Locale extends string, RT>(
|
|
|
71
73
|
Effect.Effect.Error<Eff>
|
|
72
74
|
>
|
|
73
75
|
|
|
76
|
+
const makeCommand =
|
|
77
|
+
(actionName: string, errorDef?: Error) =>
|
|
78
|
+
<Args extends ReadonlyArray<any>, A, E, R extends RT | CommandContext>(
|
|
79
|
+
handler: (...args: Args) => Effect.Effect<A, E, R>
|
|
80
|
+
) => {
|
|
81
|
+
const limit = Error.stackTraceLimit
|
|
82
|
+
Error.stackTraceLimit = 2
|
|
83
|
+
const localErrorDef = new Error()
|
|
84
|
+
Error.stackTraceLimit = limit
|
|
85
|
+
if (!errorDef) {
|
|
86
|
+
errorDef = localErrorDef
|
|
87
|
+
}
|
|
88
|
+
const action = intl.value.formatMessage({
|
|
89
|
+
id: `action.${actionName}`,
|
|
90
|
+
defaultMessage: actionName
|
|
91
|
+
})
|
|
92
|
+
const context = { action }
|
|
93
|
+
|
|
94
|
+
const errorReporter = <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
95
|
+
self.pipe(
|
|
96
|
+
Effect.tapErrorCause(
|
|
97
|
+
Effect.fnUntraced(function*(cause) {
|
|
98
|
+
if (Cause.isInterruptedOnly(cause)) {
|
|
99
|
+
console.info(`Interrupted while trying to ${actionName}`)
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const fail = Cause.failureOption(cause)
|
|
104
|
+
if (Option.isSome(fail)) {
|
|
105
|
+
// if (fail.value._tag === "SuppressErrors") {
|
|
106
|
+
// console.info(
|
|
107
|
+
// `Suppressed error trying to ${action}`,
|
|
108
|
+
// fail.value,
|
|
109
|
+
// )
|
|
110
|
+
// return
|
|
111
|
+
// }
|
|
112
|
+
const message = `Failure trying to ${actionName}`
|
|
113
|
+
yield* reportMessage(message, {
|
|
114
|
+
action: actionName,
|
|
115
|
+
error: fail.value
|
|
116
|
+
})
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const extra = {
|
|
121
|
+
action,
|
|
122
|
+
message: `Unexpected Error trying to ${actionName}`
|
|
123
|
+
}
|
|
124
|
+
yield* reportRuntimeError(cause, extra)
|
|
125
|
+
})
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const theHandler = flow(
|
|
130
|
+
handler,
|
|
131
|
+
// all must be within the Effect.fn to fit within the Span
|
|
132
|
+
Effect.provideService(CommandContext, context),
|
|
133
|
+
(_) => Effect.annotateCurrentSpan({ action }).pipe(Effect.zipRight(_)),
|
|
134
|
+
errorReporter
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
const [result, mut] = asResult(theHandler)
|
|
138
|
+
|
|
139
|
+
return computed(() =>
|
|
140
|
+
Object.assign(
|
|
141
|
+
(...args: Args) => {
|
|
142
|
+
const limit = Error.stackTraceLimit
|
|
143
|
+
Error.stackTraceLimit = 2
|
|
144
|
+
const errorCall = new Error()
|
|
145
|
+
Error.stackTraceLimit = limit
|
|
146
|
+
|
|
147
|
+
let cache: false | string = false
|
|
148
|
+
const captureStackTrace = () => {
|
|
149
|
+
if (cache !== false) {
|
|
150
|
+
return cache
|
|
151
|
+
}
|
|
152
|
+
if (errorCall.stack) {
|
|
153
|
+
const stackDef = errorDef!.stack!.trim().split("\n")
|
|
154
|
+
const stackCall = errorCall.stack.trim().split("\n")
|
|
155
|
+
let endStackDef = stackDef.slice(2).join("\n").trim()
|
|
156
|
+
if (!endStackDef.includes(`(`)) {
|
|
157
|
+
endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
|
|
158
|
+
}
|
|
159
|
+
let endStackCall = stackCall.slice(2).join("\n").trim()
|
|
160
|
+
if (!endStackCall.includes(`(`)) {
|
|
161
|
+
endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
|
|
162
|
+
}
|
|
163
|
+
cache = `${endStackDef}\n${endStackCall}`
|
|
164
|
+
return cache
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return runFork(Effect.withSpan(mut(...args), actionName, { captureStackTrace }))
|
|
168
|
+
}, /* make sure always create a new one, or the state won't properly propagate */
|
|
169
|
+
{
|
|
170
|
+
action,
|
|
171
|
+
result: result.value,
|
|
172
|
+
waiting: result.value.waiting
|
|
173
|
+
} as CommandProps<A, E>
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
74
178
|
return {
|
|
75
179
|
/** Version of confirmOrInterrupt that automatically includes the action name in the default messages */
|
|
76
180
|
confirmOrInterrupt: Effect.fnUntraced(function*(
|
|
@@ -440,74 +544,18 @@ export const makeUseCommand = <Locale extends string, RT>(
|
|
|
440
544
|
// TODO: combinators can freely take A, E, R and change it to whatever they want, as long as the end result Requires not more than CommandContext | R
|
|
441
545
|
...combinators: any[]
|
|
442
546
|
): any => {
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const context = { action }
|
|
547
|
+
const limit = Error.stackTraceLimit
|
|
548
|
+
Error.stackTraceLimit = 2
|
|
549
|
+
const errorDef = new Error()
|
|
550
|
+
Error.stackTraceLimit = limit
|
|
448
551
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
Effect.tapErrorCause(
|
|
452
|
-
Effect.fnUntraced(function*(cause) {
|
|
453
|
-
if (Cause.isInterruptedOnly(cause)) {
|
|
454
|
-
console.info(`Interrupted while trying to ${actionName}`)
|
|
455
|
-
return
|
|
456
|
-
}
|
|
552
|
+
return makeCommand(actionName, errorDef)(Effect.fnUntraced(fn, ...combinators as [any]) as any)
|
|
553
|
+
},
|
|
457
554
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// fail.value,
|
|
464
|
-
// )
|
|
465
|
-
// return
|
|
466
|
-
// }
|
|
467
|
-
const message = `Failure trying to ${actionName}`
|
|
468
|
-
yield* reportMessage(message, {
|
|
469
|
-
action: actionName,
|
|
470
|
-
error: fail.value
|
|
471
|
-
})
|
|
472
|
-
return
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const extra = {
|
|
476
|
-
action,
|
|
477
|
-
message: `Unexpected Error trying to ${actionName}`
|
|
478
|
-
}
|
|
479
|
-
yield* reportRuntimeError(cause, extra)
|
|
480
|
-
})
|
|
481
|
-
)
|
|
482
|
-
)
|
|
483
|
-
|
|
484
|
-
// TODO: override span stack set by Effect.fn as it points here instead of to the caller of Command.fn.
|
|
485
|
-
// perhaps copying Effect.fn implementation is better than using it?
|
|
486
|
-
const handler = Effect.fn(actionName)(
|
|
487
|
-
fn,
|
|
488
|
-
...(combinators as [any]),
|
|
489
|
-
// all must be within the Effect.fn to fit within the Span
|
|
490
|
-
Effect.provideService(CommandContext, context) as any, /* TODO */
|
|
491
|
-
((_: any) => Effect.annotateCurrentSpan({ action }).pipe(Effect.zipRight(_))) as any, /* TODO */
|
|
492
|
-
errorReporter as any /* TODO */
|
|
493
|
-
) as any // (...args: Args) => Effect.Effect<AEff, $WrappedEffectError, R>
|
|
494
|
-
|
|
495
|
-
const [result, mut] = asResult(handler)
|
|
496
|
-
|
|
497
|
-
return computed(() =>
|
|
498
|
-
Object.assign(
|
|
499
|
-
flow(
|
|
500
|
-
mut as any,
|
|
501
|
-
runFork
|
|
502
|
-
// (_) => {}
|
|
503
|
-
), /* make sure always create a new one, or the state won't properly propagate */
|
|
504
|
-
{
|
|
505
|
-
action,
|
|
506
|
-
result: result.value,
|
|
507
|
-
waiting: result.value.waiting
|
|
508
|
-
}
|
|
509
|
-
)
|
|
510
|
-
)
|
|
511
|
-
}
|
|
555
|
+
alt: makeCommand as (
|
|
556
|
+
actionName: string
|
|
557
|
+
) => <Args extends ReadonlyArray<any>, A, E, R extends RT | CommandContext>(
|
|
558
|
+
handler: (...args: Args) => Effect.Effect<A, E, R>
|
|
559
|
+
) => ComputedRef<((...a: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) & CommandProps<A, E>>
|
|
512
560
|
}
|
|
513
561
|
}
|
package/src/mutate.ts
CHANGED
|
@@ -88,7 +88,7 @@ export interface MutationOptions<A, E, R, A2 = A, E2 = E, R2 = R, I = void> {
|
|
|
88
88
|
// predicate: (_) => nses.includes(_.queryKey.filter((_) => _.startsWith("$")).join("/"))
|
|
89
89
|
// }))
|
|
90
90
|
/*
|
|
91
|
-
// const nses: string[] = []
|
|
91
|
+
// const nses: string[] = []`
|
|
92
92
|
// for (let i = 0; i < ns.length; i++) {
|
|
93
93
|
// nses.push(ns.slice(0, i + 1).join("/"))
|
|
94
94
|
// }
|
package/test/Mutation.test.ts
CHANGED
|
@@ -49,7 +49,10 @@ it.live("has custom action name", () =>
|
|
|
49
49
|
Effect
|
|
50
50
|
.gen(function*() {
|
|
51
51
|
const toasts: any[] = []
|
|
52
|
-
const { useCommand } = useExperimental({
|
|
52
|
+
const { useCommand } = useExperimental({
|
|
53
|
+
toasts,
|
|
54
|
+
messages: { "action.Test Action": "Test Action Translated" }
|
|
55
|
+
})
|
|
53
56
|
const Command = useCommand()
|
|
54
57
|
|
|
55
58
|
let executed = false
|
|
@@ -121,7 +124,10 @@ it.live("can replace the result", () =>
|
|
|
121
124
|
Effect
|
|
122
125
|
.gen(function*() {
|
|
123
126
|
const toasts: any[] = []
|
|
124
|
-
const { useCommand } = useExperimental({
|
|
127
|
+
const { useCommand } = useExperimental({
|
|
128
|
+
toasts,
|
|
129
|
+
messages: { "action.Test Action": "Test Action Translated" }
|
|
130
|
+
})
|
|
125
131
|
const Command = useCommand()
|
|
126
132
|
|
|
127
133
|
let executed = false
|
|
@@ -294,3 +300,319 @@ it.live("defect", () =>
|
|
|
294
300
|
expect(toasts.length).toBe(1) // toast should show error
|
|
295
301
|
expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
|
|
296
302
|
}))
|
|
303
|
+
|
|
304
|
+
it.live("works with alt", () =>
|
|
305
|
+
Effect
|
|
306
|
+
.gen(function*() {
|
|
307
|
+
const toasts: any[] = []
|
|
308
|
+
const { useCommand } = useExperimental({ toasts })
|
|
309
|
+
const Command = useCommand()
|
|
310
|
+
|
|
311
|
+
let executed = false
|
|
312
|
+
|
|
313
|
+
const command = Command.alt("Test Action")(
|
|
314
|
+
Effect.fnUntraced(
|
|
315
|
+
function*() {
|
|
316
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
317
|
+
expect(command.value.waiting).toBe(true)
|
|
318
|
+
|
|
319
|
+
expect(yield* CommandContext).toEqual({ action: "Test Action" })
|
|
320
|
+
|
|
321
|
+
expect(toasts.length).toBe(0)
|
|
322
|
+
|
|
323
|
+
return "test-value"
|
|
324
|
+
},
|
|
325
|
+
Effect.tap(Effect.fnUntraced(function*() {
|
|
326
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
327
|
+
})),
|
|
328
|
+
Effect.tap(() =>
|
|
329
|
+
Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => expect(_).toBe("Test Action")))
|
|
330
|
+
),
|
|
331
|
+
Effect.tap(() => executed = true)
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
expect(command.value.action).toBe("Test Action")
|
|
335
|
+
|
|
336
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
337
|
+
expect(command.value.waiting).toBe(false)
|
|
338
|
+
|
|
339
|
+
expect(r).toBe("test-value") // to confirm that the initial function has ran.
|
|
340
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
341
|
+
|
|
342
|
+
expect(command.value.result.pipe(Result.value)).toEqual(Option.some("test-value"))
|
|
343
|
+
|
|
344
|
+
expect(toasts.length).toBe(0)
|
|
345
|
+
}))
|
|
346
|
+
|
|
347
|
+
it.live("has custom action name with alt", () =>
|
|
348
|
+
Effect
|
|
349
|
+
.gen(function*() {
|
|
350
|
+
const toasts: any[] = []
|
|
351
|
+
const { useCommand } = useExperimental({
|
|
352
|
+
toasts,
|
|
353
|
+
messages: { "action.Test Action": "Test Action Translated" }
|
|
354
|
+
})
|
|
355
|
+
const Command = useCommand()
|
|
356
|
+
|
|
357
|
+
let executed = false
|
|
358
|
+
|
|
359
|
+
const command = Command.alt("Test Action")(
|
|
360
|
+
Effect.fnUntraced(
|
|
361
|
+
function*() {
|
|
362
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
363
|
+
|
|
364
|
+
expect(yield* CommandContext).toEqual({ action: "Test Action Translated" })
|
|
365
|
+
return "test-value"
|
|
366
|
+
},
|
|
367
|
+
Effect.tap(() => executed = true)
|
|
368
|
+
)
|
|
369
|
+
)
|
|
370
|
+
expect(command.value.action).toBe("Test Action Translated")
|
|
371
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
372
|
+
|
|
373
|
+
expect(r).toBe("test-value") // to confirm that the initial function has ran.
|
|
374
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
375
|
+
}))
|
|
376
|
+
|
|
377
|
+
it.live("can map the result with alt", () =>
|
|
378
|
+
Effect
|
|
379
|
+
.gen(function*() {
|
|
380
|
+
const toasts: any[] = []
|
|
381
|
+
const { useCommand } = useExperimental({ toasts })
|
|
382
|
+
const Command = useCommand()
|
|
383
|
+
|
|
384
|
+
let executed = false
|
|
385
|
+
|
|
386
|
+
const command = Command.alt("Test Action")(Effect.fnUntraced(
|
|
387
|
+
function*() {
|
|
388
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
389
|
+
|
|
390
|
+
return "test-value"
|
|
391
|
+
},
|
|
392
|
+
Effect.map((_) => _ + _),
|
|
393
|
+
Effect.tap(() => executed = true)
|
|
394
|
+
))
|
|
395
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
396
|
+
|
|
397
|
+
expect(r).toBe("test-valuetest-value") // to confirm that the initial function and map has ran.
|
|
398
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
399
|
+
}))
|
|
400
|
+
|
|
401
|
+
it.live("can receive and use input with alt", () =>
|
|
402
|
+
Effect
|
|
403
|
+
.gen(function*() {
|
|
404
|
+
const toasts: any[] = []
|
|
405
|
+
const { useCommand } = useExperimental({ toasts })
|
|
406
|
+
const Command = useCommand()
|
|
407
|
+
|
|
408
|
+
let executed = false
|
|
409
|
+
|
|
410
|
+
const command = Command.alt("Test Action")(
|
|
411
|
+
Effect.fnUntraced(
|
|
412
|
+
function*(input1: number, input2: string) {
|
|
413
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
414
|
+
|
|
415
|
+
return { input1, input2 }
|
|
416
|
+
},
|
|
417
|
+
Effect.tap(() => executed = true)
|
|
418
|
+
)
|
|
419
|
+
)
|
|
420
|
+
const r = yield* Fiber.join(command.value(1, "2")).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
421
|
+
|
|
422
|
+
expect(r).toEqual({ input1: 1, input2: "2" }) // to confirm that the initial function has ran and received input.
|
|
423
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
424
|
+
}))
|
|
425
|
+
|
|
426
|
+
it.live("can replace the result with alt", () =>
|
|
427
|
+
Effect
|
|
428
|
+
.gen(function*() {
|
|
429
|
+
const toasts: any[] = []
|
|
430
|
+
const { useCommand } = useExperimental({
|
|
431
|
+
toasts,
|
|
432
|
+
messages: { "action.Test Action": "Test Action Translated" }
|
|
433
|
+
})
|
|
434
|
+
const Command = useCommand()
|
|
435
|
+
|
|
436
|
+
let executed = false
|
|
437
|
+
|
|
438
|
+
const command = Command.alt("Test Action")(
|
|
439
|
+
Effect.fnUntraced(
|
|
440
|
+
function*() {
|
|
441
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
442
|
+
|
|
443
|
+
return "test-value"
|
|
444
|
+
},
|
|
445
|
+
Effect.zipRight(Effect.succeed(42)),
|
|
446
|
+
Effect.tap(() => executed = true)
|
|
447
|
+
)
|
|
448
|
+
)
|
|
449
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
450
|
+
|
|
451
|
+
expect(r).toBe(42) // to confirm that the initial function and zipRight has ran.
|
|
452
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
453
|
+
}))
|
|
454
|
+
|
|
455
|
+
it.live("with toasts with alt", () =>
|
|
456
|
+
Effect
|
|
457
|
+
.gen(function*() {
|
|
458
|
+
const toasts: any[] = []
|
|
459
|
+
const { useCommand } = useExperimental({
|
|
460
|
+
toasts,
|
|
461
|
+
messages: DefaultIntl.en
|
|
462
|
+
})
|
|
463
|
+
const Command = useCommand()
|
|
464
|
+
|
|
465
|
+
let executed = false
|
|
466
|
+
|
|
467
|
+
const command = Command.alt("Test Action")(
|
|
468
|
+
Effect.fnUntraced(
|
|
469
|
+
function*() {
|
|
470
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
471
|
+
|
|
472
|
+
expect(toasts.length).toBe(1)
|
|
473
|
+
expect(toasts[0].message).toBe("Test Action executing...")
|
|
474
|
+
|
|
475
|
+
return "test-value"
|
|
476
|
+
},
|
|
477
|
+
Effect.tap(Effect.fnUntraced(function*() {
|
|
478
|
+
expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
|
|
479
|
+
})),
|
|
480
|
+
Effect.tap(() =>
|
|
481
|
+
Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => expect(_).toBe("Test Action")))
|
|
482
|
+
),
|
|
483
|
+
Command.withDefaultToast,
|
|
484
|
+
Effect.tap(() => executed = true)
|
|
485
|
+
)
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed, so we flatten it.
|
|
489
|
+
|
|
490
|
+
expect(r).toBe("test-value") // to confirm that the initial function has ran.
|
|
491
|
+
expect(executed).toBe(true) // to confirm that the combinators have ran.
|
|
492
|
+
|
|
493
|
+
expect(toasts.length).toBe(1)
|
|
494
|
+
expect(toasts[0].message).toBe("Test Action Success")
|
|
495
|
+
}))
|
|
496
|
+
|
|
497
|
+
it.live("interrupted with alt", () =>
|
|
498
|
+
Effect
|
|
499
|
+
.gen(function*() {
|
|
500
|
+
let executed = false
|
|
501
|
+
const toasts: any[] = []
|
|
502
|
+
const { useCommand } = useExperimental({ toasts, messages: DefaultIntl.en })
|
|
503
|
+
const Command = useCommand()
|
|
504
|
+
|
|
505
|
+
const command = Command.alt("Test Action")(
|
|
506
|
+
Effect.fnUntraced(
|
|
507
|
+
function*() {
|
|
508
|
+
expect(toasts.length).toBe(1)
|
|
509
|
+
// @effect-diagnostics-next-line missingReturnYieldStar:off
|
|
510
|
+
yield* Effect.interrupt
|
|
511
|
+
return "test-value"
|
|
512
|
+
},
|
|
513
|
+
Command.withDefaultToast,
|
|
514
|
+
Effect.tap(() => executed = true)
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
const r = yield* Fiber.join(command.value()) // we receive an Exit as errors/results are processed
|
|
519
|
+
|
|
520
|
+
expect(executed).toBe(false) // we were interrupted after all :)
|
|
521
|
+
expect(Exit.isInterrupted(r)).toBe(true) // to confirm that the initial function has interrupted
|
|
522
|
+
|
|
523
|
+
expect(command.value.waiting).toBe(false)
|
|
524
|
+
expect(Exit.isInterrupted(Result.toExit(command.value.result))).toBe(true)
|
|
525
|
+
expect(toasts.length).toBe(0) // toast is removed on interruption. TODO: maybe a nicer user experience can be had?
|
|
526
|
+
}))
|
|
527
|
+
|
|
528
|
+
it.live("fail with alt", () =>
|
|
529
|
+
Effect
|
|
530
|
+
.gen(function*() {
|
|
531
|
+
let executed = false
|
|
532
|
+
const toasts: any[] = []
|
|
533
|
+
const { useCommand } = useExperimental({ toasts, messages: DefaultIntl.en })
|
|
534
|
+
const Command = useCommand()
|
|
535
|
+
|
|
536
|
+
const command = Command.alt("Test Action")(
|
|
537
|
+
Effect.fnUntraced(
|
|
538
|
+
function*() {
|
|
539
|
+
expect(toasts.length).toBe(1)
|
|
540
|
+
return yield* Effect.fail({ message: "Boom!" })
|
|
541
|
+
},
|
|
542
|
+
Command.withDefaultToast,
|
|
543
|
+
Effect.tap(() => executed = true)
|
|
544
|
+
)
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
const r = yield* Fiber.join(command.value()) // we receive an Exit as errors/results are processed
|
|
548
|
+
|
|
549
|
+
expect(executed).toBe(false) // we failed after all :)
|
|
550
|
+
expect(Exit.isFailure(r) && Cause.isFailure(r.cause)).toBe(true) // to confirm that the initial function has failed
|
|
551
|
+
|
|
552
|
+
expect(command.value.waiting).toBe(false)
|
|
553
|
+
expect(Exit.isFailure(Result.toExit(command.value.result))).toBe(true)
|
|
554
|
+
expect(toasts.length).toBe(1) // toast should show error
|
|
555
|
+
expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
|
|
556
|
+
}))
|
|
557
|
+
|
|
558
|
+
it.live("fail and recover with alt", () =>
|
|
559
|
+
Effect
|
|
560
|
+
.gen(function*() {
|
|
561
|
+
let executed = false
|
|
562
|
+
const toasts: any[] = []
|
|
563
|
+
const { useCommand } = useExperimental({ toasts, messages: DefaultIntl.en })
|
|
564
|
+
const Command = useCommand()
|
|
565
|
+
|
|
566
|
+
const command = Command.alt("Test Action")(
|
|
567
|
+
Effect.fnUntraced(
|
|
568
|
+
function*() {
|
|
569
|
+
expect(toasts.length).toBe(1)
|
|
570
|
+
return yield* Effect.fail({ message: "Boom!" })
|
|
571
|
+
},
|
|
572
|
+
Effect.catchAll(() => Effect.succeed("recovered")), // we recover from the error here, so the final result is success
|
|
573
|
+
Command.withDefaultToast,
|
|
574
|
+
Effect.tap(() => executed = true)
|
|
575
|
+
)
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
const r = yield* Fiber.join(command.value()).pipe(Effect.flatten) // we receive an Exit as errors/results are processed
|
|
579
|
+
|
|
580
|
+
expect(executed).toBe(true) // we recovered after all :)
|
|
581
|
+
expect(r).toBe("recovered") // to confirm that the initial function has failed but we recovered
|
|
582
|
+
|
|
583
|
+
expect(command.value.waiting).toBe(false)
|
|
584
|
+
expect(Result.toExit(command.value.result)).toEqual(Exit.succeed("recovered"))
|
|
585
|
+
expect(toasts.length).toBe(1) // toast should show error
|
|
586
|
+
expect(toasts[0].message).toBe("Test Action Success")
|
|
587
|
+
}))
|
|
588
|
+
|
|
589
|
+
it.live("defect with alt", () =>
|
|
590
|
+
Effect
|
|
591
|
+
.gen(function*() {
|
|
592
|
+
let executed = false
|
|
593
|
+
const toasts: any[] = []
|
|
594
|
+
const { useCommand } = useExperimental({ toasts, messages: DefaultIntl.en })
|
|
595
|
+
const Command = useCommand()
|
|
596
|
+
|
|
597
|
+
const command = Command.alt("Test Action")(
|
|
598
|
+
Effect.fnUntraced(
|
|
599
|
+
function*() {
|
|
600
|
+
expect(toasts.length).toBe(1)
|
|
601
|
+
return yield* Effect.die({ message: "Boom!" })
|
|
602
|
+
},
|
|
603
|
+
Command.withDefaultToast,
|
|
604
|
+
Effect.tap(() => executed = true)
|
|
605
|
+
)
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
const r = yield* Fiber.join(command.value()) // we receive an Exit as errors/results are processed
|
|
609
|
+
// TODO: confirm we reported error
|
|
610
|
+
|
|
611
|
+
expect(executed).toBe(false) // we died after all :)
|
|
612
|
+
expect(Exit.isFailure(r) && Cause.isDie(r.cause)).toBe(true) // to confirm that the initial function has died
|
|
613
|
+
|
|
614
|
+
expect(command.value.waiting).toBe(false)
|
|
615
|
+
expect(Exit.isFailure(Result.toExit(command.value.result))).toBe(true)
|
|
616
|
+
expect(toasts.length).toBe(1) // toast should show error
|
|
617
|
+
expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
|
|
618
|
+
}))
|