-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0c1167c
commit 66b7427
Showing
7 changed files
with
442 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ | |
"sourceType": "module" | ||
}, | ||
"env": { | ||
"es6": true | ||
"es6": true, | ||
"commonjs": true, | ||
"shared-node-browser": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,52 @@ | ||
# es2015-library-skeleton | ||
# chai-wait-for | ||
|
||
[![CircleCI](https://circleci.com/gh/jedwards1211/es2015-library-skeleton.svg?style=svg)](https://circleci.com/gh/jedwards1211/es2015-library-skeleton) | ||
[![Coverage Status](https://codecov.io/gh/jedwards1211/es2015-library-skeleton/branch/master/graph/badge.svg)](https://codecov.io/gh/jedwards1211/es2015-library-skeleton) | ||
[![CircleCI](https://circleci.com/gh/jcoreio/chai-wait-for.svg?style=svg)](https://circleci.com/gh/jcoreio/chai-wait-for) | ||
[![Coverage Status](https://codecov.io/gh/jcoreio/chai-wait-for/branch/master/graph/badge.svg)](https://codecov.io/gh/jcoreio/chai-wait-for) | ||
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) | ||
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) | ||
[![npm version](https://badge.fury.io/js/es2015-library-skeleton.svg)](https://badge.fury.io/js/es2015-library-skeleton) | ||
[![npm version](https://badge.fury.io/js/chai-wait-for.svg)](https://badge.fury.io/js/chai-wait-for) | ||
|
||
This is my personal skeleton for creating an ES2015 library npm package. You are welcome to use it. | ||
poll an assertion until it succeeds. Provides an especially clean syntax for working with some chai plugins like `chai-fs`, `chai-webdriverio-async` etc: | ||
|
||
## Quick start | ||
```js | ||
await waitFor('#submittedMessage').to.have.text('Your changes have been saved!') | ||
``` | ||
|
||
# Usage | ||
|
||
```sh | ||
npx 0-60 clone https://github.com/jedwards1211/es2015-library-skeleton.git | ||
npm install --save-dev chai-wait-for | ||
``` | ||
|
||
## Tools used | ||
|
||
- babel 7 | ||
- mocha | ||
- chai | ||
- istanbul | ||
- nyc | ||
- eslint | ||
- flow | ||
- prettier | ||
- husky | ||
- semantic-release | ||
- renovate | ||
- Circle CI | ||
- Codecov.io | ||
```js | ||
// First, use the plugin | ||
const chai = require('chai') | ||
const chaiWaitFor = require('chai-wait-for') | ||
chai.use(chaiWaitFor) | ||
|
||
// Then create your `waitFor` with default options: | ||
const waitFor = chaiWaitFor.bindWaitFor({ | ||
// If no assertion attempt succeeds before this time elapses (in milliseconds), the waitFor will fail. | ||
timeout: 5000, | ||
// If an assertion attempt fails, it will retry after this amount of time (in milliseconds) | ||
retryInterval: 100, | ||
}) | ||
|
||
it('wait for something', async function () { | ||
this.timeout(10000) | ||
|
||
const myObj = { foo: 0 } | ||
|
||
setInterval(() => myObj.foo++, 1000) | ||
|
||
// Then use it just like you would expect(): | ||
await waitFor(myObj).to.have.property('foo').that.equals(3) | ||
|
||
// You can also use a getter function: | ||
await waitFor(() => myObj.foo).to.equal(4) | ||
|
||
// If you need to override the defaults: | ||
waitFor.timeout(1000)(myObj).to.have.property('foo').that.equals(3) | ||
waitFor.retryInterval(500)(myObj).to.have.property('foo').that.equals(3) | ||
}) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,93 @@ | ||
/* @flow */ | ||
const chai = require('chai') | ||
|
||
/* eslint-disable no-console, no-undef */ | ||
console.log('Hello world!') | ||
class WaitFor { | ||
constructor(options, buildAssertion) { | ||
this.options = options | ||
this.buildAssertion = buildAssertion | ||
} | ||
|
||
then(onResolve, onReject) { | ||
const { timeout, retryInterval } = this.options | ||
let numAttempts = 0 | ||
let startTime = new Date().getTime() | ||
let timeoutTime = startTime + timeout | ||
|
||
const poll = async () => { | ||
numAttempts++ | ||
const thisAttemptStartTime = new Date().getTime() | ||
try { | ||
await this.buildAssertion() | ||
} catch (error) { | ||
const delay = | ||
Math.min(timeoutTime, thisAttemptStartTime + retryInterval) - | ||
new Date().getTime() | ||
|
||
if (delay <= 0) { | ||
error.message += ` (timed out after ${timeout}ms, ${numAttempts} attempts)` | ||
throw error | ||
} | ||
|
||
await new Promise((resolve) => setTimeout(resolve, delay)) | ||
await poll() | ||
} | ||
} | ||
|
||
return poll().then(onResolve, onReject) | ||
} | ||
} | ||
|
||
function bindWaitFor(options) { | ||
const bound = (value, ...args) => | ||
new WaitFor(options, () => | ||
chai.expect(typeof value === 'function' ? value() : value, ...args) | ||
) | ||
bound.timeout = (timeout) => bindWaitFor({ ...options, timeout }) | ||
bound.retryInterval = (retryInterval) => | ||
bindWaitFor({ ...options, retryInterval }) | ||
return bound | ||
} | ||
|
||
module.exports = (chai, utils) => { | ||
const Assertion = chai.Assertion | ||
|
||
const propertyNames = Object.getOwnPropertyNames(Assertion.prototype) | ||
|
||
const propertyDescs = {} | ||
for (const name of propertyNames) { | ||
propertyDescs[name] = Object.getOwnPropertyDescriptor( | ||
Assertion.prototype, | ||
name | ||
) | ||
} | ||
|
||
// We need to be careful not to trigger any getters, thus `Object.getOwnPropertyDescriptor` usage. | ||
const methodNames = propertyNames.filter((name) => { | ||
return name !== 'assert' && typeof propertyDescs[name].value === 'function' | ||
}) | ||
|
||
methodNames.forEach((methodName) => { | ||
WaitFor.prototype[methodName] = function () { | ||
return new WaitFor(this.options, () => { | ||
const assertion = this.buildAssertion() | ||
return assertion[methodName].apply(assertion, arguments) | ||
}) | ||
} | ||
}) | ||
|
||
const getterNames = propertyNames.filter((name) => { | ||
return name !== '_obj' && typeof propertyDescs[name].get === 'function' | ||
}) | ||
|
||
getterNames.forEach((getterName) => { | ||
Object.defineProperty(WaitFor.prototype, getterName, { | ||
get() { | ||
return new WaitFor(this.options, () => { | ||
const assertion = this.buildAssertion() | ||
return assertion[getterName] | ||
}) | ||
}, | ||
}) | ||
}) | ||
} | ||
|
||
module.exports.bindWaitFor = bindWaitFor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
{ | ||
"env": { | ||
"node": true, | ||
"es6": true, | ||
"mocha": true | ||
} | ||
} |
Oops, something went wrong.