Problem with combine() and Mocks
See original GitHub issueI just spent the last few days chasing my tail on this one. I was using several mocking libraries, notably ts-mockito and testdouble, and got the same behavior. If I created a mock object, wrapped it with okAsync(), and tossed that into combine(), I would get nothing in the return- the mock object was being dropped. Here’s an example test in jest that would fail:
import td from "testdouble";
interface ITestInterface {
getName(): string;
setName(name: string): void;
getAsyncResult(): ResultAsync<ITestInterface, Error>;
}
describe("Debugging and basic info tests", () => {
test("combine works with TestDouble mocks of interfaces", async () => {
// Arrange
const mock = td.object<ITestInterface>();
// Act
const result = await combine([okAsync(mock)]);
// Assert
expect(result).toBeDefined();
expect(result.isErr()).toBeFalsy();
const unwrappedResult = result._unsafeUnwrap();
expect(unwrappedResult.length).toBe(1);
expect(unwrappedResult[0]).toBe(mock);
});
});
If you run this, you’d find that the last two expect calls would fail, because combine would return an empty array! It would only do this with mocks, not with normal objects. So I dug into it, and I found a solution in the combine() code. You are using array.concat(nonArray) in the reduce() of combineResults(). I rolled my own combine and it works even with mocks. I added typing support for heterogenous lists as well, but it looks like you’re working on a slicker solution in another issue. Here’s my “fixed” combine:
export class ResultUtils {
static combine<T, T2, T3, T4, E, E2, E3, E4>(asyncResultList: [ResultAsync<T, E>, ResultAsync<T2, E2>, ResultAsync<T3, E3>, ResultAsync<T4, E4>]): ResultAsync<[T, T2, T3, T4], E | E2 | E3 | E4>;
static combine<T, T2, T3, E, E2, E3>(asyncResultList: [ResultAsync<T, E>, ResultAsync<T2, E2>, ResultAsync<T3, E3>]): ResultAsync<[T, T2, T3], E | E2 | E3>;
static combine<T, T2, E, E2>(asyncResultList: [ResultAsync<T, E>, ResultAsync<T2, E2>]): ResultAsync<[T, T2], E | E2>;
static combine<T, E>(asyncResultList: ResultAsync<T, E>[]): ResultAsync<T[],E> {
return ResultAsync.fromPromise(Promise.all(asyncResultList),
(e) => {return e as E})
.andThen(ResultUtils.combineResultList);
}
static combineResultList<T, E>(resultList: Result<T, E>[]): Result<T[], E> {
return resultList.reduce((acc: Result<T[], E>, result) => {
return acc.isOk()
? result.isErr()
? err(result.error)
: acc.map((values) => {
values.push(result.value);
return values;
})
: acc;
}, ok([]));
};
}
Issue Analytics
- State:
- Created 3 years ago
- Comments:21 (16 by maintainers)
Top GitHub Comments
@supermacro That’s great! How do you usually do this, I can give you my twitter to speak easier? https://twitter.com/kieranbosgood
Hey @kieran-osgood, sorry for the delay in responding.
I’ll be sinking my teeth into this issue and your response once again this week.