aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/cache-map.test.js4
-rw-r--r--test/data/dictionaries/valid-dictionary1/term_bank_1.json8
-rw-r--r--test/eslint-config.test.js172
-rw-r--r--test/hotkey-util.test.js8
-rw-r--r--test/json-schema.test.js8
-rw-r--r--test/language-transformer.test.js4
-rw-r--r--test/options-util.test.js4
-rw-r--r--test/playwright/playwright-util.js3
-rw-r--r--test/playwright/visual.spec.js4
-rw-r--r--test/profile-conditions-util.test.js4
10 files changed, 196 insertions, 23 deletions
diff --git a/test/cache-map.test.js b/test/cache-map.test.js
index 868c5d9a..9be5363a 100644
--- a/test/cache-map.test.js
+++ b/test/cache-map.test.js
@@ -37,7 +37,7 @@ function testConstructor() {
/** */
function testApi() {
describe('api', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
const data = [
{
maxSize: 1,
@@ -89,7 +89,7 @@ function testApi() {
]
}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
test.each(data)('api-test-%#', ({maxSize, expectedSize, calls}) => {
const cache = new CacheMap(maxSize);
diff --git a/test/data/dictionaries/valid-dictionary1/term_bank_1.json b/test/data/dictionaries/valid-dictionary1/term_bank_1.json
index d2012d33..ae32d146 100644
--- a/test/data/dictionaries/valid-dictionary1/term_bank_1.json
+++ b/test/data/dictionaries/valid-dictionary1/term_bank_1.json
@@ -2,13 +2,13 @@
["打", "だ", "n", "n", 1, ["da definition 1", "da definition 2"], 1, "E1"],
["打", "ダース", "n abbr", "n", 1, ["daasu definition 1", "daasu definition 2"], 2, "E1"],
["打つ", "うつ", "vt", "v5", 10, ["utsu definition 1", "utsu definition 2"], 3, "P E1"],
- ["打つ", "うつ", "vt", "v5", 1, ["utsu definition 3", "utsu definition 4"], 3, "P E2"],
+ ["打つ", "うつ", "vt", "v5", 1, ["utsu definition 3", "utsu definition 4"], 3, "P E2"],
["打つ", "ぶつ", "vt", "v5", 10, ["butsu definition 1", "butsu definition 2"], 3, "P E1"],
- ["打つ", "ぶつ", "vt", "v5", 1, ["butsu definition 3", "butsu definition 4"], 3, "P E2"],
+ ["打つ", "ぶつ", "vt", "v5", 1, ["butsu definition 3", "butsu definition 4"], 3, "P E2"],
["打ち込む", "うちこむ", "vt", "v5", 10, ["uchikomu definition 1", "uchikomu definition 2"], 4, "P E1"],
- ["打ち込む", "うちこむ", "vt", "v5", 1, ["uchikomu definition 3", "uchikomu definition 4"], 4, "P E2"],
+ ["打ち込む", "うちこむ", "vt", "v5", 1, ["uchikomu definition 3", "uchikomu definition 4"], 4, "P E2"],
["打ち込む", "ぶちこむ", "vt", "v5", 10, ["buchikomu definition 1", "buchikomu definition 2"], 4, "P E1"],
- ["打ち込む", "ぶちこむ", "vt", "v5", 1, ["buchikomu definition 3", "buchikomu definition 4"], 4, "P E2"],
+ ["打ち込む", "ぶちこむ", "vt", "v5", 1, ["buchikomu definition 3", "buchikomu definition 4"], 4, "P E2"],
["画像", "がぞう", "n", "n", 1, ["gazou definition 1", {"type": "image", "path": "image.gif", "width": 350, "height": 350, "description": "gazou definition 2", "pixelated": true}], 5, "P E1"],
["読む", "よむ", "vt", "v5", 100, ["to read"], 6, "P E1"],
["強み", "つよみ", "n", "n", 90, ["strong point"], 7, "P E1"],
diff --git a/test/eslint-config.test.js b/test/eslint-config.test.js
new file mode 100644
index 00000000..bddde695
--- /dev/null
+++ b/test/eslint-config.test.js
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2024 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import esbuild from 'esbuild';
+import {readFileSync} from 'fs';
+import {dirname, join} from 'path';
+import {fileURLToPath} from 'url';
+import {describe, test} from 'vitest';
+import {parseJson} from '../dev/json.js';
+
+const rootDir = join(dirname(fileURLToPath(import.meta.url)), '..');
+
+/**
+ * @param {string[]} scriptPaths
+ * @returns {Promise<string[]>}
+ */
+async function getDependencies(scriptPaths) {
+ const v = await esbuild.build({
+ entryPoints: scriptPaths,
+ bundle: true,
+ minify: false,
+ sourcemap: true,
+ target: 'es2022',
+ format: 'esm',
+ write: false,
+ metafile: true
+ });
+ const dependencies = Object.keys(v.metafile.inputs);
+ const stringComparer = new Intl.Collator('en-US'); // Invariant locale
+ dependencies.sort((a, b) => stringComparer.compare(a, b));
+ return dependencies;
+}
+
+/**
+ * @param {string[]} dependencies
+ * @returns {string[]}
+ */
+function removeLibraryDependencies(dependencies) {
+ const pattern = /^ext\/lib\//;
+ return dependencies.filter((v) => !pattern.test(v));
+}
+
+/**
+ * @param {{[key: string]: boolean}|undefined} env1
+ * @param {{[key: string]: boolean}} env2
+ * @returns {boolean}
+ */
+function envMatches(env1, env2) {
+ if (typeof env1 !== 'object' || env1 === null) { return false; }
+ const map1 = new Map(Object.entries(env1));
+ const map2 = new Map(Object.entries(env2));
+ if (map1.size !== map2.size) { return false; }
+ for (const [k1, v1] of map1) {
+ if (map2.get(k1) !== v1) { return false; }
+ }
+ return true;
+}
+
+/**
+ * @param {string[]} files1
+ * @param {string[]} files2
+ * @returns {boolean}
+ */
+function filesMatch(files1, files2) {
+ if (!Array.isArray(files1)) { return false; }
+ const set1 = new Set(files1);
+ const set2 = new Set(files2);
+ if (set1.size !== set2.size) { return false; }
+ for (const v of set1) {
+ if (!set2.has(v)) { return false; }
+ }
+ return true;
+}
+
+const targets = [
+ {
+ name: 'sandbox',
+ paths: [
+ 'ext/js/templates/sandbox/template-renderer-frame-main.js'
+ ],
+ /** @type {{[key: string]: boolean}} */
+ env: {
+ webextensions: false
+ }
+ },
+ {
+ name: 'worker',
+ paths: [
+ 'ext/js/dictionary/dictionary-worker-main.js'
+ ],
+ /** @type {{[key: string]: boolean}} */
+ env: {
+ browser: false,
+ worker: true
+ }
+ },
+ {
+ name: 'serviceworker',
+ paths: [
+ 'ext/js/background/background-main.js'
+ ],
+ /** @type {{[key: string]: boolean}} */
+ env: {
+ browser: false,
+ serviceworker: true
+ }
+ }
+];
+
+describe('Eslint configuration', () => {
+ const eslintConfigPath = '.eslintrc.json';
+ /** @type {import('core').SafeAny} */
+ const eslintConfig = parseJson(readFileSync(join(rootDir, eslintConfigPath), 'utf8'));
+ describe.each(targets)('Environment is $name', ({name, paths, env}) => {
+ test('Entry exists', async ({expect}) => {
+ const fullPaths = paths.map((v) => join(rootDir, v));
+ const dependencies = removeLibraryDependencies(await getDependencies(fullPaths));
+
+ let okay = false;
+ const candidates = [];
+ const {overrides} = eslintConfig;
+ for (let i = 0, ii = overrides.length; i < ii; ++i) {
+ const override = overrides[i];
+ if (!envMatches(override.env, env)) { continue; }
+ const {files} = override;
+ if (!Array.isArray(files)) { continue; }
+ candidates.push(i);
+ if (filesMatch(files, dependencies)) {
+ okay = true;
+ break;
+ }
+ }
+
+ if (okay) { return; }
+ switch (candidates.length) {
+ case 0:
+ {
+ const message = `No override found with "${name}" environment: ${JSON.stringify(env)}`;
+ expect(false, message).toStrictEqual(true);
+ }
+ break;
+ case 1:
+ {
+ const index = candidates[0];
+ const message = `Override at index ${index} does not have the expected files for the "${name}" environment.`;
+ expect(overrides[index].files, message).toStrictEqual(dependencies);
+ }
+ break;
+ default:
+ {
+ const message = `No override found with the correct file list for the "${name}" environment; candidate indices: [${candidates.join(', ')}].`;
+ expect([], message).toStrictEqual(dependencies);
+ }
+ break;
+ }
+ });
+ });
+});
diff --git a/test/hotkey-util.test.js b/test/hotkey-util.test.js
index 0a76d0f2..bf1124a5 100644
--- a/test/hotkey-util.test.js
+++ b/test/hotkey-util.test.js
@@ -22,7 +22,7 @@ import {HotkeyUtil} from '../ext/js/input/hotkey-util.js';
/** */
function testCommandConversions() {
describe('CommandConversions', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
/** @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']}},
@@ -40,7 +40,7 @@ function testCommandConversions() {
{os: 'linux', command: 'MacCtrl+Alt+Shift+F1', expectedCommand: 'Ctrl+Alt+Shift+F1', expectedInput: {key: 'F1', modifiers: ['ctrl', 'alt', 'shift']}},
{os: 'linux', command: 'Command+Alt+Shift+F1', expectedCommand: 'Command+Alt+Shift+F1', expectedInput: {key: 'F1', modifiers: ['meta', 'alt', 'shift']}}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
const hotkeyUtil = new HotkeyUtil();
for (const {command, os, expectedInput, expectedCommand} of data) {
@@ -58,7 +58,7 @@ function testCommandConversions() {
/** */
function testDisplayNames() {
describe('DisplayNames', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
/** @type {{os: import('environment').OperatingSystem, key: ?string, modifiers: import('input').Modifier[], expected: string}[]} */
const data = [
{os: 'win', key: null, modifiers: [], expected: ''},
@@ -137,7 +137,7 @@ function testDisplayNames() {
{os: 'unknown', key: 'KeyF', modifiers: ['mouse1'], expected: 'Mouse 1 + F'},
{os: 'unknown', key: 'F1', modifiers: ['mouse1'], expected: 'Mouse 1 + F1'}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
const hotkeyUtil = new HotkeyUtil();
diff --git a/test/json-schema.test.js b/test/json-schema.test.js
index a3686758..ab2c0c65 100644
--- a/test/json-schema.test.js
+++ b/test/json-schema.test.js
@@ -123,7 +123,7 @@ function testValidate1() {
/** */
function testValidate2() {
describe('Validate2', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
/** @type {{schema: import('ext/json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */
const data = [
// String tests
@@ -517,7 +517,7 @@ function testValidate2() {
]
}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
describe.each(data)('Schema %#', ({schema, inputs}) => {
test.each(inputs)(`schemaValidate(${schema}, $value) -> $expected`, ({expected, value}) => {
@@ -890,7 +890,7 @@ function testGetValidValueOrDefault1() {
/** */
function testProxy1() {
describe('Proxy1', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
/** @type {{schema: import('ext/json-schema').Schema, tests: {error: boolean, value?: import('ext/json-schema').Value, action: (value: import('core').SafeAny) => void}[]}[]} */
const data = [
// Object tests
@@ -1020,7 +1020,7 @@ function testProxy1() {
]
}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
describe.each(data)('Schema %#', ({schema, tests}) => {
test.each(tests)('proxy %#', ({error, value, action}) => {
diff --git a/test/language-transformer.test.js b/test/language-transformer.test.js
index 9e9a9ee3..857b5ed0 100644
--- a/test/language-transformer.test.js
+++ b/test/language-transformer.test.js
@@ -64,7 +64,7 @@ function hasTermReasons(languageTransformer, source, expectedTerm, expectedCondi
/** */
function testDeinflections() {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
const data = [
{
category: 'adjectives',
@@ -1146,7 +1146,7 @@ function testDeinflections() {
]
}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
/** @type {import('language-transformer').LanguageTransformDescriptor} */
const descriptor = parseJson(fs.readFileSync(path.join(dirname, '..', 'ext', 'data/language/japanese-transforms.json'), {encoding: 'utf8'}));
diff --git a/test/options-util.test.js b/test/options-util.test.js
index 25abe715..4a75fa14 100644
--- a/test/options-util.test.js
+++ b/test/options-util.test.js
@@ -475,7 +475,7 @@ function createProfileOptionsUpdatedTestData1() {
]
},
inputs: {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
hotkeys: [
{action: 'close', argument: '', key: 'Escape', modifiers: [], scopes: ['popup'], enabled: true},
{action: 'focusSearchBox', argument: '', key: 'Escape', modifiers: [], scopes: ['search'], enabled: true},
@@ -494,7 +494,7 @@ function createProfileOptionsUpdatedTestData1() {
{action: 'viewNote', argument: '', key: 'KeyV', modifiers: ['alt'], scopes: ['popup', 'search'], enabled: true},
{action: 'copyHostSelection', argument: '', key: 'KeyC', modifiers: ['ctrl'], scopes: ['popup'], enabled: true}
]
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
},
popupWindow: {
width: 400,
diff --git a/test/playwright/playwright-util.js b/test/playwright/playwright-util.js
index 425d6140..bf171251 100644
--- a/test/playwright/playwright-util.js
+++ b/test/playwright/playwright-util.js
@@ -23,7 +23,8 @@ const dirname = path.dirname(fileURLToPath(import.meta.url));
export const root = path.join(dirname, '..', '..');
export const test = base.extend({
- context: async ({ }, use) => {
+ // eslint-disable-next-line no-empty-pattern
+ context: async ({}, use) => {
const pathToExtension = path.join(root, 'ext');
const context = await chromium.launchPersistentContext('', {
// headless: false,
diff --git a/test/playwright/visual.spec.js b/test/playwright/visual.spec.js
index 3ecf4c6e..cc2a50d0 100644
--- a/test/playwright/visual.spec.js
+++ b/test/playwright/visual.spec.js
@@ -60,11 +60,11 @@ test('visual', async ({page, extensionId}) => {
// Otherwise prepare for it to be attached
let frame_attached;
- if (popup_frame === undefined) {
+ if (typeof popup_frame === 'undefined') {
frame_attached = page.waitForEvent('frameattached');
}
await page.mouse.move(box.x + offset.x, box.y + offset.y, {steps: 10}); // hover over the test
- if (popup_frame === undefined) {
+ if (typeof popup_frame === 'undefined') {
popup_frame = await frame_attached; // wait for popup to be attached
}
try {
diff --git a/test/profile-conditions-util.test.js b/test/profile-conditions-util.test.js
index fcd53939..261225d9 100644
--- a/test/profile-conditions-util.test.js
+++ b/test/profile-conditions-util.test.js
@@ -59,7 +59,7 @@ function testNormalizeContext() {
/** */
function testSchemas() {
describe('Schemas', () => {
- /* eslint-disable no-multi-spaces */
+ /* eslint-disable @stylistic/no-multi-spaces */
/** @type {{conditionGroups: import('settings').ProfileConditionGroup[], expectedSchema?: import('ext/json-schema').Schema, inputs?: {expected: boolean, context: import('settings').OptionsContext}[]}[]} */
const data = [
// Empty
@@ -1097,7 +1097,7 @@ function testSchemas() {
]
}
];
- /* eslint-enable no-multi-spaces */
+ /* eslint-enable @stylistic/no-multi-spaces */
test.each(data)('schemas-test-%#', ({conditionGroups, expectedSchema, inputs}) => {
const schema = createSchema(conditionGroups);