diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/deinflector.test.js | 14 | ||||
-rw-r--r-- | test/document-util.test.js | 118 | ||||
-rw-r--r-- | test/dom-text-scanner.test.js | 43 | ||||
-rw-r--r-- | test/hotkey-util.test.js | 7 |
4 files changed, 147 insertions, 35 deletions
diff --git a/test/deinflector.test.js b/test/deinflector.test.js index edb85833..77184799 100644 --- a/test/deinflector.test.js +++ b/test/deinflector.test.js @@ -21,8 +21,16 @@ import path from 'path'; import {describe, expect, test} from 'vitest'; import {Deinflector} from '../ext/js/language/deinflector.js'; +/** + * @param {Deinflector} deinflector + * @param {string} source + * @param {string} expectedTerm + * @param {string} expectedRule + * @param {string[]|undefined} expectedReasons + * @returns {{has: false, reasons: null, rules: null}|{has: true, reasons: string[], rules: number}} + */ function hasTermReasons(deinflector, source, expectedTerm, expectedRule, expectedReasons) { - for (const {term, reasons, rules} of deinflector.deinflect(source, source)) { + for (const {term, reasons, rules} of deinflector.deinflect(source)) { if (term !== expectedTerm) { continue; } if (typeof expectedRule !== 'undefined') { const expectedFlags = Deinflector.rulesToRuleFlags([expectedRule]); @@ -46,6 +54,7 @@ function hasTermReasons(deinflector, source, expectedTerm, expectedRule, expecte } +/** */ function testDeinflections() { const data = [ { @@ -915,7 +924,7 @@ function testDeinflections() { } ]; - const deinflectionReasons = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'ext', 'data/deinflect.json'))); + const deinflectionReasons = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'ext', 'data/deinflect.json'), {encoding: 'utf8'})); const deinflector = new Deinflector(deinflectionReasons); describe('deinflections', () => { @@ -939,6 +948,7 @@ function testDeinflections() { } +/** */ function main() { testDeinflections(); } diff --git a/test/document-util.test.js b/test/document-util.test.js index f2552f78..8c6ab69b 100644 --- a/test/document-util.test.js +++ b/test/document-util.test.js @@ -30,24 +30,48 @@ const dirname = path.dirname(fileURLToPath(import.meta.url)); // DOMRect class definition class DOMRect { + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ constructor(x, y, width, height) { + /** @type {number} */ this._x = x; + /** @type {number} */ this._y = y; + /** @type {number} */ this._width = width; + /** @type {number} */ this._height = height; } + /** @type {number} */ get x() { return this._x; } + /** @type {number} */ get y() { return this._y; } + /** @type {number} */ get width() { return this._width; } + /** @type {number} */ get height() { return this._height; } + /** @type {number} */ get left() { return this._x + Math.min(0, this._width); } + /** @type {number} */ get right() { return this._x + Math.max(0, this._width); } + /** @type {number} */ get top() { return this._y + Math.min(0, this._height); } + /** @type {number} */ get bottom() { return this._y + Math.max(0, this._height); } + /** @returns {string} */ + toJSON() { return '<not implemented>'; } } +/** + * @param {string} fileName + * @returns {JSDOM} + */ function createJSDOM(fileName) { const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); const dom = new JSDOM(domSource); @@ -65,10 +89,20 @@ function createJSDOM(fileName) { return dom; } +/** + * @param {Element} element + * @param {string|undefined} selector + * @returns {?Element} + */ function querySelectorChildOrSelf(element, selector) { return selector ? element.querySelector(selector) : element; } +/** + * @param {JSDOM} dom + * @param {?Node} node + * @returns {?Text|Node} + */ function getChildTextNodeOrSelf(dom, node) { if (node === null) { return null; } const Node = dom.window.Node; @@ -76,6 +110,10 @@ function getChildTextNodeOrSelf(dom, node) { return (childNode !== null && childNode.nodeType === Node.TEXT_NODE ? childNode : node); } +/** + * @param {unknown} value + * @returns {unknown} + */ function getPrototypeOfOrNull(value) { try { return Object.getPrototypeOf(value); @@ -84,12 +122,17 @@ function getPrototypeOfOrNull(value) { } } +/** + * @param {Document} document + * @returns {?Element} + */ function findImposterElement(document) { // Finds the imposter element based on it's z-index style return document.querySelector('div[style*="2147483646"]>*'); } +/** */ async function testDocument1() { const dom = createJSDOM(path.join(dirname, 'data', 'html', 'test-document1.html')); const window = dom.window; @@ -102,13 +145,16 @@ async function testDocument1() { } } +/** + * @param {JSDOM} dom + */ async function testDocumentTextScanningFunctions(dom) { const document = dom.window.document; test('DocumentTextScanningFunctions', () => { - for (const testElement of document.querySelectorAll('.test[data-test-type=scan]')) { - // Get test parameters - let { + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=scan]'))) { + // Get test parameters + const { elementFromPointSelector, caretRangeFromPointSelector, startNodeSelector, @@ -127,10 +173,10 @@ async function testDocumentTextScanningFunctions(dom) { const startNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, startNodeSelector)); const endNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, endNodeSelector)); - startOffset = parseInt(startOffset, 10); - endOffset = parseInt(endOffset, 10); - sentenceScanExtent = parseInt(sentenceScanExtent, 10); - terminateAtNewlines = (terminateAtNewlines !== 'false'); + const startOffset2 = parseInt(/** @type {string} */ (startOffset), 10); + const endOffset2 = parseInt(/** @type {string} */ (endOffset), 10); + const sentenceScanExtent2 = parseInt(/** @type {string} */ (sentenceScanExtent), 10); + const terminateAtNewlines2 = (terminateAtNewlines !== 'false'); expect(elementFromPointValue).not.toStrictEqual(null); expect(caretRangeFromPointValue).not.toStrictEqual(null); @@ -145,11 +191,25 @@ async function testDocumentTextScanningFunctions(dom) { expect(!!imposter).toStrictEqual(hasImposter === 'true'); const range = document.createRange(); - range.setStart(imposter ? imposter : startNode, startOffset); - range.setEnd(imposter ? imposter : startNode, endOffset); + range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset2); + range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset2); // Override getClientRects to return a rect guaranteed to contain (x, y) - range.getClientRects = () => [new DOMRect(x - 1, y - 1, 2, 2)]; + 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; }; @@ -192,8 +252,8 @@ async function testDocumentTextScanningFunctions(dom) { const sentenceActual = DocumentUtil.extractSentence( source, false, - sentenceScanExtent, - terminateAtNewlines, + sentenceScanExtent2, + terminateAtNewlines2, terminatorMap, forwardQuoteMap, backwardQuoteMap @@ -206,13 +266,16 @@ async function testDocumentTextScanningFunctions(dom) { }); } +/** + * @param {JSDOM} dom + */ async function testTextSourceRangeSeekFunctions(dom) { const document = dom.window.document; test('TextSourceRangeSeekFunctions', async () => { - for (const testElement of document.querySelectorAll('.test[data-test-type=text-source-range-seek]')) { - // Get test parameters - let { + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=text-source-range-seek]'))) { + // Get test parameters + const { seekNodeSelector, seekNodeIsText, seekOffset, @@ -224,34 +287,37 @@ async function testTextSourceRangeSeekFunctions(dom) { expectedResultContent } = testElement.dataset; - seekOffset = parseInt(seekOffset, 10); - seekLength = parseInt(seekLength, 10); - expectedResultOffset = parseInt(expectedResultOffset, 10); + const seekOffset2 = parseInt(/** @type {string} */ (seekOffset), 10); + const seekLength2 = parseInt(/** @type {string} */ (seekLength), 10); + const expectedResultOffset2 = parseInt(/** @type {string} */ (expectedResultOffset), 10); - let seekNode = testElement.querySelector(seekNodeSelector); - if (seekNodeIsText === 'true') { + /** @type {?Node} */ + let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector)); + if (seekNodeIsText === 'true' && seekNode !== null) { seekNode = seekNode.firstChild; } - let expectedResultNode = testElement.querySelector(expectedResultNodeSelector); - if (expectedResultNodeIsText === 'true') { + /** @type {?Node} */ + let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector)); + if (expectedResultNodeIsText === 'true' && expectedResultNode !== null) { expectedResultNode = expectedResultNode.firstChild; } const {node, offset, content} = ( - seekDirection === 'forward' ? - new DOMTextScanner(seekNode, seekOffset, true, false).seek(seekLength) : - new DOMTextScanner(seekNode, seekOffset, true, false).seek(-seekLength) + seekDirection === 'forward' ? + new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(seekLength2) : + new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(-seekLength2) ); expect(node).toStrictEqual(expectedResultNode); - expect(offset).toStrictEqual(expectedResultOffset); + expect(offset).toStrictEqual(expectedResultOffset2); expect(content).toStrictEqual(expectedResultContent); } }); } +/** */ async function main() { await testDocument1(); } diff --git a/test/dom-text-scanner.test.js b/test/dom-text-scanner.test.js index d1b31276..6d0c047b 100644 --- a/test/dom-text-scanner.test.js +++ b/test/dom-text-scanner.test.js @@ -22,11 +22,21 @@ import path from 'path'; import {expect, test} from 'vitest'; import {DOMTextScanner} from '../ext/js/dom/dom-text-scanner.js'; + +/** + * @param {string} fileName + * @returns {JSDOM} + */ function createJSDOM(fileName) { const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); return new JSDOM(domSource); } +/** + * @param {Element} element + * @param {string} selector + * @returns {?Node} + */ function querySelectorTextNode(element, selector) { let textIndex = -1; const match = /::text$|::nth-text\((\d+)\)$/.exec(selector); @@ -35,13 +45,16 @@ function querySelectorTextNode(element, selector) { selector = selector.substring(0, selector.length - match[0].length); } const result = element.querySelector(selector); + if (result === null) { + return null; + } if (textIndex < 0) { return result; } for (let n = result.firstChild; n !== null; n = n.nextSibling) { - if (n.nodeType === n.constructor.TEXT_NODE) { + if (n.nodeType === /** @type {typeof Node} */ (n.constructor).TEXT_NODE) { if (textIndex === 0) { - return n; + return /** @type {Text} */ (n); } --textIndex; } @@ -50,10 +63,16 @@ function querySelectorTextNode(element, selector) { } +/** + * @param {import('jsdom').DOMWindow} window + * @param {(element: Element) => CSSStyleDeclaration} getComputedStyle + * @param {?Node} element + * @returns {number} + */ function getComputedFontSizeInPixels(window, getComputedStyle, element) { for (; element !== null; element = element.parentNode) { if (element.nodeType === window.Node.ELEMENT_NODE) { - const fontSize = getComputedStyle(element).fontSize; + const fontSize = getComputedStyle(/** @type {Element} */ (element)).fontSize; if (fontSize.endsWith('px')) { const value = parseFloat(fontSize.substring(0, fontSize.length - 2)); return value; @@ -64,14 +83,19 @@ function getComputedFontSizeInPixels(window, getComputedStyle, element) { return defaultFontSize; } +/** + * @param {import('jsdom').DOMWindow} window + * @returns {(element: Element, pseudoElement?: ?string) => CSSStyleDeclaration} + */ function createAbsoluteGetComputedStyle(window) { // Wrapper to convert em units to px units const getComputedStyleOld = window.getComputedStyle.bind(window); + /** @type {(element: Element, pseudoElement?: ?string) => CSSStyleDeclaration} */ return (element, ...args) => { const style = getComputedStyleOld(element, ...args); return new Proxy(style, { get: (target, property) => { - let result = target[property]; + let result = /** @type {import('core').SafeAny} */ (target)[property]; if (typeof result === 'string') { result = result.replace(/([-+]?\d(?:\.\d)?(?:[eE][-+]?\d+)?)em/g, (g0, g1) => { const fontSize = getComputedFontSizeInPixels(window, getComputedStyleOld, element); @@ -85,12 +109,15 @@ function createAbsoluteGetComputedStyle(window) { } +/** + * @param {JSDOM} dom + */ async function testDomTextScanner(dom) { const document = dom.window.document; test('DomTextScanner', () => { - for (const testElement of document.querySelectorAll('y-test')) { - let testData = JSON.parse(testElement.dataset.testData); + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('y-test'))) { + let testData = JSON.parse(/** @type {string} */ (testElement.dataset.testData)); if (!Array.isArray(testData)) { testData = [testData]; } @@ -159,19 +186,21 @@ async function testDomTextScanner(dom) { } +/** */ async function testDocument1() { const dom = createJSDOM(path.join(__dirname, 'data', 'html', 'test-dom-text-scanner.html')); const window = dom.window; try { window.getComputedStyle = createAbsoluteGetComputedStyle(window); - await testDomTextScanner(dom, {DOMTextScanner}); + await testDomTextScanner(dom); } finally { window.close(); } } +/** */ async function main() { await testDocument1(); } diff --git a/test/hotkey-util.test.js b/test/hotkey-util.test.js index 8666b98b..02622c40 100644 --- a/test/hotkey-util.test.js +++ b/test/hotkey-util.test.js @@ -19,8 +19,10 @@ import {expect, test} from 'vitest'; import {HotkeyUtil} from '../ext/js/input/hotkey-util.js'; +/** */ function testCommandConversions() { test('CommandConversions', () => { + /** @type {{os: import('environment').OperatingSystem, command: string, expectedCommand: string, expectedInput: {key: string, modifiers: import('input').Modifier[]}}[]} */ const data = [ {os: 'win', command: 'Alt+F', expectedCommand: 'Alt+F', expectedInput: {key: 'KeyF', modifiers: ['alt']}}, {os: 'win', command: 'F1', expectedCommand: 'F1', expectedInput: {key: 'F1', modifiers: []}}, @@ -49,8 +51,10 @@ function testCommandConversions() { }); } +/** */ function testDisplayNames() { test('DisplayNames', () => { + /** @type {{os: import('environment').OperatingSystem, key: ?string, modifiers: import('input').Modifier[], expected: string}[]} */ const data = [ {os: 'win', key: null, modifiers: [], expected: ''}, {os: 'win', key: 'KeyF', modifiers: [], expected: 'F'}, @@ -138,8 +142,10 @@ function testDisplayNames() { }); } +/** */ function testSortModifiers() { test('SortModifiers', () => { + /** @type {{modifiers: import('input').Modifier[], expected: import('input').Modifier[]}[]} */ const data = [ {modifiers: [], expected: []}, {modifiers: ['shift', 'alt', 'ctrl', 'mouse4', 'meta', 'mouse1', 'mouse0'], expected: ['meta', 'ctrl', 'alt', 'shift', 'mouse0', 'mouse1', 'mouse4']} @@ -155,6 +161,7 @@ function testSortModifiers() { } +/** */ function main() { testCommandConversions(); testDisplayNames(); |