Skip to content

Commit

Permalink
fix: Support unenclosed inner text for details elements in to be visi…
Browse files Browse the repository at this point in the history
…ble (#396)

* fix: Support unenclosed innerText for details elements in toBeVisible
* docs: Update documentation for toBeVisible with details element examples
* Restructure tests to have a maximum depth of 5 describes
* fix: Support unenclosed innerText for details elements in toBeVisible
* docs: Update documentation for toBeVisible with details element examples
* Restructure tests to have a maximum depth of 5 describes

Co-authored-by: Ben Chidgey <feedmypixel@users.noreply.github.com>
  • Loading branch information
kschow and feedmypixel committed Apr 5, 2022
1 parent 6988a67 commit af18453
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 13 deletions.
19 changes: 12 additions & 7 deletions README.md
Expand Up @@ -49,7 +49,6 @@ clear to read and to maintain.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Installation](#installation)
- [Usage](#usage)
- [With TypeScript](#with-typescript)
Expand Down Expand Up @@ -424,6 +423,14 @@ An element is visible if **all** the following conditions are met:
</div>
<div data-testid="visible">Visible Example</div>
<div data-testid="hidden-attribute" hidden>Hidden Attribute Example</div>
<details>
<summary>Title of hidden text</summary>
Hidden Details Example
</details>
<details open>
<summary>Title of visible text</summary>
<div>Visible Details Example</div>
</details>
```

```javascript
Expand All @@ -433,6 +440,8 @@ expect(getByText('Display None Example')).not.toBeVisible()
expect(getByText('Hidden Parent Example')).not.toBeVisible()
expect(getByText('Visible Example')).toBeVisible()
expect(getByText('Hidden Attribute Example')).not.toBeVisible()
expect(getByText('Hidden Details Example')).not.toBeVisible()
expect(getByText('Visible Details Example')).toBeVisible()
```

<hr />
Expand Down Expand Up @@ -1204,12 +1213,8 @@ To perform a partial match, you can pass a `RegExp` or use
#### Examples

```html
<button aria-label="Close" aria-describedby="description-close">
X
</button>
<div id="description-close">
Closing will discard any changes
</div>
<button aria-label="Close" aria-describedby="description-close">X</button>
<div id="description-close">Closing will discard any changes</div>

<button>Delete</button>
```
Expand Down
175 changes: 175 additions & 0 deletions src/__tests__/to-be-visible.js
Expand Up @@ -134,6 +134,74 @@ describe('.toBeVisible', () => {
})
})

describe('when the <details /> inner text does not have an enclosing element', () => {
describe('when the details is not opened', () => {
beforeEach(() => {
subject = render(`
<details>
<summary>Title of hidden innerText</summary>
hidden innerText
</details>
`)
})

it('returns false to the details content', () => {
expect(subject.container.querySelector('details')).not.toBeVisible()
})

it('returns true to the details summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})

describe('when the user clicks on the summary', () => {
beforeEach(() => subject.container.querySelector('summary').click())

it('returns true to the details content', () => {
expect(subject.container.querySelector('details')).toBeVisible()
})

it('returns true to the details summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})
})
})

describe('when the details is opened', () => {
beforeEach(() => {
subject = render(`
<details open>
<summary>Title of visible innerText</summary>
visible <small>innerText</small>
</details>
`)
})

it('returns true to the details content', () => {
expect(subject.container.querySelector('details')).toBeVisible()
})

it('returns true to inner small content', () => {
expect(subject.container.querySelector('small')).toBeVisible()
})

describe('when the user clicks on the summary', () => {
beforeEach(() => subject.container.querySelector('summary').click())

it('returns false to the details content', () => {
expect(subject.container.querySelector('details')).not.toBeVisible()
})

it('returns false to the inner small content', () => {
expect(subject.container.querySelector('small')).not.toBeVisible()
})

it('returns true to the details summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})
})
})
})

describe('with a nested <details /> element', () => {
describe('when the nested <details /> is opened', () => {
beforeEach(() => {
Expand Down Expand Up @@ -247,6 +315,113 @@ describe('.toBeVisible', () => {
).toBeVisible()
})
})

describe('with nested details (unenclosed outer, enclosed inner)', () => {
describe('when both outer and inner are opened', () => {
beforeEach(() => {
subject = render(`
<details open>
<summary>Title of outer unenclosed</summary>
Unenclosed innerText
<details open>
<summary>Title of inner enclosed</summary>
<div>Enclosed innerText</div>
</details>
</details>
`)
})

it('returns true to outer unenclosed innerText', () => {
expect(subject.container.querySelector('details')).toBeVisible()
})

it('returns true to outer summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})

it('returns true to inner enclosed innerText', () => {
expect(
subject.container.querySelector('details > details > div'),
).toBeVisible()
})

it('returns true to inner summary', () => {
expect(
subject.container.querySelector('details > details > summary'),
).toBeVisible()
})
})

describe('when outer is opened and inner is not opened', () => {
beforeEach(() => {
subject = render(`
<details open>
<summary>Title of outer unenclosed</summary>
Unenclosed innerText
<details>
<summary>Title of inner enclosed</summary>
<div>Enclosed innerText</div>
</details>
</details>
`)
})

it('returns true to outer unenclosed innerText', () => {
expect(subject.container.querySelector('details')).toBeVisible()
})

it('returns true to outer summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})

it('returns false to inner enclosed innerText', () => {
expect(
subject.container.querySelector('details > details > div'),
).not.toBeVisible()
})

it('returns true to inner summary', () => {
expect(
subject.container.querySelector('details > details > summary'),
).toBeVisible()
})
})

describe('when outer is not opened and inner is opened', () => {
beforeEach(() => {
subject = render(`
<details>
<summary>Title of outer unenclosed</summary>
Unenclosed innerText
<details open>
<summary>Title of inner enclosed</summary>
<div>Enclosed innerText</div>
</details>
</details>
`)
})

it('returns true to outer unenclosed innerText', () => {
expect(subject.container.querySelector('details')).not.toBeVisible()
})

it('returns true to outer summary', () => {
expect(subject.container.querySelector('summary')).toBeVisible()
})

it('returns false to inner enclosed innerText', () => {
expect(
subject.container.querySelector('details > details > div'),
).not.toBeVisible()
})

it('returns true to inner summary', () => {
expect(
subject.container.querySelector('details > details > summary'),
).not.toBeVisible()
})
})
})
})
})
})
19 changes: 13 additions & 6 deletions src/to-be-visible.js
Expand Up @@ -14,12 +14,19 @@ function isStyleVisible(element) {
}

function isAttributeVisible(element, previousElement) {
return (
!element.hasAttribute('hidden') &&
(element.nodeName === 'DETAILS' && previousElement.nodeName !== 'SUMMARY'
? element.hasAttribute('open')
: true)
)
let detailsVisibility

if (previousElement) {
detailsVisibility =
element.nodeName === 'DETAILS' && previousElement.nodeName !== 'SUMMARY'
? element.hasAttribute('open')
: true
} else {
detailsVisibility =
element.nodeName === 'DETAILS' ? element.hasAttribute('open') : true
}

return !element.hasAttribute('hidden') && detailsVisibility
}

function isElementVisible(element, previousElement) {
Expand Down

0 comments on commit af18453

Please sign in to comment.