dom-testing-library
dom-testing-library copied to clipboard
`getByTitle` for SVGs canot find `title` if it's not a direct child of `svg`
-
@testing-library/react
version: 11.2.7 - Testing Framework and version:
jest
26x || 27x
- DOM Environment: 'jsdom'
16.x
Relevant code or config:
Source: https://testing-library.com/docs/queries/bytitle/
const Test = () => (
<>
<span title="Delete" id="2"></span>
<svg>
<title>Close</title>
<g><path /></g>
</svg>
</>
);
VS
const Test = () => (
<>
<span title="Delete" id="2"></span>
<svg>
<g>
<path>
<title>Close</title>
</path>
</g>
</svg>
</>
);
What you did:
render(<Test/>);
screen.getByTitle('Close');
What happened:
First Component - ✅ Second Component - ❌
TestingLibraryElementError: Unable to find an element with the title: Close.
Problem description:
Testing library cannot find Close
because it's not a direct child of svg
.
Suggested solution:
I should be able to find Close
even if it's not a direct child of svg
.
Thanks for the feedback
To be clear: The query should return the <path />
not the <svg />
as far as I understood SVG title element.
It sounds like we should implement walking up the tree until we find an SVG container or graphics element.
@eps1lon just wondering as a stop-gap, how would you query title
in this case as it stands right now?
Just guessing here: getByText("Close", selector: 'title')
and then walk up to the nearest SVG container or graphics element.
@eps1lon any updates for this issue?
@eps1lon any updates for this issue?
PRs welcome for https://github.com/testing-library/dom-testing-library/issues/974#issuecomment-858028323
@eps1lon, just wondering if there's really a need to climb up the tree or just the immediate parent is enough , so instead of the implementation we have, we can do something like this:
const SVGContainerAndGraphicsElements = [
'svg',
'a',
'defs',
'g',
'marker',
'mask',
'missingglyph',
'pattern',
'svg',
'switch',
'symbol',
'circle',
'ellipse',
'image',
'line',
'path',
'polygon',
'polyline',
'rect',
'text',
'use',
]
const isSvgTitle = (node: HTMLElement) =>
node.tagName.toLowerCase() === 'title' &&
node.parentElement &&
SVGContainerAndGraphicsElements.includes(
node.parentElement.tagName.toLowerCase(),
)
Wdyt?
That implementation seems too clever. It breaks as soon as any of these names and nesting are valid HTML.
Let's make it work first and then check if we need a different implementation.
I guess the code would need to traverse up O(n)
, so would something like this make sense?
const isWithinSvg = (node: HTMLElement) => {
const curParent = node.parentElement
while (curParent != null) {
if (curParent.tagName.toLowerCase() === 'svg') return true
curParent = curParent.parentElement
}
return false
}
const isSvgTitle = (node: HTMLElement) =>
node.tagName.toLowerCase() === 'title' && isWithinSvg(node)