This is an automated email from the ASF dual-hosted git repository. gerben pushed a commit to branch dom-tests in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git
commit 68e16db42de9e70619ab596c515d34a939cd2b49 Author: Gerben <[email protected]> AuthorDate: Thu May 21 16:07:16 2020 +0200 More tests — some failing Three tests fail because of an opinionated expectation: I expect a match at the start of a the text node to have that textNode as start container rather than its parent element (although technically such a Range should be equivalent). Two tests fail because we really mess up when the ancestorContainer of the scope contains text before its startContainer. Ouch. --- packages/dom/test/text-quote-match.ts | 149 ++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/packages/dom/test/text-quote-match.ts b/packages/dom/test/text-quote-match.ts index 835a3dd..e348dbe 100644 --- a/packages/dom/test/text-quote-match.ts +++ b/packages/dom/test/text-quote-match.ts @@ -55,18 +55,48 @@ const testCases: { }, ] }, + 'first characters': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + selector: { + type: 'TextQuoteSelector', + exact: 'lorem ipsum', + }, + expected: [ + { + startContainerXPath: '//b/text()', + startOffset: 0, + endContainerXPath: '//b/text()', + endOffset: 11, + }, + ] + }, + 'last characters': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + selector: { + type: 'TextQuoteSelector', + exact: 'yada yada', + }, + expected: [ + { + startContainerXPath: '//b/text()', + startOffset: 23, + endContainerXPath: '//b/text()', + endOffset: 32, + }, + ] + }, 'across elements': { - html: '<b>lorem <i>ipsum dolor</i> amet yada yada</b>', + html: '<b>lorem <i>ipsum</i> dolor <u>amet</u> yada yada</b>', selector: { type: 'TextQuoteSelector', exact: 'dolor am', }, expected: [ { - startContainerXPath: '//i/text()', - startOffset: 6, - endContainerXPath: '//b/text()[2]', - endOffset: 3, + startContainerXPath: '//b/text()[2]', + startOffset: 1, + endContainerXPath: '//u/text()', + endOffset: 2, }, ] }, @@ -151,6 +181,115 @@ describe('createTextQuoteSelectorMatcher', () => { await testMatcher(doc, doc, selector, expected); }); } + + it('handles adjacent text nodes', async () => { + const { html, selector } = testCases['simple']; + const doc = domParser.parseFromString(html, 'text/html'); + const textNode = evaluateXPath(doc, '//b/text()') as Text; + + for (let index = textNode.length - 1; index > 0; index--) + textNode.splitText(index); + // console.log([...textNode.parentNode.childNodes].map(node => node.textContent)) + // → 'l', 'o', 'r', 'e', 'm', … + + await testMatcher(doc, doc, selector, [ + { + startContainerXPath: '//b/text()[13]', + startOffset: 0, + endContainerXPath: '//b/text()[21]', + endOffset: 0, + }, + ]); + }); + + it('handles empty text nodes', async () => { + const { html, selector } = testCases['simple']; + const doc = domParser.parseFromString(html, 'text/html'); + + const textNode = evaluateXPath(doc, '//b/text()') as Text; + textNode.splitText(textNode.length); + textNode.splitText(20); + textNode.splitText(20); + textNode.splitText(17); + textNode.splitText(17); + textNode.splitText(12); + textNode.splitText(12); + textNode.splitText(0); + // console.log([...textNode.parentNode.childNodes].map(node => node.textContent)) + // → '', 'lorem ipsum ', '', 'dolor', '', ' am', '', 'et yada yada', '' + + await testMatcher(doc, doc, selector, [ + { + startContainerXPath: '//b/text()[4]', // "dolor" + startOffset: 0, + endContainerXPath: '//b/text()[8]', // "et yada yada" + endOffset: 0, + }, + ]); + }); + + it('works with parent of text as scope', async () => { + const { html, selector, expected } = testCases['simple']; + const doc = domParser.parseFromString(html, 'text/html'); + + await testMatcher(doc, evaluateXPath(doc, '//b'), selector, expected); + }); + + it('works with parent of text as scope, when matching its first characters', async () => { + const { html, selector, expected } = testCases['first characters']; + const doc = domParser.parseFromString(html, 'text/html'); + + await testMatcher(doc, evaluateXPath(doc, '//b'), selector, expected); + }); + + it('works with parent of text as scope, when matching its first characters, with an empty text node', async () => { + const { html, selector } = testCases['first characters']; + const doc = domParser.parseFromString(html, 'text/html'); + + const textNode = evaluateXPath(doc, '//b/text()') as Text; + textNode.splitText(0); + + await testMatcher(doc, evaluateXPath(doc, '//b'), selector, [ + { + startContainerXPath: '//b/text()[2]', + startOffset: 0, + endContainerXPath: '//b/text()[2]', + endOffset: 11, + }, + ]); + }); + + it('works when scope is a Range within one text node', async () => { + const { html, selector, expected } = testCases['simple']; + const doc = domParser.parseFromString(html, 'text/html'); + + // Use the substring ‘ipsum dolor amet’ as scope. + const scope = document.createRange(); + scope.setStart(evaluateXPath(doc, '//b/text()'), 6); + scope.setEnd(evaluateXPath(doc, '//b/text()'), 22); + await testMatcher(doc, scope, selector, expected); + }); + + it('works when scope is a Range with both ends inside text nodes', async () => { + const { html, selector, expected } = testCases['across elements']; + const doc = domParser.parseFromString(html, 'text/html'); + + // Use the substring ‘sum dolor am’ as scope. + const scope = document.createRange(); + scope.setStart(evaluateXPath(doc, '//i/text()'), 2); + scope.setEnd(evaluateXPath(doc, '//u/text()'), 2); + await testMatcher(doc, scope, selector, expected); + }); + + it('works when scope is a Range with both ends inside elements', async () => { + const { html, selector, expected } = testCases['across elements']; + const doc = domParser.parseFromString(html, 'text/html'); + + const scope = document.createRange(); + scope.setStart(evaluateXPath(doc, '//b'), 1); // before the <i> + scope.setEnd(evaluateXPath(doc, '//b'), 4); // before the " yada yada" + await testMatcher(doc, scope, selector, expected); + }); }); async function testMatcher(
