This is an automated email from the ASF dual-hosted git repository. gerben pushed a commit to branch more-context in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git
commit 50a17d7e2eaea670b28a1518341e83a7f36650ae Author: Gerben <[email protected]> AuthorDate: Fri Dec 25 00:26:36 2020 +0100 Update tests --- packages/dom/test/text-quote/describe-cases.ts | 295 +++++++++++++++++++++++-- packages/dom/test/text-quote/describe.test.ts | 38 +++- 2 files changed, 311 insertions(+), 22 deletions(-) diff --git a/packages/dom/test/text-quote/describe-cases.ts b/packages/dom/test/text-quote/describe-cases.ts index dec995e..9edb09b 100644 --- a/packages/dom/test/text-quote/describe-cases.ts +++ b/packages/dom/test/text-quote/describe-cases.ts @@ -18,17 +18,167 @@ * under the License. */ -import type { TextQuoteSelector } from '@annotator/selector'; +import type { TextQuoteSelector, DescribeTextQuoteOptions } from '@annotator/selector'; import type { RangeInfo } from '../utils'; -export const testCases: { +export interface DescribeTextQuoteTestCases { [name: string]: { html: string; range: RangeInfo; + options: DescribeTextQuoteOptions; expected: TextQuoteSelector; }; -} = { - simple: { +} + +export const testCasesWithoutOptions: DescribeTextQuoteTestCases = { + 'no context': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 12, + endContainerXPath: '//b/text()', + endOffset: 22, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'dolor amet', + prefix: '', + suffix: '', + }, + }, + 'use prefix to complete word': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 14, + endContainerXPath: '//b/text()', + endOffset: 22, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'lor amet', + prefix: 'do', + suffix: '', + }, + }, + 'use suffix to complete word': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 12, + endContainerXPath: '//b/text()', + endOffset: 20, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'dolor am', + prefix: '', + suffix: 'et', + }, + }, + 'add context to disambiguate': { + html: '<b>To annotate or not to annotate</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 15, + endContainerXPath: '//b/text()', + endOffset: 18, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'not', + prefix: 'or ', + suffix: ' to', + }, + }, + 'only prefix for end of text': { + html: '<b>To annotate or not to annotate</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 22, + endContainerXPath: '//b/text()', + endOffset: 30, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'annotate', + prefix: 'to ', + suffix: '', + }, + }, + 'only suffix for start of text': { + html: '<b>annotate or not to annotate, yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 0, + endContainerXPath: '//b/text()', + endOffset: 8, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'annotate', + prefix: '', + suffix: ' or', + }, + }, + 'multiple, overlapping false matches': { + html: '<b>a a a a a a a a a a</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 8, + endContainerXPath: '//b/text()', + endOffset: 13, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'a a a', + prefix: 'a a a a ', + suffix: ' a a a', + }, + }, + 'empty quote': { + html: '<b>To annotate or not to annotate</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 11, + endContainerXPath: '//b/text()', + endOffset: 11, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: '', + prefix: 'To annotate', + suffix: ' or', + }, + }, + 'across elements': { + html: '<b>To annotate or <i>not</i> to <u>anno</u>tat</b>e', + range: { + startContainerXPath: '//u/text()', + startOffset: 0, + endContainerXPath: '//b/text()[3]', + endOffset: 2, + }, + options: {}, + expected: { + type: 'TextQuoteSelector', + exact: 'annota', + prefix: 'to ', + suffix: 'te', + }, + }, +}; + +export const testCasesWithMinimalContext: DescribeTextQuoteTestCases = { + 'no context': { html: '<b>lorem ipsum dolor amet yada yada</b>', range: { startContainerXPath: '//b/text()', @@ -36,6 +186,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 20, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'dolor am', @@ -51,6 +204,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 26, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'anno', @@ -66,6 +222,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 11, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'tate', @@ -81,6 +240,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 2, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'to', @@ -96,6 +258,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 30, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'tate', @@ -111,6 +276,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 7, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: 'aaa', @@ -126,6 +294,9 @@ export const testCases: { endContainerXPath: '//b/text()', endOffset: 11, }, + options: { + minimalContext: true, + }, expected: { type: 'TextQuoteSelector', exact: '', @@ -133,19 +304,117 @@ export const testCases: { suffix: ' ', }, }, - 'across elements': { - html: '<b>To annotate or <i>not</i> to <u>anno</u>tate</b>', +}; + +export const testCasesWithMinimumQuoteLength: DescribeTextQuoteTestCases = { + 'balance prefix and suffix': { + html: '<b>lorem ipsum dolor amet yada yada</b>', range: { - startContainerXPath: '//u/text()', - startOffset: 0, - endContainerXPath: '//b/text()[3]', - endOffset: 2, + startContainerXPath: '//b/text()', + startOffset: 12, + endContainerXPath: '//b/text()', + endOffset: 17, + }, + options: { + minimumQuoteLength: 10, }, expected: { type: 'TextQuoteSelector', - exact: 'annota', - prefix: 'to ', - suffix: '', + exact: 'dolor', + prefix: 'ipsum ', + suffix: ' amet', + }, + }, + 'use prefix for end of text': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 28, + endContainerXPath: '//b/text()', + endOffset: 30, + }, + options: { + minimumQuoteLength: 10, + }, + expected: { + type: 'TextQuoteSelector', + exact: 'ya', + prefix: 'amet yada ', + suffix: 'da', + }, + }, + 'use suffix for start of text': { + html: '<b>lorem ipsum dolor amet yada yada</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 2, + endContainerXPath: '//b/text()', + endOffset: 3, + }, + options: { + minimumQuoteLength: 10, + }, + expected: { + type: 'TextQuoteSelector', + exact: 'r', + prefix: 'lo', + suffix: 'em ipsum', + }, + }, +}; + +export const testCasesWithMaxWordLength: DescribeTextQuoteTestCases = { + 'too long prefix': { + html: '<b>Surely counterantidisintermediationism is too long to quote.</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 28, + endContainerXPath: '//b/text()', + endOffset: 31, + }, + options: { + maxWordLength: 10, + }, + expected: { + type: 'TextQuoteSelector', + exact: 'dia', + prefix: 'disinterme', + suffix: 'tionism', + }, + }, + 'too long suffix': { + html: '<b>Surely counterantidisintermediationism is too long to quote.</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 14, + endContainerXPath: '//b/text()', + endOffset: 18, + }, + options: { + maxWordLength: 10, + }, + expected: { + type: 'TextQuoteSelector', + exact: 'anti', + prefix: 'counter', + suffix: 'disinterme', + }, + }, + 'default should be 50': { + html: '<b>The chromosome is ACATATTACGTTAGATATGACACCCATATAGTTATTTATAAGATGGGACAGATATTAGTTTAAAAA</b>', + range: { + startContainerXPath: '//b/text()', + startOffset: 18, + endContainerXPath: '//b/text()', + endOffset: 27, + }, + options: { + }, + expected: { + type: 'TextQuoteSelector', + exact: 'ACATATTAC', + prefix: '', + suffix: 'GTTAGATATGACACCCATATAGTTATTTATAAGATGGGACAGATATTAGT', }, }, }; diff --git a/packages/dom/test/text-quote/describe.test.ts b/packages/dom/test/text-quote/describe.test.ts index 25bfd0f..147f6d3 100644 --- a/packages/dom/test/text-quote/describe.test.ts +++ b/packages/dom/test/text-quote/describe.test.ts @@ -21,29 +21,48 @@ import { assert } from 'chai'; import { describeTextQuote } from '../../src/text-quote/describe'; import { hydrateRange, evaluateXPath } from '../utils'; -import { testCases } from './describe-cases'; +import { DescribeTextQuoteTestCases, testCasesWithMinimumQuoteLength, testCasesWithMaxWordLength } from './describe-cases'; +import { testCasesWithMinimalContext, testCasesWithoutOptions } from './describe-cases'; import { testCases as testMatchCases } from './match-cases'; const domParser = new window.DOMParser(); -describe('describeTextQuote', () => { - for (const [name, { html, range, expected }] of Object.entries(testCases)) { +function runTestCases(testCases: DescribeTextQuoteTestCases) { + for (const [name, { html, range, expected, options }] of Object.entries(testCases)) { it(`works for case: ${name}`, async () => { const doc = domParser.parseFromString(html, 'text/html'); const scope = doc.createRange(); scope.selectNodeContents(doc); - const result = await describeTextQuote(hydrateRange(range, doc), scope); + const result = await describeTextQuote(hydrateRange(range, doc), scope, options); assert.deepEqual(result, expected); }); } +} + +describe('describeTextQuote', () => { + describe('without options', () => { + runTestCases(testCasesWithoutOptions); + }); + + describe('with minimal context', () => { + runTestCases(testCasesWithMinimalContext); + }); + + describe('with minimum quote length', () => { + runTestCases(testCasesWithMinimumQuoteLength); + }); + + describe('with max word length', () => { + runTestCases(testCasesWithMaxWordLength); + }); it('works with custom scope', async () => { - const { html, range } = testCases['minimal prefix']; + const { html, range, options } = testCasesWithMinimalContext['minimal prefix']; const doc = domParser.parseFromString(html, 'text/html'); const scope = doc.createRange(); scope.setStart(evaluateXPath(doc, '//b/text()'), 15); scope.setEnd(evaluateXPath(doc, '//b/text()'), 30); // "not to annotate" - const result = await describeTextQuote(hydrateRange(range, doc), scope); + const result = await describeTextQuote(hydrateRange(range, doc), scope, options); assert.deepEqual(result, { type: 'TextQuoteSelector', exact: 'anno', @@ -53,12 +72,12 @@ describe('describeTextQuote', () => { }); it('strips part of the range outside the scope', async () => { - const { html, range } = testCases['simple']; + const { html, range, options } = testCasesWithMinimalContext['no context']; const doc = domParser.parseFromString(html, 'text/html'); const scope = doc.createRange(); scope.setStart(evaluateXPath(doc, '//b/text()'), 6); scope.setEnd(evaluateXPath(doc, '//b/text()'), 17); // "ipsum dolor" - const result = await describeTextQuote(hydrateRange(range, doc), scope); + const result = await describeTextQuote(hydrateRange(range, doc), scope, options); assert.deepEqual(result, { type: 'TextQuoteSelector', exact: 'dolor', @@ -68,11 +87,12 @@ describe('describeTextQuote', () => { }); it('works if the range equals the scope', async () => { - const { html, range, expected } = testCases['simple']; + const { html, range, expected, options } = testCasesWithMinimalContext['no context']; const doc = domParser.parseFromString(html, 'text/html'); const result = await describeTextQuote( hydrateRange(range, doc), hydrateRange(range, doc), + options, ); assert.deepEqual(result, expected); });
