diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2023-12-20 00:47:15 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-20 05:47:15 +0000 |
commit | 8b943cc97fab890085448122e7c13dd035d0e238 (patch) | |
tree | a7a749a44771c6a82b1b72bb35cc0c81d57ddb54 /test | |
parent | b13fbd47941fc20cf623871396e34a6dfe9b4dba (diff) |
JSON validation (#394)
* Set up JSON testing
* Add schema validation
* Use parseJson
* Finish types
* Disambiguate ext/json-schema from node dependency with the same name
* Add support for specifying the jsconfig file
* Don't expose types
* Update types
* Use dictionary map type
* Fix types
* Fix AJV warnings
* Move types
* Move anb rename file
* Move common mocks
* Simplify types
Diffstat (limited to 'test')
-rw-r--r-- | test/data/json.json | 174 | ||||
-rw-r--r-- | test/data/translator-test-inputs.json | 12 | ||||
-rw-r--r-- | test/fixtures/translator-test.js | 36 | ||||
-rw-r--r-- | test/jsconfig.json | 4 | ||||
-rw-r--r-- | test/json-schema.test.js | 22 | ||||
-rw-r--r-- | test/json.test.js | 189 | ||||
-rw-r--r-- | test/mocks/common.js | 52 | ||||
-rw-r--r-- | test/options-util.test.js | 29 | ||||
-rw-r--r-- | test/profile-conditions-util.test.js | 2 | ||||
-rw-r--r-- | test/utilities/translator.js | 5 |
10 files changed, 444 insertions, 81 deletions
diff --git a/test/data/json.json b/test/data/json.json new file mode 100644 index 00000000..6d806263 --- /dev/null +++ b/test/data/json.json @@ -0,0 +1,174 @@ +{ + "files": [ + {"path": "package.json", "ignore": true}, + {"path": "package-lock.json", "ignore": true}, + {"path": "jsconfig.json", "ignore": true}, + {"path": ".stylelintrc.json", "ignore": true}, + {"path": ".htmlvalidate.json", "ignore": true}, + {"path": ".eslintrc.json", "ignore": true}, + {"path": ".vscode/settings.json", "ignore": true}, + {"path": ".vscode/extensions.json", "ignore": true}, + {"path": "dev/jsconfig.json", "ignore": true}, + {"path": "ext/manifest.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary1/index.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary2/kanji_bank_1.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary2/index.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary3/kanji_meta_bank_1.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary3/index.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary4/tag_bank_1.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary4/index.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary5/term_bank_1.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary5/index.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary6/term_meta_bank_1.json", "ignore": true}, + {"path": "test/data/dictionaries/invalid-dictionary6/index.json", "ignore": true}, + {"path": "test/jsconfig.json", "ignore": true}, + + { + "path": "dev/data/manifest-variants.json", + "typeFile": "types/dev/manifest.d.ts", + "type": "ManifestConfig" + }, + { + "path": "ext/data/deinflect.json", + "typeFile": "types/ext/deinflector.d.ts", + "type": "ReasonsRaw" + }, + { + "path": "ext/data/pronunciation-style.json", + "typeFile": "types/ext/css-style-applier.d.ts", + "type": "RawStyleData" + }, + { + "path": "ext/data/structured-content-style.json", + "typeFile": "types/ext/css-style-applier.d.ts", + "type": "RawStyleData" + }, + { + "path": "ext/data/schemas/dictionary-index-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-kanji-bank-v1-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-kanji-bank-v3-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-kanji-meta-bank-v3-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-tag-bank-v3-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-term-bank-v1-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-term-bank-v3-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/dictionary-term-meta-bank-v3-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/custom-audio-list-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "ext/data/schemas/options-schema.json", + "typeFile": "types/test/json.d.ts", + "type": "AjvSchema" + }, + { + "path": "test/data/translator-test-inputs.json", + "typeFile": "types/test/translator.d.ts", + "type": "TranslatorTestInputs", + "jsconfig": "test" + }, + { + "path": "test/data/translator-test-results.json", + "typeFile": "types/test/translator.d.ts", + "type": "TranslatorTestResults", + "jsconfig": "test" + }, + { + "path": "test/data/translator-test-results-note-data1.json", + "typeFile": "types/test/translator.d.ts", + "type": "TranslatorTestNoteDataResults", + "jsconfig": "test" + }, + { + "path": "test/data/anki-note-builder-test-results.json", + "typeFile": "types/test/translator.d.ts", + "type": "AnkiNoteBuilderTestResults", + "jsconfig": "test" + }, + { + "path": "test/data/json.json", + "typeFile": "types/test/json.d.ts", + "type": "JsonInfo" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/index.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "Index", + "schema": "ext/data/schemas/dictionary-index-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/kanji_bank_1.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "KanjiV3Array", + "schema": "ext/data/schemas/dictionary-kanji-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/kanji_meta_bank_1.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "KanjiMetaArray", + "schema": "ext/data/schemas/dictionary-kanji-meta-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/tag_bank_1.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "TagArray", + "schema": "ext/data/schemas/dictionary-tag-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/tag_bank_2.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "TagArray", + "schema": "ext/data/schemas/dictionary-tag-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/tag_bank_3.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "TagArray", + "schema": "ext/data/schemas/dictionary-tag-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/term_bank_1.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "TermV3Array", + "schema": "ext/data/schemas/dictionary-term-bank-v3-schema.json" + }, + { + "path": "test/data/dictionaries/valid-dictionary1/term_meta_bank_1.json", + "typeFile": "types/ext/dictionary-data.d.ts", + "type": "TermMetaArray", + "schema": "ext/data/schemas/dictionary-term-meta-bank-v3-schema.json" + } + ] +}
\ No newline at end of file diff --git a/test/data/translator-test-inputs.json b/test/data/translator-test-inputs.json index cf4b8f6a..5afb6a60 100644 --- a/test/data/translator-test-inputs.json +++ b/test/data/translator-test-inputs.json @@ -19,12 +19,12 @@ "sortFrequencyDictionary": null, "sortFrequencyDictionaryOrder": "descending", "removeNonJapaneseCharacters": true, - "convertHalfWidthCharacters": false, - "convertNumericCharacters": false, - "convertAlphabeticCharacters": false, - "convertHiraganaToKatakana": false, - "convertKatakanaToHiragana": false, - "collapseEmphaticSequences": false, + "convertHalfWidthCharacters": "false", + "convertNumericCharacters": "false", + "convertAlphabeticCharacters": "false", + "convertHiraganaToKatakana": "false", + "convertKatakanaToHiragana": "false", + "collapseEmphaticSequences": "false", "textReplacements": [ null ], diff --git a/test/fixtures/translator-test.js b/test/fixtures/translator-test.js index cb1a3ef5..3304c587 100644 --- a/test/fixtures/translator-test.js +++ b/test/fixtures/translator-test.js @@ -18,8 +18,8 @@ import {IDBKeyRange, indexedDB} from 'fake-indexeddb'; import {readFileSync} from 'fs'; -import {fileURLToPath, pathToFileURL} from 'node:url'; -import {dirname, join, resolve} from 'path'; +import {fileURLToPath} from 'node:url'; +import {dirname, join} from 'path'; import {expect, vi} from 'vitest'; import {parseJson} from '../../dev/json.js'; import {createDictionaryArchive} from '../../dev/util.js'; @@ -28,43 +28,13 @@ import {DictionaryDatabase} from '../../ext/js/language/dictionary-database.js'; import {DictionaryImporter} from '../../ext/js/language/dictionary-importer.js'; import {JapaneseUtil} from '../../ext/js/language/sandbox/japanese-util.js'; import {Translator} from '../../ext/js/language/translator.js'; +import {chrome, fetch} from '../mocks/common.js'; import {DictionaryImporterMediaLoader} from '../mocks/dictionary-importer-media-loader.js'; import {createDomTest} from './dom-test.js'; const extDir = join(dirname(fileURLToPath(import.meta.url)), '../../ext'); const deinflectionReasonsPath = join(extDir, 'data/deinflect.json'); -/** @type {import('dev/vm').PseudoChrome} */ -const chrome = { - runtime: { - getURL: (path) => { - return pathToFileURL(join(extDir, path.replace(/^\//, ''))).href; - } - } -}; - -/** - * @param {string} url - * @returns {Promise<import('dev/vm').PseudoFetchResponse>} - */ -async function fetch(url) { - let filePath; - try { - filePath = fileURLToPath(url); - } catch (e) { - filePath = resolve(extDir, url.replace(/^[/\\]/, '')); - } - await Promise.resolve(); - const content = readFileSync(filePath, {encoding: null}); - return { - ok: true, - status: 200, - statusText: 'OK', - text: async () => content.toString('utf8'), - json: async () => parseJson(content.toString('utf8')) - }; -} - vi.stubGlobal('indexedDB', indexedDB); vi.stubGlobal('IDBKeyRange', IDBKeyRange); vi.stubGlobal('fetch', fetch); diff --git a/test/jsconfig.json b/test/jsconfig.json index 9ab0c332..a9845861 100644 --- a/test/jsconfig.json +++ b/test/jsconfig.json @@ -15,7 +15,9 @@ "*": ["../types/ext/*"], "dev/*": ["../types/dev/*"], "test/*": ["../types/test/*"], - "rollup/parseAst": ["../types/other/rollup-parse-ast"] + "rollup/parseAst": ["../types/other/rollup-parse-ast"], + "ext/json-schema": ["../types/ext/json-schema"], + "json-schema": ["json-schema"] }, "types": [ "chrome", diff --git a/test/json-schema.test.js b/test/json-schema.test.js index fb7644de..0c1a483b 100644 --- a/test/json-schema.test.js +++ b/test/json-schema.test.js @@ -23,7 +23,7 @@ import {parseJson} from '../dev/json.js'; import {JsonSchema} from '../ext/js/data/json-schema.js'; /** - * @param {import('json-schema').Schema} schema + * @param {import('ext/json-schema').Schema} schema * @param {unknown} value * @returns {boolean} */ @@ -32,18 +32,18 @@ function schemaValidate(schema, value) { } /** - * @param {import('json-schema').Schema} schema + * @param {import('ext/json-schema').Schema} schema * @param {unknown} value - * @returns {import('json-schema').Value} + * @returns {import('ext/json-schema').Value} */ function getValidValueOrDefault(schema, value) { return new JsonSchema(schema).getValidValueOrDefault(value); } /** - * @param {import('json-schema').Schema} schema - * @param {import('json-schema').Value} value - * @returns {import('json-schema').Value} + * @param {import('ext/json-schema').Schema} schema + * @param {import('ext/json-schema').Value} value + * @returns {import('ext/json-schema').Value} */ function createProxy(schema, value) { return new JsonSchema(schema).createProxy(value); @@ -62,7 +62,7 @@ function clone(value) { /** */ function testValidate1() { test('Validate1', () => { - /** @type {import('json-schema').Schema} */ + /** @type {import('ext/json-schema').Schema} */ const schema = { allOf: [ { @@ -123,7 +123,7 @@ function testValidate1() { /** */ function testValidate2() { test('Validate2', () => { - /** @type {{schema: import('json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */ + /** @type {{schema: import('ext/json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */ const data = [ // String tests { @@ -530,7 +530,7 @@ function testValidate2() { /** */ function testGetValidValueOrDefault1() { test('GetValidValueOrDefault1', () => { - /** @type {{schema: import('json-schema').Schema, inputs: [value: unknown, expected: unknown][]}[]} */ + /** @type {{schema: import('ext/json-schema').Schema, inputs: [value: unknown, expected: unknown][]}[]} */ const data = [ // Test value defaulting on objects with additionalProperties=false { @@ -702,7 +702,7 @@ function testGetValidValueOrDefault1() { type: 'object', required: ['toString'], properties: { - toString: /** @type {import('json-schema').SchemaObject} */ ({ + toString: /** @type {import('ext/json-schema').SchemaObject} */ ({ type: 'string', default: 'default' }) @@ -888,7 +888,7 @@ function testGetValidValueOrDefault1() { /** */ function testProxy1() { test('Proxy1', () => { - /** @type {{schema: import('json-schema').Schema, tests: {error: boolean, value?: import('json-schema').Value, action: (value: import('core').SafeAny) => void}[]}[]} */ + /** @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 { diff --git a/test/json.test.js b/test/json.test.js new file mode 100644 index 00000000..8cf01491 --- /dev/null +++ b/test/json.test.js @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2023 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 Ajv from 'ajv'; +import {readFileSync} from 'fs'; +import {join, dirname as pathDirname} from 'path'; +import {createGenerator} from 'ts-json-schema-generator'; +import {fileURLToPath} from 'url'; +import {describe, expect, test} from 'vitest'; +import {parseJson} from '../dev/json.js'; +import {getAllFiles} from '../dev/util.js'; + +const dirname = pathDirname(fileURLToPath(import.meta.url)); +const rootDir = join(dirname, '..'); + +/** + * @param {import('test/json').JsconfigType|undefined} jsconfigType + * @returns {string} + */ +function getJsconfigPath(jsconfigType) { + let path; + switch (jsconfigType) { + case 'dev': path = '../dev/jsconfig.json'; break; + case 'test': path = '../test/jsconfig.json'; break; + default: path = '../jsconfig.json'; break; + } + return join(dirname, path); +} + +/** + * @returns {Ajv} + */ +function createAjv() { + return new Ajv({ + meta: true, + strictTuples: false, + allowUnionTypes: true + }); +} + +/** + * @param {string} path + * @param {string} type + * @param {import('test/json').JsconfigType|undefined} jsconfigType + * @returns {import('ajv').ValidateFunction<unknown>} + */ +function createValidatorFunctionFromTypeScript(path, type, jsconfigType) { + /** @type {import('ts-json-schema-generator/dist/src/Config').Config} */ + const config = { + path, + tsconfig: getJsconfigPath(jsconfigType), + type, + jsDoc: 'none', + additionalProperties: false, + minify: false, + expose: 'none', + strictTuples: true + }; + const schema = createGenerator(config).createSchema(config.type); + const ajv = createAjv(); + return ajv.compile(schema); +} + +/** + * @param {string} path + * @returns {import('ajv').ValidateFunction<unknown>} + */ +function createValidatorFunctionFromSchemaJson(path) { + /** @type {import('ajv').Schema} */ + const schema = parseJson(readFileSync(path, {encoding: 'utf8'})); + const ajv = createAjv(); + return ajv.compile(schema); +} + +/** + * @param {string} value + * @returns {string} + */ +function normalizePathDirectorySeparators(value) { + return value.replace(/\\/g, '/'); +} + + +describe.concurrent('JSON validation', () => { + const ignoreDirectories = new Set([ + 'builds', + 'dictionaries', + 'node_modules', + 'playwright-report', + 'playwright', + 'test-results', + 'dev/lib', + 'test/playwright' + ]); + + const existingJsonFiles = getAllFiles(rootDir, (path, isDirectory) => { + const fileNameNormalized = normalizePathDirectorySeparators(path); + if (isDirectory) { + return !ignoreDirectories.has(fileNameNormalized); + } else { + return /\.json$/i.test(fileNameNormalized); + } + }); + /** @type {Set<string>} */ + const existingJsonFileSet = new Set(); + for (const path of existingJsonFiles) { + existingJsonFileSet.add(normalizePathDirectorySeparators(path)); + } + + const jsonFileName = 'json.json'; + + /** @type {import('test/json').JsonInfo} */ + const jsonFileData = parseJson(readFileSync(join(dirname, `data/${jsonFileName}`), {encoding: 'utf8'})); + + test(`Each item in ${jsonFileName} must have a unique path`, () => { + /** @type {Set<string>} */ + const set = new Set(); + for (const {path} of jsonFileData.files) { + set.add(path); + } + expect(set.size).toBe(jsonFileData.files.length); + }); + + /** @type {Map<string, import('test/json').JsonFileInfo>} */ + const jsonFileMap = new Map(); + for (const item of jsonFileData.files) { + jsonFileMap.set(item.path, item); + } + + // Validate file existance + const requiredFiles = jsonFileData.files.filter((v) => !v.ignore); + test.each(requiredFiles)('File must exist in project: $path', ({path}) => { + expect(existingJsonFileSet.has(path)).toBe(true); + }); + + // Validate new files + const existingJsonFiles2 = existingJsonFiles.map((path) => ({path: normalizePathDirectorySeparators(path)})); + test.each(existingJsonFiles2)(`File must exist in ${jsonFileName}: $path`, ({path}) => { + expect(jsonFileMap.has(path)).toBe(true); + }); + + // Validate schemas 1 + /** @type {import('test/json').JsonFileParseInfo[]} */ + const schemaValidationTargets1 = []; + for (const info of jsonFileData.files) { + if (info.ignore || !existingJsonFileSet.has(info.path)) { continue; } + schemaValidationTargets1.push(info); + } + test.each(schemaValidationTargets1)('Validating file against TypeScript: $path', ({path, typeFile, type, jsconfig}) => { + const validate = createValidatorFunctionFromTypeScript(join(rootDir, typeFile), type, jsconfig); + const data = parseJson(readFileSync(join(rootDir, path), {encoding: 'utf8'})); + const valid = validate(data); + const {errors} = validate; + expect(errors).toBe(null); + expect(valid).toBe(true); + }); + + // Validate schemas 2 + /** @type {{path: string, schema: string}[]} */ + const schemaValidationTargets2 = []; + for (const info of jsonFileData.files) { + if (info.ignore || !existingJsonFileSet.has(info.path)) { continue; } + const {schema, path} = info; + if (typeof schema !== 'string') { continue; } + schemaValidationTargets2.push({schema, path}); + } + test.each(schemaValidationTargets2)('Validating file against schema: $path', ({path, schema}) => { + const validate = createValidatorFunctionFromSchemaJson(join(rootDir, schema)); + const data = parseJson(readFileSync(join(rootDir, path), {encoding: 'utf8'})); + const valid = validate(data); + const {errors} = validate; + expect(errors).toBe(null); + expect(valid).toBe(true); + }); +}); diff --git a/test/mocks/common.js b/test/mocks/common.js new file mode 100644 index 00000000..7fe30a3e --- /dev/null +++ b/test/mocks/common.js @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 Yomitan Authors + * Copyright (C) 2020-2022 Yomichan 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 {readFileSync} from 'fs'; +import {fileURLToPath, pathToFileURL} from 'node:url'; +import {dirname, join, resolve} from 'path'; +import {parseJson} from '../../dev/json.js'; + +const extDir = join(dirname(fileURLToPath(import.meta.url)), '../../ext'); + +/** @type {import('test/mocks').ChromeMock} */ +export const chrome = { + runtime: { + getURL: (path) => { + return pathToFileURL(join(extDir, path.replace(/^\//, ''))).href; + } + } +}; + +/** @type {import('test/mocks').FetchMock} */ +export async function fetch(url) { + let filePath; + try { + filePath = fileURLToPath(url); + } catch (e) { + filePath = resolve(extDir, url.replace(/^[/\\]/, '')); + } + await Promise.resolve(); + const content = readFileSync(filePath, {encoding: null}); + return { + ok: true, + status: 200, + statusText: 'OK', + text: async () => content.toString('utf8'), + json: async () => parseJson(content.toString('utf8')) + }; +} diff --git a/test/options-util.test.js b/test/options-util.test.js index 41185756..7bb9767a 100644 --- a/test/options-util.test.js +++ b/test/options-util.test.js @@ -19,40 +19,15 @@ /* eslint-disable no-multi-spaces */ import fs from 'fs'; -import url, {fileURLToPath} from 'node:url'; +import {fileURLToPath} from 'node:url'; import path from 'path'; import {expect, test, vi} from 'vitest'; -import {parseJson} from '../dev/json.js'; import {OptionsUtil} from '../ext/js/data/options-util.js'; import {TemplatePatcher} from '../ext/js/templates/template-patcher.js'; +import {chrome, fetch} from './mocks/common.js'; const dirname = path.dirname(fileURLToPath(import.meta.url)); -/** - * @param {string} url2 - * @returns {Promise<import('dev/vm').PseudoFetchResponse>} - */ -async function fetch(url2) { - const filePath = url.fileURLToPath(url2); - await Promise.resolve(); - const content = fs.readFileSync(filePath, {encoding: null}); - return { - ok: true, - status: 200, - statusText: 'OK', - text: async () => Promise.resolve(content.toString('utf8')), - json: async () => Promise.resolve(parseJson(content.toString('utf8'))) - }; -} -/** @type {import('dev/vm').PseudoChrome} */ -const chrome = { - runtime: { - getURL(path2) { - return url.pathToFileURL(path.join(dirname, '..', 'ext', path2.replace(/^\//, ''))).href; - } - } -}; - vi.stubGlobal('fetch', fetch); vi.stubGlobal('chrome', chrome); diff --git a/test/profile-conditions-util.test.js b/test/profile-conditions-util.test.js index f64ce79c..d5c8f8d2 100644 --- a/test/profile-conditions-util.test.js +++ b/test/profile-conditions-util.test.js @@ -62,7 +62,7 @@ function testNormalizeContext() { /** */ function testSchemas() { test('Schemas', () => { - /** @type {{conditionGroups: import('settings').ProfileConditionGroup[], expectedSchema?: import('json-schema').Schema, inputs?: {expected: boolean, context: import('settings').OptionsContext}[]}[]} */ + /** @type {{conditionGroups: import('settings').ProfileConditionGroup[], expectedSchema?: import('ext/json-schema').Schema, inputs?: {expected: boolean, context: import('settings').OptionsContext}[]}[]} */ const data = [ // Empty { diff --git a/test/utilities/translator.js b/test/utilities/translator.js index 9073b206..81081af6 100644 --- a/test/utilities/translator.js +++ b/test/utilities/translator.js @@ -18,10 +18,11 @@ /** + * TODO : This function is not very type safe at the moment, could be improved. * @template {import('translation').FindTermsOptions|import('translation').FindKanjiOptions} T * @param {string} dictionaryName - * @param {import('dev/vm').OptionsPresetObject} optionsPresets - * @param {string|import('dev/vm').OptionsPresetObject|(string|import('dev/vm').OptionsPresetObject)[]} optionsArray + * @param {import('test/translator').OptionsPresetObject} optionsPresets + * @param {import('test/translator').OptionsList} optionsArray * @returns {T} * @throws {Error} */ |