Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
1/*
2 * Copyright (C) 2023-2025 Yomitan Authors
3 * Copyright (C) 2020-2022 Yomichan Authors
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19import fs from 'fs';
20import {test} from 'vitest';
21import {builtinEnvironments} from 'vitest/environments';
22
23/**
24 * @param {import('jsdom').DOMWindow} window
25 */
26function prepareWindow(window) {
27 const {document} = window;
28
29 // Define innerText setter as an alias for textContent setter
30 Object.defineProperty(window.HTMLDivElement.prototype, 'innerText', {
31 /** @returns {string} */
32 get() { return this.textContent; },
33 /** @param {string} value */
34 set(value) { this.textContent = value; },
35 });
36
37 // Placeholder for feature detection
38 document.caretRangeFromPoint = () => null;
39}
40
41/**
42 *
43 * @param {string} [htmlFilePath]
44 * @returns {Promise<{window: import('jsdom').DOMWindow; teardown: (global: unknown) => import('vitest').Awaitable<void>}>}
45 */
46export async function setupDomTest(htmlFilePath) {
47 const html = typeof htmlFilePath === 'string' ? fs.readFileSync(htmlFilePath, {encoding: 'utf8'}) : '<!DOCTYPE html>';
48 const env = builtinEnvironments.jsdom;
49 const environment = await env.setup(global, {jsdom: {html}});
50 const window = /** @type {import('jsdom').DOMWindow} */ (/** @type {unknown} */ (global.window));
51 prepareWindow(window);
52 return {
53 window,
54 teardown: (global) => environment.teardown(global),
55 };
56}
57
58/**
59 * @param {string} [htmlFilePath]
60 * @returns {import('vitest').TestAPI<{window: import('jsdom').DOMWindow}>}
61 */
62export function createDomTest(htmlFilePath) {
63 const html = typeof htmlFilePath === 'string' ? fs.readFileSync(htmlFilePath, {encoding: 'utf8'}) : '<!DOCTYPE html>';
64 return test.extend({
65 // eslint-disable-next-line no-empty-pattern
66 window: async ({}, use) => {
67 const env = builtinEnvironments.jsdom;
68 const environment = await env.setup(global, {jsdom: {html}});
69 const window = /** @type {import('jsdom').DOMWindow} */ (/** @type {unknown} */ (global.window));
70 prepareWindow(window);
71 try {
72 await use(window);
73 } finally {
74 await environment.teardown(global);
75 }
76 },
77 });
78}