aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/deinflector.test.js14
-rw-r--r--test/document-util.test.js118
-rw-r--r--test/dom-text-scanner.test.js43
-rw-r--r--test/hotkey-util.test.js7
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();