Skip to content

Commit

Permalink
feat(expect-puppeteer): add visibility option to toMatchElement (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoyuhen authored and gregberge committed Mar 13, 2019
1 parent 6e483e6 commit 46d8ec1
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
lib/
yarn-error.log
1 change: 1 addition & 0 deletions packages/expect-puppeteer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ Expect an element be present in the page or element.
- `mutation` - to execute `pageFunction` on every DOM mutation.
- `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
- `text` <[string]|[RegExp]> A text or a RegExp to match in element `textContent`.
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.

```js
// Select a row containing a text
Expand Down
31 changes: 25 additions & 6 deletions packages/expect-puppeteer/src/matchers/toMatchElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,44 @@ import { defaultOptions } from '../options'
async function toMatchElement(
instance,
selector,
{ text: searchExpr, ...options } = {},
{ text: searchExpr, visible = false, ...options } = {},
) {
options = defaultOptions(options)

const { page, handle } = await getContext(instance, () => document)

const { text, regexp } = expandSearchExpr(searchExpr)

const getElement = (handle, selector, text, regexp) => {
const elements = handle.querySelectorAll(selector)
const getElement = (handle, selector, text, regexp, visible) => {
function hasVisibleBoundingBox(element) {
const rect = element.getBoundingClientRect()
return !!(rect.top || rect.bottom || rect.width || rect.height)
}

const isVisible = element => {
if (visible) {
const style = window.getComputedStyle(element)
return (
style &&
style.visibility !== 'hidden' &&
hasVisibleBoundingBox(element)
)
}

return true
}

const elements = [...handle.querySelectorAll(selector)].filter(isVisible)
if (regexp !== null) {
const [, pattern, flags] = regexp.match(/\/(.*)\/(.*)?/)
return [...elements].find(({ textContent }) =>
return elements.find(({ textContent }) =>
textContent
.replace(/\s+/g, ' ')
.trim()
.match(new RegExp(pattern, flags)),
)
}
if (text !== null) {
return [...elements].find(({ textContent }) =>
return elements.find(({ textContent }) =>
textContent
.replace(/\s+/g, ' ')
.trim()
Expand All @@ -42,6 +59,7 @@ async function toMatchElement(
selector,
text,
regexp,
visible,
)
} catch (error) {
throw enhanceError(
Expand All @@ -58,6 +76,7 @@ async function toMatchElement(
selector,
text,
regexp,
visible,
)
return jsHandle.asElement()
}
Expand Down
36 changes: 36 additions & 0 deletions packages/expect-puppeteer/src/matchers/toMatchElement.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,42 @@ describe('toMatchElement', () => {
expect(error.message).toMatch('waiting for function failed')
}
})

it('should match using visible options', async () => {
expect.assertions(11)

const normalElement = await expect(page).toMatchElement('.normal', {
visible: true,
})
const textContentProperty = await normalElement.getProperty('textContent')
const textContent = await textContentProperty.jsonValue()
expect(textContent).toBe('normal element')

try {
await expect(page).toMatchElement('.hidden', { visible: true })
} catch (error) {
expect(error.message).toMatch('Element .hidden not found')
expect(error.message).toMatch('waiting for function failed')
}

try {
await expect(page).toMatchElement('.displayed', { visible: true })
} catch (error) {
expect(error.message).toMatch('Element .displayed not found')
expect(error.message).toMatch('waiting for function failed')
}

try {
await expect(page).toMatchElement('.displayedWithClassname', {
visible: true,
})
} catch (error) {
expect(error.message).toMatch(
'Element .displayedWithClassname not found',
)
expect(error.message).toMatch('waiting for function failed')
}
})
})

describe('ElementHandle', () => {
Expand Down
9 changes: 9 additions & 0 deletions server/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
<meta charset="utf-8">
<title>Test App</title>
</head>
<style>
.displayedWithClassname {
display: none;
}
</style>

<body>
<header>This is home!</header>
Expand All @@ -25,6 +30,10 @@
<div id="in-the-main">
A div in the main
</div>
<div style="visibility: hidden;" class="hidden">hidden element</div>
<div style="display: none" class="displayed">displayed element</div>
<div class="displayedWithClassname">displayed element</div>
<div class="normal">normal element</div>
</main>
</body>

Expand Down

0 comments on commit 46d8ec1

Please sign in to comment.