Skip to content

Commit af18453

Browse files
kschowfeedmypixel
andauthoredApr 5, 2022
fix: Support unenclosed inner text for details elements in to be visible (#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>
1 parent 6988a67 commit af18453

File tree

3 files changed

+200
-13
lines changed

3 files changed

+200
-13
lines changed
 

‎README.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ clear to read and to maintain.
4949
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
5050
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
5151

52-
5352
- [Installation](#installation)
5453
- [Usage](#usage)
5554
- [With TypeScript](#with-typescript)
@@ -424,6 +423,14 @@ An element is visible if **all** the following conditions are met:
424423
</div>
425424
<div data-testid="visible">Visible Example</div>
426425
<div data-testid="hidden-attribute" hidden>Hidden Attribute Example</div>
426+
<details>
427+
<summary>Title of hidden text</summary>
428+
Hidden Details Example
429+
</details>
430+
<details open>
431+
<summary>Title of visible text</summary>
432+
<div>Visible Details Example</div>
433+
</details>
427434
```
428435

429436
```javascript
@@ -433,6 +440,8 @@ expect(getByText('Display None Example')).not.toBeVisible()
433440
expect(getByText('Hidden Parent Example')).not.toBeVisible()
434441
expect(getByText('Visible Example')).toBeVisible()
435442
expect(getByText('Hidden Attribute Example')).not.toBeVisible()
443+
expect(getByText('Hidden Details Example')).not.toBeVisible()
444+
expect(getByText('Visible Details Example')).toBeVisible()
436445
```
437446

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

12061215
```html
1207-
<button aria-label="Close" aria-describedby="description-close">
1208-
X
1209-
</button>
1210-
<div id="description-close">
1211-
Closing will discard any changes
1212-
</div>
1216+
<button aria-label="Close" aria-describedby="description-close">X</button>
1217+
<div id="description-close">Closing will discard any changes</div>
12131218

12141219
<button>Delete</button>
12151220
```

‎src/__tests__/to-be-visible.js

+175
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,74 @@ describe('.toBeVisible', () => {
134134
})
135135
})
136136

137+
describe('when the <details /> inner text does not have an enclosing element', () => {
138+
describe('when the details is not opened', () => {
139+
beforeEach(() => {
140+
subject = render(`
141+
<details>
142+
<summary>Title of hidden innerText</summary>
143+
hidden innerText
144+
</details>
145+
`)
146+
})
147+
148+
it('returns false to the details content', () => {
149+
expect(subject.container.querySelector('details')).not.toBeVisible()
150+
})
151+
152+
it('returns true to the details summary', () => {
153+
expect(subject.container.querySelector('summary')).toBeVisible()
154+
})
155+
156+
describe('when the user clicks on the summary', () => {
157+
beforeEach(() => subject.container.querySelector('summary').click())
158+
159+
it('returns true to the details content', () => {
160+
expect(subject.container.querySelector('details')).toBeVisible()
161+
})
162+
163+
it('returns true to the details summary', () => {
164+
expect(subject.container.querySelector('summary')).toBeVisible()
165+
})
166+
})
167+
})
168+
169+
describe('when the details is opened', () => {
170+
beforeEach(() => {
171+
subject = render(`
172+
<details open>
173+
<summary>Title of visible innerText</summary>
174+
visible <small>innerText</small>
175+
</details>
176+
`)
177+
})
178+
179+
it('returns true to the details content', () => {
180+
expect(subject.container.querySelector('details')).toBeVisible()
181+
})
182+
183+
it('returns true to inner small content', () => {
184+
expect(subject.container.querySelector('small')).toBeVisible()
185+
})
186+
187+
describe('when the user clicks on the summary', () => {
188+
beforeEach(() => subject.container.querySelector('summary').click())
189+
190+
it('returns false to the details content', () => {
191+
expect(subject.container.querySelector('details')).not.toBeVisible()
192+
})
193+
194+
it('returns false to the inner small content', () => {
195+
expect(subject.container.querySelector('small')).not.toBeVisible()
196+
})
197+
198+
it('returns true to the details summary', () => {
199+
expect(subject.container.querySelector('summary')).toBeVisible()
200+
})
201+
})
202+
})
203+
})
204+
137205
describe('with a nested <details /> element', () => {
138206
describe('when the nested <details /> is opened', () => {
139207
beforeEach(() => {
@@ -247,6 +315,113 @@ describe('.toBeVisible', () => {
247315
).toBeVisible()
248316
})
249317
})
318+
319+
describe('with nested details (unenclosed outer, enclosed inner)', () => {
320+
describe('when both outer and inner are opened', () => {
321+
beforeEach(() => {
322+
subject = render(`
323+
<details open>
324+
<summary>Title of outer unenclosed</summary>
325+
Unenclosed innerText
326+
<details open>
327+
<summary>Title of inner enclosed</summary>
328+
<div>Enclosed innerText</div>
329+
</details>
330+
</details>
331+
`)
332+
})
333+
334+
it('returns true to outer unenclosed innerText', () => {
335+
expect(subject.container.querySelector('details')).toBeVisible()
336+
})
337+
338+
it('returns true to outer summary', () => {
339+
expect(subject.container.querySelector('summary')).toBeVisible()
340+
})
341+
342+
it('returns true to inner enclosed innerText', () => {
343+
expect(
344+
subject.container.querySelector('details > details > div'),
345+
).toBeVisible()
346+
})
347+
348+
it('returns true to inner summary', () => {
349+
expect(
350+
subject.container.querySelector('details > details > summary'),
351+
).toBeVisible()
352+
})
353+
})
354+
355+
describe('when outer is opened and inner is not opened', () => {
356+
beforeEach(() => {
357+
subject = render(`
358+
<details open>
359+
<summary>Title of outer unenclosed</summary>
360+
Unenclosed innerText
361+
<details>
362+
<summary>Title of inner enclosed</summary>
363+
<div>Enclosed innerText</div>
364+
</details>
365+
</details>
366+
`)
367+
})
368+
369+
it('returns true to outer unenclosed innerText', () => {
370+
expect(subject.container.querySelector('details')).toBeVisible()
371+
})
372+
373+
it('returns true to outer summary', () => {
374+
expect(subject.container.querySelector('summary')).toBeVisible()
375+
})
376+
377+
it('returns false to inner enclosed innerText', () => {
378+
expect(
379+
subject.container.querySelector('details > details > div'),
380+
).not.toBeVisible()
381+
})
382+
383+
it('returns true to inner summary', () => {
384+
expect(
385+
subject.container.querySelector('details > details > summary'),
386+
).toBeVisible()
387+
})
388+
})
389+
390+
describe('when outer is not opened and inner is opened', () => {
391+
beforeEach(() => {
392+
subject = render(`
393+
<details>
394+
<summary>Title of outer unenclosed</summary>
395+
Unenclosed innerText
396+
<details open>
397+
<summary>Title of inner enclosed</summary>
398+
<div>Enclosed innerText</div>
399+
</details>
400+
</details>
401+
`)
402+
})
403+
404+
it('returns true to outer unenclosed innerText', () => {
405+
expect(subject.container.querySelector('details')).not.toBeVisible()
406+
})
407+
408+
it('returns true to outer summary', () => {
409+
expect(subject.container.querySelector('summary')).toBeVisible()
410+
})
411+
412+
it('returns false to inner enclosed innerText', () => {
413+
expect(
414+
subject.container.querySelector('details > details > div'),
415+
).not.toBeVisible()
416+
})
417+
418+
it('returns true to inner summary', () => {
419+
expect(
420+
subject.container.querySelector('details > details > summary'),
421+
).not.toBeVisible()
422+
})
423+
})
424+
})
250425
})
251426
})
252427
})

‎src/to-be-visible.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@ function isStyleVisible(element) {
1414
}
1515

1616
function isAttributeVisible(element, previousElement) {
17-
return (
18-
!element.hasAttribute('hidden') &&
19-
(element.nodeName === 'DETAILS' && previousElement.nodeName !== 'SUMMARY'
20-
? element.hasAttribute('open')
21-
: true)
22-
)
17+
let detailsVisibility
18+
19+
if (previousElement) {
20+
detailsVisibility =
21+
element.nodeName === 'DETAILS' && previousElement.nodeName !== 'SUMMARY'
22+
? element.hasAttribute('open')
23+
: true
24+
} else {
25+
detailsVisibility =
26+
element.nodeName === 'DETAILS' ? element.hasAttribute('open') : true
27+
}
28+
29+
return !element.hasAttribute('hidden') && detailsVisibility
2330
}
2431

2532
function isElementVisible(element, previousElement) {

0 commit comments

Comments
 (0)
Please sign in to comment.