Skip to content

Commit

Permalink
more test updates (#510)
Browse files Browse the repository at this point in the history
* test updates

* remove duplicate

* fix indentation

* fix
  • Loading branch information
Casheeew authored Jan 14, 2024
1 parent 326c533 commit dcb26a8
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 180 deletions.
2 changes: 1 addition & 1 deletion test/data/html/dom-text-scanner.html
Original file line number Diff line number Diff line change
Expand Up @@ -392,4 +392,4 @@ <h1>DOMTextScanner Tests</h1>
</test-case>

</body>
</html>
</html>
291 changes: 151 additions & 140 deletions test/document-util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

import {fileURLToPath} from 'node:url';
import path from 'path';
import {describe, expect} from 'vitest';
import {afterAll, describe, expect, test} from 'vitest';
import {DocumentUtil} from '../ext/js/dom/document-util.js';
import {DOMTextScanner} from '../ext/js/dom/dom-text-scanner.js';
import {TextSourceElement} from '../ext/js/dom/text-source-element.js';
import {TextSourceRange} from '../ext/js/dom/text-source-range.js';
import {createDomTest} from './fixtures/dom-test.js';
import {setupDomTest} from './fixtures/dom-test.js';
import {parseJson} from '../dev/json.js';

const dirname = path.dirname(fileURLToPath(import.meta.url));
Expand Down Expand Up @@ -110,165 +110,176 @@ function findImposterElement(document) {
return document.querySelector('div[style*="2147483646"]>*');
}

const test = createDomTest(path.join(dirname, 'data/html/document-util.html'));
const documentUtilTestEnv = await setupDomTest(path.join(dirname, 'data/html/document-util.html'));

describe('DocumentUtil', () => {
test('Text scanning functions', ({window}) => {
const {document} = window;
for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=scan]'))) {
// Get test parameters
/** @type {import('test/document-util').DocumentUtilTestData} */
const {
elementFromPointSelector,
caretRangeFromPointSelector,
startNodeSelector,
startOffset,
endNodeSelector,
endOffset,
resultType,
sentenceScanExtent,
sentence,
hasImposter,
terminateAtNewlines
} = parseJson(/** @type {string} */ (testElement.dataset.testData));
describe('Document utility tests', () => {
const {window, teardown} = documentUtilTestEnv;
afterAll(() => teardown(global));

const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector);
const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector);
const startNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, startNodeSelector));
const endNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, endNodeSelector));
describe('DocumentUtil', () => {
describe('Text scanning functions', () => {
let testIndex = 0;
const {document} = window;
for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=scan]'))) {
test(`test-case-${testIndex++}`, () => {
// Get test parameters
/** @type {import('test/document-util').DocumentUtilTestData} */
const {
elementFromPointSelector,
caretRangeFromPointSelector,
startNodeSelector,
startOffset,
endNodeSelector,
endOffset,
resultType,
sentenceScanExtent,
sentence,
hasImposter,
terminateAtNewlines
} = parseJson(/** @type {string} */ (testElement.dataset.testData));

// Defaults to true
const terminateAtNewlines2 = typeof terminateAtNewlines === 'boolean' ? terminateAtNewlines : true;
const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector);
const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector);
const startNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, startNodeSelector));
const endNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, endNodeSelector));

expect(elementFromPointValue).not.toStrictEqual(null);
expect(caretRangeFromPointValue).not.toStrictEqual(null);
expect(startNode).not.toStrictEqual(null);
expect(endNode).not.toStrictEqual(null);
// Defaults to true
const terminateAtNewlines2 = typeof terminateAtNewlines === 'boolean' ? terminateAtNewlines : true;

// Setup functions
document.elementFromPoint = () => elementFromPointValue;
expect(elementFromPointValue).not.toStrictEqual(null);
expect(caretRangeFromPointValue).not.toStrictEqual(null);
expect(startNode).not.toStrictEqual(null);
expect(endNode).not.toStrictEqual(null);

