diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2024-02-08 06:52:06 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-08 11:52:06 +0000 |
commit | d4381831209dfbbbddd6d238c68461c9601573e2 (patch) | |
tree | 87839d80f838464ff92ebc7fa652029b9329cc96 /test | |
parent | 725a90dd6570044a3df6631051aaab8b026ca6c2 (diff) |
Update eslint (#638)
* Add json test
* Update vscode settings to better handle json
* Collapse eslint rules for easier readability
* Reorganize
* Update no-multi-spaces rule for JSON
* Rules updates
* Switch to @stylistic/eslint-plugin
* Update deprecated stylistic rules
* Group stylistic rules
* Simplify rules
* Move eslint env overrides to end of file
* Add test
* Move promiseAnimationFrame to separate file
* Remove unneeded eslint disable
* Remove unneeded
Diffstat (limited to 'test')
-rw-r--r-- | test/cache-map.test.js | 4 | ||||
-rw-r--r-- | test/data/dictionaries/valid-dictionary1/term_bank_1.json | 8 | ||||
-rw-r--r-- | test/eslint-config.test.js | 172 | ||||
-rw-r--r-- | test/hotkey-util.test.js | 8 | ||||
-rw-r--r-- | test/json-schema.test.js | 8 | ||||
-rw-r--r-- | test/language-transformer.test.js | 4 | ||||
-rw-r--r-- | test/options-util.test.js | 4 | ||||
-rw-r--r-- | test/playwright/playwright-util.js | 3 | ||||
-rw-r--r-- | test/playwright/visual.spec.js | 4 | ||||
-rw-r--r-- | test/profile-conditions-util.test.js | 4 |
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); |