From 480628b779b57cbdb54b9211ae2a93b0af60ea05 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 1 Sep 2026 11:44:45 +0200 Subject: [PATCH] chore(lint): let the linter see tests/ and scripts/ `npm run lint` was `eslint src`, so two whole trees were never linted. Across the fleet that hid roughly 3,900 errors, none of which any CI leg had shown. Most of it was the config, not the code, and the same two defects were in every app. **scripts/ had no config block at all.** These are CommonJS Node CLI checkers, and flat config defaults every `.js` to ESM with browser-ish globals, so eslint read the CommonJS wrapper itself as undefined identifiers: `require`, `process`, `__dirname`, `__filename`, `module`. A `scripts/**` block now declares the environment. Declaring beats suppressing here: `no-undef` is the rule that catches a genuinely misspelled identifier, and dozens of fake findings would bury a real one. A second block covers `scripts/**/*.mjs`, which is ESM and needs Node's globals without the CommonJS wrapper. **The tests block applied a non-TypeScript-aware rule to TypeScript.** It named `tests/**/*.ts` while setting the CORE `no-unused-vars`, which v9 deliberately turns off for `.ts` in favour of the `@typescript-eslint` version. The core rule reads the parameter names inside a function TYPE as bindings, so t?: (app: string, key: string) => string reports `app` and `key` as unused variables, and every unused `catch (e)` in a `.ts` spec reports twice. The block is split now: `.js`/`.mjs` on the core rule, `.ts`/`.tsx` on the TypeScript one, same patterns on both. Also: stale `eslint-disable` comments naming plugins eslint 10 no longer registers, which are themselves errors ("Definition for rule ... was not found"), and a rule that must not parse shell scripts. The genuinely real findings were the useful part: dead locals, unused imports, dead helper functions, unused `catch` bindings, extensionless relative imports, and a handful of `== null` comparisons spelled out so they still match null AND undefined. Verified per app: `npm run lint` 0 errors over src + tests + scripts, `prettier --check` clean, and the unit suite still green. --- eslint.config.mjs | 142 +++++++++++++++++- package.json | 2 +- scripts/build-l10n-js.js | 3 + scripts/check-l10n.js | 20 ++- scripts/check-schema-l10n.js | 3 + scripts/clean-l10n.js | 9 +- scripts/find-unwrapped.js | 26 +++- scripts/l10n-ai.js | 67 ++++++--- scripts/lib/l10n.js | 5 +- scripts/sync-l10n-ellipsis.js | 4 + scripts/sync-l10n-json.js | 9 +- tests/e2e/docs-screenshots.spec.ts | 6 +- tests/e2e/global-setup.ts | 16 +- tests/e2e/playwright.config.ts | 3 +- tests/e2e/spec-coverage/_helpers.ts | 3 +- .../e2e/spec-coverage/admin-settings.spec.ts | 6 +- .../anonymiser-backend-warning.spec.ts | 6 +- tests/e2e/spec-coverage/anonymization.spec.ts | 6 +- .../spec-coverage/consent-management.spec.ts | 8 +- .../custom-dictionary-detection.spec.ts | 9 +- .../custom-dictionary-recognition.spec.ts | 9 +- tests/e2e/spec-coverage/dashboard.spec.ts | 6 +- .../demo-data-setup-step.spec.ts | 8 +- .../spec-coverage/document-comparison.spec.ts | 4 +- .../document-validation-checks.spec.ts | 4 +- .../entity-publication-policies.spec.ts | 9 +- .../spec-coverage/features-roadmap.spec.ts | 4 +- .../e2e/spec-coverage/folder-analysis.spec.ts | 4 +- tests/e2e/spec-coverage/my-documents.spec.ts | 4 +- .../orphaned-surface-restoration.spec.ts | 6 +- .../e2e/spec-coverage/page-components.spec.ts | 4 +- tests/e2e/spec-coverage/print-preview.spec.ts | 4 +- tests/e2e/spec-coverage/signing.spec.ts | 4 +- tests/e2e/spec-coverage/templates.spec.ts | 4 +- tests/e2e/spec-coverage/versions.spec.ts | 4 +- tests/e2e/visual/_visual-helpers.ts | 4 +- tests/e2e/visual/filinq.visual.spec.ts | 2 +- tests/e2e/workflows/_fixtures.ts | 6 +- .../workflows/agent-document-editing.spec.ts | 7 +- .../workflows/anonymization-workflow.spec.ts | 14 +- tests/e2e/workflows/consent-workflow.spec.ts | 10 +- tests/e2e/workflows/dashboard-widget.spec.ts | 4 +- .../entity-relation-decision.spec.ts | 12 +- tests/e2e/workflows/entity-review.spec.ts | 20 ++- tests/e2e/workflows/file-viewer.spec.ts | 10 +- .../prohibition-override-audit-schema.spec.ts | 4 +- .../publication-policy-toggle.spec.ts | 6 +- tests/e2e/workflows/signing-workflow.spec.ts | 12 +- tests/e2e/workflows/template-detail.spec.ts | 20 ++- tests/e2e/workflows/templates-crud.spec.ts | 16 +- tests/l10n/check-l10n.js | 4 +- tests/unit/reachability.spec.js | 2 +- tests/validate-manifest.js | 2 +- tests/vitest/anonymizationGetters.spec.js | 2 +- tests/vitest/comparisonService.spec.js | 2 +- tests/vitest/fileViewerService.spec.js | 2 +- tests/vitest/registerI18n.spec.js | 2 +- tests/vitest/settingsStore.spec.js | 2 +- tests/vitest/validationService.spec.js | 2 +- 59 files changed, 419 insertions(+), 179 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 9bad6e2d4..c7c8ac1e1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -144,11 +144,32 @@ export default [ 'no-console': 'off', 'n/no-process-exit': 'off', 'n/hashbang': 'off', - // `_` / `__` as a deliberate throwaway binding β€” `catch (_)`, a - // discarded destructuring slot. Narrow on purpose: the pattern matches - // UNDERSCORES ONLY, so a real name that happens to start with `_` is - // still reported. v9 drives plain `.js` through the CORE rule (the - // `@typescript-eslint` swap is per-file-type), so it is set here. + // Tests import devDependencies by definition; this rule is about what + // ships in the published package, which tests/ never does. + 'n/no-unpublished-import': 'off', + }, + }, + + { + // `_` / `__` as a deliberate throwaway binding β€” `catch (_)`, a discarded + // destructuring slot. Narrow on purpose: the pattern matches UNDERSCORES + // ONLY, so a real name that happens to start with `_` is still reported. + // + // πŸ”΄ `.js` / `.mjs` ONLY, NOT `.ts`. The CORE rule is not TypeScript-aware: + // applied to a `.ts` file it reads the parameter NAMES inside a function + // TYPE as bindings and reports them unused. Measured on humaniq β€” + // + // t?: (app: string, key: string) => string + // + // produced four `no-unused-vars` errors for `app` and `key`, which are + // documentation, not variables. The same mis-scoping made every unused + // `catch (e)` in a `.ts` spec report TWICE, once per rule. + // + // v9 already turns the core rule off for `.ts` and drives + // `@typescript-eslint/no-unused-vars` instead; naming `.ts` here switched + // it back on. TypeScript files are handled by the block below. + files: ['tests/**/*.js', 'tests/**/*.mjs'], + rules: { 'no-unused-vars': [ 'error', { @@ -165,12 +186,117 @@ export default [ ignoreRestSiblings: true, }, ], - // Tests import devDependencies by definition; this rule is about what - // ships in the published package, which tests/ never does. - 'n/no-unpublished-import': 'off', }, }, + { + // The TypeScript half of the block above. Same intent, same patterns, on + // the rule that actually understands the language: it knows a name inside + // a function type is not a binding, so type annotations stay quiet while a + // genuinely dead local is still reported. + files: ['tests/**/*.ts', 'tests/**/*.tsx'], + rules: { + '@typescript-eslint/no-unused-vars': [ + 'error', + { + varsIgnorePattern: '^_+$', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_+$', + argsIgnorePattern: '^_', + ignoreRestSiblings: true, + }, + ], + }, + }, + + { + // πŸ”΄ Node-side CLI tooling under `scripts/`, which is COMMONJS. Flat + // config defaults every `.js` to ESM with browser-ish globals, so without + // this block eslint reports the CommonJS wrapper itself as undefined + // identifiers. Measured on this app: 52 of the 233 errors under + // `tests/` + `scripts/` were `no-undef`, ALL of them in `scripts/`, and + // all five names were the environment rather than a typo β€” `process` 23, + // `require` 20, `__dirname` 6, `__filename` 2, `module` 1. + // + // This is describing the environment, not relaxing a rule, and it is the + // same argument the test-globals block below makes: declaring them keeps + // `no-undef` able to do its real job, which is catching a genuinely + // misspelled identifier. Suppressing the rule instead would bury that. + // + // `no-console` is off because printing its report is what a CLI checker + // is FOR. + // + // πŸ”΄ NO `n/*` ENTRIES HERE, DELIBERATELY. `eslint-plugin-n` is NOT + // registered for these files under eslint 10 + @nextcloud/eslint-config + // 9, so `'n/no-process-exit': 'off'` would be dead config that reads as + // if it were doing something. Measured both ways on this app: 0 `n/` + // findings with the entries and 0 without. + // + // What DID report was the opposite β€” four `scripts/*.js` carried + // `/* eslint-disable n/no-process-exit */` and `/* eslint-disable + // n/shebang */` left over from the eslintrc era, and an inline disable + // naming an unregistered plugin is itself an error ("Definition for rule + // 'n/shebang' was not found"). Those 8 comments are removed; do not add + // `n/*` rules back to replace them. + // + // ⚠️ `.js` and `.cjs` ONLY. A `scripts/*.mjs` is genuinely ESM and must + // keep the default `sourceType`, or `import` stops parsing there. + files: ['scripts/**/*.js', 'scripts/**/*.cjs'], + languageOptions: { + sourceType: 'commonjs', + globals: { + require: 'readonly', + module: 'writable', + exports: 'writable', + process: 'readonly', + __dirname: 'readonly', + __filename: 'readonly', + console: 'readonly', + Buffer: 'readonly', + global: 'readonly', + URL: 'readonly', + TextEncoder: 'readonly', + TextDecoder: 'readonly', + }, + }, + rules: { + 'no-console': 'off', + }, + }, + + { + // The ESM half of the block above. A `scripts/*.mjs` is genuinely a module + // and must keep the default `sourceType`, so it gets Node's globals but + // none of the CommonJS wrapper. Measured: `process` reported undefined 2x + // in hermiq's generate-opengemeenten-icons.mjs and 4x in openregister's + // l10n/runtime-check.mjs, which the `.js`/`.cjs` block deliberately does + // not match. + files: ['scripts/**/*.mjs', 'tests/**/*.mjs'], + languageOptions: { + globals: { + process: 'readonly', + console: 'readonly', + Buffer: 'readonly', + global: 'readonly', + URL: 'readonly', + TextEncoder: 'readonly', + TextDecoder: 'readonly', + }, + }, + rules: { + 'no-console': 'off', + }, + }, + + { + // eslint must not try to PARSE a shell script. `tests/e2e/seed.test.sh` + // matches the `**/*.test.*` glob some presets use, and eslint then reads + // it as JavaScript and reports "Parsing error: Unexpected character" β€” + // a finding about a file it should never have opened. + ignores: ['**/*.sh', '**/*.bash'], + }, + + { // Test globals. Several apps keep their spec files INSIDE `src/`, which the // lint script scans, and neither `@nextcloud/eslint-config` nor the runner diff --git a/package.json b/package.json index b679f0358..ad85dbc0e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "NODE_ENV=production webpack --config webpack.config.js --progress", "dev": "NODE_ENV=development webpack --config webpack.config.js --progress", "watch": "NODE_ENV=development webpack --config webpack.config.js --progress --watch", - "lint": "eslint src", + "lint": "eslint src tests scripts", "lint-fix": "npm run lint -- --fix && npm run format:fix", "test": "jest --silent", "test-coverage": "jest --silent --coverage", diff --git a/scripts/build-l10n-js.js b/scripts/build-l10n-js.js index 176ef519c..335b08d2c 100644 --- a/scripts/build-l10n-js.js +++ b/scripts/build-l10n-js.js @@ -101,6 +101,9 @@ function renderJs(id, translations, pluralForm) { ].join('\n') } +/** + * + */ function main() { const check = process.argv.includes('--check') const id = appId() diff --git a/scripts/check-l10n.js b/scripts/check-l10n.js index e77730c40..8c134549a 100755 --- a/scripts/check-l10n.js +++ b/scripts/check-l10n.js @@ -1,8 +1,6 @@ #!/usr/bin/env node /* eslint-disable jsdoc/require-param */ -/* eslint-disable n/no-process-exit */ -/* eslint-disable no-console */ -/* eslint-disable n/shebang */ + /** * l10n/i18n consistency checker. * @@ -19,7 +17,6 @@ const fs = require('fs') const path = require('path') - const { loadJsTranslations, walk } = require('./lib/l10n.js') const ROOT = path.resolve(__dirname, '..') @@ -34,10 +31,16 @@ const DIM = '\x1b[2m' const BOLD = '\x1b[1m' const RESET = '\x1b[0m' +/** + * + */ function rel(p) { return path.relative(ROOT, p) } +/** + * + */ function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } @@ -155,6 +158,9 @@ const NON_DISPLAY_ATTRS = new Set([ 'back-route', // Vue Router route name passed to $router.push({ name }) ]) +/** + * + */ function findUnwrapped(vueFiles, keys) { const hits = [] for (const file of vueFiles) { @@ -232,12 +238,18 @@ function findUnwrapped(vueFiles, keys) { return hits } +/** + * + */ function printSection(title, color, body) { console.log(`${color}${BOLD}${title}${RESET}`) console.log(body) console.log('') } +/** + * + */ function main() { const { app, translations } = loadJsTranslations(L10N_FILE) const keys = new Set(Object.keys(translations)) diff --git a/scripts/check-schema-l10n.js b/scripts/check-schema-l10n.js index 8a860b330..3c4b2626f 100644 --- a/scripts/check-schema-l10n.js +++ b/scripts/check-schema-l10n.js @@ -113,6 +113,9 @@ function collect(node, where, sink) { for (const value of Object.values(node)) collect(value, where, sink) } +/** + * + */ function main() { const update = process.argv.includes('--update') const list = process.argv.includes('--list') diff --git a/scripts/clean-l10n.js b/scripts/clean-l10n.js index dbd399114..54478d998 100755 --- a/scripts/clean-l10n.js +++ b/scripts/clean-l10n.js @@ -1,8 +1,5 @@ #!/usr/bin/env node -/* eslint-disable jsdoc/require-param */ -/* eslint-disable n/no-process-exit */ -/* eslint-disable no-console */ -/* eslint-disable n/shebang */ + /** * l10n unused-key remover. * @@ -29,7 +26,6 @@ const fs = require('fs') const path = require('path') - const { loadJsTranslations, serializeJs, @@ -56,6 +52,9 @@ const apply = args.has('--apply') // ---------- Main ---------- +/** + * + */ function main() { if (!fs.existsSync(ENGLISH_FILE)) { console.error(`English source file not found: ${ENGLISH_FILE}`) diff --git a/scripts/find-unwrapped.js b/scripts/find-unwrapped.js index b8e6e167e..e21e743f1 100644 --- a/scripts/find-unwrapped.js +++ b/scripts/find-unwrapped.js @@ -1,8 +1,6 @@ #!/usr/bin/env node /* eslint-disable jsdoc/require-param */ -/* eslint-disable n/no-process-exit */ -/* eslint-disable no-console */ -/* eslint-disable n/shebang */ + /** * Candidate unwrapped-string detector. * @@ -28,7 +26,6 @@ const fs = require('fs') const path = require('path') - const { walk } = require('./lib/l10n.js') const ROOT = path.resolve(__dirname, '..') @@ -141,6 +138,9 @@ function isComponentAttrOptOut(tagName, attrName) { // ---------- CLI ---------- +/** + * + */ function parseFlags(argv) { const flags = {} const positionals = [] @@ -176,6 +176,9 @@ const minLength = flags['min-length'] // ---------- helpers ---------- +/** + * + */ function rel(p) { return path.relative(ROOT, p) } @@ -364,6 +367,9 @@ function computeTCallRanges(text, app) { return ranges } +/** + * + */ function isInsideRange(pos, ranges) { for (const [start, end] of ranges) { if (pos >= start && pos < end) return true @@ -510,6 +516,9 @@ function isInsideStoreCall(expr, pos) { return /Store$/.test(baseIdent) } +/** + * + */ function findStringLiteralsInExpression(expr) { const out = [] let i = 0 @@ -779,6 +788,9 @@ function scanScript(file, fullText, scriptStart, scriptEnd, tCallRanges) { // ---------- main ---------- +/** + * + */ function findVueFiles(roots) { const files = [] for (const root of roots) { @@ -792,6 +804,9 @@ function findVueFiles(roots) { return files } +/** + * + */ function detectAppName() { // Mirror l10n-ai's approach: read l10n/en.js and trust the registered name. const enFile = path.join(ROOT, 'l10n', 'en.js') @@ -801,6 +816,9 @@ function detectAppName() { return m ? m[2] : 'opencatalogi' } +/** + * + */ function main() { const roots = positionals.length ? positionals.map((p) => diff --git a/scripts/l10n-ai.js b/scripts/l10n-ai.js index 4ef0981e6..c34716ef4 100644 --- a/scripts/l10n-ai.js +++ b/scripts/l10n-ai.js @@ -1,8 +1,6 @@ #!/usr/bin/env node /* eslint-disable jsdoc/require-param */ -/* eslint-disable n/no-process-exit */ -/* eslint-disable no-console */ -/* eslint-disable n/shebang */ + /** * AI-focused l10n CRUD tool. Designed to be invoked one subcommand at a time * by Claude (or other automation) so individual operations stay cheap in @@ -31,7 +29,6 @@ const fs = require('fs') const path = require('path') - const { loadJsTranslations, serializeJs, @@ -138,6 +135,9 @@ function parsePluralPairs(pairs) { // ---------- file helpers ---------- +/** + * + */ function loadAll() { const files = listJsLocaleFiles(L10N_DIR) if (!files.length) { @@ -150,6 +150,9 @@ function loadAll() { })) } +/** + * + */ function writeAll(entries) { const written = [] for (const e of entries) { @@ -166,17 +169,26 @@ function writeAll(entries) { runEslintFix(written, { rootDir: ROOT, log: (m) => console.error(m) }) } +/** + * + */ function fail(msg, code = 1) { console.error(msg) process.exit(code) } +/** + * + */ function rel(p) { return path.relative(ROOT, p) } // ---------- subcommands ---------- +/** + * + */ function cmdHas(args) { const { positionals, flags } = parseArgs(args) const [key] = positionals @@ -206,6 +218,9 @@ function cmdHas(args) { } } +/** + * + */ function cmdGet(args) { const { positionals } = parseArgs(args) const [key] = positionals @@ -214,7 +229,7 @@ function cmdGet(args) { const entries = loadAll() let any = false for (const e of entries) { - if (Object.prototype.hasOwnProperty.call(e.translations, key)) { + if (Object.hasOwn(e.translations, key)) { any = true const v = e.translations[key] const out = Array.isArray(v) ? JSON.stringify(v) : v @@ -227,6 +242,9 @@ function cmdGet(args) { } } +/** + * + */ function cmdFind(args) { const { positionals } = parseArgs(args) const [substring] = positionals @@ -251,6 +269,9 @@ function cmdFind(args) { } } +/** + * + */ function cmdAdd(args) { const { positionals, opts, flags } = parseArgs(args, { repeatable: new Set(['value', 'plural']), @@ -336,7 +357,7 @@ function cmdAdd(args) { const existing = [] for (const e of entries) { if (!targetLocales.has(e.locale)) continue - if (Object.prototype.hasOwnProperty.call(e.translations, key)) { + if (Object.hasOwn(e.translations, key)) { existing.push(e.locale) } } @@ -363,6 +384,9 @@ function cmdAdd(args) { } } +/** + * + */ function cmdSet(args) { const { positionals, opts } = parseArgs(args, { repeatable: new Set(['plural']), @@ -380,7 +404,7 @@ function cmdSet(args) { `set: locale '${opts.locale}' has no l10n/${opts.locale}.js (known: ${entries.map((e) => e.locale).join(', ')})`, ) } - if (!Object.prototype.hasOwnProperty.call(target.translations, key)) { + if (!Object.hasOwn(target.translations, key)) { fail(`set: key '${key}' not present in ${opts.locale}.js. Use 'add' first.`) } @@ -406,15 +430,16 @@ function cmdSet(args) { ) } +/** + * + */ function cmdRm(args) { const { positionals, flags } = parseArgs(args) const [key] = positionals if (!key) fail('usage: rm [--force]') const entries = loadAll() - const present = entries.filter((e) => - Object.prototype.hasOwnProperty.call(e.translations, key), - ) + const present = entries.filter((e) => Object.hasOwn(e.translations, key)) if (!present.length) { fail(`rm: key '${key}' not found in any locale .js file`) } @@ -444,6 +469,9 @@ function cmdRm(args) { for (const e of toWrite) console.log(`${e.locale}.js\tremoved`) } +/** + * + */ function cmdRename(args) { const { positionals, flags } = parseArgs(args) const [oldKey, newKey] = positionals @@ -451,15 +479,11 @@ function cmdRename(args) { if (oldKey === newKey) fail('rename: old and new keys are identical') const entries = loadAll() - const present = entries.filter((e) => - Object.prototype.hasOwnProperty.call(e.translations, oldKey), - ) + const present = entries.filter((e) => Object.hasOwn(e.translations, oldKey)) if (!present.length) { fail(`rename: key '${oldKey}' not found in any locale .js file`) } - const collisions = entries.filter((e) => - Object.prototype.hasOwnProperty.call(e.translations, newKey), - ) + const collisions = entries.filter((e) => Object.hasOwn(e.translations, newKey)) if (collisions.length && !flags.force) { fail( `rename: target key '${newKey}' already exists in ${collisions.map((e) => e.locale + '.js').join(', ')}. Pass --force to overwrite.`, @@ -468,7 +492,7 @@ function cmdRename(args) { const toWrite = [] for (const e of entries) { - if (!Object.prototype.hasOwnProperty.call(e.translations, oldKey)) continue + if (!Object.hasOwn(e.translations, oldKey)) continue const next = { ...e.translations } next[newKey] = next[oldKey] delete next[oldKey] @@ -478,12 +502,18 @@ function cmdRename(args) { for (const e of toWrite) console.log(`${e.locale}.js\trenamed`) } +/** + * + */ function cmdListLocales() { const files = listJsLocaleFiles(L10N_DIR) if (!files.length) fail('list-locales: no l10n/*.js files found') for (const f of files) console.log(localeNameOf(f)) } +/** + * + */ function cmdHelp() { const text = [ 'Usage: node scripts/l10n-ai.js [args...]', @@ -509,6 +539,9 @@ function cmdHelp() { // ---------- main ---------- +/** + * + */ function main() { const [, , sub, ...rest] = process.argv if (!sub || sub === '--help' || sub === '-h') { diff --git a/scripts/lib/l10n.js b/scripts/lib/l10n.js index 58a77df5e..79f7a3af9 100644 --- a/scripts/lib/l10n.js +++ b/scripts/lib/l10n.js @@ -9,10 +9,10 @@ * out of sync (which is exactly the bug sync-l10n-json.js exists to prevent). */ +const { spawnSync } = require('child_process') const fs = require('fs') const path = require('path') const vm = require('vm') -const { spawnSync } = require('child_process') /** * Load a single l10n/*.js file and return its app name, translations object, @@ -238,6 +238,9 @@ function findKeyReferences(srcDir, app, key) { return hits } +/** + * + */ function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } diff --git a/scripts/sync-l10n-ellipsis.js b/scripts/sync-l10n-ellipsis.js index c94aef652..c427bfd33 100644 --- a/scripts/sync-l10n-ellipsis.js +++ b/scripts/sync-l10n-ellipsis.js @@ -18,6 +18,10 @@ const path = require('path') const ELLIPSIS_RE = /(? { } catch (err) { last = `request failed: ${(err as Error).message}` } - // eslint-disable-next-line no-await-in-loop + await new Promise((resolve) => setTimeout(resolve, 5_000)) } throw new Error( @@ -235,7 +237,7 @@ export default async function globalSetup(config: FullConfig): Promise { await page.evaluate(() => { try { window.localStorage.setItem('cn-support-dialog-shown:filinq', '1') - } catch (e) { + } catch { /* private mode / quota β€” the dismissOverlays fallback still applies */ } }) @@ -266,7 +268,7 @@ export default async function globalSetup(config: FullConfig): Promise { await page.evaluate(() => { try { window.localStorage.setItem('cn-walkthrough-seen:filinq', '999.0.0') - } catch (e) { + } catch { // localStorage unavailable β€” specs fall back to dismissing by hand. } }) diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index 6a595c666..b19bb3bf8 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -43,8 +43,7 @@ import { defineConfig, devices } from '@playwright/test' import * as path from 'path' - -import { resolveBaseUrl } from './base-url' +import { resolveBaseUrl } from './base-url.ts' const APP_ROOT = path.resolve(__dirname, '..', '..') diff --git a/tests/e2e/spec-coverage/_helpers.ts b/tests/e2e/spec-coverage/_helpers.ts index 0ce8d07c9..7111da9e2 100644 --- a/tests/e2e/spec-coverage/_helpers.ts +++ b/tests/e2e/spec-coverage/_helpers.ts @@ -15,7 +15,7 @@ * defects, and must not make a page-render assertion flap. */ -import { type Page } from '@playwright/test' +import type { Page } from '@playwright/test' const IGNORE = [ 'user_status', @@ -241,7 +241,6 @@ async function resolveAppBase(page: Page): Promise { await page.goto(APP, { waitUntil: 'domcontentloaded' }) await waitForAppReady(page) cachedAppBase = await page.evaluate(() => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any const oc = (window as any).OC return (oc?.generateUrl?.('/apps/filinq') as string) || '' }) diff --git a/tests/e2e/spec-coverage/admin-settings.spec.ts b/tests/e2e/spec-coverage/admin-settings.spec.ts index 665e9896c..62f5cfc02 100644 --- a/tests/e2e/spec-coverage/admin-settings.spec.ts +++ b/tests/e2e/spec-coverage/admin-settings.spec.ts @@ -23,8 +23,10 @@ // @e2e openspec/specs/processing-activity-export/spec.md#admin-exports-the-register-from-filinq // @e2e openspec/specs/processing-activity-export/spec.md#unconfigured-identity-prompts-not-blocks -import { test, expect, type Page } from '@playwright/test' -import { waitForNcContentReady } from './_helpers' +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { waitForNcContentReady } from './_helpers.ts' async function dismissOverlays(page: Page): Promise { const wizard = page.locator('#firstrunwizard') diff --git a/tests/e2e/spec-coverage/anonymiser-backend-warning.spec.ts b/tests/e2e/spec-coverage/anonymiser-backend-warning.spec.ts index 614006b2d..eba2ce1c1 100644 --- a/tests/e2e/spec-coverage/anonymiser-backend-warning.spec.ts +++ b/tests/e2e/spec-coverage/anonymiser-backend-warning.spec.ts @@ -32,8 +32,10 @@ * (see the long comment in orphaned-surface-restoration.spec.ts). */ -import { test, expect, type Page, type APIRequestContext } from '@playwright/test' -import { waitForNcContentReady, dismissOverlays, go } from './_helpers' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { dismissOverlays, go, waitForNcContentReady } from './_helpers.ts' const SETTINGS = '/index.php/settings/admin/filinq' const API_SETTINGS = '/index.php/apps/filinq/api/settings' diff --git a/tests/e2e/spec-coverage/anonymization.spec.ts b/tests/e2e/spec-coverage/anonymization.spec.ts index a90d1a480..105c09109 100644 --- a/tests/e2e/spec-coverage/anonymization.spec.ts +++ b/tests/e2e/spec-coverage/anonymization.spec.ts @@ -14,8 +14,10 @@ // @e2e openspec/specs/anonymization/spec.md#error-during-anonymization // @e2e openspec/specs/anonymization/spec.md#anonymize-another-document -import { test, expect, type Page } from '@playwright/test' -import { appUrl, waitForAppReady } from './_helpers' +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { appUrl, waitForAppReady } from './_helpers.ts' // The local `const APP = '/index.php/apps/filinq'` that used to live here is // gone β€” navigation now goes through `appUrl()`, which reads the base from the diff --git a/tests/e2e/spec-coverage/consent-management.spec.ts b/tests/e2e/spec-coverage/consent-management.spec.ts index 6b187847f..7c5906a4a 100644 --- a/tests/e2e/spec-coverage/consent-management.spec.ts +++ b/tests/e2e/spec-coverage/consent-management.spec.ts @@ -13,9 +13,11 @@ // @e2e openspec/specs/consent-management/spec.md#click-consent-to-view-details // @e2e openspec/specs/consent-management/spec.md#empty-consent-list -import { test, expect, type Page } from '@playwright/test' -import { appUrl, waitForAppReady } from './_helpers' -import { API } from '../workflows/_fixtures' +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { API } from '../workflows/_fixtures.ts' +import { appUrl, waitForAppReady } from './_helpers.ts' // `index.php`-prefixed β€” see the APP constant in ./_helpers.ts for why the // prefix is required on CI (`php -S` does not rewrite, so `/apps/...` hits diff --git a/tests/e2e/spec-coverage/custom-dictionary-detection.spec.ts b/tests/e2e/spec-coverage/custom-dictionary-detection.spec.ts index 89f30ce2b..52765cc48 100644 --- a/tests/e2e/spec-coverage/custom-dictionary-detection.spec.ts +++ b/tests/e2e/spec-coverage/custom-dictionary-detection.spec.ts @@ -42,9 +42,11 @@ * `CUSTOM_DICTIONARY` card disappears while everything else still renders. */ -import { test, expect, type APIRequestContext } from '@playwright/test' -import { go, waitForAppReady } from './_helpers' -import { harvestToken, jsonHeaders, API } from '../workflows/_fixtures' +import type { APIRequestContext } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { API, harvestToken, jsonHeaders } from '../workflows/_fixtures.ts' +import { go, waitForAppReady } from './_helpers.ts' /** Unique per run β€” the whole point of the assertion is that only WE seeded it. */ const RUN = `g19cdd-${Date.now()}` @@ -180,7 +182,6 @@ test.describe('custom-dictionary-recognition β€” a dictionary hit is detected, r }) .catch(() => null) if (res && res.status() >= 400) { - // eslint-disable-next-line no-console console.warn( `[teardown] dictionary ${dictionaryId} -> ${res.status()} (leaked)`, ) diff --git a/tests/e2e/spec-coverage/custom-dictionary-recognition.spec.ts b/tests/e2e/spec-coverage/custom-dictionary-recognition.spec.ts index 11d0bc096..022cbc8ba 100644 --- a/tests/e2e/spec-coverage/custom-dictionary-recognition.spec.ts +++ b/tests/e2e/spec-coverage/custom-dictionary-recognition.spec.ts @@ -30,9 +30,11 @@ * bottom of this file. Their anchors have been removed rather than repointed. */ -import { test, expect, type APIRequestContext, type Page } from '@playwright/test' -import { appUrl, go, waitForAppReady } from './_helpers' -import { harvestToken, jsonHeaders, API } from '../workflows/_fixtures' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { API, harvestToken, jsonHeaders } from '../workflows/_fixtures.ts' +import { appUrl, go, waitForAppReady } from './_helpers.ts' const P = `g19cdr-${Date.now()}` const SEEDED_LABEL = 'Projectnamen' // shipped by lib/Settings/filinq_register.json @@ -102,7 +104,6 @@ test.describe('custom-dictionary-recognition β€” dictionaries admin UI', () => { }) .catch(() => null) if (res && res.status() >= 400) { - // eslint-disable-next-line no-console console.warn( `[teardown] dictionary ${fixtureId} -> ${res.status()} (leaked)`, ) diff --git a/tests/e2e/spec-coverage/dashboard.spec.ts b/tests/e2e/spec-coverage/dashboard.spec.ts index ef1deb8ce..485e456c6 100644 --- a/tests/e2e/spec-coverage/dashboard.spec.ts +++ b/tests/e2e/spec-coverage/dashboard.spec.ts @@ -24,8 +24,10 @@ // @e2e openspec/specs/dashboard/spec.md#dashboard-widget-icon // @e2e openspec/specs/dashboard/spec.md#admin-settings-section-icon -import { test, expect, type Page } from '@playwright/test' -import { waitForAppReady, waitForNcContentReady } from './_helpers' +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { waitForAppReady, waitForNcContentReady } from './_helpers.ts' // `index.php`-prefixed β€” see the APP constant in ./_helpers.ts for why the // prefix is required on CI (`php -S` does not rewrite, so `/apps/...` hits diff --git a/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts b/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts index 0d537e062..f8b176b46 100644 --- a/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts +++ b/tests/e2e/spec-coverage/demo-data-setup-step.spec.ts @@ -1,3 +1,5 @@ +import type { Page } from '@playwright/test' + /* * SPDX-FileCopyrightText: 2026 Conduction B.V. * SPDX-License-Identifier: EUPL-1.2 @@ -34,7 +36,7 @@ * * @spec exclude ADR-042/ADR-111 setup contract; no per-app behavioural spec. */ -import { test, expect, type Page } from '@playwright/test' +import { expect, test } from '@playwright/test' import * as path from 'path' const STORAGE_STATE = path.resolve(__dirname, '../.auth/admin.json') @@ -53,12 +55,12 @@ async function api( method, headers: { 'Content-Type': 'application/json', - // eslint-disable-next-line no-undef + requesttoken: (window as any).OC?.requestToken || '', 'OCS-APIREQUEST': 'true', }, }) - let json: any = null + let json: any try { json = await res.json() } catch { diff --git a/tests/e2e/spec-coverage/document-comparison.spec.ts b/tests/e2e/spec-coverage/document-comparison.spec.ts index b25505621..318cf3ea5 100644 --- a/tests/e2e/spec-coverage/document-comparison.spec.ts +++ b/tests/e2e/spec-coverage/document-comparison.spec.ts @@ -15,8 +15,8 @@ // @e2e openspec/specs/document-comparison/spec.md#operator-picks-two-versions // @e2e openspec/specs/document-comparison/spec.md#advisory-panel-for-unredacted-entities -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go } from './_helpers.ts' test.describe('document-comparison β€” side-by-side view', () => { test('comparison view renders its heading, pickers and Compare action', async ({ diff --git a/tests/e2e/spec-coverage/document-validation-checks.spec.ts b/tests/e2e/spec-coverage/document-validation-checks.spec.ts index 027b8722b..4b272e093 100644 --- a/tests/e2e/spec-coverage/document-validation-checks.spec.ts +++ b/tests/e2e/spec-coverage/document-validation-checks.spec.ts @@ -15,8 +15,8 @@ // @e2e openspec/specs/document-validation-checks/spec.md#operator-sees-why-a-document-failed // @e2e openspec/specs/document-validation-checks/spec.md#scan-only-document-offers-the-ocr-path -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go } from './_helpers.ts' test.describe('document-validation-checks β€” verdict + findings UI', () => { test('My documents exposes a Validate action that opens the findings panel', async ({ diff --git a/tests/e2e/spec-coverage/entity-publication-policies.spec.ts b/tests/e2e/spec-coverage/entity-publication-policies.spec.ts index 349434eed..351b912df 100644 --- a/tests/e2e/spec-coverage/entity-publication-policies.spec.ts +++ b/tests/e2e/spec-coverage/entity-publication-policies.spec.ts @@ -39,9 +39,11 @@ * poison the next one's negative assertions. */ -import { test, expect, type APIRequestContext, type Page } from '@playwright/test' -import { go, waitForAppReady } from './_helpers' -import { harvestToken, jsonHeaders, API } from '../workflows/_fixtures' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { API, harvestToken, jsonHeaders } from '../workflows/_fixtures.ts' +import { go, waitForAppReady } from './_helpers.ts' /** Unique per run β€” the negative assertions depend on no stale twin existing. */ const P = `g19epp-${Date.now()}` @@ -193,7 +195,6 @@ test.describe('entity-publication-policies β€” three separate admin surfaces', ( }) .catch(() => null) if (res && res.status() >= 400) { - // eslint-disable-next-line no-console console.warn( `[teardown] standing consent ${created.standing} -> ${res.status()} (leaked)`, ) diff --git a/tests/e2e/spec-coverage/features-roadmap.spec.ts b/tests/e2e/spec-coverage/features-roadmap.spec.ts index 13e8a40ac..385e5d4f0 100644 --- a/tests/e2e/spec-coverage/features-roadmap.spec.ts +++ b/tests/e2e/spec-coverage/features-roadmap.spec.ts @@ -12,8 +12,8 @@ // @e2e openspec/specs/dashboard/spec.md#navigation-items-and-icons -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go, navClick } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go, navClick } from './_helpers.ts' test.describe('dashboard β€” features & roadmap page', () => { test('Features & roadmap page renders its heading and actions', async ({ diff --git a/tests/e2e/spec-coverage/folder-analysis.spec.ts b/tests/e2e/spec-coverage/folder-analysis.spec.ts index 16c1af24d..863706ded 100644 --- a/tests/e2e/spec-coverage/folder-analysis.spec.ts +++ b/tests/e2e/spec-coverage/folder-analysis.spec.ts @@ -24,8 +24,8 @@ // @e2e openspec/specs/folder-batch-analysis/spec.md#initiate-folder-analysis-by-folder-path-existing-behavior // @e2e openspec/specs/folder-batch-analysis/spec.md#folder-path-does-not-exist -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers.ts' test.describe('folder-batch-analysis β€” folder analysis UI', () => { test('Folder Analysis page renders heading, path input and Analyze action', async ({ diff --git a/tests/e2e/spec-coverage/my-documents.spec.ts b/tests/e2e/spec-coverage/my-documents.spec.ts index 3f2b03320..edab63ce3 100644 --- a/tests/e2e/spec-coverage/my-documents.spec.ts +++ b/tests/e2e/spec-coverage/my-documents.spec.ts @@ -17,8 +17,8 @@ // @e2e openspec/specs/document-register/spec.md#generated-correspondence-lifecycle -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers.ts' test.describe('document-register β€” my documents UI', () => { test('My Documents page renders the Documents header and view toggle', async ({ diff --git a/tests/e2e/spec-coverage/orphaned-surface-restoration.spec.ts b/tests/e2e/spec-coverage/orphaned-surface-restoration.spec.ts index 5c6fc7af4..1efb9d08b 100644 --- a/tests/e2e/spec-coverage/orphaned-surface-restoration.spec.ts +++ b/tests/e2e/spec-coverage/orphaned-surface-restoration.spec.ts @@ -45,8 +45,10 @@ * on the individual `test.fixme` blocks below. */ -import { test, expect, type Page } from '@playwright/test' -import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers' +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers.ts' // The views under test, named after the component files they cover. Routes are // unchanged β€” this makes the spec-to-component link readable in executable code diff --git a/tests/e2e/spec-coverage/page-components.spec.ts b/tests/e2e/spec-coverage/page-components.spec.ts index 8572a3299..7df0aad5b 100644 --- a/tests/e2e/spec-coverage/page-components.spec.ts +++ b/tests/e2e/spec-coverage/page-components.spec.ts @@ -33,8 +33,8 @@ * over the route-specific markup. */ -import { test, expect } from '@playwright/test' -import { go, waitForNcContentReady, dismissOverlays } from './_helpers' +import { expect, test } from '@playwright/test' +import { dismissOverlays, go, waitForNcContentReady } from './_helpers.ts' /** * A syntactically valid UUID that no Filinq object can have. diff --git a/tests/e2e/spec-coverage/print-preview.spec.ts b/tests/e2e/spec-coverage/print-preview.spec.ts index 5b6848bab..3555172a8 100644 --- a/tests/e2e/spec-coverage/print-preview.spec.ts +++ b/tests/e2e/spec-coverage/print-preview.spec.ts @@ -12,8 +12,8 @@ // @e2e openspec/specs/print-preview/spec.md#preview-with-inline-template -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go } from './_helpers.ts' // The view under test, named after the component file it covers. The route // is unchanged β€” this makes the spec-to-component link readable in executable diff --git a/tests/e2e/spec-coverage/signing.spec.ts b/tests/e2e/spec-coverage/signing.spec.ts index f585c4c9c..6663491a9 100644 --- a/tests/e2e/spec-coverage/signing.spec.ts +++ b/tests/e2e/spec-coverage/signing.spec.ts @@ -14,8 +14,8 @@ // @e2e openspec/specs/document-signing/spec.md#list-all-signing-requests // @e2e openspec/specs/document-signing/spec.md#view-signing-request-status -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go, navClick } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go, navClick } from './_helpers.ts' test.describe('document-signing β€” signing requests list UI', () => { test('Signing Requests page renders heading and a list or empty-state', async ({ diff --git a/tests/e2e/spec-coverage/templates.spec.ts b/tests/e2e/spec-coverage/templates.spec.ts index 4eac60ea0..fd4d2566c 100644 --- a/tests/e2e/spec-coverage/templates.spec.ts +++ b/tests/e2e/spec-coverage/templates.spec.ts @@ -12,8 +12,8 @@ // @e2e openspec/specs/template-management/spec.md#list-templates-with-namespace-filter // @e2e openspec/specs/template-management/spec.md#create-a-template -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, dismissOverlays, go, navClick } from './_helpers.ts' // The view under test, named after the component file it covers. The route // is unchanged β€” this makes the spec-to-component link readable in executable diff --git a/tests/e2e/spec-coverage/versions.spec.ts b/tests/e2e/spec-coverage/versions.spec.ts index 808701dcd..71d6fb1ea 100644 --- a/tests/e2e/spec-coverage/versions.spec.ts +++ b/tests/e2e/spec-coverage/versions.spec.ts @@ -18,8 +18,8 @@ // @e2e openspec/specs/document-versions/spec.md#compare-a-version-with-the-current-document // @e2e openspec/specs/document-versions/spec.md#compare-is-not-offered-for-non-extractable-versions -import { test, expect } from '@playwright/test' -import { attachConsoleGuard, go } from './_helpers' +import { expect, test } from '@playwright/test' +import { attachConsoleGuard, go } from './_helpers.ts' // The view under test, named after the component file it covers. The route // is unchanged β€” this makes the spec-to-component link readable in executable diff --git a/tests/e2e/visual/_visual-helpers.ts b/tests/e2e/visual/_visual-helpers.ts index a96bb7b58..0d80da57c 100644 --- a/tests/e2e/visual/_visual-helpers.ts +++ b/tests/e2e/visual/_visual-helpers.ts @@ -1,3 +1,5 @@ +import type { Locator, Page } from '@playwright/test' + /* * SPDX-License-Identifier: EUPL-1.2 * @@ -24,7 +26,7 @@ * own baselines on first run, or (b) stay non-gating until baselined in the CI * environment. See tests/e2e/visual/README in-repo wiring notes. */ -import { expect, type Page, type Locator } from '@playwright/test' +import { expect } from '@playwright/test' /** Common screenshot options applied to every visual assertion. */ export const SHOT_OPTIONS = { diff --git a/tests/e2e/visual/filinq.visual.spec.ts b/tests/e2e/visual/filinq.visual.spec.ts index 440c23a01..6cfa893fa 100644 --- a/tests/e2e/visual/filinq.visual.spec.ts +++ b/tests/e2e/visual/filinq.visual.spec.ts @@ -11,7 +11,7 @@ * See _visual-helpers.ts for the platform-rendering caveat. */ import { test } from '@playwright/test' -import { shootSurface } from './_visual-helpers' +import { shootSurface } from './_visual-helpers.ts' const APP = '/index.php/apps/filinq' diff --git a/tests/e2e/workflows/_fixtures.ts b/tests/e2e/workflows/_fixtures.ts index 6fb049088..383411246 100644 --- a/tests/e2e/workflows/_fixtures.ts +++ b/tests/e2e/workflows/_fixtures.ts @@ -31,7 +31,9 @@ * concurrent runs never collide. */ -import { type APIRequestContext, type Page, expect } from '@playwright/test' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect } from '@playwright/test' /** Shared family prefix for ALL workflow-test artefacts (every run). */ export const TEST_FAMILY = 'e2eflow-' @@ -85,7 +87,6 @@ export async function harvestToken(page: Page): Promise { // naming the token, instead of failing later as a mysterious 412 on the // first write request. await page.waitForFunction( - // eslint-disable-next-line @typescript-eslint/no-explicit-any () => Boolean( (window as any).OC?.requestToken @@ -95,7 +96,6 @@ export async function harvestToken(page: Page): Promise { { timeout: 30_000 }, ) const token = await page.evaluate( - // eslint-disable-next-line @typescript-eslint/no-explicit-any () => (window as any).OC?.requestToken || document.head.dataset.requesttoken diff --git a/tests/e2e/workflows/agent-document-editing.spec.ts b/tests/e2e/workflows/agent-document-editing.spec.ts index 53d3508ce..785d94d04 100644 --- a/tests/e2e/workflows/agent-document-editing.spec.ts +++ b/tests/e2e/workflows/agent-document-editing.spec.ts @@ -31,9 +31,10 @@ * provider; it is not automatable here because it needs a live LLM credential. */ -import { test, expect, type APIRequestContext } from '@playwright/test' +import type { APIRequestContext } from '@playwright/test' -import { harvestToken, jsonHeaders, TEST_PREFIX } from './_fixtures' +import { expect, test } from '@playwright/test' +import { harvestToken, jsonHeaders, TEST_PREFIX } from './_fixtures.ts' /** OpenRegister's MCP JSON-RPC endpoint β€” the tool surface under test. */ const MCP = '/index.php/apps/openregister/api/mcp' @@ -159,7 +160,7 @@ async function callTool( ).toBeTruthy() const text = String(body.result.content?.[0]?.text ?? '') - let payload: Record = {} + let payload: Record try { payload = JSON.parse(text) } catch { diff --git a/tests/e2e/workflows/anonymization-workflow.spec.ts b/tests/e2e/workflows/anonymization-workflow.spec.ts index 4b9fd64d2..0faabc10c 100644 --- a/tests/e2e/workflows/anonymization-workflow.spec.ts +++ b/tests/e2e/workflows/anonymization-workflow.spec.ts @@ -36,22 +36,22 @@ * @spec openspec/specs/folder-batch-analysis/spec.md#requirement-folder-batch-initiation-from-existing-nextcloud-folder */ -import { test, expect } from '@playwright/test' +import { expect, test } from '@playwright/test' import { APP, appUrl, dismissOverlays, waitForAppReady, -} from '../spec-coverage/_helpers' +} from '../spec-coverage/_helpers.ts' import { + API, + createDavFile, + createDavFolder, harvestToken, jsonHeaders, - API, - TEST_PREFIX, TEST_FAMILY, - createDavFolder, - createDavFile, -} from './_fixtures' + TEST_PREFIX, +} from './_fixtures.ts' test.describe.configure({ mode: 'serial' }) diff --git a/tests/e2e/workflows/consent-workflow.spec.ts b/tests/e2e/workflows/consent-workflow.spec.ts index 92c1ae269..e1f250ef4 100644 --- a/tests/e2e/workflows/consent-workflow.spec.ts +++ b/tests/e2e/workflows/consent-workflow.spec.ts @@ -29,18 +29,20 @@ * ------------------------------------------------------------------ */ -import { test, expect, type APIRequestContext } from '@playwright/test' -import { go, waitForAppReady } from '../spec-coverage/_helpers' +import type { APIRequestContext } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { go, waitForAppReady } from '../spec-coverage/_helpers.ts' import { API, - POLICY_PREFIX, createProhibition, createStandingConsent, getConsent, harvestToken, jsonHeaders, + POLICY_PREFIX, seedPolicyMatchedConsent, -} from './_fixtures' +} from './_fixtures.ts' /** Harvested once in `beforeAll`; every request helper needs it. */ let token = '' diff --git a/tests/e2e/workflows/dashboard-widget.spec.ts b/tests/e2e/workflows/dashboard-widget.spec.ts index ce3e40138..65237b786 100644 --- a/tests/e2e/workflows/dashboard-widget.spec.ts +++ b/tests/e2e/workflows/dashboard-widget.spec.ts @@ -19,8 +19,8 @@ * are all on markup that only this widget's template produces. */ -import { test, expect } from '@playwright/test' -import { harvestToken } from './_fixtures' +import { expect, test } from '@playwright/test' +import { harvestToken } from './_fixtures.ts' /** * Widget id β€” `FileEntitiesWidget::getId()` in lib/Dashboard/. diff --git a/tests/e2e/workflows/entity-relation-decision.spec.ts b/tests/e2e/workflows/entity-relation-decision.spec.ts index 1a3902026..afaccedcc 100644 --- a/tests/e2e/workflows/entity-relation-decision.spec.ts +++ b/tests/e2e/workflows/entity-relation-decision.spec.ts @@ -27,15 +27,17 @@ * @e2e consent-management::reversal-event-does-not-trigger-consent-creation */ -import { test, expect, type APIRequestContext, type Page } from '@playwright/test' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' import { + API, + createDavFile, + createDavFolder, harvestToken, jsonHeaders, - API, TEST_PREFIX, - createDavFolder, - createDavFile, -} from './_fixtures' +} from './_fixtures.ts' const FOLDER = `${TEST_PREFIX}-reldecision` const TERM = `Beslissing Roerdomp ${TEST_PREFIX}` diff --git a/tests/e2e/workflows/entity-review.spec.ts b/tests/e2e/workflows/entity-review.spec.ts index 397a12a9f..79f3da922 100644 --- a/tests/e2e/workflows/entity-review.spec.ts +++ b/tests/e2e/workflows/entity-review.spec.ts @@ -50,17 +50,23 @@ * rather than cleaned up. */ -import { test, expect, type APIRequestContext, type Page } from '@playwright/test' -import { appUrl, dismissOverlays, waitForAppReady } from '../spec-coverage/_helpers' +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { + appUrl, + dismissOverlays, + waitForAppReady, +} from '../spec-coverage/_helpers.ts' import { + API, + createDavFile, + createDavFolder, harvestToken, jsonHeaders, - API, - TEST_PREFIX, TEST_FAMILY, - createDavFolder, - createDavFile, -} from './_fixtures' + TEST_PREFIX, +} from './_fixtures.ts' test.describe.configure({ mode: 'serial' }) diff --git a/tests/e2e/workflows/file-viewer.spec.ts b/tests/e2e/workflows/file-viewer.spec.ts index f9b2eaf5f..32623c23d 100644 --- a/tests/e2e/workflows/file-viewer.spec.ts +++ b/tests/e2e/workflows/file-viewer.spec.ts @@ -16,15 +16,15 @@ * wrote β€” an assertion the SPA shell cannot satisfy by accident. */ -import { test, expect } from '@playwright/test' -import { go } from '../spec-coverage/_helpers' +import { expect, test } from '@playwright/test' +import { go } from '../spec-coverage/_helpers.ts' import { - harvestToken, - TEST_PREFIX, createDavFile, createDavFolder, deleteDavPath, -} from './_fixtures' + harvestToken, + TEST_PREFIX, +} from './_fixtures.ts' /** The folder MyDocumentsIndex lists by default (`myDocumentsStore.currentPath`). */ const DOCS_FOLDER = 'DocuDesk' diff --git a/tests/e2e/workflows/prohibition-override-audit-schema.spec.ts b/tests/e2e/workflows/prohibition-override-audit-schema.spec.ts index 272df70ce..39eda8fd6 100644 --- a/tests/e2e/workflows/prohibition-override-audit-schema.spec.ts +++ b/tests/e2e/workflows/prohibition-override-audit-schema.spec.ts @@ -33,8 +33,8 @@ * `.github#345` describes. */ -import { test, expect } from '@playwright/test' -import { harvestToken, jsonHeaders, TEST_PREFIX } from './_fixtures' +import { expect, test } from '@playwright/test' +import { harvestToken, jsonHeaders, TEST_PREFIX } from './_fixtures.ts' // `filinq`, not `consent`: the five registers were consolidated into one. const OR = '/index.php/apps/openregister/api/objects/filinq' diff --git a/tests/e2e/workflows/publication-policy-toggle.spec.ts b/tests/e2e/workflows/publication-policy-toggle.spec.ts index 3d354c449..655071446 100644 --- a/tests/e2e/workflows/publication-policy-toggle.spec.ts +++ b/tests/e2e/workflows/publication-policy-toggle.spec.ts @@ -98,8 +98,10 @@ * `TEST_PREFIX` and every assertion names only this run's strings. */ -import { test, expect, type APIRequestContext } from '@playwright/test' -import { harvestToken, jsonHeaders, API, TEST_PREFIX } from './_fixtures' +import type { APIRequestContext } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { API, harvestToken, jsonHeaders, TEST_PREFIX } from './_fixtures.ts' // Deliberately NOT `test.describe.configure({ mode: 'serial' })`, unlike most // files in this directory. The two tests below share no state β€” each seeds its diff --git a/tests/e2e/workflows/signing-workflow.spec.ts b/tests/e2e/workflows/signing-workflow.spec.ts index e16839897..1dd34de83 100644 --- a/tests/e2e/workflows/signing-workflow.spec.ts +++ b/tests/e2e/workflows/signing-workflow.spec.ts @@ -33,16 +33,16 @@ * @spec openspec/specs/document-signing/spec.md#view-signing-request-status */ -import { test, expect } from '@playwright/test' -import { go } from '../spec-coverage/_helpers' +import { expect, test } from '@playwright/test' +import { go } from '../spec-coverage/_helpers.ts' import { + API, + createDavFile, harvestToken, jsonHeaders, - API, - TEST_PREFIX, TEST_FAMILY, - createDavFile, -} from './_fixtures' + TEST_PREFIX, +} from './_fixtures.ts' // The views under test, named after the component files they cover. Routes are // unchanged β€” this makes the spec-to-component link readable in executable code diff --git a/tests/e2e/workflows/template-detail.spec.ts b/tests/e2e/workflows/template-detail.spec.ts index af484012f..e02b9440f 100644 --- a/tests/e2e/workflows/template-detail.spec.ts +++ b/tests/e2e/workflows/template-detail.spec.ts @@ -53,18 +53,24 @@ * that level. */ -import { test, expect, type APIRequestContext } from '@playwright/test' -import { appUrl, dismissOverlays, waitForAppReady } from '../spec-coverage/_helpers' +import type { APIRequestContext } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import { + appUrl, + dismissOverlays, + waitForAppReady, +} from '../spec-coverage/_helpers.ts' import { - harvestToken, - jsonHeaders, API, createTemplate, - getTemplate, deleteTemplate, - TEST_PREFIX, + getTemplate, + harvestToken, + jsonHeaders, TEST_FAMILY, -} from './_fixtures' + TEST_PREFIX, +} from './_fixtures.ts' // Deliberately NOT `test.describe.configure({ mode: 'serial' })`. The two // tests seed and delete their own run-stamped templates and share no state, diff --git a/tests/e2e/workflows/templates-crud.spec.ts b/tests/e2e/workflows/templates-crud.spec.ts index 3fafd4aea..671a97e32 100644 --- a/tests/e2e/workflows/templates-crud.spec.ts +++ b/tests/e2e/workflows/templates-crud.spec.ts @@ -46,20 +46,20 @@ * @spec openspec/specs/template-management/spec.md#list-templates-with-namespace-filter */ -import { test, expect } from '@playwright/test' -import { go } from '../spec-coverage/_helpers' +import { expect, test } from '@playwright/test' +import { go } from '../spec-coverage/_helpers.ts' import { - harvestToken, - jsonHeaders, API, + cleanupTemplates, createTemplate, + deleteTemplate, getTemplate, + harvestToken, + jsonHeaders, listTemplates, - deleteTemplate, - cleanupTemplates, - TEST_PREFIX, TEST_FAMILY, -} from './_fixtures' + TEST_PREFIX, +} from './_fixtures.ts' // The views under test, named after the component files they cover. Routes are // unchanged β€” this makes the spec-to-component link readable in executable code diff --git a/tests/l10n/check-l10n.js b/tests/l10n/check-l10n.js index 70c2c26c3..922da5d31 100644 --- a/tests/l10n/check-l10n.js +++ b/tests/l10n/check-l10n.js @@ -128,7 +128,7 @@ function unescape (s) { const used = new Map() function record (key, file, idx, content) { - if (key == null) { + if ((key === null || key === undefined)) { return } const k = unescape(key) @@ -154,7 +154,7 @@ for (const file of files) { const missing = [] for (const [key, locations] of used) { - if (!Object.prototype.hasOwnProperty.call(translations, key)) { + if (!Object.hasOwn(translations, key)) { missing.push({ key, locations: [...locations] }) } } diff --git a/tests/unit/reachability.spec.js b/tests/unit/reachability.spec.js index 306d01a55..98c1a4b47 100644 --- a/tests/unit/reachability.spec.js +++ b/tests/unit/reachability.spec.js @@ -23,10 +23,10 @@ * and because this file needs zero DOM. */ -import { describe, it, expect } from 'vitest' import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' +import { describe, expect, it } from 'vitest' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const REPO_ROOT = path.resolve(__dirname, '../..') diff --git a/tests/validate-manifest.js b/tests/validate-manifest.js index b3bd58612..5e2e52e59 100644 --- a/tests/validate-manifest.js +++ b/tests/validate-manifest.js @@ -93,7 +93,7 @@ function loadAjv() { // entry point. Prefer Ajv 8 (`ajv/dist/2020`) when available; otherwise // fall back to whichever ajv resolves first. let Ajv2020 = null - let addFormats = null + let addFormats const ajvCandidates = [ 'ajv/dist/2020', path.join( diff --git a/tests/vitest/anonymizationGetters.spec.js b/tests/vitest/anonymizationGetters.spec.js index b3714b043..75f3270d4 100644 --- a/tests/vitest/anonymizationGetters.spec.js +++ b/tests/vitest/anonymizationGetters.spec.js @@ -14,8 +14,8 @@ * scope. */ -import { describe, it, expect, beforeEach } from 'vitest' import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it } from 'vitest' import { useAnonymizationStore } from '../../src/store/modules/anonymization.js' beforeEach(() => { diff --git a/tests/vitest/comparisonService.spec.js b/tests/vitest/comparisonService.spec.js index 545302ef9..f3dc6d8a5 100644 --- a/tests/vitest/comparisonService.spec.js +++ b/tests/vitest/comparisonService.spec.js @@ -8,7 +8,7 @@ * and @nextcloud/router are mocked. */ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { beforeEach, describe, expect, it, vi } from 'vitest' const postMock = vi.fn() diff --git a/tests/vitest/fileViewerService.spec.js b/tests/vitest/fileViewerService.spec.js index 232d04b44..e7f45548a 100644 --- a/tests/vitest/fileViewerService.spec.js +++ b/tests/vitest/fileViewerService.spec.js @@ -12,7 +12,7 @@ * unauthenticated guard. @nextcloud/auth + router are stubbed. */ -import { describe, it, expect, afterEach } from 'vitest' +import { afterEach, describe, expect, it } from 'vitest' import { buildWebdavUrl } from '../../src/services/fileViewerService.js' import { __setCurrentUser } from '../../tests/vitest/stubs/nextcloud-auth.js' diff --git a/tests/vitest/registerI18n.spec.js b/tests/vitest/registerI18n.spec.js index 009468978..f89fbdcbb 100644 --- a/tests/vitest/registerI18n.spec.js +++ b/tests/vitest/registerI18n.spec.js @@ -13,7 +13,7 @@ * @spec openspec/specs/register-i18n/spec.md */ -import { describe, it, expect, vi } from 'vitest' +import { describe, expect, it, vi } from 'vitest' vi.mock('@nextcloud/l10n', () => ({ getLanguage: () => 'en', diff --git a/tests/vitest/settingsStore.spec.js b/tests/vitest/settingsStore.spec.js index 4906370e5..d7268521f 100644 --- a/tests/vitest/settingsStore.spec.js +++ b/tests/vitest/settingsStore.spec.js @@ -9,8 +9,8 @@ * global are mocked. */ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { createPinia, setActivePinia } from 'pinia' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { useSettingsStore } from '../../src/store/modules/settings.js' beforeEach(() => { diff --git a/tests/vitest/validationService.spec.js b/tests/vitest/validationService.spec.js index 8ddccf6f2..968e46a06 100644 --- a/tests/vitest/validationService.spec.js +++ b/tests/vitest/validationService.spec.js @@ -7,7 +7,7 @@ * @nextcloud/router are mocked. */ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { beforeEach, describe, expect, it, vi } from 'vitest' const postMock = vi.fn()