document.caretRangeFromPoint = (x, y) => {
const imposter = getChildTextNodeOrSelf(window, findImposterElement(document));
expect(!!imposter).toStrictEqual(!!hasImposter);
// Setup functions
document.elementFromPoint = () => elementFromPointValue;

const range = document.createRange();
range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset);
range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset);
document.caretRangeFromPoint = (x, y) => {
const imposter = getChildTextNodeOrSelf(window, findImposterElement(document));
expect(!!imposter).toStrictEqual(!!hasImposter);

// Override getClientRects to return a rect guaranteed to contain (x, y)
range.getClientRects = () => {
/** @type {import('test/document-types').PseudoDOMRectList} */
const domRectList = Object.assign(
[new DOMRect(x - 1, y - 1, 2, 2)],
{
/**
* @this {DOMRect[]}
* @param {number} index
* @returns {DOMRect}
*/
item: function item(index) { return this[index]; }
}
);
return domRectList;
};
return range;
};
const range = document.createRange();
range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset);
range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset);

// Test docRangeFromPoint
const source = DocumentUtil.getRangeFromPoint(0, 0, {
deepContentScan: false,
normalizeCssZoom: true
});
switch (resultType) {
case 'TextSourceRange':
expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceRange.prototype);
break;
case 'TextSourceElement':
expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceElement.prototype);
break;
case 'null':
expect(source).toStrictEqual(null);
break;
default:
expect.unreachable();
break;
}
if (source === null) { continue; }
// Override getClientRects to return a rect guaranteed to contain (x, y)
range.getClientRects = () => {
/** @type {import('test/document-types').PseudoDOMRectList} */
const domRectList = Object.assign(
[new DOMRect(x - 1, y - 1, 2, 2)],
{
/**
* @this {DOMRect[]}
* @param {number} index
* @returns {DOMRect}
*/
item: function item(index) { return this[index]; }
}
);
return domRectList;
};
return range;
};

// Sentence info
const terminatorString = '…。..??!!';
const terminatorMap = new Map();
for (const char of terminatorString) {
terminatorMap.set(char, [false, true]);
}
const quoteArray = [['「', '」'], ['『', '』'], ['\'', '\''], ['"', '"']];
const forwardQuoteMap = new Map();
const backwardQuoteMap = new Map();
for (const [char1, char2] of quoteArray) {
forwardQuoteMap.set(char1, [char2, false]);
backwardQuoteMap.set(char2, [char1, false]);
}
// Test docRangeFromPoint
const source = DocumentUtil.getRangeFromPoint(0, 0, {
deepContentScan: false,
normalizeCssZoom: true
});
switch (resultType) {
case 'TextSourceRange':
expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceRange.prototype);
break;
case 'TextSourceElement':
expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceElement.prototype);
break;
case 'null':
expect(source).toStrictEqual(null);
break;
default:
expect.unreachable();
break;
}
if (source === null) { return; }

// Sentence info
const terminatorString = '…。..??!!';
const terminatorMap = new Map();
for (const char of terminatorString) {
terminatorMap.set(char, [false, true]);
}
const quoteArray = [['「', '」'], ['『', '』'], ['\'', '\''], ['"', '"']];
const forwardQuoteMap = new Map();
const backwardQuoteMap = new Map();
for (const [char1, char2] of quoteArray) {
forwardQuoteMap.set(char1, [char2, false]);
backwardQuoteMap.set(char2, [char1, false]);
}

// Test docSentenceExtract
const sentenceActual = DocumentUtil.extractSentence(
source,
false,
sentenceScanExtent,
terminateAtNewlines2,
terminatorMap,
forwardQuoteMap,
backwardQuoteMap
).text;
expect(sentenceActual).toStrictEqual(sentence);
// Test docSentenceExtract
const sentenceActual = DocumentUtil.extractSentence(
source,
false,
sentenceScanExtent,
terminateAtNewlines2,
terminatorMap,
forwardQuoteMap,
backwardQuoteMap
).text;
expect(sentenceActual).toStrictEqual(sentence);

// Clean
source.cleanup();
}
// Clean
source.cleanup();
});
}
});
});
});

