|
18 | 18 |
|
19 | 19 | import {fileURLToPath} from 'node:url';
|
20 | 20 | import path from 'path';
|
21 |
| -import {describe, expect} from 'vitest'; |
| 21 | +import {afterAll, describe, expect, test} from 'vitest'; |
22 | 22 | import {DocumentUtil} from '../ext/js/dom/document-util.js';
|
23 | 23 | import {DOMTextScanner} from '../ext/js/dom/dom-text-scanner.js';
|
24 | 24 | import {TextSourceElement} from '../ext/js/dom/text-source-element.js';
|
25 | 25 | import {TextSourceRange} from '../ext/js/dom/text-source-range.js';
|
26 |
| -import {createDomTest} from './fixtures/dom-test.js'; |
| 26 | +import {setupDomTest} from './fixtures/dom-test.js'; |
27 | 27 | import {parseJson} from '../dev/json.js';
|
28 | 28 |
|
29 | 29 | const dirname = path.dirname(fileURLToPath(import.meta.url));
|
@@ -110,165 +110,176 @@ function findImposterElement(document) {
|
110 | 110 | return document.querySelector('div[style*="2147483646"]>*');
|
111 | 111 | }
|
112 | 112 |
|
113 |
| -const test = createDomTest(path.join(dirname, 'data/html/document-util.html')); |
| 113 | +const documentUtilTestEnv = await setupDomTest(path.join(dirname, 'data/html/document-util.html')); |
114 | 114 |
|
115 |
| -describe('DocumentUtil', () => { |
116 |
| - test('Text scanning functions', ({window}) => { |
117 |
| - const {document} = window; |
118 |
| - for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=scan]'))) { |
119 |
| - // Get test parameters |
120 |
| - /** @type {import('test/document-util').DocumentUtilTestData} */ |
121 |
| - const { |
122 |
| - elementFromPointSelector, |
123 |
| - caretRangeFromPointSelector, |
124 |
| - startNodeSelector, |
125 |
| - startOffset, |
126 |
| - endNodeSelector, |
127 |
| - endOffset, |
128 |
| - resultType, |
129 |
| - sentenceScanExtent, |
130 |
| - sentence, |
131 |
| - hasImposter, |
132 |
| - terminateAtNewlines |
133 |
| - } = parseJson(/** @type {string} */ (testElement.dataset.testData)); |
| 115 | +describe('Document utility tests', () => { |
| 116 | + const {window, teardown} = documentUtilTestEnv; |
| 117 | + afterAll(() => teardown(global)); |
134 | 118 |
|
135 |
| - const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector); |
136 |
| - const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector); |
137 |
| - const startNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, startNodeSelector)); |
138 |
| - const endNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, endNodeSelector)); |
| 119 | + describe('DocumentUtil', () => { |
| 120 | + describe('Text scanning functions', () => { |
| 121 | + let testIndex = 0; |
| 122 | + const {document} = window; |
| 123 | + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=scan]'))) { |
| 124 | + test(`test-case-${testIndex++}`, () => { |
| 125 | + // Get test parameters |
| 126 | + /** @type {import('test/document-util').DocumentUtilTestData} */ |
| 127 | + const { |
| 128 | + elementFromPointSelector, |
| 129 | + caretRangeFromPointSelector, |
| 130 | + startNodeSelector, |
| 131 | + startOffset, |
| 132 | + endNodeSelector, |
| 133 | + endOffset, |
| 134 | + resultType, |
| 135 | + sentenceScanExtent, |
| 136 | + sentence, |
| 137 | + hasImposter, |
| 138 | + terminateAtNewlines |
| 139 | + } = parseJson(/** @type {string} */ (testElement.dataset.testData)); |
139 | 140 |
|
140 |
| - // Defaults to true |
141 |
| - const terminateAtNewlines2 = typeof terminateAtNewlines === 'boolean' ? terminateAtNewlines : true; |
| 141 | + const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector); |
| 142 | + const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector); |
| 143 | + const startNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, startNodeSelector)); |
| 144 | + const endNode = getChildTextNodeOrSelf(window, querySelectorChildOrSelf(testElement, endNodeSelector)); |
142 | 145 |
|
143 |
| - expect(elementFromPointValue).not.toStrictEqual(null); |
144 |
| - expect(caretRangeFromPointValue).not.toStrictEqual(null); |
145 |
| - expect(startNode).not.toStrictEqual(null); |
146 |
| - expect(endNode).not.toStrictEqual(null); |
| 146 | + // Defaults to true |
| 147 | + const terminateAtNewlines2 = typeof terminateAtNewlines === 'boolean' ? terminateAtNewlines : true; |
147 | 148 |
|
148 |
| - // Setup functions |
149 |
| - document.elementFromPoint = () => elementFromPointValue; |
| 149 | + expect(elementFromPointValue).not.toStrictEqual(null); |
| 150 | + expect(caretRangeFromPointValue).not.toStrictEqual(null); |
| 151 | + expect(startNode).not.toStrictEqual(null); |
| 152 | + expect(endNode).not.toStrictEqual(null); |
150 | 153 |
|
151 |
| - document.caretRangeFromPoint = (x, y) => { |
152 |
| - const imposter = getChildTextNodeOrSelf(window, findImposterElement(document)); |
153 |
| - expect(!!imposter).toStrictEqual(!!hasImposter); |
| 154 | + // Setup functions |
| 155 | + document.elementFromPoint = () => elementFromPointValue; |
154 | 156 |
|
155 |
| - const range = document.createRange(); |
156 |
| - range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset); |
157 |
| - range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset); |
| 157 | + document.caretRangeFromPoint = (x, y) => { |
| 158 | + const imposter = getChildTextNodeOrSelf(window, findImposterElement(document)); |
| 159 | + expect(!!imposter).toStrictEqual(!!hasImposter); |
158 | 160 |
|
159 |
| - // Override getClientRects to return a rect guaranteed to contain (x, y) |
160 |
| - range.getClientRects = () => { |
161 |
| - /** @type {import('test/document-types').PseudoDOMRectList} */ |
162 |
| - const domRectList = Object.assign( |
163 |
| - [new DOMRect(x - 1, y - 1, 2, 2)], |
164 |
| - { |
165 |
| - /** |
166 |
| - * @this {DOMRect[]} |
167 |
| - * @param {number} index |
168 |
| - * @returns {DOMRect} |
169 |
| - */ |
170 |
| - item: function item(index) { return this[index]; } |
171 |
| - } |
172 |
| - ); |
173 |
| - return domRectList; |
174 |
| - }; |
175 |
| - return range; |
176 |
| - }; |
| 161 | + const range = document.createRange(); |
| 162 | + range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset); |
| 163 | + range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset); |
177 | 164 |
|
178 |
| - // Test docRangeFromPoint |
179 |
| - const source = DocumentUtil.getRangeFromPoint(0, 0, { |
180 |
| - deepContentScan: false, |
181 |
| - normalizeCssZoom: true |
182 |
| - }); |
183 |
| - switch (resultType) { |
184 |
| - case 'TextSourceRange': |
185 |
| - expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceRange.prototype); |
186 |
| - break; |
187 |
| - case 'TextSourceElement': |
188 |
| - expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceElement.prototype); |
189 |
| - break; |
190 |
| - case 'null': |
191 |
| - expect(source).toStrictEqual(null); |
192 |
| - break; |
193 |
| - default: |
194 |
| - expect.unreachable(); |
195 |
| - break; |
196 |
| - } |
197 |
| - if (source === null) { continue; } |
| 165 | + // Override getClientRects to return a rect guaranteed to contain (x, y) |
| 166 | + range.getClientRects = () => { |
| 167 | + /** @type {import('test/document-types').PseudoDOMRectList} */ |
| 168 | + const domRectList = Object.assign( |
| 169 | + [new DOMRect(x - 1, y - 1, 2, 2)], |
| 170 | + { |
| 171 | + /** |
| 172 | + * @this {DOMRect[]} |
| 173 | + * @param {number} index |
| 174 | + * @returns {DOMRect} |
| 175 | + */ |
| 176 | + item: function item(index) { return this[index]; } |
| 177 | + } |
| 178 | + ); |
| 179 | + return domRectList; |
| 180 | + }; |
| 181 | + return range; |
| 182 | + }; |
198 | 183 |
|
199 |
| - // Sentence info |
200 |
| - const terminatorString = '…。..??!!'; |
201 |
| - const terminatorMap = new Map(); |
202 |
| - for (const char of terminatorString) { |
203 |
| - terminatorMap.set(char, [false, true]); |
204 |
| - } |
205 |
| - const quoteArray = [['「', '」'], ['『', '』'], ['\'', '\''], ['"', '"']]; |
206 |
| - const forwardQuoteMap = new Map(); |
207 |
| - const backwardQuoteMap = new Map(); |
208 |
| - for (const [char1, char2] of quoteArray) { |
209 |
| - forwardQuoteMap.set(char1, [char2, false]); |
210 |
| - backwardQuoteMap.set(char2, [char1, false]); |
211 |
| - } |
| 184 | + // Test docRangeFromPoint |
| 185 | + const source = DocumentUtil.getRangeFromPoint(0, 0, { |
| 186 | + deepContentScan: false, |
| 187 | + normalizeCssZoom: true |
| 188 | + }); |
| 189 | + switch (resultType) { |
| 190 | + case 'TextSourceRange': |
| 191 | + expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceRange.prototype); |
| 192 | + break; |
| 193 | + case 'TextSourceElement': |
| 194 | + expect(getPrototypeOfOrNull(source)).toStrictEqual(TextSourceElement.prototype); |
| 195 | + break; |
| 196 | + case 'null': |
| 197 | + expect(source).toStrictEqual(null); |
| 198 | + break; |
| 199 | + default: |
| 200 | + expect.unreachable(); |
| 201 | + break; |
| 202 | + } |
| 203 | + if (source === null) { return; } |
| 204 | + |
| 205 | + // Sentence info |
| 206 | + const terminatorString = '…。..??!!'; |
| 207 | + const terminatorMap = new Map(); |
| 208 | + for (const char of terminatorString) { |
| 209 | + terminatorMap.set(char, [false, true]); |
| 210 | + } |
| 211 | + const quoteArray = [['「', '」'], ['『', '』'], ['\'', '\''], ['"', '"']]; |
| 212 | + const forwardQuoteMap = new Map(); |
| 213 | + const backwardQuoteMap = new Map(); |
| 214 | + for (const [char1, char2] of quoteArray) { |
| 215 | + forwardQuoteMap.set(char1, [char2, false]); |
| 216 | + backwardQuoteMap.set(char2, [char1, false]); |
| 217 | + } |
212 | 218 |
|
213 |
| - // Test docSentenceExtract |
214 |
| - const sentenceActual = DocumentUtil.extractSentence( |
215 |
| - source, |
216 |
| - false, |
217 |
| - sentenceScanExtent, |
218 |
| - terminateAtNewlines2, |
219 |
| - terminatorMap, |
220 |
| - forwardQuoteMap, |
221 |
| - backwardQuoteMap |
222 |
| - ).text; |
223 |
| - expect(sentenceActual).toStrictEqual(sentence); |
| 219 | + // Test docSentenceExtract |
| 220 | + const sentenceActual = DocumentUtil.extractSentence( |
| 221 | + source, |
| 222 | + false, |
| 223 | + sentenceScanExtent, |
| 224 | + terminateAtNewlines2, |
| 225 | + terminatorMap, |
| 226 | + forwardQuoteMap, |
| 227 | + backwardQuoteMap |
| 228 | + ).text; |
| 229 | + expect(sentenceActual).toStrictEqual(sentence); |
224 | 230 |
|
225 |
| - // Clean |
226 |
| - source.cleanup(); |
227 |
| - } |
| 231 | + // Clean |
| 232 | + source.cleanup(); |
| 233 | + }); |
| 234 | + } |
| 235 | + }); |
228 | 236 | });
|
229 |
| -}); |
230 | 237 |
|
231 |
| -describe('DOMTextScanner', () => { |
232 |
| - test('Seek functions', async ({window}) => { |
233 |
| - const {document} = window; |
234 |
| - for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=text-source-range-seek]'))) { |
235 |
| - // Get test parameters |
236 |
| - /** @type {import('test/document-util').DOMTextScannerTestData} */ |
237 |
| - const { |
238 |
| - seekNodeSelector, |
239 |
| - seekNodeIsText, |
240 |
| - seekOffset, |
241 |
| - seekLength, |
242 |
| - seekDirection, |
243 |
| - expectedResultNodeSelector, |
244 |
| - expectedResultNodeIsText, |
245 |
| - expectedResultOffset, |
246 |
| - expectedResultContent |
247 |
| - } = parseJson(/** @type {string} */ (testElement.dataset.testData)); |
| 238 | + describe('DOMTextScanner', () => { |
| 239 | + describe('Seek functions', () => { |
| 240 | + let testIndex = 0; |
| 241 | + const {document} = window; |
| 242 | + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case[data-test-type=text-source-range-seek]'))) { |
| 243 | + test(`test-case-${testIndex++}`, () => { |
| 244 | + // Get test parameters |
| 245 | + /** @type {import('test/document-util').DOMTextScannerTestData} */ |
| 246 | + const { |
| 247 | + seekNodeSelector, |
| 248 | + seekNodeIsText, |
| 249 | + seekOffset, |
| 250 | + seekLength, |
| 251 | + seekDirection, |
| 252 | + expectedResultNodeSelector, |
| 253 | + expectedResultNodeIsText, |
| 254 | + expectedResultOffset, |
| 255 | + expectedResultContent |
| 256 | + } = parseJson(/** @type {string} */ (testElement.dataset.testData)); |
248 | 257 |
|
249 |
| - /** @type {?Node} */ |
250 |
| - let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector)); |
251 |
| - if (seekNodeIsText && seekNode !== null) { |
252 |
| - seekNode = seekNode.firstChild; |
253 |
| - } |
| 258 | + /** @type {?Node} */ |
| 259 | + let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector)); |
| 260 | + if (seekNodeIsText && seekNode !== null) { |
| 261 | + seekNode = seekNode.firstChild; |
| 262 | + } |
254 | 263 |
|
255 |
| - const expectedResultContent2 = expectedResultContent.join('\n'); |
| 264 | + const expectedResultContent2 = expectedResultContent.join('\n'); |
256 | 265 |
|
257 |
| - /** @type {?Node} */ |
258 |
| - let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector)); |
259 |
| - if (expectedResultNodeIsText && expectedResultNode !== null) { |
260 |
| - expectedResultNode = expectedResultNode.firstChild; |
261 |
| - } |
| 266 | + /** @type {?Node} */ |
| 267 | + let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector)); |
| 268 | + if (expectedResultNodeIsText && expectedResultNode !== null) { |
| 269 | + expectedResultNode = expectedResultNode.firstChild; |
| 270 | + } |
262 | 271 |
|
263 |
| - const {node, offset, content} = ( |
| 272 | + const {node, offset, content} = ( |
264 | 273 | seekDirection === 'forward' ?
|
265 | 274 | new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset, true, false).seek(seekLength) :
|
266 | 275 | new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset, true, false).seek(-seekLength)
|
267 |
| - ); |
| 276 | + ); |
268 | 277 |
|
269 |
| - expect(node).toStrictEqual(expectedResultNode); |
270 |
| - expect(offset).toStrictEqual(expectedResultOffset); |
271 |
| - expect(content).toStrictEqual(expectedResultContent2); |
272 |
| - } |
| 278 | + expect(node).toStrictEqual(expectedResultNode); |
| 279 | + expect(offset).toStrictEqual(expectedResultOffset); |
| 280 | + expect(content).toStrictEqual(expectedResultContent2); |
| 281 | + }); |
| 282 | + } |
| 283 | + }); |
273 | 284 | });
|
274 | 285 | });
|
0 commit comments