Skip to content

Commit

Permalink
feat: add attribute() assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
jedwards1211 committed Dec 18, 2020
1 parent a47781a commit 53e1447
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 1 deletion.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ Then, we can add our assertion to the chain.
- `await expect(selector).to.be.selected()` - Test whether or not [at least one] matching element is selected
- `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.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.attribute('attributeName')` - Test whether [at least one] matching element has the given attribute
- `await expect(selector).to.have.attribute('attributeName', 'string')` - Test the attribute value of the selected element(s) against supplied string. Succeeds if at least one element matches exactly
- `await expect(selector).to.have.attribute('attributeName', /regex/)` - Test the attribute value of the selected element(s) against supplied regular expression. Succeeds if at least one element matches exactly
- `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.value('string')` - Test that [at least one] selected element has a value matching the given string
- `await expect(selector).to.have.value(/regex/)` - Test that [at least one] selected element has a value matching the given regular expression
- `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 Down
80 changes: 80 additions & 0 deletions src/assertions/attribute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

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

if (arguments.length === 1) {
const elements = await client.$$(selector)
if (!elements.length) {
throw new chai.AssertionError(
negate
? `Expected element <${selector}> to not have attribute ${attribute}, but no matching elements were found`
: `Expected element <${selector}> to have attribute ${attribute}, but no matching elements were found`
)
}

const values = []
const filteredList = (await Promise.all(
elements.map(async element => {
const value = await element.getAttribute(attribute)
values.push(value)
return value !== undefined
})
)).filter(Boolean)

this.assert(
filteredList.length > 0,
`Expected element <${selector}> to have attribute ${attribute}, but only found: ${values
.map(t => JSON.stringify(t))
.join(', ')}`,
`Expected element <${selector}> to not have attribute ${attribute}, but found: ${values
.map(t => JSON.stringify(t))
.join(', ')}`
)
return
}

const expectedStr =
typeof expected === 'string' ? JSON.stringify(expected) : expected

const elements = await client.$$(selector)
if (!elements.length) {
throw new chai.AssertionError(
negate
? `Expected element <${selector}> to not have attribute ${attribute} with value ${expectedStr}, but no matching elements were found`
: `Expected element <${selector}> to have attribute ${attribute} with value ${expectedStr}, but no matching elements were found`
)
}

const values = []
const filteredList = (await Promise.all(
elements.map(async element => {
const value = await element.getAttribute(attribute)
values.push(value)
return (
value !== undefined &&
(expected instanceof RegExp
? value.match(expected)
: value === expected)
)
})
)).filter(Boolean)

this.assert(
filteredList.length > 0,
`Expected element <${selector}> to have attribute ${attribute} with value ${expectedStr}, but only found: ${values
.map(t => JSON.stringify(t))
.join(', ')}`,
`Expected element <${selector}> to not have attribute ${attribute} with value ${expectedStr}, but found: ${values
.map(t => JSON.stringify(t))
.join(', ')}`
)
}

export default attribute
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import attribute from './assertions/attribute'
import clickable from './assertions/clickable'
import count from './assertions/count'
import displayed from './assertions/displayed'
Expand All @@ -12,6 +13,7 @@ import value from './assertions/value'
export default function(client, options = {}) {
return function chaiWebdriverIO(chai, utils) {
const methodsToAdd = {
attribute,
clickable,
count,
displayed,
Expand Down
278 changes: 278 additions & 0 deletions test/assertions/attribute-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/**
* NOTICE
* This file has been modified from the source in
* https://github.com/marcodejongh/chai-webdriverio
*/

import chai, { expect } from 'chai'
import FakeClient from '../stubs/fake-client'
import FakeElement from '../stubs/fake-element'
import { describe, beforeEach, it } from 'mocha'
import chaiWebdriverio from '../../src'

const fakeClient = new FakeClient()
const fakeElement1 = new FakeElement()
const fakeElement2 = new FakeElement()

describe('attribute', () => {
beforeEach(() => {
fakeClient.__resetStubs__()
fakeElement1.__resetStubs__()
fakeElement2.__resetStubs__()

chai.use(chaiWebdriverio(fakeClient))
})

describe(`When element doesn't exist`, function() {
beforeEach(() => {
fakeClient.$$.withArgs('.some-selector').resolves([])
})

describe('When not negated', function() {
it(`should reject`, async function() {
await expect('.some-selector')
.to.have.attribute('foo')
.to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo, but no matching elements were found'
)
await expect('.some-selector')
.to.have.attribute('foo', 'bar')
.to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo with value "bar", but no matching elements were found'
)
})
})
describe('When negated', function() {
it(`should reject`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo, but no matching elements were found'
)
await expect(
expect('.some-selector')
.to.not.have.attribute('foo', 'bar')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo with value "bar", but no matching elements were found'
)
})
})
})