describe('DOMTextScanner', () => {
test('Seek functions', async ({window}) => {
const {document} = window;
for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=text-source-range-seek]'))) {
// Get test parameters
/** @type {import('test/document-util').DOMTextScannerTestData} */
const {
seekNodeSelector,
seekNodeIsText,
seekOffset,
seekLength,
seekDirection,
expectedResultNodeSelector,
expectedResultNodeIsText,
expectedResultOffset,
expectedResultContent
} = parseJson(/** @type {string} */ (testElement.dataset.testData));
describe('DOMTextScanner', () => {
describe('Seek functions', () => {
let testIndex = 0;
const {document} = window;
for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=text-source-range-seek]'))) {
test(`test-case-${testIndex++}`, () => {
// Get test parameters
/** @type {import('test/document-util').DOMTextScannerTestData} */
const {
seekNodeSelector,
seekNodeIsText,
seekOffset,
seekLength,
seekDirection,
expectedResultNodeSelector,
expectedResultNodeIsText,
expectedResultOffset,
expectedResultContent
} = parseJson(/** @type {string} */ (testElement.dataset.testData));

/** @type {?Node} */
let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector));
if (seekNodeIsText && seekNode !== null) {
seekNode = seekNode.firstChild;
}
/** @type {?Node} */
let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector));
if (seekNodeIsText && seekNode !== null) {
seekNode = seekNode.firstChild;
}

const expectedResultContent2 = expectedResultContent.join('\n');
const expectedResultContent2 = expectedResultContent.join('\n');

/** @type {?Node} */
let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector));
if (expectedResultNodeIsText && expectedResultNode !== null) {
expectedResultNode = expectedResultNode.firstChild;
}
/** @type {?Node} */
let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector));
if (expectedResultNodeIsText && expectedResultNode !== null) {
expectedResultNode = expectedResultNode.firstChild;
}

const {node, offset, content} = (
const {node, offset, content} = (
seekDirection === 'forward' ?
new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset, true, false).seek(seekLength) :
new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset, true, false).seek(-seekLength)
);
);

expect(node).toStrictEqual(expectedResultNode);
expect(offset).toStrictEqual(expectedResultOffset);
expect(content).toStrictEqual(expectedResultContent2);
}
expect(node).toStrictEqual(expectedResultNode);
expect(offset).toStrictEqual(expectedResultOffset);
expect(content).toStrictEqual(expectedResultContent2);
});
}
});
});
});
12 changes: 7 additions & 5 deletions test/dom-text-scanner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@

import {fileURLToPath} from 'node:url';
import path from 'path';
import {describe, expect} from 'vitest';
import {afterAll, describe, expect, test} from 'vitest';
import {parseJson} from '../dev/json.js';
import {DOMTextScanner} from '../ext/js/dom/dom-text-scanner.js';
import {createDomTest} from './fixtures/dom-test.js';
import {setupDomTest} from './fixtures/dom-test.js';

const dirname = path.dirname(fileURLToPath(import.meta.url));

Expand Down Expand Up @@ -101,11 +101,13 @@ function createAbsoluteGetComputedStyle(window) {
};
}


const test = createDomTest(path.join(dirname, 'data/html/dom-text-scanner.html'));
const domTestEnv = await setupDomTest(path.join(dirname, 'data/html/dom-text-scanner.html'));

describe('DOMTextScanner', () => {
test('Seek tests', ({window}) => {
const {window, teardown} = domTestEnv;
afterAll(() => teardown(global));

test('Seek tests', () => {
const {document} = window;
window.getComputedStyle = createAbsoluteGetComputedStyle(window);

Expand Down
14 changes: 14 additions & 0 deletions test/fixtures/dom-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ function prepareWindow(window) {
document.caretRangeFromPoint = () => null;
}

/**
*
* @param {string} [htmlFilePath]
* @returns {Promise<{window: import('jsdom').DOMWindow; teardown: (global: unknown) => import('vitest').Awaitable<void>}>}
*/
export async function setupDomTest(htmlFilePath) {
const html = typeof htmlFilePath === 'string' ? fs.readFileSync(htmlFilePath, {encoding: 'utf8'}) : '<!DOCTYPE html>';
const env = builtinEnvironments.jsdom;
const {teardown} = await env.setup(global, {jsdom: {html}});
const window = /** @type {import('jsdom').DOMWindow} */ (/** @type {unknown} */ (global.window));
prepareWindow(window);
return {window, teardown};
}

/**
* @param {string} [htmlFilePath]
* @returns {import('vitest').TestAPI<{window: import('jsdom').DOMWindow}>}
Expand Down
Loading

0 comments on commit dcb26a8

Please sign in to comment.