diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js index a8e00011..9db9c06e 100644 --- a/src/__tests__/element-queries.js +++ b/src/__tests__/element-queries.js @@ -642,6 +642,23 @@ test('query/get title element of SVG', () => { expect(queryByTitle('Close').id).toEqual('svg-title') }) +test('query/get nested title element of SVG graphics element', () => { + const {getByTitle, queryByTitle} = render(` +
+ + + + Close + + + +
+ `) + + expect(getByTitle('Close').id).toEqual('svg-path') + expect(queryByTitle('Close').id).toEqual('svg-path') +}) + test('queryByTitle matches case with non-string matcher', () => { const {queryByTitle} = render(``) expect(queryByTitle(1)).toBeTruthy() diff --git a/src/queries/title.ts b/src/queries/title.ts index 7366855f..b44c75dd 100644 --- a/src/queries/title.ts +++ b/src/queries/title.ts @@ -14,9 +14,21 @@ import { buildQueries, } from './all-utils' -const isSvgTitle = (node: HTMLElement) => - node.tagName.toLowerCase() === 'title' && - node.parentElement?.tagName.toLowerCase() === 'svg' +const getSvgTitleOwner = (node: HTMLElement) => { + if ( + node.tagName.toLowerCase() !== 'title' || + node.namespaceURI !== 'http://www.w3.org/2000/svg' + ) { + return null + } + + const parent = node.parentElement + if (!parent || parent.tagName.toLowerCase() === 'svg') { + return node + } + + return parent +} const queryAllByTitle: AllByBoundAttribute = ( container, @@ -26,14 +38,25 @@ const queryAllByTitle: AllByBoundAttribute = ( checkContainerType(container) const matcher = exact ? matches : fuzzyMatches const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer}) - return Array.from( - container.querySelectorAll('[title], svg > title'), - ).filter( - node => - matcher(node.getAttribute('title'), node, text, matchNormalizer) || - (isSvgTitle(node) && - matcher(getNodeText(node), node, text, matchNormalizer)), - ) + const results = new Set() + + Array.from( + container.querySelectorAll('[title], svg title'), + ).forEach(node => { + if (matcher(node.getAttribute('title'), node, text, matchNormalizer)) { + results.add(node) + } + + const svgTitleOwner = getSvgTitleOwner(node) + if ( + svgTitleOwner && + matcher(getNodeText(node), svgTitleOwner, text, matchNormalizer) + ) { + results.add(svgTitleOwner) + } + }) + + return Array.from(results) } const getMultipleError: GetErrorFunction<[unknown]> = (c, title) =>