Skip to content

Commit

Permalink
webdriverio: extend wait command prefixes (#3548)
Browse files Browse the repository at this point in the history
## Proposed changes

Avoid waiting for element in commands with prefixes: waitUntil, waitFor, waitToBe, isExisting, isDisplayed.

Useful to use with different assertion libraries like:
`assert.strictEqual($('foo').toBeDisplayed(), true)` or `assert.strictEqual($('foo').isExistingWithin(5000), true)`, etc

## Types of changes

- [ ] Bugfix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Checklist

- [x] I have read the [CONTRIBUTING](https://github.com/webdriverio/webdriverio/blob/master/CONTRIBUTING.md) doc
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] I have added necessary documentation (if appropriate)

## Further comments

implements #3545

### Reviewers: @webdriverio/technical-committee
  • Loading branch information
mgrybyk authored and christian-bromann committed Feb 20, 2019
1 parent 422387e commit 9e03559
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 2 deletions.
15 changes: 14 additions & 1 deletion docs/CustomCommands.md
Expand Up @@ -16,7 +16,7 @@ browser.addCommand("getUrlAndTitle", function (customVar) {
});
```

Additionally, you can extend the element instance with your own set of commands, by passing 'true' as the final argument.
Additionally, you can extend the element instance with your own set of commands, by passing 'true' as the final argument. By default element is expected to be existing in `waitforTimeout` milliseconds otherwise exception will be thrown.

```js
browser.addCommand("waitAndClick", function () {
Expand All @@ -39,6 +39,19 @@ it('should use my custom command', () => {
});
```

If there is a need to control element existance in custom commands it is possible either to add command to browser and pass selector or add command to element with name that starts with one of: waitUntil, waitFor, isExisting, isDisplayed.

```js
browser.addCommand("isDisplayedWithin", function (timeout) {
try {
this.waitForDisplayed(timeout)
return true
} catch (err) {
return false
}
}, true);
```

__Note:__ if you register a custom command to the browser scope the command won't be accessible for elements. Likewise, if you register a command to the element scope, it won't be accessible at the browser scope:

```js
Expand Down
2 changes: 1 addition & 1 deletion packages/webdriverio/src/middlewares.js
Expand Up @@ -18,7 +18,7 @@ export const elementErrorHandler = (fn) => (commandName, commandFn) => {
* - elementId couldn't be fetched in the first place
* - command is not explicit wait command for existance or displayedness
*/
if (!this.elementId && !commandName.match(/(wait(Until|ForDisplayed|ForExist|ForEnabled)|isExisting|isDisplayed)/)) {
if (!this.elementId && !commandName.match(/(waitUntil|waitFor|isExisting|isDisplayed)/)) {
log.debug(
`command ${commandName} was called on an element ("${this.selector}") ` +
'that wasn\'t found, waiting for it...'
Expand Down
65 changes: 65 additions & 0 deletions packages/webdriverio/tests/middleware.test.js
Expand Up @@ -2,10 +2,22 @@ import logger from '@wdio/logger'
import { remote } from '../src'
import request from 'request'

jest.mock('../src/commands/element/waitUntil', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => { return true })
}))
jest.mock('../src/commands/element/waitForDisplayed', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => { return true })
}))
jest.mock('../src/commands/element/waitForExist', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => { return true })
}))
jest.mock('../src/commands/element/waitForEnabled', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => { return true })
}))

const waitForExist = require('../src/commands/element/waitForExist')

Expand All @@ -27,6 +39,7 @@ describe('middleware', () => {

afterEach(() => {
warn.mockClear()
waitForExist.default.mockClear()
})

it('should throw an error if the element is never found', async () => {
Expand Down Expand Up @@ -64,4 +77,56 @@ describe('middleware', () => {
expect(warn.mock.calls).toHaveLength(1)
expect(warn.mock.calls).toEqual([['Request encountered a stale element - terminating request']])
})

describe('should NOT wait on element if', () => {
// wdio default waitForExist command
it('elem EXISTS and command = waitForExist', async () => {
const elem = await browser.$('#exists')
await elem.waitForExist()
expect(waitForExist.default.mock.calls).toHaveLength(1)
})

const commands = [
// wdio default commands
'waitUntil',
'waitForDisplayed',
'waitForEnabled',

// custom commands
'waitUntilFoo',
'waitForFoo',
'isExistingFoo',
'isDisplayedFoo']

commands.forEach(commandName => {
it(`elem NOT_FOUND and command = ${commandName}`, async () => {
browser.addCommand(commandName, () => {}, true)
const elem = await browser.$('#nonexisting')
await elem[commandName]()
expect(waitForExist.default.mock.calls).toHaveLength(0)
})
})

it('elem EXISTS and command = foo', async () => {
browser.addCommand('foo', () => {}, true)
const elem = await browser.$('#exists')
await elem.foo()
expect(waitForExist.default.mock.calls).toHaveLength(0)
})

it('elem EXISTS and command = isExisting', async () => {
const elem = await browser.$('#exists')
await elem.isExisting()
expect(waitForExist.default.mock.calls).toHaveLength(0)
})
})

describe('should wait on element if', () => {
it('elem NOT_FOUND and command = foo', async () => {
browser.addCommand('foo', () => {}, true)
const elem = await browser.$('#nonexisting')
await elem.foo()
expect(waitForExist.default.mock.calls).toHaveLength(1)
})
})
})

0 comments on commit 9e03559

Please sign in to comment.