Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
1/*
2 * Copyright (C) 2023-2025 Yomitan Authors
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18import {describe, expect, afterAll, test, vi} from 'vitest';
19import {setupDomTest} from './fixtures/dom-test.js';
20import {querySelectorNotNull} from '../ext/js/dom/query-selector.js';
21import {SearchDisplayController} from '../ext/js/display/search-display-controller.js';
22import {Display} from '../ext/js/display/display.js';
23import {DisplayAudio} from '../ext/js/display/display-audio.js';
24import {SearchPersistentStateController} from '../ext/js/display/search-persistent-state-controller.js';
25import {Application} from '../ext/js/application.js';
26import {CrossFrameAPI} from '../ext/js/comm/cross-frame-api.js';
27import {API} from '../ext/js/comm/api.js';
28import {DocumentFocusController} from '../ext/js/dom/document-focus-controller.js';
29import {HotkeyHandler} from '../ext/js/input/hotkey-handler.js';
30import {WebExtension} from '../ext/js/extension/web-extension.js';
31
32const documentSearchDisplayControllerEnv = await setupDomTest('ext/search.html');
33
34const {window, teardown} = documentSearchDisplayControllerEnv;
35
36const {document} = window;
37
38const frameId = 1;
39const tabId = 1;
40const webExtension = new WebExtension();
41const hotkeyHandler = new HotkeyHandler();
42const documentFocusController = new DocumentFocusController();
43const displayPageType = 'search';
44const api = new API(webExtension);
45const crossFrameAPI = new CrossFrameAPI(api, tabId, frameId);
46const application = new Application(api, crossFrameAPI);
47const display = new Display(application, displayPageType, documentFocusController, hotkeyHandler);
48const displayAudio = new DisplayAudio(display);
49const searchPersistentStateController = new SearchPersistentStateController();
50
51const searchDisplayController = new SearchDisplayController(display, displayAudio, searchPersistentStateController);
52
53// eslint-disable-next-line no-underscore-dangle
54const onKeyDownMethod = searchDisplayController._onKeyDown.bind(searchDisplayController);
55
56/**
57 * @type {HTMLInputElement}
58 */
59const queryInput = querySelectorNotNull(document, '#search-textbox');
60
61const focusSpy = vi.spyOn(queryInput, 'focus');
62
63describe('Keyboard Event Handling', () => {
64 afterAll(() => teardown(global));
65
66 const validKeypressEvents = [
67 new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: false, altKey: false}),
68 new KeyboardEvent('keydown', {key: 'Backspace'}),
69 new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: true, metaKey: false, altKey: false}),
70 ];
71
72 const invalidKeypressEvents = [
73 new KeyboardEvent('keydown', {key: '', ctrlKey: true, metaKey: false, altKey: false}),
74 new KeyboardEvent('keydown', {key: '', ctrlKey: false, metaKey: true, altKey: false}),
75 new KeyboardEvent('keydown', {key: '', ctrlKey: false, metaKey: false, altKey: true}),
76 new KeyboardEvent('keydown', {key: ' ', ctrlKey: false, metaKey: false, altKey: false}),
77 new KeyboardEvent('keydown', {key: 'a', ctrlKey: true, metaKey: false, altKey: false}),
78 new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: true, altKey: false}),
79 new KeyboardEvent('keydown', {key: 'a', ctrlKey: false, metaKey: false, altKey: true}),
80 new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: false, metaKey: true, altKey: false}),
81 new KeyboardEvent('keydown', {key: 'Backspace', ctrlKey: false, metaKey: false, altKey: true}),
82 new KeyboardEvent('keydown', {key: 'ArrowDown'}),
83 ];
84
85 test('should test that onKeyDown function focuses input for valid keys', () => {
86 for (const event of validKeypressEvents) {
87 queryInput.blur();
88 onKeyDownMethod(event);
89 }
90
91 expect(focusSpy.mock.calls.length).toBe(validKeypressEvents.length);
92 focusSpy.mockReset();
93 });
94
95
96 test('should test that onKeyDown function does not focus input for invalid keys', () => {
97 for (const event of invalidKeypressEvents) {
98 queryInput.blur();
99 onKeyDownMethod(event);
100 }
101
102 expect(focusSpy.mock.calls.length).toBe(0);
103 });
104});