Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support explicit return value of unknown (#42) #47

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,32 @@ function assert(condition, message) {

// Returns value in mapping corresponding to matching searchVal key.
function getNextVal(searchVal, mapping) {
let found = false
let value
if (isMap(mapping)) {
for (let [key, val] of mapping.entries()) {
if (deepEqual(key, searchVal)) {
found = true
value = val
break
}
}
} else {
value = (mapping.find(keyVal => deepEqual(keyVal[0], searchVal)) || [])[1]
const emptyArray = []
const match = mapping.find(keyVal => deepEqual(keyVal[0], searchVal)) || emptyArray
if (match !== emptyArray) {
found = true
}
value = match[1]
}

if (typeof value === 'function') {
return value()
return {
found,
nextVal: value(),
}
}
return value
return found ? { found, nextVal: value } : { found }
}

// Used to stringify yielded values. Output includes functions
Expand Down Expand Up @@ -127,13 +137,13 @@ function sagaTestEngine(effects, genFunc, opts, ...initialArgs) {
let counter = 0

while (!isDone) {
const nextVal = getNextVal(val, mapping)
const { found, nextVal } = getNextVal(val, mapping)
const throwError = shouldThrowError(nextVal)
let genResult

// Yielded value must appear in mapping, or be a PUT Effect.
const isFirstLoop = counter === 0
const nextValFound = nextVal !== undefined
const nextValFound = found
const yieldedUndefined = val === undefined
const yieldedEffectShouldBeCollected = isEffect(val, effects) || isNestedEffect(val, effects)
assert(
Expand Down
86 changes: 51 additions & 35 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,34 +140,36 @@ test('shouldThrowError correctly identifies a throw effect', t => {

test('getNextVal', t => {
// Nested Array
t.is(2, getNextVal(1, [[1, 2]]))
t.is(2, getNextVal(1, [[1, 2], [1, 3]]))
t.is(4, getNextVal(3, [[1, 2], [3, 4]]))
t.is(
'val',
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, [[1, 2]]))
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, [[1, 2], [1, 3]]))
t.deepEqual({ found: true, nextVal: 4 }, getNextVal(3, [[1, 2], [3, 4]]))
t.deepEqual(
{ found: true, nextVal: 'val' },
getNextVal({ a: { b: { c: 1 } } }, [[{ a: { b: { c: 1 } } }, 'val']]),
'Handled deeply-nested objects in arrays'
)
t.is(
undefined,
t.deepEqual(
{ found: false },
getNextVal({ a: { b: { c: 2 } } }, [[{ a: { b: { c: 1 } } }, 'val']]),
'Handled deeply-nested objects in arrays part 2'
)
t.deepEqual({ found: true, nextVal: undefined }, getNextVal(1, [[1, undefined]]))

// Nested Array with simple stubs
t.is(2, getNextVal(1, [[1, () => 2]]))
t.is(2, getNextVal(1, [[1, () => 2], [1, () => 3]]))
t.is(4, getNextVal(3, [[1, () => 2], [3, () => 4]]))
t.is(
'val',
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, [[1, () => 2]]))
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, [[1, () => 2], [1, () => 3]]))
t.deepEqual({ found: true, nextVal: 4 }, getNextVal(3, [[1, () => 2], [3, () => 4]]))
t.deepEqual(
{ found: true, nextVal: 'val' },
getNextVal({ a: { b: { c: 1 } } }, [[{ a: { b: { c: 1 } } }, () => 'val']]),
'Handled deeply-nested objects in arrays with simple stubs'
)
t.is(
undefined,
t.deepEqual(
{ found: false },
getNextVal({ a: { b: { c: 2 } } }, [[{ a: { b: { c: 1 } } }, () => 'val']]),
'Handled deeply-nested objects in arrays part 2 with simple stubs'
)
t.deepEqual({ found: true, nextVal: undefined }, getNextVal(1, [[1, () => undefined]]))

// Nested Array with generator stubs
const stub1 = stub(function*() {
Expand All @@ -179,45 +181,59 @@ test('getNextVal', t => {
}
})

t.is(2, getNextVal(1, [[1, stub1]]), 'Handle generator stub call 1')
t.is(3, getNextVal(1, [[1, stub1]]), 'Handle generator stub call 2')
t.is(4, getNextVal(1, [[1, stub1]]), 'Handle generator stub call 3')
t.deepEqual(
{ found: true, nextVal: 2 },
getNextVal(1, [[1, stub1]]),
'Handle generator stub call 1'
)
t.deepEqual(
{ found: true, nextVal: 3 },
getNextVal(1, [[1, stub1]]),
'Handle generator stub call 2'
)
t.deepEqual(
{ found: true, nextVal: 4 },
getNextVal(1, [[1, stub1]]),
'Handle generator stub call 3'
)

// Map
t.is(2, getNextVal(1, new Map([[1, 2]])))
t.is(4, getNextVal(3, new Map([[1, 2], [3, 4]])))
t.is(
'val',
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, new Map([[1, 2]])))
t.deepEqual({ found: true, nextVal: 4 }, getNextVal(3, new Map([[1, 2], [3, 4]])))
t.deepEqual(
{ found: true, nextVal: 'val' },
getNextVal({ a: { b: { c: 1 } } }, new Map([[{ a: { b: { c: 1 } } }, 'val']])),
'Handled deeply-nested objects in Map'
)
t.is(
undefined,
t.deepEqual(
{ found: false },
getNextVal({ a: { b: { c: 2 } } }, new Map([[{ a: { b: { c: 1 } } }, 'val']])),
'Handled deeply-nested objects in Map part 2'
)
t.deepEqual({ found: true, nextVal: undefined }, getNextVal(1, new Map([[1, undefined]])))

// Map with simple stubs
t.is(2, getNextVal(1, new Map([[1, () => 2]])))
t.is(4, getNextVal(3, new Map([[1, () => 2], [3, () => 4]])))
t.is(
'val',
t.deepEqual({ found: true, nextVal: 2 }, getNextVal(1, new Map([[1, () => 2]])))
t.deepEqual({ found: true, nextVal: 4 }, getNextVal(3, new Map([[1, () => 2], [3, () => 4]])))
t.deepEqual(
{ found: true, nextVal: 'val' },
getNextVal({ a: { b: { c: 1 } } }, new Map([[{ a: { b: { c: 1 } } }, () => 'val']])),
'Handled deeply-nested objects in Map with simple stubs'
)
t.is(
undefined,
t.deepEqual(
{ found: false },
getNextVal({ a: { b: { c: 2 } } }, new Map([[{ a: { b: { c: 1 } } }, () => 'val']])),
'Handled deeply-nested objects in Map part 2 with simple stubs'
)
t.deepEqual({ found: true, nextVal: undefined }, getNextVal(1, new Map([[1, () => undefined]])))

// Handles value not found.
t.is(undefined, getNextVal(100, []))
t.is(undefined, getNextVal(100, new Map([])))
t.is(undefined, getNextVal(100, [[1, 2]]))
t.is(undefined, getNextVal(100, new Map([[1, 2]])))
t.is(undefined, getNextVal(undefined, []))
t.is(undefined, getNextVal(undefined, new Map([])))
t.deepEqual({ found: false }, getNextVal(100, []))
t.deepEqual({ found: false }, getNextVal(100, new Map([])))
t.deepEqual({ found: false }, getNextVal(100, [[1, 2]]))
t.deepEqual({ found: false }, getNextVal(100, new Map([[1, 2]])))
t.deepEqual({ found: false }, getNextVal(undefined, []))
t.deepEqual({ found: false }, getNextVal(undefined, new Map([])))
})

test('sagaTestEngine throws under bad conditions', t => {
Expand Down