0.2.0 - Mid migration

This commit is contained in:
Daniel Mason 2022-04-25 14:47:15 +12:00
parent 139e6a915e
commit 7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions

29
web/node_modules/tryer/.gitlab-ci.yml generated vendored Normal file
View file

@ -0,0 +1,29 @@
cache:
key: "$CI_JOB_NAME"
untracked: true
paths:
- node_modules/
before_script:
- npm install
.test_template: &npm_test
script:
- npm run lint
- npm test
test:node4:
image: node:4
<<: *npm_test
test:node6:
image: node:6
<<: *npm_test
test:node8:
image: node:8
<<: *npm_test
test:node10:
image: node:10
<<: *npm_test

68
web/node_modules/tryer/.jshintrc generated vendored Normal file
View file

@ -0,0 +1,68 @@
{
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"es3": true,
"forin": true,
"freeze": true,
"immed": true,
"indent": 2,
"latedef": "nofunc",
"newcap": true,
"noarg": true,
"noempty": true,
"nonbsp": true,
"nonew": true,
"plusplus": true,
"quotmark": "single",
"strict": true,
"trailing": true,
"undef": true,
"unused": true,
"asi": false,
"boss": false,
"debug": false,
"eqnull": false,
"es5": false,
"esnext": false,
"evil": false,
"expr": false,
"funcscope": false,
"iterator": false,
"lastsemic": false,
"laxbreak": false,
"laxcomma": false,
"loopfunc": false,
"moz": false,
"multistr": false,
"proto": false,
"scripturl": false,
"shadow": false,
"smarttabs": false,
"sub": false,
"supernew": false,
"validthis": false,
"browser": false,
"couch": false,
"devel": false,
"dojo": false,
"jquery": false,
"mootools": false,
"node": false,
"nonstandard": false,
"phantom": false,
"prototypejs": false,
"rhino": false,
"worker": false,
"wsh": false,
"yui": false,
"nomen": true,
"onevar": true,
"passfail": false,
"white": false
}

11
web/node_modules/tryer/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,11 @@
language: node_js
node_js:
- "8"
- "6"
- "4"
- "0.12"
- "0.10"
branches:
only:
- master

3
web/node_modules/tryer/AUTHORS generated vendored Normal file
View file

@ -0,0 +1,3 @@
Phil Booth <pmbooth@gmail.com> (https://philbooth.me/)
Andrew Lawson (https://github.com/adlawson)
Tim O'Sulg (https://github.com/timgluz)

36
web/node_modules/tryer/CHANGES.md generated vendored Normal file
View file

@ -0,0 +1,36 @@
# Changes
## 1.0.1
### Other changes
* project: migrate to gitlab (0046018)
## 1.0.0
* Update:a83cc21 Update dependencies. (a83cc21)
* Fix:0c80670 Fix component info. (0c80670)
* chore: add change log (2787c9f)
* breaking change: export the entrypoint function directly (e56e066)
* chore: set indentation to two spaces (04419ce)
* chore: convert the unit tests to vanilla js (d87f514)
* feature: add browser-based test runner (24bdeab)
* chore: update dev deps (d56cbd4)
* fix: fix lint errors (52ae898)
* chore: update target node versions (d5a8b6b)
* fix: speed up the unit tests a bit (b8adf00)
* chore: insert whitespace (012e12b)
* breaking change: rename from trier to tryer (d7b121d)
* fix: tolerate missing options argument (7417ed9)
* fix: improve the readme (807112e)
* breaking change: ditch the stupid context and args options (009ef33)
* feature: handle promises returned by actions (e24a0cf)
* fix: fix lint errors (d4e6321)
* chore: update minified lib (066bbc5)
* chore: add a note about lib size to the readme (55b883b)
* chore: update copyright statement (3805ac6)
## 0.3.6
Legacy version, `trier`.

20
web/node_modules/tryer/COPYING generated vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright © 2013, 2017 Phil Booth
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

303
web/node_modules/tryer/README.md generated vendored Normal file
View file

@ -0,0 +1,303 @@
# tryer
[![Build status](https://gitlab.com/philbooth/tryer/badges/master/pipeline.svg)](https://gitlab.com/philbooth/tryer/pipelines)
[![Package status](https://img.shields.io/npm/v/tryer.svg)](https://www.npmjs.com/package/tryer)
[![Downloads](https://img.shields.io/npm/dm/tryer.svg)](https://www.npmjs.com/package/tryer)
[![License](https://img.shields.io/npm/l/tryer.svg)](https://opensource.org/licenses/MIT)
Because everyone loves a tryer!
Conditional
and repeated
function invocation
for node
and browser.
* [Say what?](#say-what)
* [What size is it?](#what-size-is-it)
* [How do I install it?](#how-do-i-install-it)
* [How do I use it?](#how-do-i-use-it)
* [Loading the library](#loading-the-library)
* [Calling the exported function](#calling-the-exported-function)
* [Examples](#examples)
* [How do I set up the dev environment?](#how-do-i-set-up-the-dev-environment)
* [What license is it released under?](#what-license-is-it-released-under)
## Say what?
Sometimes,
you want to defer
calling a function
until a certain
pre-requisite condition is met.
Other times,
you want to
call a function
repeatedly
until some post-requisite condition
is satisfied.
Occasionally,
you might even want
to do both
for the same function.
To save you writing
explicit conditions
and loops
on each of those occasions,
`tryer` implements
a predicate-based approach
that hides the cruft
behind a simple,
functional interface.
Additionally,
it allows you to easily specify
retry intervals
and limits,
so that your code
doesn't hog the CPU.
It also supports
exponential backoff
of retry intervals,
which can be useful
when handling
indefinite error states
such as network failure.
## What size is it?
5.6 kb unminified with comments, 1.1 kb minified, 0.5 kb minified + gzipped.
## How do I install it?
Via npm:
```
npm i tryer --save
```
Or if you just want the git repo:
```
git clone git@gitlab.com:philbooth/tryer.git
```
## How do I use it?
### Loading the library
If you are running in
Node.js
or another CommonJS-style
environment,
you can `require`
tryer like so:
```javascript
const tryer = require('tryer');
```
It also the supports
the AMD-style format
preferred by Require.js.
If you are
including `tryer`
with an HTML `<script>` tag,
or neither of the above environments
are detected,
it will be exported globally as `tryer`.
### Calling the exported function
`tryer` is a function
that can be invoked to
call other functions
conditionally and repeatedly,
without the need for
explicit `if` statements
or loops in your own code.
`tryer` takes one argument,
an options object
that supports
the following properties:
* `action`:
The function that you want to invoke.
If `action` returns a promise,
iterations will not end
until the promise is resolved or rejected.
Alternatively,
`action` may take a callback argument, `done`,
to signal that it is asynchronous.
In that case,
you are responsible
for calling `done`
when the action is finished.
If `action` is not set,
it defaults to an empty function.
* `when`:
A predicate
that tests the pre-condition
for invoking `action`.
Until `when` returns true
(or a truthy value),
`action` will not be called.
Defaults to
a function that immediately returns `true`.
* `until`:
A predicate
that tests the post-condition
for invoking `action`.
After `until` returns true
(or a truthy value),
`action` will no longer be called.
Defaults to
a function that immediately returns `true`.
* `fail`:
The error handler.
A function
that will be called
if `limit` falsey values
are returned by `when` or `until`.
Defaults to an empty function.
* `pass`:
Success handler.
A function
that will be called
after `until` has returned truthily.
Defaults to an empty function.
* `limit`:
Failure limit,
representing the maximum number
of falsey returns from `when` or `until`
that will be permitted
before invocation is deemed to have failed.
A negative number
indicates that the attempt
should never fail,
instead continuing
for as long as `when` and `until`
have returned truthy values.
Defaults to `-1`.
* `interval`:
The retry interval,
in milliseconds.
A negative number indicates
that each subsequent retry
should wait for twice the interval
from the preceding iteration
(i.e. exponential backoff).
The default value is `-1000`,
signifying that
the initial retry interval
should be one second
and that each subsequent attempt
should wait for double the length
of the previous interval.
### Examples
```javascript
// Attempt to insert a database record, waiting until `db.isConnected`
// before doing so. The retry interval is 1 second on each iteration
// and the call will fail after 10 attempts.
tryer({
action: () => db.insert(record),
when: () => db.isConnected,
interval: 1000,
limit: 10,
fail () {
log.error('No database connection, terminating.');
process.exit(1);
}
});
```
```javascript
// Attempt to send an email message, optionally retrying with
// exponential backoff starting at 1 second. Continue to make
// attempts indefinitely until the call succeeds.
let sent = false;
tryer({
action (done) {
smtp.send(email, error => {
if (! error) {
sent = true;
}
done();
});
},
until: () => sent,
interval: -1000,
limit: -1
});
```
```javascript
// Poll a device at 30-second intervals, continuing indefinitely.
tryer({
action: () => device.poll().then(response => handle(response)),
interval: 30000,
limit: -1
});
```
## How do I set up the dev environment?
The dev environment relies on
[Chai],
[JSHint],
[Mocha],
[please-release-me],
[spooks.js] and
[UglifyJS].
The source code is in
`src/tryer.js`
and the unit tests are in
`test/unit.js`.
To install the dependencies:
```
npm i
```
To run the tests:
```
npm t
```
To lint the code:
```
npm run lint
```
To regenerate the minified lib:
```
npm run minify
```
## What license is it released under?
[MIT](COPYING)
[chai]: http://chaijs.com/
[jshint]: http://jshint.com/
[mocha]: http://mochajs.org/
[please-release-me]: https://gitlab.com/philbooth/please-release-me
[spooks.js]: https://gitlab.com/philbooth/spooks.js
[uglifyjs]: http://lisperator.net/uglifyjs/
[license]: COPYING

16
web/node_modules/tryer/bower.json generated vendored Normal file
View file

@ -0,0 +1,16 @@
{
"name": "tryer",
"version": "1.0.1",
"main": "lib/tryer.min.js",
"ignore": [
"AUTHORS",
"component.json",
"config",
"node_modules",
"package.json",
"README.md",
"src",
"test"
]
}

24
web/node_modules/tryer/component.json generated vendored Normal file
View file

@ -0,0 +1,24 @@
{
"name": "tryer",
"version": "1.0.1",
"description": "Because everyone loves a tryer! Conditional and repeated task invocation for node and browser.",
"repo": "philbooth/tryer",
"license": "MIT",
"main": "src/tryer.js",
"keywords": [
"repeat",
"retry",
"predicate",
"conditional",
"invocation",
"execution",
"loop",
"condition",
"termination",
"exponential",
"backoff"
],
"scripts": [
"src/tryer.js"
]
}

1
web/node_modules/tryer/lib/tryer.min.js generated vendored Normal file
View file

@ -0,0 +1 @@
!function(n){"use strict";function t(r){var n;function t(){i("when",t)&&e()}function i(n,t){return!!r[n]()||(r.count+=1,0<=(u=r).limit&&u.count>=u.limit?r.fail():(i=t,e=function(n){var t=n.interval;n.interval<0&&(n.interval*=2);return t}(r),setTimeout(i,Math.abs(e))),!1);var i,e,u}function e(){var n;if(0===r.action.length)return(n=r.action())&&f(n.then)?n.then(u,u):u();r.action(u)}function u(){i("until",e)&&r.pass()}r={count:0,when:o((n=(n=r)||{}).when),until:o(n.until),action:c(n.action),fail:c(n.fail),pass:c(n.pass),interval:a(n.interval,-1e3),limit:a(n.limit,-1)},t()}function o(n){return u(n,f,i)}function f(n){return"function"==typeof n}function i(){return!0}function c(n){return u(n,f,e)}function e(){}function u(n,t,i){return t(n)?n:i}function a(n,t){return u(n,r,t)}function r(n){return"number"==typeof n&&n==n}"function"==typeof define&&define.amd?define(function(){return t}):"undefined"!=typeof module&&null!==module?module.exports=t:n.tryer=t}(this);

40
web/node_modules/tryer/package.json generated vendored Normal file
View file

@ -0,0 +1,40 @@
{
"name": "tryer",
"version": "1.0.1",
"description": "Because everyone loves a tryer! Conditional and repeated task invocation for node and browser.",
"homepage": "https://gitlab.com/philbooth/tryer",
"bugs": "https://gitlab.com/philbooth/tryer/issues",
"license": "MIT",
"author": "Phil Booth <pmbooth@gmail.com> (https://philbooth.me/)",
"main": "./src/tryer",
"repository": {
"type": "git",
"url": "git+https://gitlab.com/philbooth/tryer.git"
},
"keywords": [
"repeat",
"retry",
"predicate",
"conditional",
"invocation",
"execution",
"loop",
"condition",
"termination",
"exponential",
"backoff"
],
"devDependencies": {
"chai": "4.1.x",
"jshint": "2.9.x",
"mocha": "5.2.x",
"please-release-me": "2.0.x",
"spooks": "2.0.x",
"uglify-js": "3.4.x"
},
"scripts": {
"lint": "jshint src/tryer.js test/unit.js",
"test": "mocha --ui tdd --reporter spec --colors test/unit.js",
"minify": "uglifyjs ./src/tryer.js --compress --mangle --output ./lib/tryer.min.js"
}
}

210
web/node_modules/tryer/src/tryer.js generated vendored Normal file
View file

@ -0,0 +1,210 @@
// Conditional and repeated task invocation for node and browser.
/*globals setTimeout, define, module */
(function (globals) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(function () {
return tryer;
});
} else if (typeof module !== 'undefined' && module !== null) {
module.exports = tryer;
} else {
globals.tryer = tryer;
}
// Public function `tryer`.
//
// Performs some action when pre-requisite conditions are met and/or until
// post-requisite conditions are satisfied.
//
// @option action {function} The function that you want to invoke. Defaults to `() => {}`.
// If `action` returns a promise, iterations will not end until
// the promise is resolved or rejected. Alternatively, `action`
// may take a callback argument, `done`, to signal that it is
// asynchronous. In that case, you are responsible for calling
// `done` when the action is finished.
//
// @option when {function} Predicate used to test pre-conditions. Should return `false`
// to postpone `action` or `true` to perform it. Defaults to
// `() => true`.
//
// @option until {function} Predicate used to test post-conditions. Should return `false`
// to retry `action` or `true` to terminate it. Defaults to
// `() => true`.
//
// @option fail {function} Callback to be invoked if `limit` tries are reached. Defaults
// to `() => {}`.
//
// @option pass {function} Callback to be invoked after `until` has returned truthily.
// Defaults to `() => {}`.
//
// @option interval {number} Retry interval in milliseconds. A negative number indicates
// that subsequent retries should wait for double the interval
// from the preceding iteration (exponential backoff). Defaults
// to -1000.
//
// @option limit {number} Maximum retry count, at which point the call fails and retries
// will cease. A negative number indicates that retries should
// continue indefinitely. Defaults to -1.
//
// @example
// tryer({
// when: () => db.isConnected,
// action: () => db.insert(user),
// fail () {
// log.error('No database connection, terminating.');
// process.exit(1);
// },
// interval: 1000,
// limit: 10
// });
//
// @example
// let sent = false;
// tryer({
// until: () => sent,
// action: done => {
// smtp.send(email, error => {
// if (! error) {
// sent = true;
// }
// done();
// });
// },
// pass: next,
// interval: -1000,
// limit: -1
// });
function tryer (options) {
options = normaliseOptions(options);
iterateWhen();
function iterateWhen () {
if (preRecur()) {
iterateUntil();
}
}
function preRecur () {
return conditionallyRecur('when', iterateWhen);
}
function conditionallyRecur (predicateKey, iterate) {
if (! options[predicateKey]()) {
incrementCount(options);
if (shouldFail(options)) {
options.fail();
} else {
recur(iterate, postIncrementInterval(options));
}
return false;
}
return true;
}
function iterateUntil () {
var result;
if (isActionSynchronous(options)) {
result = options.action();
if (result && isFunction(result.then)) {
return result.then(postRecur, postRecur);
}
return postRecur();
}
options.action(postRecur);
}
function postRecur () {
if (conditionallyRecur('until', iterateUntil)) {
options.pass();
}
}
}
function normaliseOptions (options) {
options = options || {};
return {
count: 0,
when: normalisePredicate(options.when),
until: normalisePredicate(options.until),
action: normaliseFunction(options.action),
fail: normaliseFunction(options.fail),
pass: normaliseFunction(options.pass),
interval: normaliseNumber(options.interval, -1000),
limit: normaliseNumber(options.limit, -1)
};
}
function normalisePredicate (fn) {
return normalise(fn, isFunction, yes);
}
function isFunction (fn) {
return typeof fn === 'function';
}
function yes () {
return true;
}
function normaliseFunction (fn) {
return normalise(fn, isFunction, nop);
}
function nop () {
}
function normalise (thing, predicate, defaultValue) {
if (predicate(thing)) {
return thing;
}
return defaultValue;
}
function normaliseNumber (number, defaultNumber) {
return normalise(number, isNumber, defaultNumber);
}
function isNumber (number) {
return typeof number === 'number' && number === number;
}
function isActionSynchronous (options) {
return options.action.length === 0;
}
function incrementCount (options) {
options.count += 1;
}
function shouldFail (options) {
return options.limit >= 0 && options.count >= options.limit;
}
function postIncrementInterval (options) {
var currentInterval = options.interval;
if (options.interval < 0) {
options.interval *= 2;
}
return currentInterval;
}
function recur (fn, interval) {
setTimeout(fn, Math.abs(interval));
}
}(this));

24
web/node_modules/tryer/test/index.html generated vendored Normal file
View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>tryer unit tests</title>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/spooks/src/spooks.min.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script>
mocha.setup('tdd');
</script>
<script src="../lib/tryer.min.js"></script>
<script src="unit.js"></script>
<script>
mocha.checkLeaks();
mocha.run();
</script>
</body>
</html>

513
web/node_modules/tryer/test/unit.js generated vendored Normal file
View file

@ -0,0 +1,513 @@
/*globals chai, spooks, require, tryer, suite, setup, test, setTimeout, Promise */
(function (require, spooks) {
'use strict';
var assert, modulePath;
if (require === undefined) {
assert = chai.assert;
require = function () { return tryer; };
} else {
assert = require('chai').assert;
spooks = require('spooks');
modulePath = '../src/tryer';
}
suite('tryer:', function () {
test('require does not throw', function () {
assert.doesNotThrow(function () {
require(modulePath);
});
});
suite('require:', function () {
var tryer;
setup(function () {
tryer = require(modulePath);
});
test('function is exported', function () {
assert.isFunction(tryer);
});
test('tryer does not throw when options is missing', function () {
assert.doesNotThrow(function () {
tryer();
});
});
test('tryer does not throw when options is object', function () {
assert.doesNotThrow(function () {
tryer({});
});
});
suite('when passing immediately:', function () {
var log, predicate, action, fail, pass;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ true ] });
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
pass = spooks.fn({ name: 'pass', log: log, callback: done });
tryer({
when: predicate,
action: action,
fail: fail,
pass: pass,
interval: 0,
limit: 3
});
});
test('predicate was called once', function () {
assert.strictEqual(log.counts.predicate, 1);
});
test('action was called once', function () {
assert.strictEqual(log.counts.action, 1);
});
test('fail was not called', function () {
assert.strictEqual(log.counts.fail, 0);
});
test('pass was called once', function () {
assert.strictEqual(log.counts.pass, 1);
});
});
suite('when failing three times:', function () {
var log, predicate, action, fail, pass;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ false ] });
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
pass = spooks.fn({ name: 'pass', log: log, callback: done });
tryer({
when: predicate,
action: action,
fail: fail,
pass: pass,
interval: 0,
limit: 3
});
});
test('predicate was called three times', function () {
assert.strictEqual(log.counts.predicate, 3);
});
test('action was not called', function () {
assert.strictEqual(log.counts.action, 0);
});
test('fail was called once', function () {
assert.strictEqual(log.counts.fail, 1);
});
test('pass was not called', function () {
assert.strictEqual(log.counts.pass, 0);
});
});
suite('when failing five times:', function () {
var log, predicate, action, fail;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ false ] });
action = spooks.fn({ name: 'action', log: log, callback: done });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
tryer({ when: predicate, action: action, fail: fail, interval: 0, limit: 5 });
});
test('predicate was called five times', function () {
assert.strictEqual(log.counts.predicate, 5);
});
test('action was not called', function () {
assert.strictEqual(log.counts.action, 0);
});
test('fail was called once', function () {
assert.strictEqual(log.counts.fail, 1);
});
});
suite('when failing exponentially:', function () {
var log, timestamps, predicate, action, fail;
setup(function (done) {
log = {};
timestamps = [];
predicate = spooks.fn({
name: 'predicate',
log: log,
results: [ false ],
callback: function () {
timestamps.push(Date.now());
}
});
action = spooks.fn({ name: 'action', log: log, callback: done });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
timestamps.push(Date.now());
tryer({ when: predicate, action: action, fail: fail, interval: -10, limit: 4 });
});
test('five timestamps were recorded', function () {
assert.lengthOf(timestamps, 5);
});
test('first interval is immediate', function () {
assert.isTrue(timestamps[1] < timestamps[0] + 5);
});
test('second interval is about 10 ms', function () {
assert.isTrue(timestamps[2] >= timestamps[1] + 10);
assert.isTrue(timestamps[2] < timestamps[1] + 15);
});
test('third interval is about 20 ms', function () {
assert.isTrue(timestamps[3] >= timestamps[2] + 20);
assert.isTrue(timestamps[3] < timestamps[2] + 30);
});
test('fourth interval is about 40 ms', function () {
assert.isTrue(timestamps[4] >= timestamps[3] + 40);
assert.isTrue(timestamps[4] < timestamps[3] + 50);
});
});
suite('until passing immediately:', function () {
var log, predicate, action, fail, pass;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ true ] });
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
pass = spooks.fn({ name: 'pass', log: log, callback: done });
tryer({
until: predicate,
action: action,
fail: fail,
pass: pass,
interval: 0,
limit: 3
});
});
test('predicate was called once', function () {
assert.strictEqual(log.counts.predicate, 1);
});
test('action was called once', function () {
assert.strictEqual(log.counts.action, 1);
});
test('fail was not called', function () {
assert.strictEqual(log.counts.fail, 0);
});
test('pass was called once', function () {
assert.strictEqual(log.counts.pass, 1);
});
test('pass was called once', function () {
assert.strictEqual(log.counts.pass, 1);
});
});
suite('until failing three times:', function () {
var log, predicate, action, fail, pass;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ false ] });
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
pass = spooks.fn({ name: 'pass', log: log, callback: done });
tryer({
until: predicate,
action: action,
fail: fail,
pass: pass,
interval: 0,
limit: 3
});
});
test('predicate was called three times', function () {
assert.strictEqual(log.counts.predicate, 3);
});
test('action was called three times', function () {
assert.strictEqual(log.counts.action, 3);
});
test('fail was called once', function () {
assert.strictEqual(log.counts.fail, 1);
});
test('pass was not called', function () {
assert.strictEqual(log.counts.pass, 0);
});
});
suite('until failing five times:', function () {
var log, predicate, action, fail;
setup(function (done) {
log = {};
predicate = spooks.fn({ name: 'predicate', log: log, results: [ false ] });
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
tryer({ until: predicate, action: action, fail: fail, interval: 0, limit: 5 });
});
test('predicate was called five times', function () {
assert.strictEqual(log.counts.predicate, 5);
});
test('action was called five times', function () {
assert.strictEqual(log.counts.action, 5);
});
test('fail was called once', function () {
assert.strictEqual(log.counts.fail, 1);
});
});
suite('until failing exponentially:', function () {
var log, timestamps, predicate, action, fail;
setup(function (done) {
log = {};
timestamps = [];
predicate = spooks.fn({
name: 'predicate',
log: log,
results: [ false ],
callback: function () {
timestamps.push(Date.now());
}
});
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
timestamps.push(Date.now());
tryer({ until: predicate, action: action, fail: fail, interval: -10, limit: 4 });
});
test('five timestamps were recorded', function () {
assert.lengthOf(timestamps, 5);
});
test('first interval is immediate', function () {
assert.isTrue(timestamps[1] < timestamps[0] + 5);
});
test('second interval is about 10 ms', function () {
assert.isTrue(timestamps[2] >= timestamps[1] + 10);
assert.isTrue(timestamps[2] < timestamps[1] + 20);
});
test('third interval is about 20 ms', function () {
assert.isTrue(timestamps[3] >= timestamps[2] + 20);
assert.isTrue(timestamps[3] < timestamps[2] + 30);
});
test('fourth interval is about 40 ms', function () {
assert.isTrue(timestamps[4] >= timestamps[3] + 40);
assert.isTrue(timestamps[4] < timestamps[3] + 50);
});
});
suite('when failing once then passing and until failing twice then passing', function () {
var log, predicateLoggers, predicates, action, fail, pass;
setup(function (done) {
log = {};
predicateLoggers = {
when: spooks.fn({ name: 'when', log: log }),
until: spooks.fn({ name: 'until', log: log })
};
predicates = {
when: function () {
predicateLoggers.when.apply(this, arguments);
if (log.counts.when === 1) {
return false;
}
return true;
},
until: function () {
predicateLoggers.until.apply(this, arguments);
if (log.counts.until < 3) {
return false;
}
return true;
}
};
action = spooks.fn({ name: 'action', log: log });
fail = spooks.fn({ name: 'fail', log: log, callback: done });
pass = spooks.fn({ name: 'pass', log: log, callback: done });
tryer({
when: predicates.when,
until: predicates.until,
action: action,
fail: fail,
pass: pass,
interval: 0,
limit: 4
});
});
test('when was called twice', function () {
assert.strictEqual(log.counts.when, 2);
});
test('action was called three times', function () {
assert.strictEqual(log.counts.action, 3);
});
test('until was called three times', function () {
assert.strictEqual(log.counts.until, 3);
});
test('fail was not called', function () {
assert.strictEqual(log.counts.fail, 0);
});
test('pass was called once', function () {
assert.strictEqual(log.counts.pass, 1);
});
});
suite('asynchronous action:', function () {
var log, timestamps, predicate, action;
setup(function (done) {
log = {};
timestamps = [];
predicate = function () {
timestamps.push(Date.now());
return false;
};
action = function (tryerDone) {
setTimeout(tryerDone, 10);
};
timestamps.push(Date.now());
tryer({ until: predicate, action: action, fail: done, interval: 0, limit: 3 });
});
test('four timestamps were recorded', function () {
assert.lengthOf(timestamps, 4);
});
test('first interval is about 10 ms', function () {
assert.isTrue(timestamps[1] >= timestamps[0] + 10);
assert.isTrue(timestamps[1] < timestamps[0] + 20);
});
test('second interval is about 10 ms', function () {
assert.isTrue(timestamps[2] >= timestamps[1] + 10);
assert.isTrue(timestamps[2] < timestamps[1] + 20);
});
test('third interval is about 10 ms', function () {
assert.isTrue(timestamps[3] >= timestamps[2] + 10);
assert.isTrue(timestamps[3] < timestamps[2] + 20);
});
});
if (typeof Promise === 'function') {
suite('promise-resolving action:', function () {
var log, timestamps, predicate, action;
setup(function (done) {
log = {};
timestamps = [];
predicate = function () {
timestamps.push(Date.now());
return false;
};
action = function () {
return new Promise(function (resolve) {
setTimeout(resolve, 10);
});
};
timestamps.push(Date.now());
tryer({ until: predicate, action: action, fail: done, interval: 0, limit: 3 });
});
test('four timestamps were recorded', function () {
assert.lengthOf(timestamps, 4);
});
test('first interval is about 10 ms', function () {
assert.isTrue(timestamps[1] >= timestamps[0] + 10);
assert.isTrue(timestamps[1] < timestamps[0] + 20);
});
test('second interval is about 10 ms', function () {
assert.isTrue(timestamps[2] >= timestamps[1] + 10);
assert.isTrue(timestamps[2] < timestamps[1] + 20);
});
test('third interval is about 10 ms', function () {
assert.isTrue(timestamps[3] >= timestamps[2] + 10);
assert.isTrue(timestamps[3] < timestamps[2] + 20);
});
});
suite('promise-rejecting action:', function () {
var log, timestamps, predicate, action;
setup(function (done) {
log = {};
timestamps = [];
predicate = function () {
timestamps.push(Date.now());
return false;
};
action = function () {
return new Promise(function (_, reject) {
setTimeout(reject, 10);
});
};
timestamps.push(Date.now());
tryer({ until: predicate, action: action, fail: done, interval: 0, limit: 3 });
});
test('four timestamps were recorded', function () {
assert.lengthOf(timestamps, 4);
});
test('first interval is about 10 ms', function () {
assert.isTrue(timestamps[1] >= timestamps[0] + 10);
assert.isTrue(timestamps[1] < timestamps[0] + 20);
});
test('second interval is about 10 ms', function () {
assert.isTrue(timestamps[2] >= timestamps[1] + 10);
assert.isTrue(timestamps[2] < timestamps[1] + 20);
});
test('third interval is about 10 ms', function () {
assert.isTrue(timestamps[3] >= timestamps[2] + 10);
assert.isTrue(timestamps[3] < timestamps[2] + 20);
});
});
}
});
});
}(
typeof require === 'function' ? require : undefined,
typeof spooks === 'object' ? spooks : undefined)
);