Utility-functions that can be usefull when you have asynchronous tests in javascript.
$ npm install async-test-util --save-dev
// es6
import AsyncTestUtil from 'async-test-util';
// es5
var AsyncTestUtil = require('async-test-util');
Waits until the given time has expired and then resolves.
it('should wait', async() => {
await AsyncTestUtil.wait(200);
console.log('200 ms is over');
});
Waits until the given timeout has expired or the resolve was triggered manually
it('should wait until observable fired or time is over', async() => {
const resolveable = AsyncTestUtil.waitResolveable(200);
myObservable.subscribe(sth => {
console.log('got first event');
resolveable.resolve();
});
await resolveable.promise;
});
Waits until the given predicate-function returns a truthy value. Throws if the optional timeout has passed before.
it('should wait until server is online', async() => {
const checkServer = async() => {
try{
await fetch('http://example.com/api/');
return true;
}catch(err) {
return false;
}
};
await AsyncTestUtil.waitUntil(checkServer);
});
With timeout:
it('should wait until server is online (maxtime: 1000ms)', async() => {
const checkServer = async() => {
try{
await fetch('http://example.com/api/');
return true;
}catch(err) {
return false;
}
};
await AsyncTestUtil.waitUntil(checkServer, 1000);
});
With return value:
it('should wait until server is online (maxtime: 1000ms)', async() => {
const checkServer = async() => {
try{
const response = await fetch('http://example.com/api/');
return await response.json();
}catch(err) {
return false;
}
};
const firstSuccessfullResponse = await AsyncTestUtil.waitUntil(checkServer, 1000);
});
Waits forever, never resolves.
it('should never resolve', async() => {
let resolved = false;
AsyncTestUtil
.waitForever()
.then(() => resolved = true);
await AsyncTestUtil.wait(100);
assert.equal(false, resolved);
});
Runs the given predicate-function forever. Between each run, the interval-time is awaited.
it('should run forever', async() => {
let t = 0;
const pred = () => t++;
AsyncTestUtil.runForever(
pred, // predicate-function
10 // interval
);
await AsyncTestUtil.wait(100);
assert.ok(t > 4);
const lastT = t;
await AsyncTestUtil.wait(100);
assert.ok(t > lastT);
});
Async-Form of assert.throws. Asserts that the given function throws with the defined error, throws if not.
// with error-type
it('should throw because route does not exist', async() => {
const getServerVersion = async() => {
const response = await fetch('http://example.com/foobar/');
return response;
};
await AsyncTestUtil.assertThrows(
() => getServerVersion(), // function that throws (required)
Error // Error-type (optional)
);
});
// with error-text-flag
it('should throw because route does not exist', async() => {
const pingServer = async() => {
try{
await fetch('http://example.com/foobar/');
}catch(err) {
throw new Error('route not reachable');
}
};
await AsyncTestUtil.assertThrows(
() => pingServer(), // function that throws (required)
Error, // Error-type (optional)
'reachable' // text-flag, throw if error-message does not include this (optional)
);
// or you can pass a string-array to ensure all is in error message
await AsyncTestUtil.assertThrows(
() => pingServer(), // function that throws (required)
Error, // Error-type (optional)
['route', 'reachable'] // text-flag, throw if error-message does not include this (optional)
);
});
// assertThrows returns the error
it('should have the custom error-property', async() => {
const throwingFunction = async()=>{
const error = new Error('error message');
error.foo = 'bar';
throw error;
}
const thrown = await AsyncTestUtil.assertThrows(
() => pingServer(), // function that throws (required)
Error, // Error-type (optional)
'message' // text-flag, throw if error-message does not include this (optional)
);
assert.equal(thrown.foo, 'bar');
});
Recieves an object with promises as values. Returns ans object with the resolved promises as values. Use this in test-setups to improve the test-speed by running everything in parallel.
// instead of this
const database = await connectDatabase();
const user1 = await getUser();
const user2 = await getUser();
// do this
const {
database,
user1,
user2
} = await AsyncTestUtil.resolveValues({
database: connectDatabase();
user1: getUser();
user2: getUser();
});
Returns true if the given value is a Promise
;
const is = AsyncTestUtil.isPromise(myAsyncFunction()); // true
const is = AsyncTestUtil.isPromise('foobar'); // false
Transforms the given value to a promise if it was no promise before.
const ensurePromise = AsyncTestUtil.promisify(maybeAsyncFunction());
// now you are sure this is a promise
ensurePromise.then(/* ... */)
Creates a random string. Takes length as first parameter an custom charset as second.
console.log(AsyncTestUtil.randomString());
// > 'rhfkx'
console.log(AsyncTestUtil.randomString(10));
// > 'dhcvkledzu'
console.log(AsyncTestUtil.randomString(
6, // (optional) length
'abc' // (optional) charset, only this will be used to create the string
));
// > 'acbcba'
Creates a random number. Optional range can be given.
console.log(AsyncTestUtil.randomNumber());
// > 56
console.log(AsyncTestUtil.randomNumber(
1000, // min-value (default=0)
2000 // max-value (default=1000)
));
// > 1768
Creates a random boolean. Returns true
or false
.
console.log(AsyncTestUtil.randomBoolean());
// > true
Reference to clone. Does exactly the same thing.
it('should not modify the original object', () => {
const original = {
foo: 'bar',
level: 1
};
const cloned = AsyncTestUtil.clone(original);
cloned.level = 2;
assert.equal(original.level, 1);
});
Reference to deep-equal. Does exactly the same thing.
it('the 2 objects should be equal', () => {
const obj1 = {
foo: 'bar',
level: 1
};
const obj2 = {
foo: 'bar',
level: 1
};
assert.ok(AsyncTestUtil.deepEqual(obj1, obj2));
});
Works equal to performance.now but works in browsers and nodeJs.
it('should take less then 200 milliseconds', () => {
const now = AsyncTestUtil.performanceNow(); // in milliseconds
await doSomething();
const later = AsyncTestUtil.performanceNow(); // in milliseconds
assert.ok((now + 50 * 1000 ) > later);
});