Skip to content

Commit

Permalink
feat: refactor to support upcoming chai-wait-for approach
Browse files Browse the repository at this point in the history
BREAKING CHANGE: rename .to.be.there() -> .to.be.existing(), add .to.be.focused()
  • Loading branch information
jedwards1211 committed Dec 17, 2020
1 parent bb670f7 commit 404acde
Show file tree
Hide file tree
Showing 34 changed files with 1,163 additions and 1,398 deletions.
27 changes: 4 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ All assertions start with a [WebdriverIO-compatible selector](http://webdriver.i

Then, we can add our assertion to the chain.

- `await expect(selector).to.be.there()` - Test whether [at least one] matching element exists in the DOM
- `await expect(selector).to.be.existing()` - Test whether [at least one] matching element exists in the DOM
- `await expect(selector).to.be.displayed()` - Test whether or not [at least one] matching element is displayed
- `await expect(selector).to.be.focused()` - Test whether or not [at least one] matching element is focused
- `await expect(selector).to.have.text('string')` - Test the text value of the selected element(s) against supplied string. Succeeds if at least one element matches exactly
- `await expect(selector).to.have.text(/regex/)` - Test the text value of the selected element(s) against the supplied regular expression. Succeeds if at least one element matches
- `await expect(selector).to.have.count(number)` - Test how many elements exist in the DOM with the supplied selector
- `await expect(selector).to.have.value('x')` - Test that [at least one] selected element has the given value
- `await expect(selector).to.have.focus()` - Test that [at least one] selected element has focus
- `await expect(selector).to.have.focus()` - (alias for `to.be.focused()`)

You can also always add a `not` in there to negate the assertion:

Expand All @@ -54,31 +55,11 @@ await chai
.to.not.contain.text("I'm a kitty!")
```

## Default Wait Time

As an optional argument to the initializer, you can add an `options` object in this format:

```javascript
var options = { defaultWait: 500 } // 500ms
chai.use(chaiWebdriver(browser, options))
```

The `defaultWait` parameter will cause chai-webdriverio to wait the specified number of milliseconds
for a given selector to appear before failing (if it is not yet present on the page). You can use `immediately`
to skip this default wait time:

```javascript
await expect(selector).to.immediately.have.text('string') // fails immediately if element is not found
```

**Beware:** For `immediately` to work, your [implicit wait time in WebdriverIO](http://webdriver.io/guide/testrunner/timeouts.html#Session-Implicit-Wait-Timeout)
must be set to 0. The immediately flag has no way to skip WebdriverIO's implicit wait.

## Compatability

### WebdriverIO

Only intended to be compatible with Webdriver 5 right now.
Only intended to be compatible with Webdriver 5/6 right now.

### Node.js

Expand Down
12 changes: 12 additions & 0 deletions chains/immediately.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'

Object.defineProperty(exports, '__esModule', {
value: true,
})
exports.default = immediately

function immediately(client, chai, utils) {
chai.Assertion.addChainableMethod('immediately', function() {
utils.flag(this, 'immediately', true)
})
}
File renamed without changes.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"husky": "^1.1.4",
"istanbul": "^0.4.5",
"lint-staged": "^8.0.4",
"mocha": "^6.2.1",
"mocha": "^8.2.1",
"nyc": "^13.1.0",
"prettier": "^1.15.2",
"prettier-eslint": "^8.8.2",
Expand Down
26 changes: 26 additions & 0 deletions src/assertions/atLeastOne.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

const atLeastOne = customize => (client, chai, utils, options) =>
async function(expected) {
const selector = utils.flag(this, 'object')

const { predicate, errorMsg, errorMsgNegate, notFoundMessage } = customize(
selector,
expected
)

const elements = await client.$$(selector)
if (!elements.length) throw new chai.AssertionError(notFoundMessage)

const filteredList = (await Promise.all(elements.map(predicate))).filter(
Boolean
)

this.assert(filteredList.length > 0, errorMsg, errorMsgNegate)
}

export default atLeastOne
37 changes: 37 additions & 0 deletions src/assertions/booleanAssertion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

const booleanAssertion = ({ predicate, expectation, allowNone }) => (
client,
chai,
utils,
options
) =>
async function(expected) {
const selector = utils.flag(this, 'object')
const negate = utils.flag(this, 'negate')

const elements = await client.$$(selector)
if (!allowNone && !elements.length) {
throw new chai.AssertionError(
negate
? `Expected <${selector}> to not be ${expectation} but no matching elements were found`
: `Expected <${selector}> to be ${expectation} but no matching elements were found`
)
}

const filteredList = (await Promise.all(elements.map(predicate))).filter(
Boolean
)

this.assert(
filteredList.length > 0,
`Expected <${selector}> to be ${expectation} but it is not`,
`Expected <${selector}> to not be ${expectation} but it is`
)
}

export default booleanAssertion
68 changes: 8 additions & 60 deletions src/assertions/count.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,19 @@
* https://github.com/marcodejongh/chai-webdriverio
*/

import configWithDefaults from '../util/default-config'

async function hasCount(client, selector, count, countStore) {
const elements = await client.$$(selector)
countStore.count = elements.length
return elements.length === count
}

async function waitUntilCount(
client,
selector,
count,
defaultWait = 0,
reverse
) {
const countStore = {}

if (!reverse) {
try {
await client.waitUntil(
() => hasCount(client, selector, count, countStore),
defaultWait
)
} catch (error) {
throw new Error(
`Element with selector <${selector}> does not appear in the DOM ${count} times ` +
`within ${defaultWait} ms, but it shows up ${
countStore.count
} times instead.`
)
}
} else {
await client.waitUntil(
async () => !(await hasCount(client, selector, count, countStore)),
defaultWait,
`Element with selector <${selector}> still appears in the DOM ${count} times after ${defaultWait} ms`
)
}
}

export default function count(client, chai, utils, options) {
const config = configWithDefaults(options)
chai.Assertion.addMethod('count', async function(expected) {
const count = (client, chai, utils, options) =>
async function(expected) {
const selector = utils.flag(this, 'object')
const negate = utils.flag(this, 'negate')
const immediately = utils.flag(this, 'immediately')

if (!immediately) {
await waitUntilCount(
client,
selector,
expected,
config.defaultWait,
negate
)
}

const countStore = {}
const elements = await client.$$(selector)

this.assert(
await hasCount(client, selector, expected, countStore),
elements.length === expected,
`Expected <${selector}> to appear in the DOM ${expected} times, but it shows up ${
countStore.count
elements.length
} times instead.`,
`Expected <${selector}> not to appear in the DOM ${expected} times, but it does.`
)
})
}
}

export default count
36 changes: 6 additions & 30 deletions src/assertions/displayed.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,10 @@
* https://github.com/marcodejongh/chai-webdriverio
*/

import configWithDefaults from '../util/default-config'
import doesOneElementSatisfy from '../util/doesOneElementSatisfy'
import booleanAssertion from './booleanAssertion'

const isOneElementDisplayed = doesOneElementSatisfy(el => el.isDisplayed())

export default function displayed(client, chai, utils, options) {
const config = configWithDefaults(options)

chai.Assertion.addMethod('displayed', async function() {
const negate = utils.flag(this, 'negate')
const selector = utils.flag(this, 'object')
const immediately = utils.flag(this, 'immediately')

const errorMsg = `Expected <${selector}> to be displayed but it is not`
const errorMsgNegate = `Expected <${selector}> to not be displayed but it is`

if (!immediately) {
await client.waitUntil(
async () => (await isOneElementDisplayed(client, selector)) === !negate,
config.defaultWait,
negate ? errorMsgNegate : errorMsg
)
}

this.assert(
await isOneElementDisplayed(client, selector),
errorMsg,
errorMsgNegate
)
})
}
export default booleanAssertion({
predicate: el => el.isDisplayed(),
expectation: 'displayed',
allowNone: true,
})
36 changes: 6 additions & 30 deletions src/assertions/enabled.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,10 @@
* https://github.com/marcodejongh/chai-webdriverio
*/

import configWithDefaults from '../util/default-config'
import doesOneElementSatisfy from '../util/doesOneElementSatisfy'
import booleanAssertion from './booleanAssertion'

const isOneElementEnabled = doesOneElementSatisfy(el => el.isEnabled())

export default function enabled(client, chai, utils, options) {
const config = configWithDefaults(options)

chai.Assertion.addMethod('enabled', async function() {
const negate = utils.flag(this, 'negate')
const selector = utils.flag(this, 'object')
const immediately = utils.flag(this, 'immediately')

const errorMsg = `Expected <${selector}> to be enabled but it is not`
const errorMsgNegate = `Expected <${selector}> to not be enabled but it is`

if (!immediately) {
await client.waitUntil(
async () => (await isOneElementEnabled(client, selector)) === !negate,
config.defaultWait,
negate ? errorMsgNegate : errorMsg
)
}

this.assert(
await isOneElementEnabled(client, selector),
errorMsg,
errorMsgNegate
)
})
}
export default booleanAssertion({
predicate: el => el.isEnabled(),
expectation: 'enabled',
allowNone: false,
})
13 changes: 13 additions & 0 deletions src/assertions/existing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

import booleanAssertion from './booleanAssertion'

export default booleanAssertion({
predicate: el => el.isExisting(),
expectation: 'existing',
allowNone: true,
})
37 changes: 0 additions & 37 deletions src/assertions/focus.js

This file was deleted.

13 changes: 13 additions & 0 deletions src/assertions/focused.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

import booleanAssertion from './booleanAssertion'

export default booleanAssertion({
predicate: el => el.isFocused(),
expectation: 'focused',
allowNone: false,
})
Loading

0 comments on commit 404acde

Please sign in to comment.