describe('When element exists', () => {
let elementAttribute = 'Never gonna give you up'

beforeEach(() => {
fakeElement1.getAttribute.withArgs('foo').resolves(elementAttribute)
fakeElement1.getAttribute.withArgs('bar').resolves(undefined)
fakeClient.$$.withArgs('.some-selector').resolves([fakeElement1])
})

describe(`When not negated`, function() {
it(`should resolve when attribute is present`, async function() {
await expect('.some-selector').to.have.attribute('foo')
})
it(`should resolve when attribute equals expectation`, async function() {
await expect('.some-selector').to.have.attribute(
'foo',
elementAttribute
)
})
it(`should resolve when attribute matches expectation`, async function() {
await expect('.some-selector').to.have.attribute('foo', /give you up/)
})
it(`should reject when attribute is missing`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('bar')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute bar, but only found: '
)
await expect(
expect('.some-selector')
.to.have.attribute('bar', 'baz')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute bar with value "baz", but only found: '
)
})
it(`should reject when attribute doesn't equal expectation`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('foo', 'blah')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo with value "blah", but only found: "Never gonna give you up"'
)
})
it(`should reject when attribute doesn't match expectation`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('foo', /^gonna/)
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo with value /^gonna/, but only found: "Never gonna give you up"'
)
})
})

describe(`When negated`, function() {
it(`should resolve when attribute is missing`, async function() {
await expect('.some-selector').to.not.have.attribute('bar')
await expect('.some-selector').to.not.have.attribute('bar', 'blargh')
})
it(`should resolve when attribute doesn't equal expectation`, async function() {
await expect('.some-selector').to.not.have.attribute('foo', 'blargh')
})
it(`should resolve when attribute doesn't match expectation`, async function() {
await expect('.some-selector').to.not.have.attribute('foo', /foog/)
})
it(`should reject when attribute is not missing`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo, but found: "Never gonna give you up"'
)
})
it(`should reject when attribute equals expectation`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo', elementAttribute)
.then(null)
).to.be.rejectedWith(
`Expected element <.some-selector> to not have attribute foo with value "Never gonna give you up", but found: "Never gonna give you up"`
)
})
it(`should reject when attribute matches expectation`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo', /gonna/)
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo with value /gonna/, but found: "Never gonna give you up"'
)
})
})
})
describe(`When multiple elements exist`, function() {
let elementAttribute1 = 'Never gonna give you up'
let elementAttribute2 = 'Never gonna let you down'

beforeEach(() => {
fakeElement1.getAttribute.resolves(elementAttribute1)
fakeElement2.getAttribute.resolves(elementAttribute2)
fakeElement1.getAttribute.withArgs('foo').resolves(elementAttribute1)
fakeElement1.getAttribute.withArgs('bar').resolves(undefined)
fakeElement2.getAttribute.withArgs('foo').resolves(elementAttribute2)
fakeElement2.getAttribute.withArgs('bar').resolves(undefined)
fakeClient.$$.withArgs('.some-selector').resolves([
fakeElement1,
fakeElement2,
])
})

describe(`When not negated`, function() {
it(`should resolve when attribute is present`, async function() {
await expect('.some-selector').to.have.attribute('foo')
})
it(`should resolve when attribute equals expectation`, async function() {
await expect('.some-selector').to.have.attribute(
'foo',
elementAttribute1
)
await expect('.some-selector').to.have.attribute(
'foo',
elementAttribute2
)
})
it(`should resolve when attribute matches expectation`, async function() {
await expect('.some-selector').to.have.attribute('foo', /Never gonna/)
await expect('.some-selector').to.have.attribute('foo', /give you up/)
await expect('.some-selector').to.have.attribute('foo', /let you down/)
})
it(`should reject when attribute is missing`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('bar')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute bar, but only found: '
)
await expect(
expect('.some-selector')
.to.have.attribute('bar', 'blargh')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute bar with value "blargh", but only found: '
)
})
it(`should reject when attribute doesn't equal expectation`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('foo', 'blah')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo with value "blah", but only found: "Never gonna give you up", "Never gonna let you down"'
)
})
it(`should reject when attribute doesn't match expectation`, async function() {
await expect(
expect('.some-selector')
.to.have.attribute('foo', /^gonna/)
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to have attribute foo with value /^gonna/, but only found: "Never gonna give you up", "Never gonna let you down"'
)
})
})
describe(`When negated`, function() {
it(`should resolve when attribute is missing`, async function() {
await expect('.some-selector').to.not.have.attribute('bar')
await expect('.some-selector').to.not.have.attribute('bar', 'blargh')
})
it(`should resolve when attribute doesn't equal expectation`, async function() {
await expect('.some-selector').to.not.have.attribute('foo', 'blargh')
})
it(`should resolve when attribute doesn't match expectation`, async function() {
await expect('.some-selector').to.not.have.attribute('foo', /foog/)
})
it(`should reject when attribute is not missing`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo')
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo, but found: "Never gonna give you up", "Never gonna let you down"'
)
})
it(`should reject when attribute equals expectation`, async function() {
for (const attribute of [elementAttribute1, elementAttribute2]) {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo', attribute)
.then(null)
).to.be.rejectedWith(
`Expected element <.some-selector> to not have attribute foo with value ${JSON.stringify(
attribute
)}, but found: "Never gonna give you up", "Never gonna let you down"`
)
}
})
it(`should reject when attribute matches expectation`, async function() {
await expect(
expect('.some-selector')
.to.not.have.attribute('foo', /gonna/)
.then(null)
).to.be.rejectedWith(
'Expected element <.some-selector> to not have attribute foo with value /gonna/, but found: "Never gonna give you up", "Never gonna let you down"'
)
})
})
})
})

0 comments on commit 53e1447

Please sign in to comment.