Comments (7)
I have some experience with the testing of complex async projects. If you can tell me what's the trouble that makes you want to choose sync, I may help you to find a better way to test, other than hacking a primary lib.
A couple of years ago I had alot of problems with async tests where things finishing in different orders resulted in different results and then inconsistent tests. In those cases there were multiple setTimeout's with different times and not only was it inconsistent but slow (I realise that promises in particular don't suffer from long timeouts.. but if you start making calls sync it tends to affect everything).
So I prefer to mock out date, mock out timers like setTimeout and flush promises. It means you can have full control on the execution order and make one test in one order and one in another.
I wouldn't want to change nextTick to just be sync because it changes the behaviour e.g.
let a;
Promise.reject().catch(() => a());
a = () => console.log('only works async');
but what I do prefer to do is to treat my unit test like its a top level environment - e.g. once user code has returned to the test, if I run pending timers / flush promises then, I keep almost the same behaviour as a live environment, but control execution from my tests.
but your right, I have managed to implement this using nextTick:
// replace Promise with one with a Promise.flush function to make promises sync
import Yaku from 'yaku';
const queue = [];
let timeoutid = null;
function runQueue() {
const q = queue.slice(0);
queue.length = 0;
for (let i = 0; i < q.length; i++) {
q[i]();
}
}
// Promises should run as normal but be able to be flushed
// as if the test ended and the setImmediate began
Yaku.nextTick = (fn) => {
queue.push(fn);
if (!timeoutid) {
timeoutid = global.setImmediate(Yaku.flush);
}
};
Yaku.flush = () => {
while (queue.length) {
runQueue();
}
global.clearImmediate(timeoutid);
timeoutid = null;
};
Yaku.resolvedValue = (promise) => {
let value;
promise.then((resolvedValue) => {
value = resolvedValue;
});
Yaku.flush();
return value;
};
Yaku.isFulfilled = (promise) => {
let isFulfilled = false;
promise.then(function() {
isFulfilled = true;
});
Yaku.flush();
return isFulfilled;
};
Yaku.isRejected = (promise) => {
let isRejected = false;
promise.catch(function() {
isRejected = true;
});
Yaku.flush();
return isRejected;
};
// stop unhandled exceptions on Promise.reject which occurs often in the testing code
const originalPromiseReject = Yaku.reject;
Yaku.reject = (value) => {
const promise = originalPromiseReject.call(Yaku, value);
promise.catch(() => {});
return promise;
};
export const isRejected = Yaku.isRejected;
export const isFulfilled = Yaku.isFulfilled;
export const resolvedValue = Yaku.resolvedValue;
export const flush = Yaku.flush;
global.Promise = Yaku;
and I am a bit more on the fence about this than I used to be - I test with jest and it does have pretty good support for promises, so I could probably keep promises async and use async tests, then use fake timers only to skip waiting for any setTimeouts.
btw in case your wondering why I mention setTimeouts so often - that is to mock rest requests and websocket data that come in at different times and orders.
from yaku.
Actually, there's an easier approach, have you read this section of the doc?
https://github.com/ysmood/yaku#yakunexttick?
I'm not sure if this is what you want, but if you want to resolve promise synchronously without any side effect it should work for you.
from yaku.
BTW, it's better to use the async resolution which will enforce you to think asynchronously and reduce some production bugs that caused by lacking asynchronous planning.
I have some experience with the testing of complex async projects. If you can tell me what's the trouble that makes you want to choose sync, I may help you to find a better way to test, other than hacking a primary lib.
from yaku.
thats a good point. I could try implementing a scheduler on top of this, which records setTimeout, then on flush, clears it and runs it immediately.
from yaku.
Actually what you want to do is have full control of the IO, I think you already know pure-function, for Yaku the only input IO to the outside world is nextTick
, so if you take control of it you can make Yaku a pure module without any IO side effect.
If you want to go extremely, you'd better also mock all other common IOs, including File, Net, and Timer, then you even don't have to touch Yaku, you'll get what you want automatically because Yaku uses Timer internally.
If your system is fully inside a sandbox without any IO to outside world, you will get the best performance of a single CPU core for your tests. Normally people don't do that because IO is not always the bottleneck of the project, they prefer to put the time to more important problems.
If you want to leverage multiple CPU cores without all those common IOs, you might need to create a new test framework other than something like ava. Actually, I'm interested to create a perfect IO sandbox test framework for multiple CPU cores.
from yaku.
// stop unhandled exceptions on Promise.reject which occurs often in the testing code
const originalPromiseReject = Yaku.reject;
Yaku.reject = (value) => {
const promise = originalPromiseReject.call(Yaku, value);
promise.catch(() => {});
return promise;
};
About this code, I recommend you to read the doc of this section:
https://github.com/ysmood/yaku#yakuunhandledrejectionreason-p
nextTick
is the only input IO of Yaku,
unhandledRejection
is the only output IO of Yaku, so you can use it to mute Yaku
from yaku.
Close because of no activity
from yaku.
Related Issues (20)
- Only the core works well with old browsers HOT 1
- Something strange (Slow resolve on pageload) HOT 23
- Yaku doesn't work if div with id="process" exists HOT 2
- Can't register global unhandled rejection HOT 1
- Does not work on UC Browser HOT 9
- incorrect behavior with unhandledrejection events HOT 8
- Yaku.all is overridden by yaku/utils/all on yaku.brower.full.min.js version HOT 3
- difference between return Promise.reject(x) and throw x HOT 7
- Finally swallows rejections HOT 4
- Bind to Angular 1.x digest? HOT 6
- Bad references in package.json HOT 1
- 0.18.3 is broken if window.Promise is set to Yaku HOT 3
- Implement Promise.try() ? HOT 1
- Incorrect promise when calling `resolve` twice HOT 1
- global.Promise should be non-enumerable and should have correct name property HOT 5
- "hash" util/helper request HOT 3
- Support for Promise.allSetteled HOT 2
- Bug: Stealing a resolver and using it to trigger reentrancy HOT 3
- Promise.all and Promise.allSettled doesn't work if the promise array has been created in a different frame. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from yaku.