3 changed files with 292 additions and 1 deletions
Split View
Diff Options
-
1jasmine-async-await/unit-tests/js-3.6.0/SpecRunner.html
-
268jasmine-async-await/unit-tests/js-3.6.0/spec/PromisesAndCallbacksSpec.js
-
24jasmine-async-await/unit-tests/js-3.6.0/spec/sampleSpec.js
@ -0,0 +1,268 @@ |
|||
describe('Promise', () => { |
|||
it('Promise executor is run SYNCHRONOUSLY', () => { |
|||
let executorRun = false; |
|||
new Promise(function executor() { |
|||
executorRun = true; |
|||
}); |
|||
|
|||
expect(executorRun).toBe(true); |
|||
}); |
|||
|
|||
it('you can resolve a promise', (done) => { |
|||
new Promise((resolve) => setTimeout(resolve, 1)) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('... or you can reject a promise', (done) => { |
|||
new Promise((resolve, reject) => setTimeout(reject, 1)) |
|||
.then(undefined, done); |
|||
}); |
|||
|
|||
it('An error inside the executor, rejects the promise', (done) => { |
|||
new Promise(function executor() { |
|||
throw 'Error'; |
|||
}).catch(done); |
|||
}); |
|||
|
|||
it('you can use Promise.resolve() to wrap values or promises', (done) => { |
|||
function iMayReturnAPromise() { |
|||
return Math.random() >= 0.5 ? Promise.resolve() : 5; |
|||
} |
|||
|
|||
Promise.resolve(iMayReturnAPromise()).then(done); |
|||
}); |
|||
|
|||
it('you can use Promise.resolve() to execute something just after', (done) => { |
|||
let arr = []; |
|||
Promise.resolve().then(() => arr.push(2)); |
|||
arr.push(1); |
|||
|
|||
setTimeout(() => { |
|||
expect(arr).toEqual([1, 2]); |
|||
done(); |
|||
}, 1); |
|||
}); |
|||
|
|||
/** @see https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ **/ |
|||
it('Promise.resolve() is normally executed before setTimeout(..., 0)', (done) => { |
|||
let arr = []; |
|||
setTimeout(() => arr.push('timeOut'), 0); |
|||
Promise.resolve().then(() => { |
|||
arr.push('resolve'); |
|||
}); |
|||
|
|||
setTimeout(() => { |
|||
expect(arr).toEqual(['resolve', 'timeOut']); |
|||
done(); |
|||
}, 1); |
|||
}); |
|||
|
|||
it('you can create rejected promises', (done) => { |
|||
Promise.reject('reason').catch(done); |
|||
}); |
|||
/* |
|||
it('pay attention to "Uncaught (in promise) ..."', () => { |
|||
Promise.reject('The error').catch(); // Outputs in the console Uncaught (in promise) The error
|
|||
}); |
|||
*/ |
|||
|
|||
// Chaining promises
|
|||
it('you can chain promise because .then(...) returns a promise', (done) => { |
|||
fetch('https://jsonplaceholder.typicode.com/posts/1') |
|||
.then(response => response.json()) |
|||
.then(json => expect(json.userId).toBe(1)) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('you can use the fail callback of .then(success, fail) to handle rejected promises', (done) => { |
|||
Promise.reject() |
|||
.then(function success() { |
|||
throw 'I must not be executed'; |
|||
}, function fail() { |
|||
done(); |
|||
}); |
|||
}); |
|||
|
|||
it('... or you can use .catch() to handle rejected promises', (done) => { |
|||
Promise.reject() |
|||
.then(function success() { |
|||
throw 'I must not be executed'; |
|||
}) |
|||
.catch(done); |
|||
}); |
|||
|
|||
it('also .catch() returns a promise, allowing promise chaining', (done) => { |
|||
Promise.reject() |
|||
.catch(() => undefined) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('you must return a rejected promise if you want to execute the next fail callback', (done) => { |
|||
function someApiCall() { |
|||
return Promise.reject('Error'); |
|||
} |
|||
|
|||
someApiCall() |
|||
.catch((err) => { |
|||
console.error(err); |
|||
return Promise.reject(err); // Without this line, .catch gets not called
|
|||
}) |
|||
.catch(done); |
|||
}); |
|||
|
|||
it('... or you can throw an error if you want to execute the next fail callback', (done) => { |
|||
function someApiCall() { |
|||
return Promise.reject('Error'); |
|||
} |
|||
|
|||
someApiCall() |
|||
.catch((err) => { |
|||
console.error(err); |
|||
throw err; // Without this line, .catch gets not called
|
|||
}) |
|||
.catch(done); |
|||
}); |
|||
|
|||
it('values returned inside .then()/.catch() callbacks are provided to the next callback', (done) => { |
|||
Promise.resolve(1) |
|||
.then(value => value + 1) |
|||
.then(value => expect(value).toBe(2)); |
|||
|
|||
Promise.reject(1) |
|||
.catch(value => value + 1) |
|||
.then(value => expect(value).toBe(2)); |
|||
|
|||
setTimeout(() => { |
|||
done(); |
|||
}, 1); |
|||
}); |
|||
|
|||
|
|||
// New await/async syntax
|
|||
it('you can use the new await/async syntax', async () => { |
|||
function timeout(ms) { |
|||
return new Promise((resolve) => setTimeout(resolve, ms)); |
|||
} |
|||
|
|||
const start = Date.now(); |
|||
const delay = 200; |
|||
|
|||
await timeout(delay + 1); // Just 1ms tolerance
|
|||
|
|||
expect(Date.now() - start).toBeGreaterThanOrEqual(delay); |
|||
}); |
|||
|
|||
it('an async function returns a promise', (done) => { |
|||
async function iAmAsync() { |
|||
return 1; |
|||
} |
|||
|
|||
iAmAsync() |
|||
.then((val) => expect(val).toBe(1)) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('await just awaits a promise resolution', async (done) => { |
|||
await Promise.resolve(); |
|||
done(); |
|||
}); |
|||
|
|||
it('await will throw an error if the promise fail', async (done) => { |
|||
try { |
|||
await Promise.reject(); |
|||
fail('I will not be executed'); |
|||
} catch (err) { |
|||
done(); |
|||
} |
|||
}); |
|||
|
|||
it("Don't use new Promise(...), prefer chaining", (done) => { |
|||
const url = 'https://jsonplaceholder.typicode.com/posts/1'; |
|||
|
|||
function badlyDesignedCustomFetch() { |
|||
return new Promise((resolve, reject) => { |
|||
fetch(url).then((response) => { |
|||
if (response.ok) { |
|||
resolve(response); |
|||
} else { |
|||
reject('Fetch failed'); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
function wellDesignedCustomFetch() { |
|||
return fetch(url).then((response) => { |
|||
if (!response.ok) { |
|||
return Promise.reject('Fetch failed'); |
|||
} |
|||
return (response); |
|||
}); |
|||
} |
|||
|
|||
Promise.all([badlyDesignedCustomFetch(), wellDesignedCustomFetch()]).then(done); |
|||
}); |
|||
|
|||
|
|||
// Parallel execution of promises
|
|||
it('you can use Promise.all([...]) to execute promises in parallel', (done) => { |
|||
const url = 'https://jsonplaceholder.typicode.com/posts'; |
|||
const p1 = fetch(`${url}/1`); |
|||
const p2 = fetch(`${url}/2`); |
|||
|
|||
|
|||
Promise.all([p1, p2]) |
|||
.then(([res1, res2]) => { |
|||
return Promise.all([res1.json(), res2.json()]) |
|||
}) |
|||
.then(([post1, post2]) => { |
|||
expect(post1.id).toBe(1); |
|||
expect(post2.id).toBe(2); |
|||
}) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('Promise.all([...]) will fail if any of the promises fails', (done) => { |
|||
const p1 = Promise.resolve(1); |
|||
const p2 = Promise.reject('Error'); |
|||
|
|||
Promise.all([p1, p2]) |
|||
.then(() => { |
|||
fail('I will not be executed') |
|||
}) |
|||
.catch(done); |
|||
}); |
|||
|
|||
it("if you don't want Promise.all() to fail, wrap the promises in a promise that will not fail", (done) => { |
|||
function iMayFail(val) { |
|||
return Math.random() >= 0.5 ? Promise.resolve(val) : Promise.reject(val); |
|||
} |
|||
|
|||
function promiseOr(p, value) { |
|||
return p.then(res => res, () => value); |
|||
} |
|||
|
|||
const p1 = iMayFail(10); |
|||
const p2 = iMayFail(9); |
|||
|
|||
Promise.all([promiseOr(p1, null), promiseOr(p2, null)]) |
|||
.then(([val1, val2]) => { |
|||
expect(val1 === 10 || val1 === null).toBe(true); |
|||
expect(val2 === 9 || val2 === null).toBe(true); |
|||
}) |
|||
.catch(() => { |
|||
fail('I will not be executed') |
|||
}) |
|||
.then(done); |
|||
}); |
|||
|
|||
it('Promise.race([...]) will resolve as soon as one of the promises resolves o rejects', (done) => { |
|||
const timeout = new Promise((resolve, reject) => setTimeout(reject, 100)); |
|||
const data = fetch('https://jsonplaceholder.typicode.com/posts/1'); |
|||
|
|||
Promise.race([data, timeout]) |
|||
.then(() => console.log('Fetch OK')) |
|||
.catch(() => console.log('Fetch timeout')) |
|||
.then(done); |
|||
}); |
|||
}); |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue