[go: up one dir, main page]

Skip to content

Commit

Permalink
feat(task.all): added Task.all static method
Browse files Browse the repository at this point in the history
* feat(task.all): added Task.all static method and its tests

* fix(syntax): fixed trailing whitespaces

* fix(test): Improved testing
  • Loading branch information
dggluz authored and hrajchert committed Dec 11, 2017
1 parent 06c4efd commit 8c377e8
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"profile": "https://github.com/dggluz",
"contributions": [
"code",
"ideas"
"ideas",
"test"
]
}
]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Initialized with [@alexjoverm](https://twitter.com/alexjoverm)'s [TypeScript Lib

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
| [<img src="https://avatars0.githubusercontent.com/u/2634059?v=4" width="100px;"/><br /><sub><b>Hernan Rajchert</b></sub>](https://github.com/hrajchert)<br />[💻](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Code") [🎨](#design-hrajchert "Design") [📖](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Documentation") [💡](#example-hrajchert "Examples") [⚠️](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1573956?v=4" width="100px;"/><br /><sub><b>Gonzalo Gluzman</b></sub>](https://github.com/dggluz)<br />[💻](https://github.com/hrajchert/@acamica/task/commits?author=dggluz "Code") [🤔](#ideas-dggluz "Ideas, Planning, & Feedback") |
| [<img src="https://avatars0.githubusercontent.com/u/2634059?v=4" width="100px;"/><br /><sub><b>Hernan Rajchert</b></sub>](https://github.com/hrajchert)<br />[💻](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Code") [🎨](#design-hrajchert "Design") [📖](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Documentation") [💡](#example-hrajchert "Examples") [⚠️](https://github.com/hrajchert/@acamica/task/commits?author=hrajchert "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1573956?v=4" width="100px;"/><br /><sub><b>Gonzalo Gluzman</b></sub>](https://github.com/dggluz)<br />[💻](https://github.com/hrajchert/@acamica/task/commits?author=dggluz "Code") [🤔](#ideas-dggluz "Ideas, Planning, & Feedback") [⚠️](https://github.com/hrajchert/@acamica/task/commits?author=dggluz "Tests") |
| :---: | :---: |
<!-- ALL-CONTRIBUTORS-LIST:END -->

Expand Down
45 changes: 45 additions & 0 deletions src/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,51 @@ export class Task <T, E> {
});
}

static all <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>, Task<T6, E6>, Task<T7, E7>, Task<T8, E8>, Task<T9, E9>, Task<T10, E10>]): Task<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8 | E9 | E10>;
static all <T1, T2, T3, T4, T5, T6, T7, T8, T9, E1, E2, E3, E4, E5, E6, E7, E8, E9> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>, Task<T6, E6>, Task<T7, E7>, Task<T8, E8>, Task<T9, E9>]): Task<[T1, T2, T3, T4, T5, T6, T7, T8, T9], E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8 | E9>;
static all <T1, T2, T3, T4, T5, T6, T7, T8, E1, E2, E3, E4, E5, E6, E7, E8> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>, Task<T6, E6>, Task<T7, E7>, Task<T8, E8>]): Task<[T1, T2, T3, T4, T5, T6, T7, T8], E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8>;
static all <T1, T2, T3, T4, T5, T6, T7, E1, E2, E3, E4, E5, E6, E7> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>, Task<T6, E6>, Task<T7, E7>]): Task<[T1, T2, T3, T4, T5, T6, T7], E1 | E2 | E3 | E4 | E5 | E6 | E7>;
static all <T1, T2, T3, T4, T5, T6, E1, E2, E3, E4, E5, E6> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>, Task<T6, E6>]): Task<[T1, T2, T3, T4, T5, T6], E1 | E2 | E3 | E4 | E5 | E6>;
static all <T1, T2, T3, T4, T5, E1, E2, E3, E4, E5> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>, Task<T5, E5>]): Task<[T1, T2, T3, T4, T5], E1 | E2 | E3 | E4 | E5>;
static all <T1, T2, T3, T4, E1, E2, E3, E4> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>, Task<T4, E4>]): Task<[T1, T2, T3, T4], E1 | E2 | E3 | E4>;
static all <T1, T2, T3, E1, E2, E3> (tasks: [Task<T1, E1>, Task<T2, E2>, Task<T3, E3>]): Task<[T1, T2, T3], E1 | E2 | E3>;
static all <T1, T2, E1, E2> (tasks: [Task<T1, E1>, Task<T2, E2>]): Task<[T1, T2], E1 | E2>;
static all <T1, E1> (tasks: [Task<T1, E1>]): Task<[T1], E1>;
static all <T, E> (tasks: Task<T, E>[]) {
// Flag to track if any Task has resolved
let rejected = false;
// Array that we'll fill with the resolved values, in order
const resolvedValues: T[] = [];
// Counter of resolved Tasks (we can't use resolvedValues.length since we add elements through index)
let resolvedQty = 0;

return new Task((outerResolve, outerReject) => {
tasks.forEach((aTask, index) => {
aTask
.fork(err => {
// We do only reject if there was no previous rejection
if (!rejected) {
rejected = true;
outerReject(err);
}
}, x => {
// Shouldn't resolve if another Task has rejected
if (rejected) {
return;
}

// Track resolved value (in order)
resolvedValues[index] = x;
// ...and how many tasks has resolved
resolvedQty++;
if (resolvedQty === tasks.length) {
outerResolve(resolvedValues);
}
});
});
});
}

