Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
test('saga iteration', () => {
let actual = []
const middleware = sagaMiddleware()
createStore(() => ({}), {}, applyMiddleware(middleware))
function* genFn() {
actual.push(yield 1)
actual.push(yield 2)
return 3
}
const task = middleware.run(genFn) // saga should return a promise of the iterator result
expect(is.promise(task.toPromise())).toBe(true)
return task.toPromise().then(res => {
// saga's iterator should return false from isRunning()
expect(task.isRunning()).toBe(false) // saga returned promise should resolve with the iterator return value
expect(res).toBe(3) // saga should collect yielded values from the iterator
expect(actual).toEqual([1, 2])
})
})
test('saga error handling', () => {
asap(() => {
let result
try {
result = (channel ? channel.put : env.dispatch)(action)
} catch (error) {
cb(error, true)
return
}
if (resolve && is.promise(result)) {
resolvePromise(result, cb)
} else {
cb(result)
}
})
// Put effects are non cancellables
function runCallEffect(env, { context, fn, args }, cb, { task }) {
// catch synchronous failures; see #152
try {
const result = fn.apply(context, args)
if (is.promise(result)) {
resolvePromise(result, cb)
return
}
if (is.iterator(result)) {
// resolve iterator
proc(env, result, task.context, currentEffectId, getMetaInfo(fn), /* isRoot */ false, cb)
return
}
cb(result)
} catch (error) {
cb(error, true)
}
}
/**
each effect runner must attach its own logic of cancellation to the provided callback
it allows this generator to propagate cancellation downward.
ATTENTION! effect runners must setup the cancel logic by setting cb.cancel = [cancelMethod]
And the setup must occur before calling the callback
This is a sort of inversion of control: called async functions are responsible
of completing the flow by calling the provided continuation; while caller functions
are responsible for aborting the current flow by calling the attached cancel function
Library users can attach their own cancellation logic to promises by defining a
promise[CANCEL] method in their returned promises
ATTENTION! calling cancel must have no effect on an already completed or cancelled effect
**/
if (is.promise(effect)) {
resolvePromise(effect, currCb)
} else if (is.iterator(effect)) {
// resolve iterator
proc(env, effect, task.context, effectId, meta, /* isRoot */ false, currCb)
} else if (effect && effect[IO]) {
const effectRunner = effectRunnerMap[effect.type]
effectRunner(env, effect.payload, currCb, executingContext)
} else {
// anything else returned as is
currCb(effect)
}
}
const next = arg => {
if (!resolved) {
resolved = true
// Only promises returned from fork will be interpreted. See #1573
return { value: result, done: !is.promise(result) }
} else {
return { value: arg, done: true }
}
}
const isError = desc.status === REJECTED;
const formatter = new DescriptorFormatter(isCancel, isError, color);
const winnerInd = desc.winner ? (isError ? "✘" : "✓") : "";
formatter.addLabel(winnerInd).addLabel(desc.label);
if (desc.root) {
formatter
.addEffectType("root")
.resetStyle()
.addCall(desc.saga.name, desc.args)
.addDescResult(desc);
} else if (is.iterator(desc.effect)) {
formatter.addValue(desc.effect.name).addDescResult(desc, true);
} else if (is.promise(desc.effect)) {
formatter
.addEffectType("promise")
.resetStyle()
.addDescResult(desc);
} else if (is.effect(desc.effect)) {
const { type, payload } = desc.effect;
if (type === effectTypes.TAKE) {
formatter
.addEffectType("take")
.resetStyle()
.addValue(payload.channel == null ? payload.pattern : payload)
.addDescResult(desc);
} else if (type === effectTypes.PUT) {
formatter
.addEffectType("put")
const isError = desc.status === REJECTED
const formatter = new DescriptorFormatter(isCancel, isError)
const winnerInd = desc.winner ? (isError ? '✘' : '✓') : ''
formatter.addLabel(winnerInd).addLabel(desc.label)
if (desc.root) {
formatter
.addEffectType('root')
.resetStyle()
.addCall(desc.saga.name, desc.args)
.addDescResult(desc)
} else if (is.iterator(desc.effect)) {
formatter.addValue(desc.effect.name).addDescResult(desc, true)
} else if (is.promise(desc.effect)) {
formatter
.addEffectType('promise')
.resetStyle()
.addDescResult(desc)
} else if (is.effect(desc.effect)) {
const { type, payload } = desc.effect
if (type === effectTypes.TAKE) {
formatter
.addEffectType('take')
.resetStyle()
.addValue(payload.channel == null ? payload.pattern : payload)
.addDescResult(desc)
} else if (type === effectTypes.PUT) {
formatter
.addEffectType('put')