map<TResult> (fn: IMapFn<T, TResult>): Task<TResult, E | UncaughtError> {
return new Task((outerResolve, outerReject) => {
this.fork(
Expand Down
98 changes: 98 additions & 0 deletions test/task.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,102 @@ describe('Task', () => {
);
});
});

describe('all', () => {
it('should work with a single resolved Task', cb => {
// GIVEN: a resolved Task
const task = Task.resolve(5);

// WHEN: we do a Task.all from the previous one Task
const tAll = Task.all([task]);

// THEN: the resulting Task is resolved with an array of the resolved value
tAll.fork(
jestAssertNever(cb),
assertFork(cb, x => expect(x).toEqual([5]))
);
});

it('should work with a single rejected Task', cb => {
// GIVEN: a rejected Task
const task = Task.reject('Buu!');

// WHEN: we do a Task.all from the previous one Task
const tAll = Task.all([task]);

// THEN: the resulting Task is rejected with the rejected error
tAll.fork(
assertFork(cb, err => expect(err).toEqual('Buu!')),
jestAssertUntypedNeverCalled(cb)
);
});

it('should resolve if all task are resolved', cb => {
// GIVEN: a bunch of resolved Tasks
const task1 = Task.resolve(10);
const task2 = Task.resolve('100');
const task3 = Task.resolve(true);

// WHEN: we do a Task.all from the previous Tasks
const tAll = Task.all([task1, task2, task3]);

// THEN: the resulting Task is resolved with the resolved values
tAll.fork(
jestAssertNever(cb),
assertFork(cb, x => expect(x).toEqual([10, '100', true]))
);
});

it('should wait async tasks', cb => {
// GIVEN: a bunch of resolved Tasks
const task1 = Task.resolve(10);
const task2 = new Task<string, never>(resolve => setTimeout(_ => resolve('foo'), 10));
const task3 = Task.resolve(true);

// WHEN: we do a Task.all from the previous Tasks
const tAll = Task.all([task1, task2, task3]);

// THEN: the resulting Task is resolved with the resolved values
tAll.fork(
jestAssertNever(cb),
assertFork(cb, x => expect(x).toEqual([10, 'foo', true]))
);
});

it('should reject if there is even one rejected one', cb => {
// GIVEN: a rejected Task
const task1 = Task.resolve(10);
const task2 = Task.reject('Buu!');
const task3 = Task.resolve(1000);

// WHEN: we do a Task.all from the previous one Task
const tAll = Task.all([task1, task2, task3]);

// THEN: the resulting Task is rejected with the rejected error
tAll.fork(
assertFork(cb, err => expect(err).toEqual('Buu!')),
jestAssertUntypedNeverCalled(cb)
);
});

it('should reject with the first rejection', cb => {
// GIVEN: three rejected Task
const task1 = Task.reject('Foo');
const task2 = new Task<never, number>((_, reject) => setTimeout(_ => reject(9), 0));
const task3 = new Task<never, boolean>((_, reject) => setTimeout(_ => reject(true), 0));

// WHEN: we do a Task.all from the previous one Task
const tAll = Task.all([task1, task2, task3]);

// THEN: the resulting Task is rejected with the first rejected error
tAll.fork(
err => {
expect(err).toEqual('Foo');
// Need to wait to make sure we test all lines in coverage
setTimeout(cb, 10);
},
jestAssertUntypedNeverCalled(cb)
);
});
});
});

0 comments on commit 8c377e8

Please sign in to comment.