diff --git a/.changelog/20260706081519_ci_4595_to_equal_markup_vitest_matcher.md b/.changelog/20260706081519_ci_4595_to_equal_markup_vitest_matcher.md new file mode 100644 index 000000000..0c3976cb9 --- /dev/null +++ b/.changelog/20260706081519_ci_4595_to_equal_markup_vitest_matcher.md @@ -0,0 +1,13 @@ +--- +type: Major breaking change + +scope: + - ckeditor5-dev-tests + +closes: + - ckeditor/ckeditor5-internal#4595 +--- + +Replaced the `equalMarkup` Chai assertion with the `toEqualMarkup()` Vitest matcher to match the Vitest naming style. Update the call sites (`expect( a ).to.equalMarkup( b )` → `expect( a ).toEqualMarkup( b )`) and register the matcher in a Vitest setup file via `expect.extend( { toEqualMarkup } )`, importing it from `@ckeditor/ckeditor5-dev-tests`. + +The main entry point of the package now exposes only the custom Vitest matchers, so it can be imported in a browser context (for example, in a Vitest setup file). It no longer exports the `runAutomatedTests()`, `runManualTests()`, and `parseArguments()` functions, which were only used internally by the test runner binaries. Additionally, the unused `attribute` Chai assertion was removed. diff --git a/.changelog/20260706082819_remove_karma_test_runner.md b/.changelog/20260706082819_remove_karma_test_runner.md new file mode 100644 index 000000000..7c95717ad --- /dev/null +++ b/.changelog/20260706082819_remove_karma_test_runner.md @@ -0,0 +1,17 @@ +--- +type: Major breaking change + +scope: + - ckeditor5-dev-tests + - ckeditor5-dev-utils + +see: + - ckeditor/ckeditor5-internal#4595 +--- + +Removed the automated test runner: the `ckeditor5-dev-tests-run-automated` binary and the entire Karma testing environment. Automated tests are now executed directly with Vitest, using the packages' own `test` scripts. The manual test server (`ckeditor5-dev-tests-run-manual`) is unaffected. + +Along with the Karma environment, the following were removed: + +* The IntelliJ Karma runner integration and desktop notifications support (`node-notifier`). +* The `loaders.getCoverageLoader()` function from `@ckeditor/ckeditor5-dev-utils`. diff --git a/eslint.config.js b/eslint.config.js index edb9f8873..b5fab7aec 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -69,9 +69,7 @@ export default defineConfig( [ languageOptions: { globals: { - ...globals.mocha, ...globals.browser, - '__karma__': true, CKEditorInspector: true, io: true } diff --git a/packages/ckeditor5-dev-tests/README.md b/packages/ckeditor5-dev-tests/README.md index fe4cf9b4e..70d10d58a 100644 --- a/packages/ckeditor5-dev-tests/README.md +++ b/packages/ckeditor5-dev-tests/README.md @@ -4,7 +4,9 @@ CKEditor 5 testing environment [![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-dev-tests.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-dev-tests) [![CircleCI](https://circleci.com/gh/ckeditor/ckeditor5-dev.svg?style=shield)](https://app.circleci.com/pipelines/github/ckeditor/ckeditor5-dev?branch=master) -Testing environment for [CKEditor 5](https://ckeditor.com). It's based on [Karma](https://karma-runner.github.io/) and [webpack](https://webpack.github.io/) and it's normally used in the [CKEditor 5 development environment](https://github.com/ckeditor/ckeditor5). Read more about [CKEditor 5's testing environment](https://docs.ckeditor.com/ckeditor5/latest/framework/guides/contributing/testing-environment.html). +Testing environment for [CKEditor 5](https://ckeditor.com). It provides the manual test server (manual tests are compiled and served with [webpack](https://webpack.js.org/)) and the custom [Vitest](https://vitest.dev/) matchers used by the automated tests. It's normally used in the [CKEditor 5 development environment](https://github.com/ckeditor/ckeditor5). Read more about [CKEditor 5's testing environment](https://docs.ckeditor.com/ckeditor5/latest/framework/guides/contributing/testing-environment.html). + +Automated tests are executed directly with Vitest using the packages' own `test` scripts — this package no longer provides an automated test runner. More information about development tools packages can be found at the following URL: . @@ -16,91 +18,35 @@ First, you need to install the package: npm i --save-dev @ckeditor/ckeditor5-dev-tests ``` -An example npm task to test CKEditor 5 packages (used e.g. in https://github.com/ckeditor/ckeditor5) can look like this: +An example npm task to serve manual tests of CKEditor 5 packages (used e.g. in https://github.com/ckeditor/ckeditor5) can look like this: ```json { "scripts": { - "test": "node ./node_modules/.bin/ckeditor5-dev-tests-run-automated", "manual": "node ./node_modules/.bin/ckeditor5-dev-tests-run-manual" } } ``` -If you encounter problems with big test folders pass `--max_old_space_size=4096` option to node runner: - -```json -{ - "scripts": { - "test": "node --max_old_space_size=4096 ./node_modules/.bin/ckeditor5-dev-tests-run-automated" - } -} -``` - -You can also use the bin script for testing a package: - -```bash -# For running all the tests (for the current package and all dependencies). -./node_modules/.bin/ckeditor5-dev-tests --files=* - -# For running tests in the current package. -./node_modules/.bin/ckeditor5-dev-tests -``` - #### CLI options -* `browsers` - Browsers which will be used to run the tests. Also available as an alias: `-b`. -* `coverage` - Whether to generate code coverage. Also available as an alias: `-c`. -* `debug` - Allows specifying custom debug flags. For example, the `--debug engine` option uncomments the `// @if CK_DEBUG_ENGINE //` lines in the code. By default `--debug` is set to true even if you did not specify it. This enables the base set of debug logs (`// @if CK_DEBUG //`) which should always be enabled in the testing environment. You can completely turn off the debug mode by setting the `--debug false` option or `--no-debug`. -* `files` - Package names, directories or files to tests. Also available as an alias: `-f`. Read more about this option in the [Rules for using the `--files` option](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/testing-environment.html#rules-for-using-the-files-option) section. -* `language` – Specifies a language that will be used while building tests. By default it is `en`. -* `production` - Run strictest set of checks. E.g. it fails test run when there are [console calls](https://github.com/ckeditor/ckeditor5/issues/1996) or [DOM leaks](https://github.com/ckeditor/ckeditor5/issues/6002). -* `repositories` (`-r`) - Specifies names of repositories containing packages that should be tested. Those repositories should be cloned into the `external/` directory in the root directory of the project. It's a shortcut of the `--files` option as these repository packages' names will be read by the tool automatically. -* `reporter` - Mocha reporter – either `mocha` (default) or `dots` (less verbose one). -* `server` - Whether to run the server without opening any browser. -* `source-map` - Whether to generate the source maps. Also available as an alias: `-s`. -* `verbose` - Whether to informs about Webpack's work. Also available as an alias: `-v`. -* `watch` - Whether to watch the files and executing tests whenever any file changes. Also available as an alias: `-w`. - -#### Examples - -Test the `ckeditor5-enter` and `ckeditor5-paragraph` packages and generate code coverage report: +* `files` - Package names, directories or files to serve. Also available as an alias: `-f`. Read more about this option in the [Rules for using the `--files` option](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/testing-environment.html#rules-for-using-the-files-option) section. +* `repositories` (`-r`) - Specifies names of repositories containing packages that should be served. Those repositories should be cloned into the `external/` directory in the root directory of the project. It's a shortcut of the `--files` option as these repository packages' names will be read by the tool automatically. +* `debug` (`-d`) - Allows specifying custom debug flags. For example, the `--debug engine` option uncomments the `// @if CK_DEBUG_ENGINE //` lines in the code. By default `--debug` is set to true even if you did not specify it. This enables the base set of debug logs (`// @if CK_DEBUG //`) which should always be enabled in the testing environment. You can completely turn off the debug mode by setting the `--debug false` option or `--no-debug`. -```bash -$ npm t -- -c --files=enter,paragraph -``` - -Run `tests/view/**/*.js` tests from `ckeditor5-engine` and rerun them once any file change (the watch mode): - -```bash -$ npm t -- -w --files=engine/view/ -``` - -Test specified files in `ckeditor5-basic-styles` on two browsers (Chrome and Firefox): - -```bash -$ npm t -- --browsers=Chrome,Firefox --files=basic-styles/bold,basic-styles/italic -``` +Run with `--help` to see all available options. -Test all installed packages: +## Custom Vitest matchers -```bash -$ npm t -- --files=* -``` +The `toEqualMarkup()` matcher tests whether two given strings containing markup language are equal, formatting the markup before showing a diff. Register it in a Vitest setup file: -Test all installed packages except one (or more): +```js +import { expect } from 'vitest'; +import { toEqualMarkup } from '@ckeditor/ckeditor5-dev-tests'; -```bash -$ npm t -- --files='!(engine)' -$ npm t -- --files='!(engine|ui)' +expect.extend( { toEqualMarkup } ); ``` -## IDE integrations - -The CKEditor 5 can be integrated with IDEs via integrations. - -Currently only the IntelliJ based IDEs are supported (WebStorm, PHPStorm, etc). Detailed information are provided in [`bin/intellijkarmarunner/README.md`](./bin/intellijkarmarunner/README.md). - ## Changelog See the [`CHANGELOG.md`](https://github.com/ckeditor/ckeditor5-dev/blob/master/packages/ckeditor5-dev-tests/CHANGELOG.md) file. diff --git a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/README.md b/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/README.md deleted file mode 100644 index 112eb42c5..000000000 --- a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Test runner adapter for IntelliJ - -This runner allows to benefit from integrated testing environment inside your IDE. With proper setup you can -- run pre-defined set of tests (group of packages) -- run any tests right from the editor -- run tests in debug mode inside IDE -- run tests with coverage - -In order to run CKEditor 5 tests integrated into an IntelliJ IDE of your preference (WebStorm, PHPStorm, etc) you need to have [`Karma`](https://plugins.jetbrains.com/plugin/7287-karma/) plugin installed. - -## Basic run configuration - -Use this configuration for running tests as you would use `--files` directive: - -```bash -pnpm run test --files=engine,basic-styles -``` - -1. In the IDE, go to _Run_ > _Edit configurations..._: -1. Add a new configuration of type "**Karma**" and a name of your preference. -1. In "Configuration file", selected the "**node\_modules/ckeditor5-dev-tests/bin/intellijkarmarunner/karma.config.cjs**" file. -1. In "Karma Package", selected the "**node\_modules/ckeditor5-dev-tests/bin/intellijkarmarunner**" directory. -1. In "Karma options", input the CKEditor 5 tests arguments. E.g. `--files=engine,basic-styles`. -1. In "Working directory", select the base `ckeditor5` directory. -1. In "Test name", select the "All tests" option. -1. Save the configuration. - -**Note**: This `karma.config.js` configuration file does nothing, but it's necessary to avoid the IDE complaining that there is no configuration file set. - -Now just run this configuration directly inside your IntelliJ IDE and the tests will be reported in the IDE itself, including the bells and whistles that the IDE provides. - -## Enabling IDE integrations - -## Running single test or test suite - -The IntelliJ IDE provides a way to run single file or a suite using icons in the left gutter of the editing window. To enable the Karma configuration template must be changed. - -1. In the IDE, go to _Run_ > _Edit configurations..._: -1. Select the _Templates_ > "**Karma**". -1. In "Configuration file", selected the "**node\_modules/ckeditor5-dev-tests/bin/intellijkarmarunner/karma.config.js**" file. -1. In "Karma Package", selected the "**node\_modules/ckeditor5-dev-tests/bin/intellijkarmarunner**" directory. -1. In "Karma options", input the CKEditor 5 tests arguments `-sc` to enable code navigation and coverage. -1. In "Working directory", select the base `ckeditor5` directory. -1. In "Test name", select the "Test" option. -1. Save the template. - -**Note** The coverage will only be collected when using the "Run with coverage". - -**Note** This will create a temporary run configuration which you can save . - -### Using code navigation from the test output window - -It is convenient to directly navigate from a failed test output message containing stack trace. To enable that use `-s` sourcemap switch when defining new configuration to "Karma options" field. - -### Running tests with coverage - -To run tests with coverage (`pnpm run test -c`) add the `-c` switch when defining new configuration to "Karma options" field. - -**Note**: Must be combined with `-s` switch to display the coverage in files inside IDE. diff --git a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/bin/karma b/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/bin/karma deleted file mode 100755 index ae2abdd59..000000000 --- a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/bin/karma +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env node - -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -// This file is the one called by IntelliJ's test runner. -// -// Out goal here is intercepting the command line arguments sent by IntelliJ and transform -// them so our test script adds the IntelliJ test reporter when running karma. - -// The following proccess.argv is received from the IntelliJ runner: -// [ -// '/local path.../node', -// -// // This file. -// '/local path.../ckeditor5-dev-tests/bin/intellijkarmarunner/bin/karma', -// -// 'start', -// -// // InlelliJ configuration for Karma, which injects its reporters. -// '/local path.../karma-intellij/lib/intellij.conf.js', -// -// // Karma arguments, if set in the test runner configuration dialog. -// ... -// ] - -// Take the IntelliJ configuration file path. -const intellijConfig = process.argv.find( item => item.includes( 'intellij.conf.js' ) ); - -// Set the path as an command line argument that is understood by our test script. -process.argv.push( '--karma-config-overrides=' + intellijConfig ); - -// Now running the tests. -import( '../../testautomated.js' ); diff --git a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/karma.config.cjs b/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/karma.config.cjs deleted file mode 100644 index 5ca312ae8..000000000 --- a/packages/ckeditor5-dev-tests/bin/intellijkarmarunner/karma.config.cjs +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -module.exports = function() { - // No configurations are really set here. This file is just a dumb configuration file to be - // used when setting up the IntelliJ test runner so the IDE will no complain that there is - // no configuration file set. -}; diff --git a/packages/ckeditor5-dev-tests/bin/postinstall.js b/packages/ckeditor5-dev-tests/bin/postinstall.js deleted file mode 100755 index 75c22a6a1..000000000 --- a/packages/ckeditor5-dev-tests/bin/postinstall.js +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env node - -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import isWsl from 'is-wsl'; -import { execSync } from 'node:child_process'; -import { createRequire } from 'node:module'; - -const require = createRequire( import.meta.url ); - -if ( isWsl ) { - const executables = [ - require.resolve( 'node-notifier/vendor/snoreToast/snoretoast-x64.exe' ), - require.resolve( 'node-notifier/vendor/snoreToast/snoretoast-x86.exe' ) - ]; - - for ( const item of executables ) { - execSync( `chmod +x ${ item }` ); - } -} diff --git a/packages/ckeditor5-dev-tests/bin/testautomated.js b/packages/ckeditor5-dev-tests/bin/testautomated.js deleted file mode 100755 index 35ee58e10..000000000 --- a/packages/ckeditor5-dev-tests/bin/testautomated.js +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node - -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import fs from 'node:fs'; -import { styleText } from 'node:util'; -import { loadEnvFile } from 'node:process'; -import * as tests from '../lib/index.js'; - -const options = tests.parseArguments( process.argv.slice( 2 ), { - commandName: 'ckeditor5-dev-tests-run-automated' -} ); - -if ( options.files.length === 0 ) { - options.files = [ '*' ]; -} - -if ( fs.existsSync( '.env' ) ) { - loadEnvFile( '.env' ); -} - -tests.runAutomatedTests( options ) - .then( () => { - process.exit( 0 ); - } ) - .catch( error => { - const message = error instanceof Error ? error.stack : error.toString(); - console.log( styleText( 'red', message ) ); - - // Mark result of this task as invalid. - process.exit( 1 ); - } ); diff --git a/packages/ckeditor5-dev-tests/bin/testmanual.js b/packages/ckeditor5-dev-tests/bin/testmanual.js index fde8c068d..aa276d652 100755 --- a/packages/ckeditor5-dev-tests/bin/testmanual.js +++ b/packages/ckeditor5-dev-tests/bin/testmanual.js @@ -8,9 +8,10 @@ import fs from 'node:fs'; import { styleText } from 'node:util'; import { loadEnvFile } from 'node:process'; -import * as tests from '../lib/index.js'; +import runManualTests from '../lib/tasks/runmanualtests.js'; +import parseArguments from '../lib/utils/parsearguments.js'; -const options = tests.parseArguments( process.argv.slice( 2 ), { +const options = parseArguments( process.argv.slice( 2 ), { allowDefaultIdentityFile: true, commandName: 'ckeditor5-dev-tests-run-manual' } ); @@ -19,7 +20,7 @@ if ( fs.existsSync( '.env' ) ) { loadEnvFile( '.env' ); } -tests.runManualTests( options ) +runManualTests( options ) .catch( error => { const message = error instanceof Error ? error.stack : error.toString(); console.log( styleText( 'red', message ) ); diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorbefore.js b/packages/ckeditor5-dev-tests/lib/index.d.ts similarity index 57% rename from packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorbefore.js rename to packages/ckeditor5-dev-tests/lib/index.d.ts index fc14c9077..7f096bee2 100644 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorbefore.js +++ b/packages/ckeditor5-dev-tests/lib/index.d.ts @@ -3,6 +3,4 @@ * For licensing, see LICENSE.md. */ -beforeEach( function() { - this._lastDomElements = new WeakSet( document.body.children ); -} ); +export { toEqualMarkup, MarkupMatcherResult } from './vitest/matchers.js'; diff --git a/packages/ckeditor5-dev-tests/lib/index.js b/packages/ckeditor5-dev-tests/lib/index.js index 759db9523..e3e3f4726 100644 --- a/packages/ckeditor5-dev-tests/lib/index.js +++ b/packages/ckeditor5-dev-tests/lib/index.js @@ -3,6 +3,4 @@ * For licensing, see LICENSE.md. */ -export { default as runAutomatedTests } from './tasks/runautomatedtests.js'; -export { default as runManualTests } from './tasks/runmanualtests.js'; -export { default as parseArguments } from './utils/parsearguments.js'; +export { toEqualMarkup } from './vitest/matchers.js'; diff --git a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js deleted file mode 100644 index c4d1b94f9..000000000 --- a/packages/ckeditor5-dev-tests/lib/tasks/runautomatedtests.js +++ /dev/null @@ -1,464 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import fs from 'node:fs'; -import { spawn } from 'node:child_process'; -import { styleText } from 'node:util'; -import { logger } from '@ckeditor/ckeditor5-dev-utils'; -import getKarmaConfig from '../utils/automated-tests/getkarmaconfig.js'; -import { globSync } from 'glob'; -import { minimatch } from 'minimatch'; -import { mkdirp } from 'mkdirp'; -import karmaLogger from 'karma/lib/logger.js'; -import karma from 'karma'; -import transformFileOptionToTestGlob from '../utils/transformfileoptiontotestglob.js'; -import upath from 'upath'; - -// Glob patterns that should be ignored. It means if a specified test file is located under path -// that matches to these patterns, the file will be skipped. -const IGNORE_GLOBS = [ - // Ignore files which are saved in `manual/` directory. There are manual tests. - upath.join( '**', 'tests', '**', 'manual', '**', '*.{js,ts}' ), - // Ignore `_utils` directory as well because there are saved utils for tests. - upath.join( '**', 'tests', '**', '_utils', '**', '*.{js,ts}' ) -]; - -export default async function runAutomatedTests( options ) { - if ( !options.production ) { - console.warn( styleText( - 'yellow', - '⚠ You\'re running tests in dev mode - some error protections are loose. Use the `--production` flag ' + - 'to use strictest verification methods.' - ) ); - } - - const globPatterns = resolveTestGlobs( options.files ); - const testFiles = collectTestFiles( globPatterns ); - const { karmaFiles, vitestSelection, vitestPackageRoots } = partitionByRunner( testFiles ); - - if ( !karmaFiles.length && !vitestSelection.length ) { - throw new Error( 'No test files found. Specified patterns are invalid.' ); - } - - if ( karmaFiles.length && vitestSelection.length && ( options.watch || options.server ) ) { - throw new Error( - 'Watch/server mode cannot be used in a mixed Karma + Vitest run. ' + - 'Run watch/server mode separately for Karma and Vitest packages.' - ); - } - - if ( options.watch && vitestSelection.length > 1 ) { - throw new Error( - 'Watch mode cannot be used for multiple Vitest projects in one run. ' + - 'Run watch mode separately for each Vitest project.' - ); - } - - const errors = []; - - if ( karmaFiles.length ) { - try { - await runKarmaTests( options, karmaFiles ); - } catch ( error ) { - errors.push( error ); - } - } - - if ( vitestSelection.length ) { - try { - await spawnVitest( options, vitestSelection, vitestPackageRoots ); - } catch ( error ) { - errors.push( error ); - } - } - - if ( errors.length ) { - throw aggregateErrors( errors ); - } -} - -// -- Glob resolution & file collection ----------------------------------------------------------- - -function resolveTestGlobs( files ) { - if ( !Array.isArray( files ) || files.length === 0 ) { - throw new Error( 'Test runner requires files to test. `options.files` has to be a non-empty array.' ); - } - - const globMap = {}; - - for ( const file of files ) { - globMap[ file ] = transformFileOptionToTestGlob( file ); - } - - return globMap; -} - -function collectTestFiles( globPatterns ) { - karmaLogger.setupFromConfig( { logLevel: 'INFO' } ); - - const log = karmaLogger.create( 'config' ); - const allFiles = []; - - for ( const [ pattern, resolvedGlobs ] of Object.entries( globPatterns ) ) { - let hasFiles = false; - - for ( const glob of resolvedGlobs ) { - const files = globSync( glob ).map( f => upath.normalize( f ) ); - - if ( files.length ) { - hasFiles = true; - } - - allFiles.push( - ...files.filter( file => !IGNORE_GLOBS.some( ignore => minimatch( file, ignore ) ) ) - ); - } - - if ( !hasFiles ) { - log.warn( 'Pattern "%s" does not match any file.', pattern ); - } - } - - return allFiles; -} - -// -- Runner partitioning -------------------------------------------------------------------------- - -function partitionByRunner( testFiles ) { - const karmaFiles = []; - const vitestSelection = new Map(); - const vitestPackageRoots = new Map(); - const runnerCache = new Map(); - - for ( const filePath of testFiles ) { - const packageRoot = getPackageRoot( filePath ); - - if ( !runnerCache.has( packageRoot ) ) { - runnerCache.set( packageRoot, detectPackageRunner( packageRoot ) ); - } - - const { runner, projectName } = runnerCache.get( packageRoot ); - - if ( runner === 'vitest' ) { - const files = vitestSelection.get( projectName ) || []; - files.push( filePath ); - vitestSelection.set( projectName, files ); - vitestPackageRoots.set( projectName, packageRoot ); - } else { - karmaFiles.push( filePath ); - } - } - - return { - karmaFiles, - vitestSelection: [ ...vitestSelection.entries() ], - vitestPackageRoots - }; -} - -function getPackageRoot( filePath ) { - const normalized = upath.normalize( filePath ); - const testsIndex = normalized.lastIndexOf( '/tests/' ); - - if ( testsIndex === -1 ) { - throw new Error( `Cannot determine package root for "${ filePath }".` ); - } - - return normalized.slice( 0, testsIndex ); -} - -function detectPackageRunner( packageRoot ) { - const projectName = upath.basename( packageRoot ).replace( /^ckeditor5-/, '' ); - const packageJson = JSON.parse( fs.readFileSync( upath.join( packageRoot, 'package.json' ), 'utf8' ) ); - const runner = packageJson.scripts?.test?.includes( 'vitest' ) ? 'vitest' : 'karma'; - - return { projectName, runner }; -} - -// -- Karma runner --------------------------------------------------------------------------------- - -async function runKarmaTests( options, karmaFiles ) { - const entryFilePath = upath.join( process.cwd(), 'build', '.automated-tests', 'entry-point.js' ); - - createKarmaEntryFile( entryFilePath, karmaFiles, options.production ); - - // Build globPatterns from karmaFiles only, so the coverage loader instruments - // just the Karma packages' source code — not Vitest packages that happen to be - // imported transitively. - return startKarmaServer( { - ...options, - entryFile: entryFilePath, - globPatterns: { karma: karmaFiles } - } ); -} - -function createKarmaEntryFile( entryFilePath, files, production ) { - const utilsDir = upath.join( import.meta.dirname, '..', 'utils', 'automated-tests' ); - const testImports = [ ...files ]; - - // Set global license key in the `before` hook. - testImports.unshift( upath.join( utilsDir, 'licensekeybefore.js' ) ); - - // Inject the leak detector root hooks. Need to be split into two parts due to #598. - testImports.splice( 0, 0, upath.join( utilsDir, 'leaksdetectorbefore.js' ) ); - testImports.push( upath.join( utilsDir, 'leaksdetectorafter.js' ) ); - - const entryLines = testImports.map( file => `import "${ file }";` ); - - // Inject the custom chai assertions. See ckeditor/ckeditor5#9668. - const assertionsDir = upath.join( utilsDir, 'assertions' ); - const customAssertions = fs.readdirSync( assertionsDir ).map( assertionFileName => { - return [ - assertionFileName, - upath.parse( assertionFileName ).name.replace( /-([a-z])/g, value => value[ 1 ].toUpperCase() ) - ]; - } ); - - // Two loops are needed to achieve correct order in `ckeditor5/build/.automated-tests/entry-point.js`. - for ( const [ fileName, functionName ] of customAssertions ) { - entryLines.push( `import ${ functionName }Factory from "${ assertionsDir }/${ fileName }";` ); - } - for ( const [ , functionName ] of customAssertions ) { - entryLines.push( `${ functionName }Factory( chai );` ); - } - - if ( production ) { - entryLines.unshift( assertConsoleUsageToThrowErrors() ); - } - - mkdirp.sync( upath.dirname( entryFilePath ) ); - fs.writeFileSync( entryFilePath, entryLines.join( '\n' ) + '\n' ); - - // Webpack watcher compiles the file in a loop. It causes to Karma that runs tests multiple times in watch mode. - // A ugly hack blocks the loop and tests are executed once. - // See: https://github.com/webpack/watchpack/issues/25. - const now = Date.now() / 1000; - // 10 sec is default value of FS_ACCURENCY (which is hardcoded in Webpack watcher). - const then = now - 10; - fs.utimesSync( entryFilePath, then, then ); -} - -function startKarmaServer( options ) { - return new Promise( ( resolve, reject ) => { - const KarmaServer = karma.Server; - const parseConfig = karma.config.parseConfig; - - const config = getKarmaConfig( options ); - const parsedConfig = parseConfig( null, config, { throwErrors: true } ); - - const server = new KarmaServer( parsedConfig, exitCode => { - if ( exitCode === 0 ) { - resolve(); - } else { - reject( new Error( `Karma finished with "${ exitCode }" code.` ) ); - } - } ); - - if ( options.coverage ) { - const coveragePath = upath.join( process.cwd(), 'coverage' ); - - server.on( 'run_complete', () => { - // Use timeout to not write to the console in the middle of Karma's status. - setTimeout( () => { - const log = logger(); - - log.info( `Coverage report saved in '${ styleText( 'cyan', coveragePath ) }'.` ); - } ); - } ); - } - - server.start(); - } ); -} - -// -- Vitest runner -------------------------------------------------------------------------------- - -async function spawnVitest( options, vitestSelection, packageRoots ) { - const errors = []; - - for ( const [ project, selectedFiles ] of vitestSelection ) { - try { - await spawnVitestProject( options, project, selectedFiles, packageRoots.get( project ) ); - } catch ( error ) { - errors.push( error ); - } - } - - if ( options.coverage ) { - try { - await mergeVitestCoverage( vitestSelection ); - } catch ( error ) { - errors.push( error ); - } - } - - if ( errors.length ) { - if ( errors.length === 1 ) { - throw errors[ 0 ]; - } - - const details = errors.map( e => `- ${ e.message }` ).join( '\n' ); - throw new Error( `Vitest execution failed in multiple projects:\n${ details }` ); - } -} - -// Vitest runs from the package directory, so it loads the package-level config directly. -// Using the workspace config with `--project ` hangs in browser mode when multiple -// test files run, because per-file isolation does not tear down the browser context. -// Running per-package avoids that path while keeping coverage compatible: reports still -// go to the workspace `coverage-vitest//` directory via absolute -// `--coverage.reportsDirectory`. -function spawnVitestProject( options, project, selectedFiles, packageRoot ) { - return new Promise( ( resolve, reject ) => { - const args = [ 'vitest' ]; - - args.push( options.watch ? '--watch' : '--run' ); - - if ( options.coverage ) { - const coverageDir = upath.join( process.cwd(), 'coverage-vitest', project ); - - args.push( - '--coverage.enabled', - '--coverage.reportsDirectory', coverageDir, - // Force the reporters the wrapper expects. The package's own `vitest.config.ts` - // defaults to `text`/`html` (developer-friendly); downstream coverage merging - // needs `json` (for nyc) and `lcovonly` (collected by - // `check-unit-tests-for-package.mjs`). - '--coverage.reporter', 'json', - '--coverage.reporter', 'lcovonly', - '--coverage.reporter', 'html' - ); - } - - for ( const filePath of selectedFiles ) { - args.push( upath.relative( packageRoot, filePath ) ); - } - - const child = spawn( 'pnpm', args, { - stdio: 'inherit', - cwd: packageRoot, - shell: process.platform === 'win32' - } ); - - child.on( 'error', reject ); - - child.on( 'close', exitCode => { - if ( exitCode === 0 || exitCode === 130 ) { - resolve(); - } else { - reject( new Error( `Vitest finished with "${ exitCode }" code.` ) ); - } - } ); - } ); -} - -function mergeVitestCoverage( vitestSelection ) { - const cwd = process.cwd(); - const coverageBaseDir = upath.join( cwd, 'coverage-vitest' ); - const nycOutputDir = upath.join( coverageBaseDir, '.nyc_output' ); - - mkdirp.sync( nycOutputDir ); - - // Copy each project's coverage-final.json into .nyc_output/ so nyc can merge them. - for ( const [ project ] of vitestSelection ) { - const sourceFile = upath.join( coverageBaseDir, project, 'coverage-final.json' ); - - if ( fs.existsSync( sourceFile ) ) { - fs.copyFileSync( sourceFile, upath.join( nycOutputDir, `${ project }.json` ) ); - } - } - - const log = logger(); - - return new Promise( ( resolve, reject ) => { - const child = spawn( 'pnpx', [ - 'nyc', 'report', - '--temp-dir', nycOutputDir, - '--report-dir', coverageBaseDir, - '--reporter', 'html', - '--reporter', 'json', - '--reporter', 'lcovonly', - '--reporter', 'text-summary' - ], { - stdio: 'inherit', - cwd, - shell: process.platform === 'win32' - } ); - - child.on( 'error', reject ); - - child.on( 'close', exitCode => { - if ( exitCode === 0 ) { - log.info( `Combined Vitest coverage report saved in '${ styleText( 'cyan', coverageBaseDir ) }'.` ); - resolve(); - } else { - reject( new Error( `nyc report finished with "${ exitCode }" code.` ) ); - } - } ); - } ); -} - -// -- Error handling ------------------------------------------------------------------------------- - -function aggregateErrors( errors ) { - if ( errors.length === 1 ) { - return errors[ 0 ]; - } - - const details = errors.map( e => `- ${ e.message }` ).join( '\n' ); - return new Error( `Test execution failed in multiple runners:\n${ details }` ); -} - -// -- Console assertion (production mode) ---------------------------------------------------------- - -function assertConsoleUsageToThrowErrors() { - const functionString = makeConsoleUsageToThrowErrors.toString(); - - return functionString - // Extract the body of the function from between the opening and closing braces. - .substring( - functionString.indexOf( '{' ) + 1, - functionString.lastIndexOf( '}' ) - ) - // Remove the leading and trailing new lines. - .trim() - // Decrease indent for the extracted function body by one tab. - .replace( /^\t/gm, '' ); -} - -function makeConsoleUsageToThrowErrors() { - const originalWarn = console.warn; - - window.production = true; - - // Important: Do not remove the comment below. It is used to assert this function insertion in tests. - // - // Make using any method from the console to fail. - before( () => { - Object.keys( console ) - .filter( methodOrProperty => typeof console[ methodOrProperty ] === 'function' ) - .forEach( method => { - console[ method ] = ( ...data ) => { - originalWarn( 'Detected `console.' + method + '()`:', ...data ); - - // Previously, the error was thrown at this point. Unfortunately, it may happen that some asynchronous piece of code - // will call a console method after Mocha has finished the test. In that case: - // * Mocha will not be able to catch such a thrown error, even though it has registered the "uncaughtException" and the - // "unhandledRejection" error handlers. - // * Mocha will not be able to mark the test as failed. - // * Karma will finish the whole test run, and in the console, you will see something like "Executed 42 of 191 SUCCESS". - // - // Probably the test that causes such problems is incorrectly written: - // * The "done()" function is not called at the right moment, or the test does not return a promise. - // * Not all dependencies used in the source code under test are mocked, and they cause side effects, i.e., asynchronous - // console method calls after the test is over. - // - // To ensure that the console methods usage still fail the whole test run, we are calling the error handler from Karma - // to stop the Karma server. - __karma__.error( 'Detected `console.' + method + '()`: ' + data[ 0 ] ); - }; - } ); - } ); -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/attribute.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/attribute.js deleted file mode 100644 index c65e6d808..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/attribute.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -/** - * Factory function that registers the `attribute` assertion. - * - * @param {Chai} chai - */ -export default chai => { - /** - * Asserts that the target has an attribute with the given key name. - * - * expect( selection ).to.have.attribute( 'linkHref' ); - * - * When `value` is provided, `.attribute` also asserts that the attribute's value is equal to the given `value`. - * - * expect( selection ).to.have.attribute( 'linkHref', 'example.com' ); - * - * Negations works as well. - * - * @param {string} key Key of attribute to assert. - * @param {string} [value] Attribute value to assert. - */ - chai.Assertion.addMethod( 'attribute', function attributeAssertion( key, value ) { - const obj = this._obj; - - if ( arguments.length === 1 ) { - // Check if it has the method at all. - new chai.Assertion( obj ).to.respondTo( 'hasAttribute' ); - - // Check if it has the attribute. - const hasAttribute = obj.hasAttribute( key ); - this.assert( - hasAttribute === true, - `expected #{this} to have attribute '${ key }'`, - `expected #{this} to not have attribute '${ key }'`, - !chai.util.flag( this, 'negate' ), - hasAttribute - ); - } - - // If a value was given. - if ( arguments.length >= 2 ) { - // Check if it has the method at all. - new chai.Assertion( obj ).to.respondTo( 'getAttribute' ); - - const attributeValue = obj.getAttribute( key ); - this.assert( - attributeValue === value, - `expected #{this} to have attribute '${ key }' of #{exp}, but got #{act}`, - `expected #{this} to not have attribute '${ key }' of #{exp}`, - value, - attributeValue - ); - } - } ); -}; diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/equal-markup.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/equal-markup.js deleted file mode 100644 index 2f6e51ddd..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/assertions/equal-markup.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { AssertionError } from 'assertion-error'; -import { html_beautify as beautify } from 'js-beautify'; - -/** - * Factory function that registers the `equalMarkup` assertion. - * - * @param {Chai} chai - */ -export default chai => { - /** - * Custom assertion that tests whether two given strings containing markup language are equal. - * Unlike `expect().to.equal()` form Chai assertion library, this assertion formats the markup before showing a diff. - * - * This assertion can be used to test HTML strings and string containing serialized model. - * - * // Will throw an assertion error. - * expect( - * 'foo bXXX[]r baz' - * ).to.equalMarkup( - * 'foo bYYY[]r baz' - * ); - * - * Please note that if the difference in the markup concerns only whitespace characters inside tags (e.g. between attributes), - * a diff between unformatted (rather than formatted) strings is displayed. - * - * // Will throw an assertion error, but without formatting the markup. - * expect( - * '[]foobar' - * ).to.equalMarkup( - * '[]foobar' - * ); - * - * @param {string} expected Markup to compare. - */ - chai.Assertion.addMethod( 'equalMarkup', function( expected ) { - const actual = this._obj; - const message = 'Expected markup strings to be equal'; - - if ( actual !== expected ) { - const actualFormatted = formatMarkup( actual ); - const expectedFormatted = formatMarkup( expected ); - const areFormattedStringsEqual = actualFormatted === expectedFormatted; - - // HTML beautification tool removes all redundant whitespace characters inside tags and this behavior cannot be configured. - // Therefore, if there is no difference between formatted strings, but we know they are different, display raw (unformatted) - // strings instead. - const data = { - actual: areFormattedStringsEqual ? actual : actualFormatted, - expected: areFormattedStringsEqual ? expected : expectedFormatted, - showDiff: true - }; - - throw new AssertionError( message, data ); - } - } ); -}; - -// Renames the $text occurrences as it is not properly formatted by the beautifier - it is tread as a block. -const TEXT_TAG_PLACEHOLDER = 'span data-cke="true"'; -const TEXT_TAG_PLACEHOLDER_REGEXP = new RegExp( TEXT_TAG_PLACEHOLDER, 'g' ); - -function formatMarkup( string ) { - const htmlSafeString = string.replace( /\$text/g, TEXT_TAG_PLACEHOLDER ); - - const beautifiedMarkup = beautify( htmlSafeString, { - indent_size: 2, - space_in_empty_paren: true - } ); - - return beautifiedMarkup.replace( TEXT_TAG_PLACEHOLDER_REGEXP, '$text' ); -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getkarmaconfig.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getkarmaconfig.js deleted file mode 100644 index db8b3c4f0..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getkarmaconfig.js +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import { createRequire } from 'node:module'; -import getWebpackConfigForAutomatedTests from './getwebpackconfig.js'; -import { resolvePath } from '../resolve-path.js'; - -const require = createRequire( import.meta.url ); - -const AVAILABLE_REPORTERS = [ - 'mocha', - 'dots' -]; - -/** - * @param {object} options - * @returns {object} - */ -export default function getKarmaConfig( options ) { - if ( !AVAILABLE_REPORTERS.includes( options.reporter ) ) { - throw new Error( `Specified reporter is not supported. Available reporters: ${ AVAILABLE_REPORTERS.join( ', ' ) }.` ); - } - - const basePath = process.cwd(); - const coverageDir = path.join( basePath, 'coverage' ); - const utilsAssets = path.resolve( - resolvePath( '@ckeditor/ckeditor5-utils/package.json', { paths: [ basePath ] } ), - '..', 'tests', '_assets' - ); - - const preprocessorMap = { - [ options.entryFile ]: [ 'webpack' ] - }; - - if ( options.sourceMap ) { - preprocessorMap[ options.entryFile ].push( 'sourcemap' ); - } - - const karmaConfig = { - // Base path that will be used to resolve all patterns (eg. files, exclude). - basePath, - - // Frameworks to use. Available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: [ 'mocha', 'sinon-chai', 'webpack' ], - - // For unknown reasons, sometimes Karma does not fill the list automatically. So, all available plugins must be specified manually. - plugins: [ - require.resolve( 'karma-chai' ), - require.resolve( 'karma-chrome-launcher' ), - require.resolve( 'karma-coverage' ), - require.resolve( 'karma-firefox-launcher' ), - require.resolve( 'karma-mocha' ), - require.resolve( 'karma-mocha-reporter' ), - require.resolve( 'karma-sinon' ), - require.resolve( 'karma-sinon-chai' ), - require.resolve( 'karma-sourcemap-loader' ), - require.resolve( 'karma-webpack' ) - ], - - // Files saved in directory `ckeditor5-utils/tests/_assets/` package are available under: http://0.0.0.0:{port}/assets/ - proxies: { - '/assets/': utilsAssets + '/', - - // See: https://github.com/ckeditor/ckeditor5/issues/8823. - '/example.com/image.png': path.join( utilsAssets, 'sample.png' ), - '/www.example.com/image.png': path.join( utilsAssets, 'sample.png' ) - }, - - // List of files/patterns to load in the browser. - files: [ - options.entryFile, - { - pattern: path.resolve( utilsAssets, '**', '*' ), - watched: false, - included: false, - served: true, - nocache: false - } - ], - - // Preprocess matching files before serving them to the browser. - // Available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: preprocessorMap, - - webpack: getWebpackConfigForAutomatedTests( { - ...options, - files: Object.keys( options.globPatterns ).map( key => options.globPatterns[ key ] ) - } ), - - webpackMiddleware: { - noInfo: true, - stats: 'minimal' - }, - - // Test results reporter to use. Possible values: 'dots', 'progress'. - // Available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: [ options.reporter ], - - // Web server port. - port: options.port || 9876, - - // Enable/Disable colors in the output (reporters and logs). - colors: true, - - // Level of logging. Possible values: - // config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: 'INFO', - - // Start these browsers. - // Available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: getBrowsers( options ), - - customLaunchers: { - CHROME_CI: { - base: 'Chrome', - flags: getFlagsForBrowser( 'CHROME_CI' ) - }, - CHROME_LOCAL: { - base: 'Chrome', - flags: getFlagsForBrowser( 'CHROME_LOCAL' ) - }, - ChromeHeadlessCustom: { - base: 'ChromeHeadless', - flags: getFlagsForBrowser( 'CHROME_HEADLESS' ) - } - }, - - // Continuous Integration mode. If true, Karma captures browsers, runs the tests and exits. - singleRun: true, - - // Concurrency level. How many browser should be started simultaneous. - concurrency: Infinity, - - // How long will Karma wait for a message from a browser before disconnecting from it (in ms). - browserNoActivityTimeout: 0, - - // Shows differences in object comparison. - mochaReporter: { - showDiff: true - } - }; - - // Notification is enabled by default when executing all tests. - if ( options.notify || !options.files ) { - karmaConfig.reporters.push( 'karmanotifier' ); - karmaConfig.plugins.push( require( path.join( import.meta.dirname, 'karmanotifier.js' ) ) ); - } - - if ( options.watch || options.server ) { - // Enable/Disable watching file and executing tests whenever any file changes. - karmaConfig.autoWatch = true; - karmaConfig.singleRun = false; - } - - if ( options.verbose ) { - karmaConfig.webpackMiddleware.noInfo = false; - delete karmaConfig.webpackMiddleware.stats; - } - - if ( options.coverage ) { - karmaConfig.reporters.push( 'coverage' ); - - karmaConfig.coverageReporter = { - reporters: [ - /** - * Prints a table after tests result. - * - * Since we don't have access to the generated HTML report on CI, - * we want to print all the results to the console so that it's - * easier to find out which files and lines are not covered. - */ - { - type: process.env.CI ? 'text' : 'text-summary' - }, - // Generates HTML tables with the results. - { - dir: coverageDir, - type: 'html' - }, - { - dir: coverageDir, - type: 'json' - }, - // Generates "lcov.info" file. It's used by external code coverage services. - { - type: 'lcovonly', - dir: coverageDir - } - ], - watermarks: { - statements: [ 50, 100 ], - functions: [ 50, 100 ], - branches: [ 50, 100 ], - lines: [ 50, 100 ] - } - }; - } - - if ( options.karmaConfigOverrides ) { - const overrides = require( options.karmaConfigOverrides ); - overrides( karmaConfig ); - - // Watch for source files when running in Intellij IDE, for instance, WebStorm. - // Otherwise, Karma compiles sources once, and the test bundle uses old code. - // For the future reference: https://youtrack.jetbrains.com/issue/WEB-12496. - karmaConfig.webpack.watch = true; - - // Remove "instrumenter" if coverage reporter was removed by overrides - // (especially when debugging in Intellij IDE). - if ( !karmaConfig.reporters.includes( 'coverage' ) && karmaConfig.webpack.module ) { - const moduleRules = karmaConfig.webpack.module.rules; - const ruleIdx = moduleRules.findIndex( rule => rule.loader === 'babel-loader' ); - - if ( ruleIdx != -1 ) { - moduleRules.splice( ruleIdx, 1 ); - } - } - } - - return karmaConfig; -} - -// Returns the value of Karma's browser option. -// @returns {Array|null} -function getBrowsers( options ) { - if ( options.server || !options.browsers ) { - return null; - } - - return options.browsers.map( browser => { - if ( browser === 'ChromeHeadless' ) { - return 'ChromeHeadlessCustom'; - } - - if ( browser !== 'Chrome' ) { - return browser; - } - - return process.env.CI ? 'CHROME_CI' : 'CHROME_LOCAL'; - } ); -} - -// Returns the array of configuration flags for given browser. -// -// @param {string} browser -// @returns {Array.} -function getFlagsForBrowser( browser ) { - const commonFlags = [ - '--disable-background-timer-throttling', - '--js-flags="--expose-gc"', - '--disable-renderer-backgrounding', - '--disable-backgrounding-occluded-windows', - '--disable-search-engine-choice-screen', - '--window-size=1920,1080' - ]; - - if ( browser === 'CHROME_CI' ) { - return [ - ...commonFlags, - '--no-sandbox' - ]; - } - - return [ - ...commonFlags, - '--remote-debugging-port=9222' - ]; -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getwebpackconfig.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getwebpackconfig.js deleted file mode 100644 index 0a9e76e0b..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getwebpackconfig.js +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import webpack from 'webpack'; -import { loaders } from '@ckeditor/ckeditor5-dev-utils'; -import getDefinitionsFromFile from '../getdefinitionsfromfile.js'; -import getProtobufJsInquireWebpackRule from '../getprotobufjsinquirewebpackrule.js'; -import TreatWarningsAsErrorsWebpackPlugin from './treatwarningsaserrorswebpackplugin.js'; - -/** - * @param {object} options - * @returns {object} - */ -export default function getWebpackConfigForAutomatedTests( options ) { - const definitions = Object.assign( {}, getDefinitionsFromFile( options.identityFile ) ); - - const config = { - mode: 'development', - - watchOptions: { - aggregateTimeout: 500 - }, - - plugins: [ - new webpack.EnvironmentPlugin( { - CKEDITOR_LICENSE_KEY: '' - } ), - new webpack.DefinePlugin( definitions ), - new webpack.ProvidePlugin( { - Buffer: [ 'buffer', 'Buffer' ], - process: 'process/browser.js' - } ), - - /** - * Disable tree-shaking because it removes tests for packages with `sideEffects` field in `package.json`. - * - * Workaround for https://github.com/ckeditor/ckeditor5/issues/17767#issuecomment-2598263796. - */ - { - apply( compiler ) { - compiler.options.optimization = { - ...compiler.options.optimization, - sideEffects: false - }; - } - } - ], - - resolve: { - fallback: { - 'timers': false - }, - - extensions: options.resolveJsFirst ? - [ '.js', '.ts', '.json' ] : - [ '.ts', '.js', '.json' ], - - extensionAlias: { - '.js': [ '.ts', '.js' ] - } - }, - - module: { - rules: [ - getProtobufJsInquireWebpackRule(), - - options.coverage ? loaders.getCoverageLoader( { files: options.files } ) : null, - - loaders.getIconsLoader(), - - loaders.getStylesLoader( { - minify: true - } ), - - loaders.getTypeScriptLoader( { configFile: options.tsconfig } ), - - loaders.getFormattedTextLoader() - ].filter( Boolean ) - }, - - resolveLoader: { - modules: [ - 'node_modules', - path.resolve( import.meta.dirname, '..', '..', '..', 'node_modules' ) - ] - }, - - output: { - // Get rid of the "webpack://" protocol to make the paths clickable in the terminal. - devtoolModuleFilenameTemplate: info => info.resourcePath - } - }; - - if ( options.sourceMap ) { - // After bumping the webpack to v5 and other related tools/libs/whatever, the source maps stopped working for unknown reasons. - // The only way to make them work again was to use the inline source maps. - // - // See https://github.com/ckeditor/ckeditor5/issues/11006. - config.devtool = 'inline-source-map'; - - // Since webpack v5 it looks like splitting out the source code into the commons and runtime chunks broke the source map support. - config.optimization = { - ...config.optimization, - runtimeChunk: false, - splitChunks: false - }; - } - - if ( options.cache ) { - config.cache = { - type: 'filesystem' - }; - } - - if ( options.production ) { - config.plugins.push( new TreatWarningsAsErrorsWebpackPlugin() ); - } - - return config; -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/karmanotifier.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/karmanotifier.js deleted file mode 100644 index 49a02a06b..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/karmanotifier.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import notifier from 'node-notifier'; - -const ckeditor5icon = path.join( import.meta.dirname, '..', 'icons', 'ckeditor5.png' ); - -const defaultNotifyOptions = { - appID: 'CKEditor 5 Tests', - sound: false, - icon: ckeditor5icon -}; - -export default { 'reporter:karmanotifier': [ 'type', karmaNotifier ] }; -karmaNotifier.$inject = [ 'helper' ]; - -function karmaNotifier( helper ) { - const { formatTimeInterval } = helper; - - this.onBrowserComplete = browser => { - const result = browser.lastResult; - const footer = `\n\nExecution time: ${ formatTimeInterval( result.totalTime ) }\n${ browser.name }`; - - if ( result.disconnected ) { - notifier.notify( { - title: 'CKEditor 5 tests: Disconnected.', - message: 'Browser was disconnected before all tests finished.' + footer, - ...defaultNotifyOptions - } ); - - return; - } - - if ( result.error ) { - notifier.notify( { - title: 'CKEditor 5 tests: Error.', - message: 'An unexpected error occurred.' + footer, - ...defaultNotifyOptions - } ); - - return; - } - - if ( result.failed ) { - notifier.notify( { - title: 'CKEditor 5 tests: Failure.', - message: `Out of ${ result.total } tests, ${ result.failed } failed.` + footer, - ...defaultNotifyOptions - } ); - - return; - } - - notifier.notify( { - title: 'CKEditor 5 tests: Success.', - message: `All ${ result.success } tests passed.` + footer, - ...defaultNotifyOptions - } ); - }; -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorafter.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorafter.js deleted file mode 100644 index 3eb1b2de5..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/leaksdetectorafter.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -afterEach( function() { - const leakedElementMarkups = Array.from( document.body.children ).filter( el => !this._lastDomElements.has( el ) ).map( el => { - const html = el.outerHTML.length > 80 ? - el.outerHTML.substr( 0, 77 ) + '...' : - el.outerHTML; - return html; - } ); - - if ( leakedElementMarkups.length ) { - const errorMessage = `Elements leaked (${ leakedElementMarkups.length }):\n` + - leakedElementMarkups.join( '\n' ) + '\n' + - 'Be a good citizen and clean your DOM once you\'re done with it.'; - - this._lastDomElements = null; - - // See https://github.com/ckeditor/ckeditor5-dev/issues/586#issuecomment-571573488. - if ( window.production ) { - throw new Error( errorMessage ); - } else { - console.error( errorMessage ); - } - } -} ); diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/licensekeybefore.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/licensekeybefore.js deleted file mode 100644 index 8dcc6d046..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/licensekeybefore.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -before( function() { - window.CKEDITOR_GLOBAL_LICENSE_KEY = process.env.CKEDITOR_LICENSE_KEY || 'GPL'; -} ); diff --git a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/treatwarningsaserrorswebpackplugin.js b/packages/ckeditor5-dev-tests/lib/utils/automated-tests/treatwarningsaserrorswebpackplugin.js deleted file mode 100644 index c591f87e3..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/automated-tests/treatwarningsaserrorswebpackplugin.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -const PLUGIN_NAME = 'TreatWarningsAsErrorsWebpackPlugin'; - -/** - * Webpack plugin that reassigns warnings as errors and makes the browser test run fail. - */ -export default class TreatWarningsAsErrorsWebpackPlugin { - apply( compiler ) { - compiler.hooks.thisCompilation.tap( PLUGIN_NAME, compilation => { - compilation.hooks.processAssets.tap( { - name: PLUGIN_NAME, - stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS - }, () => { - const warnings = compilation.warnings; - - if ( !warnings.length && !compilation.errors.length ) { - return; - } - - compilation.errors = [ - ...compilation.errors, - ...warnings - ]; - - compilation.warnings = []; - - prependFailureToEntrypoints( compilation, compiler.webpack.sources.ConcatSource ); - } ); - } ); - } -} - -function prependFailureToEntrypoints( compilation, ConcatSource ) { - const files = new Set(); - - for ( const entrypoint of compilation.entrypoints.values() ) { - for ( const file of entrypoint.getFiles() ) { - if ( file.endsWith( '.js' ) ) { - files.add( file ); - } - } - } - - for ( const file of files ) { - compilation.updateAsset( file, source => new ConcatSource( - 'throw new Error( "Webpack compilation failed. See terminal output for details." );\n', - source - ) ); - } -} diff --git a/packages/ckeditor5-dev-tests/lib/utils/manual-tests/getwebpackconfig.js b/packages/ckeditor5-dev-tests/lib/utils/manual-tests/getwebpackconfig.js index 512270251..e65c13270 100644 --- a/packages/ckeditor5-dev-tests/lib/utils/manual-tests/getwebpackconfig.js +++ b/packages/ckeditor5-dev-tests/lib/utils/manual-tests/getwebpackconfig.js @@ -113,10 +113,8 @@ export default function getWebpackConfigForManualTests( options ) { // See https://github.com/ckeditor/ckeditor5/issues/11006. // // Previously, the 'cheap-source-map' was used, because Safari had problem with ES6 + inline source maps. - // We could use cheap source maps everywhere, but karma-webpack doesn't support it. The `columns` and `module` options - // set to `false` are equivalent to the use of `webpackConfig.devtool = 'cheap-source-map'`. - // - // See https://github.com/webpack/karma-webpack/pull/76. + // The `columns` and `module` options set to `false` are equivalent to the use of + // `webpackConfig.devtool = 'cheap-source-map'`. new webpack.SourceMapDevToolPlugin( { columns: false, module: true, diff --git a/packages/ckeditor5-dev-tests/lib/utils/parsearguments.js b/packages/ckeditor5-dev-tests/lib/utils/parsearguments.js index 1fde7c084..c83920b89 100644 --- a/packages/ckeditor5-dev-tests/lib/utils/parsearguments.js +++ b/packages/ckeditor5-dev-tests/lib/utils/parsearguments.js @@ -24,69 +24,46 @@ export default function parseArguments( args, settings = {} ) { const minimistConfig = { string: [ 'additional-languages', - 'browsers', 'cwd', 'debug', 'files', 'identity-file', - 'karma-config-overrides', 'language', 'port', - 'reporter', 'repositories', 'tsconfig' ], boolean: [ - 'cache', - 'coverage', 'disable-watch', 'help', - 'notify', - 'production', - 'resolve-js-first', - 'server', 'silent', 'source-map', - 'verbose', - 'watch' + 'verbose' ], alias: { - b: 'browsers', - c: 'coverage', d: 'debug', f: 'files', h: 'help', i: 'identity-file', - n: 'notify', r: 'repositories', s: 'source-map', - v: 'verbose', - w: 'watch' + v: 'verbose' }, default: { 'additional-languages': null, - browsers: 'Chrome', - cache: false, - coverage: false, cwd: process.cwd(), 'disable-watch': false, files: [], 'identity-file': null, language: 'en', - notify: false, - production: false, - reporter: 'mocha', repositories: [], - 'resolve-js-first': false, - server: false, silent: false, 'source-map': true, tsconfig: null, - verbose: false, - watch: false + verbose: false }, unknown: arg => { @@ -103,10 +80,6 @@ export default function parseArguments( args, settings = {} ) { process.exit( 0 ); } - if ( settings.commandName ) { - unknownArgs.push( ...getUnsupportedOptions( settings.commandName, args ) ); - } - if ( unknownArgs.length ) { const uniqueArgs = [ ...new Set( unknownArgs ) ]; @@ -125,12 +98,9 @@ export default function parseArguments( args, settings = {} ) { 'disable-watch', 'source-map', 'identity-file', - 'karma-config-overrides', - 'additional-languages', - 'resolve-js-first' + 'additional-languages' ] ); splitOptionsToArray( options, [ - 'browsers', 'files', 'repositories', 'additionalLanguages' @@ -302,58 +272,6 @@ export default function parseArguments( args, settings = {} ) { } } - /** - * Checks that no options exclusive to the other command type were used. - * For example, `--coverage` is only valid for automated tests, so passing it - * to the manual-test command is an error. - * - * The set of allowed options is derived from the help-text option groups so - * that the two stay in sync automatically. - * - * @param {string} commandName - * @param {Array.} rawArgs - * @returns {Array.} - */ - function getUnsupportedOptions( commandName, rawArgs ) { - const isManual = commandName.includes( 'manual' ); - const allowedGroups = isManual ? getManualOptionGroups() : getAutomatedOptionGroups(); - - const allowedNames = new Set(); - - for ( const group of allowedGroups ) { - for ( const option of group.options ) { - allowedNames.add( `--${ option.name }` ); - - if ( option.alias ) { - allowedNames.add( `-${ option.alias }` ); - } - } - } - - const unsupportedArgs = []; - - for ( const arg of rawArgs ) { - if ( arg.startsWith( '--' ) ) { - const flag = arg.split( '=' )[ 0 ]; - const baseFlag = flag.startsWith( '--no-' ) ? `--${ flag.slice( 5 ) }` : flag; - - if ( !allowedNames.has( baseFlag ) ) { - unsupportedArgs.push( flag ); - } - } else if ( arg.startsWith( '-' ) ) { - for ( const letter of arg.slice( 1 ) ) { - const flag = `-${ letter }`; - - if ( minimistConfig.alias[ letter ] && !allowedNames.has( flag ) ) { - unsupportedArgs.push( flag ); - } - } - } - } - - return unsupportedArgs; - } - /** * Prints help text for the CLI command. * @@ -361,14 +279,11 @@ export default function parseArguments( args, settings = {} ) { */ function printHelp( settings ) { const commandName = settings.commandName || 'ckeditor5-dev-tests'; - const isManual = commandName.includes( 'manual' ); - const description = isManual ? - 'Compiles and serves manual tests with a live-reloading dev server.' : - 'Runs automated tests using Karma and Vitest.'; + const description = 'Compiles and serves manual tests with a live-reloading dev server.'; - const optionGroups = isManual ? getManualOptionGroups() : getAutomatedOptionGroups(); - const examples = isManual ? getManualExamples( commandName ) : getAutomatedExamples( commandName ); + const optionGroups = getManualOptionGroups(); + const examples = getManualExamples( commandName ); const lines = [ '', @@ -407,76 +322,6 @@ export default function parseArguments( args, settings = {} ) { console.log( lines.join( '\n' ) ); } - /** - * @returns {Array.} - */ - function getAutomatedOptionGroups() { - return [ - { - title: 'Test selection', - options: [ - { - alias: 'f', name: 'files', hint: 'pattern', - description: 'Package names, directories, or files to test (comma-separated)', - default: '*' - }, - { - alias: 'r', name: 'repositories', hint: 'names', - description: 'Repository names whose packages should be tested (comma-separated)' - }, - { - alias: 'b', name: 'browsers', hint: 'names', - description: 'Browsers for running tests (comma-separated)', - default: 'Chrome' - } - ] - }, - { - title: 'Test execution', - options: [ - { alias: 'c', name: 'coverage', description: 'Generate code coverage report' }, - { alias: 'w', name: 'watch', description: 'Watch files and re-run tests on changes' }, - { - alias: 'd', name: 'debug', hint: 'flags', - description: 'Debug flags (e.g. --debug engine,ui). Use --no-debug to disable', - default: 'CK_DEBUG' - }, - { name: 'production', description: 'Run strictest checks (fail on console calls, DOM leaks)' }, - { name: 'server', description: 'Run Karma server without opening a browser' }, - { name: 'reporter', hint: 'type', description: 'Mocha reporter: "mocha" or "dots"', default: 'mocha' } - ] - }, - { - title: 'Build configuration', - options: [ - { alias: 's', name: 'source-map', description: 'Generate source maps', default: 'true' }, - { name: 'language', hint: 'code', description: 'Language for building tests', default: 'en' }, - { name: 'additional-languages', hint: 'codes', description: 'Additional languages for translations (comma-separated)' }, - { name: 'cache', description: 'Use Webpack filesystem cache' }, - { name: 'resolve-js-first', description: 'Resolve .js files before .ts files' }, - { name: 'tsconfig', hint: 'path', description: 'Path to TypeScript configuration file' }, - { name: 'karma-config-overrides', hint: 'path', description: 'Path to Karma config overrides file' }, - { alias: 'i', name: 'identity-file', hint: 'path', description: 'File providing secret keys for test scripts' } - ] - }, - { - title: 'Output', - options: [ - { alias: 'v', name: 'verbose', description: 'Show Webpack processing details' }, - { alias: 'n', name: 'notify', description: 'Enable desktop notifications on test completion' }, - { name: 'silent', description: 'Hide processed files info' } - ] - }, - { - title: 'Other', - options: [ - { name: 'cwd', hint: 'path', description: 'Set current working directory' }, - { alias: 'h', name: 'help', description: 'Show this help message' } - ] - } - ]; - } - /** * @returns {Array.} */ @@ -517,7 +362,6 @@ export default function parseArguments( args, settings = {} ) { { alias: 's', name: 'source-map', description: 'Generate source maps', default: 'true' }, { name: 'language', hint: 'code', description: 'Language for building tests', default: 'en' }, { name: 'additional-languages', hint: 'codes', description: 'Additional languages for translations (comma-separated)' }, - { name: 'production', description: 'Run strictest checks' }, { name: 'tsconfig', hint: 'path', description: 'Path to TypeScript configuration file' }, { alias: 'i', name: 'identity-file', hint: 'path', description: 'File providing secret keys for test scripts' } ] @@ -526,7 +370,6 @@ export default function parseArguments( args, settings = {} ) { title: 'Output', options: [ { alias: 'v', name: 'verbose', description: 'Show Webpack processing details' }, - { alias: 'n', name: 'notify', description: 'Enable desktop notifications' }, { name: 'silent', description: 'Hide processed files info' } ] }, @@ -540,19 +383,6 @@ export default function parseArguments( args, settings = {} ) { ]; } - /** - * @param {string} commandName - * @returns {Array.} - */ - function getAutomatedExamples( commandName ) { - return [ - { description: 'Test specific packages with coverage', command: `${ commandName } -c --files=enter,paragraph` }, - { description: 'Watch mode for engine view tests', command: `${ commandName } -w --files=engine/view/` }, - { description: 'Test on multiple browsers', command: `${ commandName } --browsers=Chrome,Firefox --files=basic-styles/bold` }, - { description: 'Test all packages', command: `${ commandName } --files=*` } - ]; - } - /** * @param {string} commandName * @returns {Array.} diff --git a/packages/ckeditor5-dev-tests/lib/utils/resolve-path.js b/packages/ckeditor5-dev-tests/lib/utils/resolve-path.js deleted file mode 100644 index 1ec2dd656..000000000 --- a/packages/ckeditor5-dev-tests/lib/utils/resolve-path.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { createRequire } from 'node:module'; - -/** - * Wrapper around `require.resolve()` to allow mocking it in tests. - */ -export function resolvePath( path, options ) { - const require = createRequire( import.meta.url ); - - return require.resolve( path, options ); -} diff --git a/packages/ckeditor5-dev-tests/lib/vitest/matchers.d.ts b/packages/ckeditor5-dev-tests/lib/vitest/matchers.d.ts new file mode 100644 index 000000000..3ac3dab35 --- /dev/null +++ b/packages/ckeditor5-dev-tests/lib/vitest/matchers.d.ts @@ -0,0 +1,27 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import 'vitest'; + +export interface MarkupMatcherResult { + pass: boolean; + message: () => string; + actual?: string; + expected?: string; +} + +export declare function toEqualMarkup( received: string, expected: string ): MarkupMatcherResult; + +declare module 'vitest' { + // The type parameter must be named `T` to match the `Matchers` declaration in Vitest, + // as interface merging requires identical type parameter lists. + interface Matchers { + + /** + * Asserts that two markup strings are equal. Unlike `toEqual()`, it formats the markup before showing a diff. + */ + toEqualMarkup( expected: string ): T; + } +} diff --git a/packages/ckeditor5-dev-tests/lib/vitest/matchers.js b/packages/ckeditor5-dev-tests/lib/vitest/matchers.js new file mode 100644 index 000000000..302edf2e7 --- /dev/null +++ b/packages/ckeditor5-dev-tests/lib/vitest/matchers.js @@ -0,0 +1,78 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +// The `js-beautify` package is a CommonJS module that does not declare its named exports in a way detectable +// by Node.js, so it must be imported via the default export to work in both Node.js and Vitest environments. +import jsBeautify from 'js-beautify'; + +const { html_beautify: beautify } = jsBeautify; + +/** + * Custom matcher that tests whether two given strings containing markup language are equal. + * Unlike `expect().toEqual()`, this matcher formats the markup before showing a diff. + * + * It can be used to test HTML strings and strings containing a serialized model. + * + * To register the matcher, use the `expect.extend()` API in a Vitest setup file: + * + * import { expect } from 'vitest'; + * import { toEqualMarkup } from '@ckeditor/ckeditor5-dev-tests'; + * + * expect.extend( { toEqualMarkup } ); + * + * Then, in tests: + * + * // Will fail with a diff of formatted markup strings. + * expect( + * 'foo bXXX[]r baz' + * ).toEqualMarkup( + * 'foo bYYY[]r baz' + * ); + * + * Please note that if the difference in the markup concerns only whitespace characters inside tags (e.g. between attributes), + * a diff between unformatted (rather than formatted) strings is displayed. + * + * @param {string} received Markup to compare. + * @param {string} expected Markup to compare. + * @returns {object} The matcher result. + */ +export function toEqualMarkup( received, expected ) { + if ( received === expected ) { + return { + pass: true, + message: () => 'Expected markup strings not to be equal' + }; + } + + const receivedFormatted = formatMarkup( received ); + const expectedFormatted = formatMarkup( expected ); + + // HTML beautification tool removes all redundant whitespace characters inside tags and this behavior cannot be configured. + // Therefore, if there is no difference between formatted strings, but we know they are different, display raw (unformatted) + // strings instead. + const areFormattedStringsEqual = receivedFormatted === expectedFormatted; + + return { + pass: false, + message: () => 'Expected markup strings to be equal', + actual: areFormattedStringsEqual ? received : receivedFormatted, + expected: areFormattedStringsEqual ? expected : expectedFormatted + }; +} + +// Renames the $text occurrences as it is not properly formatted by the beautifier - it is treated as a block. +const TEXT_TAG_PLACEHOLDER = 'span data-cke="true"'; +const TEXT_TAG_PLACEHOLDER_REGEXP = new RegExp( TEXT_TAG_PLACEHOLDER, 'g' ); + +function formatMarkup( string ) { + const htmlSafeString = string.replace( /\$text/g, TEXT_TAG_PLACEHOLDER ); + + const beautifiedMarkup = beautify( htmlSafeString, { + indent_size: 2, + space_in_empty_paren: true + } ); + + return beautifiedMarkup.replace( TEXT_TAG_PLACEHOLDER_REGEXP, '$text' ); +} diff --git a/packages/ckeditor5-dev-tests/package.json b/packages/ckeditor5-dev-tests/package.json index c0db9a03b..0edcd7a59 100644 --- a/packages/ckeditor5-dev-tests/package.json +++ b/packages/ckeditor5-dev-tests/package.json @@ -23,49 +23,22 @@ "bin" ], "bin": { - "ckeditor5-dev-tests-run-automated": "bin/testautomated.js", "ckeditor5-dev-tests-run-manual": "bin/testmanual.js" }, "dependencies": { - "@babel/core": "^7.29.0", "@ckeditor/ckeditor5-dev-translations": "workspace:*", "@ckeditor/ckeditor5-dev-utils": "workspace:*", "@ckeditor/ckeditor5-inspector": "^5.0.1", - "@types/chai": "^4.3.20", - "@types/karma-sinon-chai": "^2.0.6", - "@types/mocha": "^10.0.10", - "@types/sinon": "^10.0.20", - "assertion-error": "^2.0.1", - "babel-plugin-istanbul": "^7.0.1", "buffer": "^6.0.3", - "chai": "^4.5.0", "chokidar": "^4.0.3", "commonmark": "^0.31.2", "del": "^8.0.1", "dom-combiner": "^0.1.3", "es-toolkit": "^1.45.1", "glob": "^13.0.6", - "is-wsl": "^3.1.1", "js-beautify": "^1.15.4", - "karma": "^6.4.4", - "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^3.2.0", - "karma-coverage": "^2.2.1", - "karma-firefox-launcher": "^2.1.3", - "karma-mocha": "^2.0.1", - "karma-mocha-reporter": "^2.2.5", - "karma-sinon": "^1.0.5", - "karma-sinon-chai": "^2.0.2", - "karma-sourcemap-loader": "^0.4.0", - "karma-webpack": "^5.0.1", - "minimatch": "^10.2.5", "minimist": "^1.2.8", - "mkdirp": "^3.0.1", - "mocha": "^11.7.5", - "node-notifier": "^10.0.1", "process": "^0.11.10", - "sinon": "^9.2.4", - "sinon-chai": "^3.7.0", "socket.io": "^4.8.3", "typescript": "5.5.4", "upath": "^2.0.1", @@ -76,19 +49,11 @@ "vitest": "^4.1.2" }, "scripts": { - "postinstall": "node bin/postinstall.js", "test": "vitest run --config vitest.config.js", "coverage": "vitest run --config vitest.config.js --coverage" }, "depcheckIgnore": [ - "@babel/core", - "@types/chai", - "@types/karma-sinon-chai", - "@types/mocha", - "@types/sinon", - "babel-plugin-istanbul", "buffer", - "mocha", "process", "typescript" ] diff --git a/packages/ckeditor5-dev-tests/tests/index.js b/packages/ckeditor5-dev-tests/tests/index.js index 427074cca..f0186f686 100644 --- a/packages/ckeditor5-dev-tests/tests/index.js +++ b/packages/ckeditor5-dev-tests/tests/index.js @@ -3,35 +3,14 @@ * For licensing, see LICENSE.md. */ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import * as index from '../lib/index.js'; -import runAutomatedTests from '../lib/tasks/runautomatedtests.js'; -import runManualTests from '../lib/tasks/runmanualtests.js'; -import parseArguments from '../lib/utils/parsearguments.js'; - -vi.mock( '../lib/tasks/runautomatedtests.js' ); -vi.mock( '../lib/tasks/runmanualtests.js' ); -vi.mock( '../lib/utils/parsearguments.js' ); +import { toEqualMarkup } from '../lib/vitest/matchers.js'; describe( 'index.js', () => { - describe( 'runAutomatedTests()', () => { - it( 'should be a function', () => { - expect( index.runAutomatedTests ).to.be.a( 'function' ); - expect( index.runAutomatedTests ).toEqual( runAutomatedTests ); - } ); - } ); - - describe( 'runManualTests()', () => { - it( 'should be a function', () => { - expect( index.runManualTests ).to.be.a( 'function' ); - expect( index.runManualTests ).toEqual( runManualTests ); - } ); - } ); - - describe( 'parseArguments()', () => { - it( 'should be a function', () => { - expect( index.parseArguments ).to.be.a( 'function' ); - expect( index.parseArguments ).toEqual( parseArguments ); + describe( 'toEqualMarkup()', () => { + it( 'should be re-exported', () => { + expect( index.toEqualMarkup ).toEqual( toEqualMarkup ); } ); } ); } ); diff --git a/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js b/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js deleted file mode 100644 index c5de7428c..000000000 --- a/packages/ckeditor5-dev-tests/tests/tasks/runautomatedtests.js +++ /dev/null @@ -1,1367 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import fs from 'node:fs'; -import { spawn } from 'node:child_process'; -import { styleText } from 'node:util'; -import { globSync } from 'glob'; -import { mkdirp } from 'mkdirp'; -import karma from 'karma'; -import karmaLogger from 'karma/lib/logger.js'; -import transformFileOptionToTestGlob from '../../lib/utils/transformfileoptiontotestglob.js'; -import upath from 'upath'; - -const stubs = vi.hoisted( () => ( { - log: { - log: vi.fn(), - error: vi.fn(), - warn: vi.fn(), - info: vi.fn() - }, - karma: { - server: { - constructor: vi.fn(), - on: vi.fn(), - start: vi.fn() - } - }, - spawn: { - call: vi.fn() - }, - devUtilsLogger: { - info: vi.fn(), - warning: vi.fn(), - error: vi.fn() - } -} ) ); - -vi.mock( 'node:child_process', () => ( { - spawn: vi.fn( ( ...args ) => { - stubs.spawn.call( ...args ); - - const callbacks = {}; - - return { - on: ( eventName, callback ) => { - callbacks[ eventName ] = callback; - }, - emit: ( eventName, ...eventArgs ) => { - if ( callbacks[ eventName ] ) { - callbacks[ eventName ]( ...eventArgs ); - } - } - }; - } ) -} ) ); - -vi.mock( 'karma', () => ( { - default: { - Server: class KarmaServer { - constructor( ...args ) { - stubs.karma.server.constructor( ...args ); - } - - on( ...args ) { - return stubs.karma.server.on( ...args ); - } - - start( ...args ) { - return stubs.karma.server.start( ...args ); - } - }, - config: { - parseConfig: vi.fn() - } - } -} ) ); - -vi.mock( 'node:util', () => ( { - styleText: vi.fn( ( _style, text ) => text ) -} ) ); - -vi.mock( 'node:fs' ); -vi.mock( 'mkdirp' ); -vi.mock( 'glob' ); -vi.mock( 'karma/lib/logger.js' ); -vi.mock( '@ckeditor/ckeditor5-dev-utils', () => ( { - logger: vi.fn( () => stubs.devUtilsLogger ) -} ) ); -vi.mock( '../../lib/utils/automated-tests/getkarmaconfig.js' ); -vi.mock( '../../lib/utils/transformfileoptiontotestglob.js' ); - -describe( 'runAutomatedTests()', () => { - let runAutomatedTests; - - beforeEach( async () => { - vi.spyOn( process, 'cwd' ).mockReturnValue( '/workspace' ); - stubs.spawn.call.mockReset(); - - // Default: return empty JSON for package.json reads (no scripts → Karma runner). - vi.mocked( fs ).readFileSync.mockReturnValue( '{}' ); - - vi.mocked( karmaLogger ).create.mockImplementation( name => { - expect( name ).to.equal( 'config' ); - - return stubs.log; - } ); - - runAutomatedTests = ( await import( '../../lib/tasks/runautomatedtests.js' ) ).default; - } ); - - // -- Karma-only tests ------------------------------------------------------------------------- - - it( 'should create an entry file before tests execution', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const expectedEntryPointContent = [ - 'import "/workspace/packages/ckeditor5-basic-styles/tests/bold.js";', - 'import "/workspace/packages/ckeditor5-basic-styles/tests/italic.js";' - ].join( '\n' ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( mkdirp ).sync ).toHaveBeenCalledExactlyOnceWith( '/workspace/build/.automated-tests' ); - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - '/workspace/build/.automated-tests/entry-point.js', - expect.stringContaining( expectedEntryPointContent ) - ); - } ); - - it( 'throws when files are not specified', async () => { - await expect( runAutomatedTests( { production: true } ) ) - .rejects.toThrow( 'Test runner requires files to test. `options.files` has to be a non-empty array.' ); - } ); - - it( 'throws when specified files are invalid', async () => { - const options = { - files: [ - 'basic-foo', - 'bar-core' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-foo/tests/**/*.js', - '/workspace/packages/ckeditor-basic-foo/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-bar-core/tests/**/*.js', - '/workspace/packages/ckeditor-bar-core/tests/**/*.js' - ] ); - - vi.mocked( globSync ).mockReturnValue( [] ); - - await expect( runAutomatedTests( options ) ) - .rejects.toThrow( 'No test files found. Specified patterns are invalid.' ); - - expect( stubs.log.warn ).toHaveBeenCalledTimes( 2 ); - expect( stubs.log.warn ).toHaveBeenCalledWith( 'Pattern "%s" does not match any file.', 'basic-foo' ); - expect( stubs.log.warn ).toHaveBeenCalledWith( 'Pattern "%s" does not match any file.', 'bar-core' ); - } ); - - it( 'throws when Karma config parser throws', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-foo/tests/**/*.js', - '/workspace/packages/ckeditor-basic-foo/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-bar-core/tests/**/*.js', - '/workspace/packages/ckeditor-bar-core/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - vi.mocked( karma ).config.parseConfig.mockImplementation( () => { - throw new Error( 'Example error from Karma config parser.' ); - } ); - - await expect( runAutomatedTests( options ) ) - .rejects.toThrow( 'Example error from Karma config parser.' ); - } ); - - it( 'should warn when the `production` option is set to `false`', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: false - }; - - const consoleWarnStub = vi.spyOn( console, 'warn' ).mockImplementation( () => {} ); - - vi.mocked( styleText ).mockReturnValue( 'chalk.yellow: warn' ); - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( consoleWarnStub ).toHaveBeenCalledExactlyOnceWith( 'chalk.yellow: warn' ); - expect( vi.mocked( styleText ) ).toHaveBeenCalledExactlyOnceWith( - 'yellow', - '⚠ You\'re running tests in dev mode - some error protections are loose. ' + - 'Use the `--production` flag to use strictest verification methods.' - ); - } ); - - it( 'should not add the code making console use throw an error when the `production` option is set to false', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: false - }; - - vi.spyOn( console, 'warn' ).mockImplementation( () => { - } ); - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - expect.any( String ), - expect.not.stringContaining( '// Make using any method from the console to fail.' ) - ); - } ); - - it( 'should add the code making console use throw an error when the `production` option is set to true', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.spyOn( console, 'warn' ).mockImplementation( () => { - } ); - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - expect.any( String ), - expect.stringContaining( '// Make using any method from the console to fail.' ) - ); - } ); - - it( 'should load custom assertions automatically (camelCase in paths)', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [ 'assertionA.js', 'assertionB.js' ] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const assertionsDir = upath.join( import.meta.dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ); - - const expectedEntryPointContent = [ - `import assertionAFactory from "${ assertionsDir }/assertionA.js";`, - `import assertionBFactory from "${ assertionsDir }/assertionB.js";`, - 'assertionAFactory( chai );', - 'assertionBFactory( chai );' - ].join( '\n' ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( mkdirp ).sync ).toHaveBeenCalledExactlyOnceWith( '/workspace/build/.automated-tests' ); - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - '/workspace/build/.automated-tests/entry-point.js', - expect.stringContaining( expectedEntryPointContent ) - ); - } ); - - it( 'should load custom assertions automatically (kebab-case in paths)', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [ 'assertion-a.js', 'assertion-b.js' ] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-basic-styles/tests/**/*.js', - '/workspace/packages/ckeditor-basic-styles/tests/**/*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-basic-styles/tests/bold.js', - '/workspace/packages/ckeditor5-basic-styles/tests/italic.js' - ] ); - - const assertionsDir = upath.join( import.meta.dirname, '..', '..', 'lib', 'utils', 'automated-tests', 'assertions' ); - - const expectedEntryPointContent = [ - `import assertionAFactory from "${ assertionsDir }/assertion-a.js";`, - `import assertionBFactory from "${ assertionsDir }/assertion-b.js";`, - 'assertionAFactory( chai );', - 'assertionBFactory( chai );', - '' - ].join( '\n' ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( mkdirp ).sync ).toHaveBeenCalledExactlyOnceWith( '/workspace/build/.automated-tests' ); - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - '/workspace/build/.automated-tests/entry-point.js', - expect.stringContaining( expectedEntryPointContent ) - ); - } ); - - it( 'should load custom assertions automatically (Windows paths)', async () => { - const options = { - files: [ - 'basic-styles' - ], - production: true - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [ 'assertion-a.js', 'assertion-b.js' ] ); - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\**\\*.js', - '\\workspace\\packages\\ckeditor-basic-styles\\tests\\**\\*.js' - ] ); - - vi.mocked( globSync ) - .mockReturnValue( [] ) - .mockReturnValueOnce( [ - '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\bold.js', - '\\workspace\\packages\\ckeditor5-basic-styles\\tests\\italic.js' - ] ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - } ); - - await promise; - - expect( vi.mocked( mkdirp ).sync ).toHaveBeenCalledExactlyOnceWith( '/workspace/build/.automated-tests' ); - expect( vi.mocked( fs ).writeFileSync ).toHaveBeenCalledExactlyOnceWith( - '/workspace/build/.automated-tests/entry-point.js', - expect.stringContaining( [ - 'import "/workspace/packages/ckeditor5-basic-styles/tests/bold.js";', - 'import "/workspace/packages/ckeditor5-basic-styles/tests/italic.js";' - ].join( '\n' ) ) - ); - } ); - - // -- Vitest-only tests ------------------------------------------------------------------------ - - it( 'should run only Vitest when all selected packages use Vitest', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 0 ); - - await promise; - - expect( stubs.karma.server.constructor ).not.toHaveBeenCalled(); - expect( stubs.spawn.call ).toHaveBeenCalledExactlyOnceWith( - 'pnpm', - [ - 'vitest', - '--run', - 'tests/model/model.js' - ], - { - stdio: 'inherit', - cwd: '/workspace/packages/ckeditor5-engine', - shell: process.platform === 'win32' - } - ); - expect( vi.mocked( fs ).writeFileSync ).not.toHaveBeenCalledWith( - '/workspace/build/.automated-tests/entry-point.js', - expect.any( String ) - ); - } ); - - it( 'should pass --watch flag to Vitest when watch mode is enabled', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: true, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 0 ); - - await promise; - - expect( stubs.spawn.call ).toHaveBeenCalledExactlyOnceWith( - 'pnpm', - [ - 'vitest', - '--watch', - 'tests/model/model.js' - ], - expect.objectContaining( { cwd: '/workspace/packages/ckeditor5-engine' } ) - ); - } ); - - it( 'should pass coverage flags to Vitest and merge coverage with nyc', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - vi.mocked( fs ).existsSync.mockReturnValue( true ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - // First spawn: vitest project run. - const [ vitestProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - vitestProcess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - - // Second spawn: nyc report merge. - const [ , nycProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - nycProcess.emit( 'close', 0 ); - - await promise; - - // Vitest was called with per-project coverage directory and forced reporters. - expect( stubs.spawn.call ).toHaveBeenNthCalledWith( - 1, - 'pnpm', - [ - 'vitest', - '--run', - '--coverage.enabled', - '--coverage.reportsDirectory', - '/workspace/coverage-vitest/engine', - '--coverage.reporter', - 'json', - '--coverage.reporter', - 'lcovonly', - '--coverage.reporter', - 'html', - 'tests/model/model.js' - ], - expect.objectContaining( { cwd: '/workspace/packages/ckeditor5-engine' } ) - ); - - // coverage-final.json was copied into .nyc_output. - expect( vi.mocked( fs ).existsSync ).toHaveBeenCalledWith( - '/workspace/coverage-vitest/engine/coverage-final.json' - ); - expect( vi.mocked( fs ).copyFileSync ).toHaveBeenCalledWith( - '/workspace/coverage-vitest/engine/coverage-final.json', - '/workspace/coverage-vitest/.nyc_output/engine.json' - ); - - // nyc report was called with correct reporters. - expect( stubs.spawn.call ).toHaveBeenNthCalledWith( - 2, - 'pnpx', - [ - 'nyc', 'report', - '--temp-dir', '/workspace/coverage-vitest/.nyc_output', - '--report-dir', '/workspace/coverage-vitest', - '--reporter', 'html', - '--reporter', 'json', - '--reporter', 'lcovonly', - '--reporter', 'text-summary' - ], - expect.objectContaining( { stdio: 'inherit', cwd: '/workspace' } ) - ); - - // Log message was printed. - expect( stubs.devUtilsLogger.info ).toHaveBeenCalled(); - } ); - - it( 'should reject when Vitest process exits with non-zero code', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 1 ); - - await expect( promise ).rejects.toThrow( 'Vitest finished with "1" code.' ); - } ); - - // Regression: ckeditor/ckeditor5-commercial#10462. Going through the workspace config with - // `--project ` triggers a hang in Vitest browser mode whenever more than one test file - // runs. Spawning per-package (cwd = package root, no --project flag) side-steps that path. - it( 'should spawn Vitest with cwd set to the package root and no --project flag', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js', - '/workspace/packages/ckeditor5-engine/tests/view/view.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 0 ); - - await promise; - - const [ [ command, args, spawnOptions ] ] = stubs.spawn.call.mock.calls; - - expect( command ).to.equal( 'pnpm' ); - expect( spawnOptions ).toEqual( expect.objectContaining( { - cwd: '/workspace/packages/ckeditor5-engine' - } ) ); - expect( args ).not.toContain( '--project' ); - // File paths are passed relative to the package root, not the workspace root. - expect( args ).toEqual( expect.arrayContaining( [ - 'tests/model/model.js', - 'tests/view/view.js' - ] ) ); - expect( args ).not.toEqual( expect.arrayContaining( [ - expect.stringMatching( /^packages\// ) - ] ) ); - } ); - - // Regression: ckeditor/ckeditor5-commercial#10462. Running per-package means the package's - // own `vitest.config.ts` wins, and its `text`/`html` reporters are not enough for the CI - // merge step — so the wrapper forces `json` (nyc) and `lcovonly` (lcov collation) on top. - it( 'should force json, lcovonly and html reporters when coverage is enabled', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - vi.mocked( fs ).existsSync.mockReturnValue( false ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ vitestProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - vitestProcess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - - const [ , nycProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - nycProcess.emit( 'close', 0 ); - - await promise; - - const [ [ , args ] ] = stubs.spawn.call.mock.calls; - - expect( args ).toEqual( expect.arrayContaining( [ - '--coverage.reporter', 'json', - '--coverage.reporter', 'lcovonly', - '--coverage.reporter', 'html' - ] ) ); - } ); - - // -- Mixed Karma + Vitest tests --------------------------------------------------------------- - - it( 'should route mixed package selection to Karma and Vitest', async () => { - const options = { - files: [ 'utils', 'emoji' ], - production: true, - coverage: false, - watch: false - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/**/*.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/**/*.js' ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/emoji.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-emoji/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'karma start' } } ); - } - - return '{}'; - } ); - - const promise = runAutomatedTests( options ); - - setTimeout( () => { - const [ firstCall ] = stubs.karma.server.constructor.mock.calls; - const [ , exitCallback ] = firstCall; - - exitCallback( 0 ); - - setTimeout( () => { - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - - subprocess.emit( 'close', 0 ); - } ); - } ); - - await promise; - - expect( stubs.karma.server.constructor ).toHaveBeenCalledOnce(); - expect( stubs.spawn.call ).toHaveBeenCalledExactlyOnceWith( - 'pnpm', - [ 'vitest', '--run', 'tests/first.js' ], - { - stdio: 'inherit', - cwd: '/workspace/packages/ckeditor5-utils', - shell: process.platform === 'win32' - } - ); - } ); - - it( 'should throw when watch mode is used with mixed Karma + Vitest packages', async () => { - const options = { - files: [ 'utils', 'emoji' ], - production: true, - coverage: false, - watch: true - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/**/*.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/**/*.js' ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/emoji.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-emoji/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'karma start' } } ); - } - - return '{}'; - } ); - - await expect( runAutomatedTests( options ) ).rejects.toThrow( - 'Watch/server mode cannot be used in a mixed Karma + Vitest run. ' + - 'Run watch/server mode separately for Karma and Vitest packages.' - ); - } ); - - it( 'should throw when server mode is used with mixed Karma + Vitest packages', async () => { - const options = { - files: [ 'utils', 'emoji' ], - production: true, - coverage: false, - server: true - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/**/*.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/**/*.js' ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/emoji.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-emoji/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'karma start' } } ); - } - - return '{}'; - } ); - - await expect( runAutomatedTests( options ) ).rejects.toThrow( - 'Watch/server mode cannot be used in a mixed Karma + Vitest run. ' + - 'Run watch/server mode separately for Karma and Vitest packages.' - ); - } ); - - it( 'should aggregate errors when both runners fail', async () => { - const options = { - files: [ 'utils', 'emoji' ], - production: true, - coverage: false, - watch: false - }; - - vi.mocked( fs ).readdirSync.mockReturnValue( [] ); - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/**/*.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/**/*.js' ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [ '/workspace/packages/ckeditor5-emoji/tests/emoji.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-emoji/package.json' ) ) { - return JSON.stringify( { scripts: {} } ); - } - - return '{}'; - } ); - - vi.mocked( karma ).config.parseConfig.mockImplementation( () => { - throw new Error( 'Karma finished with "1" code.' ); - } ); - - const promise = runAutomatedTests( options ); - - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 2 ); - - await expect( promise ).rejects.toThrow( /Test execution failed in multiple runners/ ); - } ); - - // -- Multiple Vitest projects test ------------------------------------------------------------ - - it( 'should run each Vitest project in a separate process with selected files', async () => { - const options = { - files: [ 'utils', 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-utils/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/model.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-engine/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - return '{}'; - } ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ firstSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - firstSubprocess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - const [ , secondSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - secondSubprocess.emit( 'close', 0 ); - - await promise; - - expect( stubs.spawn.call ).toHaveBeenNthCalledWith( - 1, - 'pnpm', - [ - 'vitest', - '--run', - 'tests/first.js' - ], - { - stdio: 'inherit', - cwd: '/workspace/external/ckeditor5/packages/ckeditor5-utils', - shell: process.platform === 'win32' - } - ); - expect( stubs.spawn.call ).toHaveBeenNthCalledWith( - 2, - 'pnpm', - [ - 'vitest', - '--run', - 'tests/model.js' - ], - { - stdio: 'inherit', - cwd: '/workspace/external/ckeditor5/packages/ckeditor5-engine', - shell: process.platform === 'win32' - } - ); - } ); - - it( 'should throw when watch mode is used with multiple Vitest projects', async () => { - const options = { - files: [ 'utils', 'engine' ], - production: true, - watch: true, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-utils/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/model.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-engine/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - return '{}'; - } ); - - await expect( runAutomatedTests( options ) ).rejects.toThrow( - 'Watch mode cannot be used for multiple Vitest projects in one run. ' + - 'Run watch mode separately for each Vitest project.' - ); - - expect( stubs.spawn.call ).not.toHaveBeenCalled(); - } ); - - it( 'should continue running remaining Vitest projects after a project failure', async () => { - const options = { - files: [ 'utils', 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-utils/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/model.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-engine/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - return '{}'; - } ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ firstSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - firstSubprocess.emit( 'close', 1 ); - - await new Promise( resolve => setTimeout( resolve ) ); - const [ , secondSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - secondSubprocess.emit( 'close', 0 ); - - await expect( promise ).rejects.toThrow( 'Vitest finished with "1" code.' ); - expect( stubs.spawn.call ).toHaveBeenCalledTimes( 2 ); - } ); - - it( 'should merge Vitest coverage even when a project fails', async () => { - const options = { - files: [ 'utils', 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-utils/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/**/*.js' - ] ) - .mockReturnValueOnce( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js', - '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-utils/tests/first.js' ] ) - .mockReturnValueOnce( [] ) - .mockReturnValueOnce( [ '/workspace/external/ckeditor5/packages/ckeditor5-engine/tests/model.js' ] ); - vi.mocked( fs ).readFileSync.mockImplementation( path => { - if ( path.includes( 'ckeditor5-utils/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - if ( path.includes( 'ckeditor5-engine/package.json' ) ) { - return JSON.stringify( { scripts: { test: 'vitest run' } } ); - } - - return '{}'; - } ); - vi.mocked( fs ).existsSync.mockReturnValue( false ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ firstSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - firstSubprocess.emit( 'close', 1 ); - - await new Promise( resolve => setTimeout( resolve ) ); - const [ , secondSubprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - secondSubprocess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - const [ , , nycProcess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - nycProcess.emit( 'close', 0 ); - - await expect( promise ).rejects.toThrow( 'Vitest finished with "1" code.' ); - expect( stubs.spawn.call ).toHaveBeenCalledTimes( 3 ); - expect( stubs.spawn.call ).toHaveBeenNthCalledWith( - 3, - 'pnpx', - expect.arrayContaining( [ 'nyc', 'report' ] ), - expect.objectContaining( { cwd: '/workspace' } ) - ); - } ); - - // -- Edge cases ------------------------------------------------------------------------------- - - it( 'should resolve when Vitest exits with code 130 (SIGINT)', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'close', 130 ); - - await promise; - } ); - - it( 'should reject when spawn emits an error event', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ subprocess ] = vi.mocked( spawn ).mock.results.map( result => result.value ); - subprocess.emit( 'error', new Error( 'spawn ENOENT' ) ); - - await expect( promise ).rejects.toThrow( 'spawn ENOENT' ); - } ); - - it( 'should skip copying coverage-final.json when the file does not exist', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - vi.mocked( fs ).existsSync.mockReturnValue( false ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ vitestProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - vitestProcess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - - const [ , nycProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - nycProcess.emit( 'close', 0 ); - - await promise; - - expect( vi.mocked( fs ).copyFileSync ).not.toHaveBeenCalled(); - } ); - - it( 'should reject when nyc report fails', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - vi.mocked( fs ).existsSync.mockReturnValue( false ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ vitestProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - vitestProcess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - - const [ , nycProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - nycProcess.emit( 'close', 1 ); - - await expect( promise ).rejects.toThrow( 'nyc report finished with "1" code.' ); - } ); - - it( 'should reject when nyc spawn emits an error', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: true - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/model/model.js' - ] ); - vi.mocked( fs ).readFileSync.mockReturnValue( JSON.stringify( { - scripts: { test: 'vitest --run' } - } ) ); - vi.mocked( fs ).existsSync.mockReturnValue( false ); - - const promise = runAutomatedTests( options ); - await new Promise( resolve => setTimeout( resolve ) ); - - const [ vitestProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - vitestProcess.emit( 'close', 0 ); - - await new Promise( resolve => setTimeout( resolve ) ); - - const [ , nycProcess ] = vi.mocked( spawn ).mock.results.map( r => r.value ); - nycProcess.emit( 'error', new Error( 'nyc ENOENT' ) ); - - await expect( promise ).rejects.toThrow( 'nyc ENOENT' ); - } ); - - it( 'should throw when a test file path does not contain /tests/ segment', async () => { - const options = { - files: [ 'engine' ], - production: true, - watch: false, - coverage: false - }; - - vi.mocked( transformFileOptionToTestGlob ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/tests/**/*.js' - ] ); - vi.mocked( globSync ).mockReturnValue( [ - '/workspace/packages/ckeditor5-engine/src/model.js' - ] ); - - await expect( runAutomatedTests( options ) ).rejects.toThrow( - 'Cannot determine package root for "/workspace/packages/ckeditor5-engine/src/model.js".' - ); - } ); -} ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/attribute.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/attribute.js deleted file mode 100644 index 43db9ec8d..000000000 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/attribute.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { beforeAll, describe, expect, it, chai } from 'vitest'; -import attributeFactory from '../../../../lib/utils/automated-tests/assertions/attribute.js'; - -describe( 'attribute chai assertion', () => { - beforeAll( () => { - attributeFactory( chai ); - } ); - - it( 'should be added to chai assertions', () => { - const assertion = new chai.Assertion(); - - expect( assertion ).to.have.property( 'attribute' ); - expect( assertion.attribute ).to.be.instanceof( Function ); - } ); - - it( 'should assert the target has a \'hasAttribute\' method', () => { - expect( { hasAttribute: () => true } ).to.have.attribute( 'foo' ); - - expect( function() { - expect( {} ).not.to.have.attribute( 'bar' ); - } ).to.throw( 'expected {} to respond to \'hasAttribute\'' ); - - expect( function() { - expect( {} ).to.have.attribute( 'bar' ); - } ).to.throw( 'expected {} to respond to \'hasAttribute\'' ); - } ); - - it( 'should assert the \'target.hasAttribute\' returns \'true\' for the given type', () => { - expect( { hasAttribute: () => true } ).to.have.attribute( 'foo' ); - - expect( function() { - expect( { hasAttribute: () => false } ).to.have.attribute( 'bar' ); - } ).to.throw( 'expected { Object (hasAttribute) } to have attribute \'bar\'' ); - } ); - - it( 'negated, should assert the \'target.hasAttribute\' returns \'false\' for the given type', () => { - expect( { hasAttribute: () => false } ).not.to.have.attribute( 'foo' ); - - expect( function() { - expect( { hasAttribute: () => true } ).not.to.have.attribute( 'bar' ); - } ).to.throw( 'expected { Object (hasAttribute) } to not have attribute \'bar\'' ); - } ); - - it( 'should assert the \'target.getAttribute\' returns the given value for the given type', () => { - expect( { - hasAttribute: () => true, - getAttribute: () => 'bar' - } ).to.have.attribute( 'foo', 'bar' ); - - expect( function() { - expect( { - hasAttribute: () => true, - getAttribute: () => 'bar' - } ).to.have.attribute( 'foo', 'baz' ); - } ).to.throw( 'expected { …(2) } to have attribute \'foo\' of \'baz\', but got \'bar\'' ); - } ); - - it( 'negated, should assert for the given type the \'target.getAttribute\' returns a value different than the given one', () => { - expect( { - hasAttribute: () => true, - getAttribute: () => 'bar' - } ).to.not.have.attribute( 'foo', 'baz' ); - - expect( function() { - expect( { - hasAttribute: () => true, - getAttribute: () => 'baz' - } ).to.not.have.attribute( 'foo', 'baz' ); - } ).to.throw( 'expected { …(2) } to not have attribute \'foo\' of \'baz\'' ); - } ); -} ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/equal-markup.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/equal-markup.js deleted file mode 100644 index 518823a2f..000000000 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/assertions/equal-markup.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { beforeAll, describe, expect, it, chai } from 'vitest'; -import equalMarkupFactory from '../../../../lib/utils/automated-tests/assertions/equal-markup.js'; - -describe( 'equalMarkup chai assertion', () => { - beforeAll( () => { - equalMarkupFactory( chai ); - } ); - - it( 'should be added to chai assertions', () => { - const assertion = new chai.Assertion(); - - expect( assertion ).to.have.property( 'equalMarkup' ); - expect( assertion.equalMarkup ).to.be.instanceof( Function ); - } ); - - it( 'should not throw for equal markups', () => { - expect( function() { - expect( - 'foo bXXX[]r baz' - ).to.equalMarkup( - 'foo bXXX[]r baz' - ); - } ).to.not.throw(); - } ); - - it( 'should throw AssertionError for unequal markups', () => { - expect( function() { - expect( - 'foo bXXX[]r baz' - ).to.equalMarkup( - 'foo bYYY[]r baz' - ); - } ).to.throw( 'Expected markup strings to be equal' ); - } ); - - it( 'should format the actual markup', () => { - try { - expect( - '

foo

' - ).to.equalMarkup( - 'bar' - ); - } catch ( assertionError ) { - expect( assertionError.actual ).to.equal( - '
\n' + - '

foo

\n' + - '
' - ); - } - } ); - - it( 'should format the expected markup', () => { - try { - expect( - 'foo' - ).to.equalMarkup( - '

foo

' - ); - } catch ( assertionError ) { - expect( assertionError.expected ).to.equal( - '
\n' + - '

foo

\n' + - '
' - ); - } - } ); - - it( 'should format model text node with attributes as inline', () => { - try { - expect( - 'foo' - ).to.equalMarkup( - '<$text bold="true">foo' - ); - } catch ( assertionError ) { - expect( assertionError.expected ).to.equal( - '<$text bold="true">foo' - ); - } - } ); - - it( 'should format nested model structure properly', () => { - try { - expect( - 'foo' - ).to.equalMarkup( - '
' + - '' + - '' + - '' + - '<$text bold="true">foo' + - '' + - '' + - '<$text bold="true">bar' + - '<$text bold="true">baz' + - '' + - '' + - '
' + - '
' - ); - } catch ( assertionError ) { - expect( assertionError.expected ).to.equal( - '
\n' + - ' \n' + - ' \n' + - ' \n' + - ' <$text bold="true">foo\n' + - ' \n' + - ' \n' + - ' <$text bold="true">bar\n' + - ' <$text bold="true">baz\n' + - ' \n' + - ' \n' + - '
\n' + - '
' - ); - } - } ); - - it( 'should not format strings if beautifier returns equal markups after formatting', () => { - try { - expect( - '

foo

' - ).to.equalMarkup( - '

foo

' - ); - } catch ( assertionError ) { - expect( assertionError.actual ).to.equal( '

foo

' ); - expect( assertionError.expected ).to.equal( '

foo

' ); - } - } ); -} ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js deleted file mode 100644 index ee8fa5780..000000000 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getkarmaconfig.js +++ /dev/null @@ -1,336 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import getWebpackConfigForAutomatedTests from '../../../lib/utils/automated-tests/getwebpackconfig.js'; -import getKarmaConfig from '../../../lib/utils/automated-tests/getkarmaconfig.js'; - -vi.mock( '../../../lib/utils/automated-tests/getwebpackconfig.js' ); - -vi.mock( '../../../lib/utils/resolve-path.js', () => ( { - resolvePath: ( pathToResolve, options ) => path.join( options.paths[ 0 ], 'node_modules', pathToResolve ) -} ) ); - -describe( 'getKarmaConfig()', () => { - const originalEnv = process.env; - const karmaConfigOverrides = { - // A relative path according to the tested file. - // From: /ckeditor5-dev/packages/ckeditor5-dev-tests/lib/utils/automated-tests/getkarmaconfig.js - // To: /ckeditor5-dev/packages/ckeditor5-dev-tests/tests/utils/automated-tests/fixtures/karma-config-overrides/*.cjs - noop: '../../../tests/fixtures/karma-config-overrides/noop.cjs', - removeCoverage: '../../../tests/fixtures/karma-config-overrides/removecoverage.cjs' - }; - - beforeEach( () => { - vi.spyOn( process, 'cwd' ).mockReturnValue( 'workspace' ); - - process.env = Object.assign( {}, originalEnv, { CI: false } ); - } ); - - afterEach( () => { - process.env = originalEnv; - } ); - - it( 'should return basic karma config for all tested files', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( { webpackConfig: true } ); - - const options = { - files: [ '*' ], - reporter: 'mocha', - sourceMap: false, - coverage: false, - browsers: [ 'Chrome' ], - watch: false, - verbose: false, - entryFile: 'workspace/entry-file.js', - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - }; - - const karmaConfig = getKarmaConfig( options ); - - expect( vi.mocked( getWebpackConfigForAutomatedTests ) ).toHaveBeenCalledExactlyOnceWith( { - ...options, - files: [ - 'workspace/packages/ckeditor5-*/tests/**/*.js' - ] - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - basePath: 'workspace', - frameworks: expect.any( Array ), - files: expect.any( Array ), - preprocessors: expect.any( Object ), - webpack: expect.any( Object ), - webpackMiddleware: expect.any( Object ), - reporters: expect.any( Array ), - browsers: expect.any( Array ), - singleRun: true - } ) ); - - expect( karmaConfig.webpack ).toEqual( expect.objectContaining( { - webpackConfig: true - } ) ); - } ); - - // See: https://github.com/ckeditor/ckeditor5/issues/8823 - it( 'should define proxies to static assets resources', () => { - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - sourceMap: false, - coverage: false, - browsers: [ 'Chrome' ], - watch: false, - verbose: false, - entryFile: 'workspace/entry-file.js', - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - proxies: expect.any( Object ), - files: expect.any( Array ) - } ) ); - expect( karmaConfig.proxies ).toEqual( expect.objectContaining( { - '/assets/': expect.any( String ), - '/example.com/image.png': expect.any( String ), - '/www.example.com/image.png': expect.any( String ) - } ) ); - - expect( karmaConfig.files ).toHaveLength( 2 ); - expect( karmaConfig.files ).toEqual( expect.arrayContaining( [ - 'workspace/entry-file.js', - expect.objectContaining( { - pattern: expect.stringContaining( path.join( 'ckeditor5-utils', 'tests', '_assets', '**', '*' ) ) - } ) - ] ) ); - } ); - - it( 'should contain a list of available plugins', () => { - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - sourceMap: false, - coverage: false, - browsers: [ 'Chrome' ], - watch: false, - verbose: false, - entryFile: 'workspace/entry-file.js', - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - files: expect.any( Array ) - } ) ); - expect( karmaConfig.files ).not.toHaveLength( 0 ); - } ); - - it( 'should enable webpack watcher when passed the "karmaConfigOverrides" option (execute in Intellij)', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( { watch: null } ); - - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - karmaConfigOverrides: karmaConfigOverrides.noop, - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - } ); - - expect( karmaConfig.webpack ).toEqual( expect.objectContaining( { - watch: true - } ) ); - } ); - - it( 'should configure coverage reporter', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( {} ); - - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - karmaConfigOverrides: karmaConfigOverrides.noop, - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - }, - coverage: true - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - reporters: expect.arrayContaining( [ 'coverage' ] ), - coverageReporter: { - reporters: expect.any( Array ), - watermarks: expect.any( Object ) - } - } ) ); - } ); - - it( 'should use `text-summary` reporter for local development', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( {} ); - - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - karmaConfigOverrides: karmaConfigOverrides.noop, - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - }, - coverage: true - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - reporters: expect.arrayContaining( [ 'coverage' ] ), - coverageReporter: { - reporters: expect.arrayContaining( [ { type: 'text-summary' } ] ), - watermarks: expect.any( Object ) - } - } ) ); - } ); - - it( 'should use `text` reporter on CI', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( {} ); - vi.stubEnv( 'CI', true ); - - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - karmaConfigOverrides: karmaConfigOverrides.noop, - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - }, - coverage: true - } ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - reporters: expect.arrayContaining( [ 'coverage' ] ), - coverageReporter: { - reporters: expect.arrayContaining( [ { type: 'text' } ] ), - watermarks: expect.any( Object ) - } - } ) ); - - vi.unstubAllEnvs(); - } ); - - it( 'should remove webpack babel-loader if coverage reporter is removed by overrides', () => { - vi.mocked( getWebpackConfigForAutomatedTests ).mockReturnValue( { - module: { - rules: [ - { - loader: 'babel-loader' - }, - { - loader: 'other-loader' - } - ] - } - } ); - - const karmaConfig = getKarmaConfig( { - files: [ '*' ], - reporter: 'mocha', - karmaConfigOverrides: karmaConfigOverrides.removeCoverage, - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - }, - coverage: true - } ); - - const loaders = karmaConfig.webpack.module.rules.map( rule => rule.loader ); - - expect( karmaConfig ).not.toEqual( expect.objectContaining( { - reporters: expect.arrayContaining( [ 'coverage' ] ) - } ) ); - - expect( loaders ).not.toEqual( expect.arrayContaining( [ 'babel-loader' ] ) ); - expect( loaders ).toEqual( expect.arrayContaining( [ 'other-loader' ] ) ); - } ); - - it( 'should return custom browser launchers with flags (`CHROME_CI`)', () => { - const options = { - reporter: 'mocha', - files: [ '*' ], - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - }; - - const karmaConfig = getKarmaConfig( options ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - customLaunchers: expect.any( Object ) - } ) ); - - expect( karmaConfig.customLaunchers ).toEqual( expect.objectContaining( { - CHROME_CI: expect.objectContaining( { - base: 'Chrome', - flags: expect.arrayContaining( [ - '--disable-background-timer-throttling', - '--js-flags="--expose-gc"', - '--disable-renderer-backgrounding', - '--disable-backgrounding-occluded-windows', - '--disable-search-engine-choice-screen', - '--no-sandbox', - '--window-size=1920,1080' - ] ) - } ) - } ) ); - } ); - - it( 'should return custom browser launchers with flags (`CHROME_LOCAL`)', () => { - const options = { - reporter: 'mocha', - files: [ '*' ], - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - }; - - const karmaConfig = getKarmaConfig( options ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - customLaunchers: expect.any( Object ) - } ) ); - - expect( karmaConfig.customLaunchers ).toEqual( expect.objectContaining( { - CHROME_LOCAL: expect.objectContaining( { - base: 'Chrome', - flags: expect.arrayContaining( [ - '--disable-background-timer-throttling', - '--js-flags="--expose-gc"', - '--disable-renderer-backgrounding', - '--disable-backgrounding-occluded-windows', - '--disable-search-engine-choice-screen', - '--remote-debugging-port=9222', - '--window-size=1920,1080' - ] ) - } ) - } ) ); - } ); - - it( 'should inherit Chrome flags from the headed mode when using the headless version', () => { - const options = { - reporter: 'mocha', - files: [ '*' ], - globPatterns: { - '*': 'workspace/packages/ckeditor5-*/tests/**/*.js' - } - }; - - const karmaConfig = getKarmaConfig( options ); - - expect( karmaConfig ).toEqual( expect.objectContaining( { - customLaunchers: expect.any( Object ) - } ) ); - - expect( karmaConfig.customLaunchers.ChromeHeadlessCustom.base ).toEqual( 'ChromeHeadless' ); - expect( karmaConfig.customLaunchers.ChromeHeadlessCustom.flags ).toStrictEqual( karmaConfig.customLaunchers.CHROME_LOCAL.flags ); - } ); -} ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getwebpackconfig.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getwebpackconfig.js deleted file mode 100644 index db42fc4a4..000000000 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/getwebpackconfig.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { describe, expect, it, vi } from 'vitest'; -import { DefinePlugin, EnvironmentPlugin } from 'webpack'; -import { loaders } from '@ckeditor/ckeditor5-dev-utils'; -import TreatWarningsAsErrorsWebpackPlugin from '../../../lib/utils/automated-tests/treatwarningsaserrorswebpackplugin.js'; -import getWebpackConfigForAutomatedTests from '../../../lib/utils/automated-tests/getwebpackconfig.js'; -import getDefinitionsFromFile from '../../../lib/utils/getdefinitionsfromfile.js'; -import getProtobufJsInquireWebpackRule from '../../../lib/utils/getprotobufjsinquirewebpackrule.js'; - -vi.mock( '@ckeditor/ckeditor5-dev-utils' ); -vi.mock( '../../../lib/utils/getdefinitionsfromfile.js' ); -vi.mock( '../../../lib/utils/getprotobufjsinquirewebpackrule.js' ); -vi.mock( '../../../lib/utils/automated-tests/treatwarningsaserrorswebpackplugin', () => ( { - default: class TreatWarningsAsErrorsWebpackPlugin {} -} ) ); -describe( 'getWebpackConfigForAutomatedTests()', () => { - it( 'should return basic webpack configuration object', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - debug: [], - tsconfig: '/tsconfig/path' - } ); - - expect( webpackConfig.resolve.extensions ).to.deep.equal( [ '.ts', '.js', '.json' ] ); - expect( webpackConfig.resolve.fallback.timers ).to.equal( false ); - - expect( vi.mocked( loaders.getIconsLoader ) ).toHaveBeenCalledOnce(); - expect( vi.mocked( loaders.getFormattedTextLoader ) ).toHaveBeenCalledOnce(); - expect( vi.mocked( loaders.getCoverageLoader ) ).not.toHaveBeenCalledOnce(); - expect( vi.mocked( loaders.getStylesLoader ) ).toHaveBeenCalledExactlyOnceWith( { - minify: true - } ); - expect( vi.mocked( loaders.getTypeScriptLoader ) ).toHaveBeenCalledExactlyOnceWith( { - configFile: '/tsconfig/path' - } ); - - expect( webpackConfig.resolveLoader.modules[ 0 ] ).to.equal( 'node_modules' ); - expect( webpackConfig.devtool ).to.equal( undefined ); - expect( webpackConfig.output ).to.have.property( 'devtoolModuleFilenameTemplate' ); - } ); - - it( 'should add the @protobufjs/inquire webpack rule', () => { - getWebpackConfigForAutomatedTests( {} ); - - expect( vi.mocked( getProtobufJsInquireWebpackRule ) ).toHaveBeenCalledOnce(); - } ); - - it( 'should aggregate events when running with the enabled watch mode', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( {} ); - - expect( webpackConfig ).to.have.property( 'watchOptions' ); - expect( webpackConfig.watchOptions ).to.have.property( 'aggregateTimeout', 500 ); - } ); - - it( 'should not include the ck-debug-loader', () => { - getWebpackConfigForAutomatedTests( { - files: [ '**/*.js' ] - } ); - - expect( vi.mocked( loaders.getJavaScriptLoader ) ).not.toHaveBeenCalledOnce(); - } ); - - it( 'should return webpack configuration containing a loader for measuring the coverage', () => { - getWebpackConfigForAutomatedTests( { - coverage: true, - files: [ '**/*.js' ] - } ); - - expect( vi.mocked( loaders.getCoverageLoader ) ).toHaveBeenCalledOnce(); - } ); - - it( 'should return webpack configuration with source map support', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - sourceMap: true - } ); - - expect( webpackConfig.devtool ).to.equal( 'inline-source-map' ); - expect( webpackConfig.optimization ).to.deep.equal( { - runtimeChunk: false, - splitChunks: false - } ); - } ); - - it( 'should contain a correct paths in resolveLoader', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( {} ); - - const firstPath = webpackConfig.resolveLoader.modules[ 0 ]; - const secondPath = webpackConfig.resolveLoader.modules[ 1 ]; - - expect( firstPath ).to.equal( 'node_modules' ); - - expect( secondPath ).to.match( /node_modules$/ ); - expect( require( 'node:fs' ).existsSync( secondPath ) ).to.equal( true ); - } ); - - it( 'should return webpack configuration with loaded identity file', () => { - vi.mocked( getDefinitionsFromFile ).mockReturnValue( { LICENSE_KEY: 'secret' } ); - - const webpackConfig = getWebpackConfigForAutomatedTests( { - identityFile: 'path/to/secrets.js' - } ); - - const plugin = webpackConfig.plugins.find( plugin => plugin instanceof DefinePlugin ); - - expect( vi.mocked( getDefinitionsFromFile ) ).toHaveBeenCalledExactlyOnceWith( 'path/to/secrets.js' ); - expect( plugin.definitions.LICENSE_KEY ).to.equal( 'secret' ); - } ); - - it( 'should return webpack configuration with environment definition', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( {} ); - const plugin = webpackConfig.plugins.find( plugin => plugin instanceof EnvironmentPlugin ); - - expect( plugin.keys ).toEqual( expect.arrayContaining( [ 'CKEDITOR_LICENSE_KEY' ] ) ); - expect( plugin.defaultValues ).toEqual( expect.objectContaining( { - CKEDITOR_LICENSE_KEY: '' - } ) ); - } ); - - it( 'should return webpack configuration with correct extension resolve order', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - resolveJsFirst: true - } ); - - expect( webpackConfig.resolve.extensions ).to.deep.equal( [ '.js', '.ts', '.json' ] ); - } ); - - it( 'should return webpack configuration with cache enabled', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - cache: true - } ); - - expect( webpackConfig.cache ).to.deep.equal( { - type: 'filesystem' - } ); - } ); - - it( 'should get rid of the "webpack://" protocol to make the paths clickable in the terminal', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( {} ); - - const { devtoolModuleFilenameTemplate } = webpackConfig.output; - - const info = { resourcePath: 'foo/bar/baz' }; - - expect( devtoolModuleFilenameTemplate( info ) ).to.equal( info.resourcePath ); - } ); - - it( 'should add TreatWarningsAsErrorsWebpackPlugin to plugins if options.production is true', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - production: true - } ); - - const plugin = webpackConfig.plugins.find( plugin => plugin instanceof TreatWarningsAsErrorsWebpackPlugin ); - - expect( plugin ).toBeTruthy(); - } ); - - it( 'should load TypeScript files first when importing JS files', () => { - const webpackConfig = getWebpackConfigForAutomatedTests( { - production: true - } ); - - expect( webpackConfig.resolve.extensionAlias ).to.be.an( 'object' ); - expect( webpackConfig.resolve.extensionAlias[ '.js' ] ).to.be.an( 'array' ); - expect( webpackConfig.resolve.extensionAlias[ '.js' ] ).to.deep.equal( [ - '.ts', - '.js' - ] ); - } ); -} ); diff --git a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/treatwarningsaserrorswebpackplugin.js b/packages/ckeditor5-dev-tests/tests/utils/automated-tests/treatwarningsaserrorswebpackplugin.js deleted file mode 100644 index 431b20851..000000000 --- a/packages/ckeditor5-dev-tests/tests/utils/automated-tests/treatwarningsaserrorswebpackplugin.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import { describe, expect, it } from 'vitest'; -import webpack from 'webpack'; -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import TreatWarningsAsErrorsWebpackPlugin from '../../../lib/utils/automated-tests/treatwarningsaserrorswebpackplugin.js'; - -describe( 'TreatWarningsAsErrorsWebpackPlugin', () => { - it( 'should reassign warnings to errors, emit the code and make the bundle fail', () => { - return new Promise( ( resolve, reject ) => { - runCompiler( - { - mode: 'development', - entry: './treatwarningsaserrorswebpackplugin/entrypoint.cjs', - plugins: [ - { - apply( compiler ) { - compiler.hooks.make.tap( 'MakeCompilationWarning', compilation => { - compilation.errors.push( new Error( 'Compilation error 1' ) ); - compilation.warnings.push( new Error( 'Compilation warning 1' ) ); - } ); - } - }, - new TreatWarningsAsErrorsWebpackPlugin() - ] - }, - ( err, stats, outputPath ) => { - if ( err ) { - return reject( err ); - } - - try { - const statsJson = stats.toJson( { errorDetails: false } ); - const asset = statsJson.assets.find( asset => asset.name.endsWith( '.js' ) ); - const assetContent = fs.readFileSync( path.join( outputPath, asset.name ), 'utf-8' ); - - expect( statsJson.errors.length ).to.equal( 2 ); - expect( statsJson.warnings.length ).to.equal( 0 ); - expect( statsJson.errors[ 0 ].message ).to.equal( 'Compilation error 1' ); - expect( statsJson.errors[ 1 ].message ).to.equal( 'Compilation warning 1' ); - expect( asset.emitted ).to.equal( true ); - expect( assetContent ).to.contain( 'Webpack compilation failed. See terminal output for details.' ); - resolve(); - } catch ( error ) { - reject( error ); - } - } ); - } ); - } ); -} ); - -function runCompiler( options, callback ) { - options.context = path.join( import.meta.dirname, '..', '..', 'fixtures' ); - options.output = { - path: fs.mkdtempSync( path.join( os.tmpdir(), 'treat-warnings-as-errors-webpack-plugin-' ) ) - }; - - const compiler = webpack( options ); - - compiler.run( ( err, stats ) => { - compiler.close( closeError => { - callback( err || closeError, stats, options.output.path ); - fs.rmSync( options.output.path, { recursive: true, force: true } ); - } ); - } ); -} diff --git a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/getwebpackconfig.js b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/getwebpackconfig.js index 80599849e..77603d50e 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/manual-tests/getwebpackconfig.js +++ b/packages/ckeditor5-dev-tests/tests/utils/manual-tests/getwebpackconfig.js @@ -42,7 +42,6 @@ describe( 'getWebpackConfigForManualTests()', () => { vi.mocked( loaders ).getStylesLoader.mockReturnValue( {} ); vi.mocked( loaders ).getTypeScriptLoader.mockReturnValue( {} ); vi.mocked( loaders ).getFormattedTextLoader.mockReturnValue( {} ); - vi.mocked( loaders ).getCoverageLoader.mockReturnValue( {} ); vi.mocked( loaders ).getJavaScriptLoader.mockReturnValue( {} ); } ); @@ -79,8 +78,6 @@ describe( 'getWebpackConfigForManualTests()', () => { debugFlags: debug } ); - expect( vi.mocked( loaders ).getCoverageLoader ).not.toHaveBeenCalledOnce(); - expect( webpackConfig ).toEqual( expect.objectContaining( { // To avoid "eval()" in files. mode: 'none', diff --git a/packages/ckeditor5-dev-tests/tests/utils/parsearguments.js b/packages/ckeditor5-dev-tests/tests/utils/parsearguments.js index 512b89efd..755ba2e97 100644 --- a/packages/ckeditor5-dev-tests/tests/utils/parsearguments.js +++ b/packages/ckeditor5-dev-tests/tests/utils/parsearguments.js @@ -43,20 +43,17 @@ describe( 'parseArguments()', () => { '/home/.secret/file.key', '--additional-languages', 'de,fr', - '--resolve-js-first', '--disable-watch' ] ); expect( options[ 'source-map' ] ).to.be.undefined; expect( options[ 'identity-file' ] ).to.be.undefined; expect( options[ 'additional-languages' ] ).to.be.undefined; - expect( options[ 'resolve-js-first' ] ).to.be.undefined; expect( options[ 'disable-watch' ] ).to.be.undefined; expect( options.sourceMap ).to.equal( true ); expect( options.identityFile ).to.equal( '/home/.secret/file.key' ); expect( options.additionalLanguages ).to.deep.equal( [ 'de', 'fr' ] ); - expect( options.resolveJsFirst ).to.equal( true ); expect( options.disableWatch ).to.equal( true ); } ); @@ -64,10 +61,6 @@ describe( 'parseArguments()', () => { vi.mocked( fs ).readFileSync.mockReturnValue( '{}' ); const options = parseArguments( [ - '-b', - 'Chrome,Firefox', - '-c', - 'true', '-d', 'engine', '-f', @@ -79,18 +72,14 @@ describe( 'parseArguments()', () => { '-s', 'true', '-v', - 'false', - '-w', - true + 'false' ] ); - for ( const key of [ 'b', 'c', 'd', 'f', 'i', 'r', 's', 'v', 'w' ] ) { + for ( const key of [ 'd', 'f', 'i', 'r', 's', 'v' ] ) { expect( options[ key ], `Checked "${ key }"` ).to.be.undefined; } - expect( options.coverage ).to.equal( true ); expect( options.verbose ).to.equal( false ); - expect( options.browsers ).to.deep.equal( [ 'Chrome', 'Firefox' ] ); expect( options.debug ).to.deep.equal( [ 'CK_DEBUG', 'CK_DEBUG_ENGINE' ] ); expect( options.files ).to.deep.equal( [ 'core' ] ); expect( options.repositories ).to.deep.equal( [ 'custom-monorepo' ] ); @@ -358,26 +347,7 @@ describe( 'parseArguments()', () => { return str.replace( /\u001b\[[0-9;]*m/g, '' ); } - it( 'should print help and exit when --help is passed (automated mode)', () => { - parseArguments( [ '--help' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); - - expect( processExitStub ).toHaveBeenCalledWith( 0 ); - expect( consoleLogStub ).toHaveBeenCalledOnce(); - - const output = stripAnsi( consoleLogStub.mock.calls[ 0 ][ 0 ] ); - - expect( output ).toContain( 'ckeditor5-dev-tests-run-automated [options]' ); - expect( output ).toContain( 'Runs automated tests using Karma and Vitest.' ); - expect( output ).toContain( '--coverage' ); - expect( output ).toContain( '--watch' ); - expect( output ).toContain( '--browsers' ); - expect( output ).toContain( 'Test selection' ); - expect( output ).toContain( 'Test execution' ); - expect( output ).toContain( 'Build configuration' ); - expect( output ).toContain( 'Examples' ); - } ); - - it( 'should print help and exit when --help is passed (manual mode)', () => { + it( 'should print help and exit when --help is passed', () => { parseArguments( [ '--help' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); expect( processExitStub ).toHaveBeenCalledWith( 0 ); @@ -392,10 +362,11 @@ describe( 'parseArguments()', () => { expect( output ).toContain( 'Server' ); expect( output ).not.toContain( '--coverage' ); expect( output ).not.toContain( 'Test execution' ); + expect( output ).toContain( 'Examples' ); } ); it( 'should print help and exit when -h alias is passed', () => { - parseArguments( [ '-h' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); + parseArguments( [ '-h' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); expect( processExitStub ).toHaveBeenCalledWith( 0 ); expect( consoleLogStub ).toHaveBeenCalledOnce(); @@ -440,11 +411,11 @@ describe( 'parseArguments()', () => { } ); it( 'should not print error when only known options are passed', () => { - const options = parseArguments( [ '--coverage', '--verbose' ] ); + const options = parseArguments( [ '--silent', '--verbose' ] ); expect( processExitStub ).not.toHaveBeenCalled(); expect( consoleErrorStub ).not.toHaveBeenCalled(); - expect( options.coverage ).to.equal( true ); + expect( options.silent ).to.equal( true ); expect( options.verbose ).to.equal( true ); } ); @@ -458,7 +429,7 @@ describe( 'parseArguments()', () => { } ); } ); - describe( 'command-specific option validation', () => { + describe( 'unknown aliases and negated flags', () => { let processExitStub, consoleErrorStub; beforeEach( () => { @@ -489,20 +460,6 @@ describe( 'parseArguments()', () => { expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( '--watch' ); } ); - it( 'should reject --disable-watch when running automated tests', () => { - parseArguments( [ '--disable-watch' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); - - expect( processExitStub ).toHaveBeenCalledWith( 1 ); - expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( '--disable-watch' ); - } ); - - it( 'should reject --port when running automated tests', () => { - parseArguments( [ '--port', '9000' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); - - expect( processExitStub ).toHaveBeenCalledWith( 1 ); - expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( '--port' ); - } ); - it( 'should report multiple unsupported options at once', () => { parseArguments( [ '--coverage', '--watch' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); @@ -510,14 +467,6 @@ describe( 'parseArguments()', () => { expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( 'Unknown options: --coverage, --watch' ); } ); - it( 'should accept --coverage for automated tests', () => { - const options = parseArguments( [ '--coverage' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); - - expect( processExitStub ).not.toHaveBeenCalled(); - expect( consoleErrorStub ).not.toHaveBeenCalled(); - expect( options.coverage ).to.equal( true ); - } ); - it( 'should accept --disable-watch for manual tests', () => { const options = parseArguments( [ '--disable-watch' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); @@ -527,11 +476,11 @@ describe( 'parseArguments()', () => { } ); it( 'should skip validation when commandName is not provided', () => { - const options = parseArguments( [ '--coverage', '--disable-watch' ] ); + const options = parseArguments( [ '--verbose', '--disable-watch' ] ); expect( processExitStub ).not.toHaveBeenCalled(); expect( consoleErrorStub ).not.toHaveBeenCalled(); - expect( options.coverage ).to.equal( true ); + expect( options.verbose ).to.equal( true ); expect( options.disableWatch ).to.equal( true ); } ); @@ -543,16 +492,15 @@ describe( 'parseArguments()', () => { expect( options.port ).to.equal( 9000 ); } ); - it( 'should reject individual letters in combined short flags', () => { + it( 'should reject combined unknown short flags', () => { parseArguments( [ '-cw' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); expect( processExitStub ).toHaveBeenCalledWith( 1 ); expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( '-c' ); - expect( consoleErrorStub.mock.calls[ 0 ][ 0 ] ).toContain( '-w' ); } ); it( 'should not reject --no-* flags for options valid in the current command', () => { - const options = parseArguments( [ '--no-debug' ], { commandName: 'ckeditor5-dev-tests-run-automated' } ); + const options = parseArguments( [ '--no-debug' ], { commandName: 'ckeditor5-dev-tests-run-manual' } ); expect( processExitStub ).not.toHaveBeenCalled(); expect( consoleErrorStub ).not.toHaveBeenCalled(); diff --git a/packages/ckeditor5-dev-tests/tests/vitest/matchers.js b/packages/ckeditor5-dev-tests/tests/vitest/matchers.js new file mode 100644 index 000000000..469e168c9 --- /dev/null +++ b/packages/ckeditor5-dev-tests/tests/vitest/matchers.js @@ -0,0 +1,144 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import { beforeAll, describe, expect, it } from 'vitest'; +import { toEqualMarkup } from '../../lib/vitest/matchers.js'; + +describe( 'toEqualMarkup matcher', () => { + beforeAll( () => { + expect.extend( { toEqualMarkup } ); + } ); + + it( 'should be a function', () => { + expect( toEqualMarkup ).toBeInstanceOf( Function ); + } ); + + it( 'should not throw for equal markups', () => { + expect( function() { + expect( + 'foo bXXX[]r baz' + ).toEqualMarkup( + 'foo bXXX[]r baz' + ); + } ).to.not.throw(); + } ); + + it( 'should throw an assertion error for unequal markups', () => { + expect( function() { + expect( + 'foo bXXX[]r baz' + ).toEqualMarkup( + 'foo bYYY[]r baz' + ); + } ).to.throw( 'Expected markup strings to be equal' ); + } ); + + it( 'should support the negated form for unequal markups', () => { + expect( function() { + expect( + 'foo bXXX[]r baz' + ).not.toEqualMarkup( + 'foo bYYY[]r baz' + ); + } ).to.not.throw(); + } ); + + it( 'should throw an assertion error for the negated form and equal markups', () => { + expect( function() { + expect( + 'foo bXXX[]r baz' + ).not.toEqualMarkup( + 'foo bXXX[]r baz' + ); + } ).to.throw( 'Expected markup strings not to be equal' ); + } ); + + it( 'should format the received markup', () => { + const result = toEqualMarkup( + '

foo

', + 'bar' + ); + + expect( result.pass ).toEqual( false ); + expect( result.actual ).toEqual( + '
\n' + + '

foo

\n' + + '
' + ); + } ); + + it( 'should format the expected markup', () => { + const result = toEqualMarkup( + 'foo', + '

foo

' + ); + + expect( result.pass ).toEqual( false ); + expect( result.expected ).toEqual( + '
\n' + + '

foo

\n' + + '
' + ); + } ); + + it( 'should format model text node with attributes as inline', () => { + const result = toEqualMarkup( + 'foo', + '<$text bold="true">foo' + ); + + expect( result.pass ).toEqual( false ); + expect( result.expected ).toEqual( + '<$text bold="true">foo' + ); + } ); + + it( 'should format nested model structure properly', () => { + const result = toEqualMarkup( + 'foo', + '
' + + '' + + '' + + '' + + '<$text bold="true">foo' + + '' + + '' + + '<$text bold="true">bar' + + '<$text bold="true">baz' + + '' + + '' + + '
' + + '
' + ); + + expect( result.pass ).toEqual( false ); + expect( result.expected ).toEqual( + '
\n' + + ' \n' + + ' \n' + + ' \n' + + ' <$text bold="true">foo\n' + + ' \n' + + ' \n' + + ' <$text bold="true">bar\n' + + ' <$text bold="true">baz\n' + + ' \n' + + ' \n' + + '
\n' + + '
' + ); + } ); + + it( 'should not format strings if beautifier returns equal markups after formatting', () => { + const result = toEqualMarkup( + '

foo

', + '

foo

' + ); + + expect( result.pass ).toEqual( false ); + expect( result.actual ).toEqual( '

foo

' ); + expect( result.expected ).toEqual( '

foo

' ); + } ); +} ); diff --git a/packages/ckeditor5-dev-utils/package.json b/packages/ckeditor5-dev-utils/package.json index 382b99f6a..e8f8b68c4 100644 --- a/packages/ckeditor5-dev-utils/package.json +++ b/packages/ckeditor5-dev-utils/package.json @@ -25,7 +25,6 @@ "dependencies": { "@types/shelljs": "^0.10.0", "@types/through2": "^2.0.41", - "babel-loader": "^10.1.1", "cli-cursor": "^5.0.0", "cli-spinners": "^3.4.0", "css-loader": "^7.1.4", diff --git a/packages/ckeditor5-dev-utils/src/loaders/getcoverageloader.ts b/packages/ckeditor5-dev-utils/src/loaders/getcoverageloader.ts deleted file mode 100644 index a3daf9531..000000000 --- a/packages/ckeditor5-dev-utils/src/loaders/getcoverageloader.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import { resolveLoader } from './resolve-loader.js'; - -type CoverageLoaderConfig = { - test: RegExp; - use: Array<{ - loader: string; - options: { - plugins: Array; - }; - }>; - include: Array; - exclude: Array; -}; - -const escapedPathSep = path.sep == '/' ? '/' : '\\\\'; - -export default function getCoverageLoader( { files }: { files: Array> } ): CoverageLoaderConfig { - return { - test: /\.[jt]s$/, - use: [ - { - loader: resolveLoader( 'babel-loader' ), - options: { - plugins: [ - 'babel-plugin-istanbul' - ] - } - } - ], - include: getPathsToIncludeForCoverage( files ), - exclude: [ - new RegExp( `${ escapedPathSep }(lib)${ escapedPathSep }` ) - ] - }; -} - -/** - * Returns an array of `/ckeditor5-name\/src\//` regexps based on passed globs. - * E.g., `ckeditor5-utils/**\/*.js` will be converted to `/ckeditor5-utils\/src/`. - * - * This loose way of matching packages for CC works with packages under various paths. - * E.g., `workspace/ckeditor5-utils` and `ckeditor5/node_modules/ckeditor5-utils` and every other path. - */ -function getPathsToIncludeForCoverage( globs: Array> ): Array { - const values = globs - .reduce( ( returnedPatterns, globPatterns ) => { - returnedPatterns.push( ...globPatterns ); - - return returnedPatterns; - }, [] as Array ) - .map( glob => { - const matchCKEditor5 = glob.match( /\/(ckeditor5-[^/]+)\/(?!.*ckeditor5-)/ ); - - if ( matchCKEditor5 ) { - const packageName = matchCKEditor5[ 1 ]! - // A special case when --files='!engine' or --files='!engine|ui' was passed. - // Convert it to /ckeditor5-(?!engine)[^/]\/src\//. - .replace( /ckeditor5-!\(([^)]+)\)\*/, 'ckeditor5-(?!$1)[^' + escapedPathSep + ']+' ) - .replace( 'ckeditor5-*', 'ckeditor5-[a-z]+' ); - - return new RegExp( packageName + escapedPathSep + 'src' + escapedPathSep ); - } - } ) - // Filter undefined ones. - .filter( path => path ); - - return [ ...new Set( values as Array ) ]; -} diff --git a/packages/ckeditor5-dev-utils/src/loaders/index.ts b/packages/ckeditor5-dev-utils/src/loaders/index.ts index 1d357dbda..ee6ab8958 100644 --- a/packages/ckeditor5-dev-utils/src/loaders/index.ts +++ b/packages/ckeditor5-dev-utils/src/loaders/index.ts @@ -3,7 +3,6 @@ * For licensing, see LICENSE.md. */ -export { default as getCoverageLoader } from './getcoverageloader.js'; export { default as getTypeScriptLoader } from './gettypescriptloader.js'; export { default as getDebugLoader } from './getdebugloader.js'; export { default as getIconsLoader } from './geticonsloader.js'; diff --git a/packages/ckeditor5-dev-utils/tests/loaders/getcoverageloader.ts b/packages/ckeditor5-dev-utils/tests/loaders/getcoverageloader.ts deleted file mode 100644 index 8a6479efd..000000000 --- a/packages/ckeditor5-dev-utils/tests/loaders/getcoverageloader.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. - * For licensing, see LICENSE.md. - */ - -import path from 'node:path'; -import { describe, expect, it } from 'vitest'; -import getCoverageLoader from '../../src/loaders/getcoverageloader.js'; - -const escapedPathSep = path.sep == '/' ? '/' : '\\\\'; - -describe( 'getCoverageLoader()', () => { - it( 'should be a function', () => { - expect( getCoverageLoader ).to.be.a( 'function' ); - } ); - - it( 'should return a definition containing a loader for measuring the coverage', () => { - const coverageLoader = getCoverageLoader( { - files: [] - } ); - - expect( coverageLoader ).to.be.an( 'object' ); - expect( '/path/to/javascript.js' ).to.match( coverageLoader.test ); - expect( '/path/to/typescript.ts' ).to.match( coverageLoader.test ); - - expect( coverageLoader.include ).to.be.an( 'array' ); - expect( coverageLoader.include ).to.lengthOf( 0 ); - expect( coverageLoader.exclude ).to.be.an( 'array' ); - expect( coverageLoader.exclude ).to.lengthOf( 1 ); - - expect( coverageLoader.use ).to.be.an( 'array' ); - expect( coverageLoader.use ).to.lengthOf( 1 ); - - const babelLoader = coverageLoader.use.at( 0 )!; - - expect( babelLoader.loader ).to.include( 'babel-loader' ); - } ); - - it( 'should return a definition containing a loader for measuring the coverage (include glob check)', () => { - const coverageLoader = getCoverageLoader( { - files: [ - // -f utils - [ 'node_modules/ckeditor5-utils/tests/**/*.js' ] - ] - } ); - - expect( coverageLoader ).to.be.an( 'object' ); - expect( coverageLoader ).to.have.property( 'include' ); - expect( coverageLoader.include ).to.be.an( 'array' ); - expect( coverageLoader.include ).to.deep.equal( [ - new RegExp( [ 'ckeditor5-utils', 'src', '' ].join( escapedPathSep ) ) - ] ); - } ); - - it( 'should return a definition containing a loader for measuring the coverage (exclude glob check)', () => { - const coverageLoader = getCoverageLoader( { - files: [ - // -f !utils - [ 'node_modules/ckeditor5-!(utils)/tests/**/*.js' ] - ] - } ); - - expect( coverageLoader ).to.be.an( 'object' ); - expect( coverageLoader ).to.have.property( 'include' ); - expect( coverageLoader.include ).to.be.an( 'array' ); - expect( coverageLoader.include ).to.deep.equal( [ - new RegExp( [ 'ckeditor5-!(utils)', 'src', '' ].join( escapedPathSep ) ) - ] ); - } ); - - it( 'should return a definition containing a loader for measuring the coverage (for root named ckeditor5-*)', () => { - const coverageLoader = getCoverageLoader( { - files: [ - [ '/ckeditor5-collab/packages/ckeditor5-alignment/tests/**/*.{js,ts}' ] - ] - } ); - - expect( coverageLoader ).to.be.an( 'object' ); - expect( coverageLoader ).to.have.property( 'include' ); - expect( coverageLoader.include ).to.be.an( 'array' ); - expect( coverageLoader.include ).to.deep.equal( [ - new RegExp( [ 'ckeditor5-alignment', 'src', '' ].join( escapedPathSep ) ) - ] ); - } ); -} ); diff --git a/packages/ckeditor5-dev-utils/tests/loaders/index.ts b/packages/ckeditor5-dev-utils/tests/loaders/index.ts index 59ddae6ad..e8482cbfe 100644 --- a/packages/ckeditor5-dev-utils/tests/loaders/index.ts +++ b/packages/ckeditor5-dev-utils/tests/loaders/index.ts @@ -5,7 +5,6 @@ import { describe, expect, it, vi } from 'vitest'; import * as loaders from '../../src/loaders/index.js'; -import getCoverageLoader from '../../src/loaders/getcoverageloader.js'; import getTypeScriptLoader from '../../src/loaders/gettypescriptloader.js'; import getDebugLoader from '../../src/loaders/getdebugloader.js'; import getIconsLoader from '../../src/loaders/geticonsloader.js'; @@ -13,7 +12,6 @@ import getFormattedTextLoader from '../../src/loaders/getformattedtextloader.js' import getJavaScriptLoader from '../../src/loaders/getjavascriptloader.js'; import getStylesLoader from '../../src/loaders/getstylesloader.js'; -vi.mock( '../../src/loaders/getcoverageloader.js' ); vi.mock( '../../src/loaders/gettypescriptloader.js' ); vi.mock( '../../src/loaders/getdebugloader.js' ); vi.mock( '../../src/loaders/geticonsloader.js' ); @@ -22,13 +20,6 @@ vi.mock( '../../src/loaders/getjavascriptloader.js' ); vi.mock( '../../src/loaders/getstylesloader.js' ); describe( 'loaders/index.js', () => { - describe( 'getCoverageLoader()', () => { - it( 'should be a function', () => { - expect( loaders.getCoverageLoader ).to.be.a( 'function' ); - expect( loaders.getCoverageLoader ).toEqual( getCoverageLoader ); - } ); - } ); - describe( 'getTypeScriptLoader()', () => { it( 'should be a function', () => { expect( loaders.getTypeScriptLoader ).to.be.a( 'function' ); diff --git a/packages/ckeditor5-dev-utils/tests/loaders/resolve-loader.ts b/packages/ckeditor5-dev-utils/tests/loaders/resolve-loader.ts index 5319cb54b..5fcb7ca93 100644 --- a/packages/ckeditor5-dev-utils/tests/loaders/resolve-loader.ts +++ b/packages/ckeditor5-dev-utils/tests/loaders/resolve-loader.ts @@ -13,9 +13,9 @@ describe( 'resolveLoader()', () => { } ); it( 'should resolve a loader path', () => { - const loaderPath = resolveLoader( 'babel-loader' ); + const loaderPath = resolveLoader( 'raw-loader' ); expect( loaderPath ).to.be.a( 'string' ); - expect( loaderPath ).toEndWith( join( 'node_modules', 'babel-loader', 'lib', 'index.js' ) ); + expect( loaderPath ).toEndWith( join( 'node_modules', 'raw-loader', 'dist', 'cjs.js' ) ); } ); } ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index addaeb717..064558019 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -379,9 +379,6 @@ importers: packages/ckeditor5-dev-tests: dependencies: - '@babel/core': - specifier: ^7.29.0 - version: 7.29.7(supports-color@8.1.1) '@ckeditor/ckeditor5-dev-translations': specifier: workspace:* version: link:../ckeditor5-dev-translations @@ -391,30 +388,9 @@ importers: '@ckeditor/ckeditor5-inspector': specifier: ^5.0.1 version: 5.0.1 - '@types/chai': - specifier: ^4.3.20 - version: 4.3.20 - '@types/karma-sinon-chai': - specifier: ^2.0.6 - version: 2.0.6 - '@types/mocha': - specifier: ^10.0.10 - version: 10.0.10 - '@types/sinon': - specifier: ^10.0.20 - version: 10.0.20 - assertion-error: - specifier: ^2.0.1 - version: 2.0.1 - babel-plugin-istanbul: - specifier: ^7.0.1 - version: 7.0.1 buffer: specifier: ^6.0.3 version: 6.0.3 - chai: - specifier: ^4.5.0 - version: 4.5.0 chokidar: specifier: ^4.0.3 version: 4.0.3 @@ -433,72 +409,18 @@ importers: glob: specifier: ^13.0.6 version: 13.0.6 - is-wsl: - specifier: ^3.1.1 - version: 3.1.1 js-beautify: specifier: ^1.15.4 version: 1.15.4 - karma: - specifier: ^6.4.4 - version: 6.4.4(supports-color@8.1.1) - karma-chai: - specifier: ^0.1.0 - version: 0.1.0(chai@4.5.0)(karma@6.4.4(supports-color@8.1.1)) - karma-chrome-launcher: - specifier: ^3.2.0 - version: 3.2.0 - karma-coverage: - specifier: ^2.2.1 - version: 2.2.1(supports-color@8.1.1) - karma-firefox-launcher: - specifier: ^2.1.3 - version: 2.1.3 - karma-mocha: - specifier: ^2.0.1 - version: 2.0.1 - karma-mocha-reporter: - specifier: ^2.2.5 - version: 2.2.5(karma@6.4.4(supports-color@8.1.1)) - karma-sinon: - specifier: ^1.0.5 - version: 1.0.5(karma@6.4.4(supports-color@8.1.1))(sinon@9.2.4) - karma-sinon-chai: - specifier: ^2.0.2 - version: 2.0.2(chai@4.5.0)(sinon-chai@3.7.0(chai@4.5.0)(sinon@9.2.4))(sinon@9.2.4) - karma-sourcemap-loader: - specifier: ^0.4.0 - version: 0.4.0 - karma-webpack: - specifier: ^5.0.1 - version: 5.0.1(webpack@5.107.2(esbuild@0.28.1)) - minimatch: - specifier: ^10.2.5 - version: 10.2.5 minimist: specifier: ^1.2.8 version: 1.2.8 - mkdirp: - specifier: ^3.0.1 - version: 3.0.1 - mocha: - specifier: ^11.7.5 - version: 11.7.6 - node-notifier: - specifier: ^10.0.1 - version: 10.0.1 process: specifier: ^0.11.10 version: 0.11.10 - sinon: - specifier: ^9.2.4 - version: 9.2.4 - sinon-chai: - specifier: ^3.7.0 - version: 3.7.0(chai@4.5.0)(sinon@9.2.4) socket.io: specifier: ^4.8.3 - version: 4.8.3 + version: 4.8.3(supports-color@8.1.1) typescript: specifier: 5.5.4 version: 5.5.4 @@ -561,9 +483,6 @@ importers: '@types/through2': specifier: ^2.0.41 version: 2.0.41 - babel-loader: - specifier: ^10.1.1 - version: 10.1.1(@babel/core@7.29.7)(webpack@5.107.2(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.15)) cli-cursor: specifier: ^5.0.0 version: 5.0.0 @@ -680,40 +599,14 @@ packages: resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.7': - resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.7': - resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.29.7': - resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} - engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.29.7': resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.29.7': - resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.29.7': - resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.29.7': - resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} @@ -722,14 +615,6 @@ packages: resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.29.7': - resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.7': - resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} - engines: {node: '>=6.9.0'} - '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} @@ -767,10 +652,6 @@ packages: '@colordx/core@5.4.3': resolution: {integrity: sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ==} - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -1181,14 +1062,6 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.6': - resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} - engines: {node: '>=8'} - '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1865,21 +1738,6 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} - '@sinonjs/commons@1.8.6': - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - - '@sinonjs/fake-timers@6.0.1': - resolution: {integrity: sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==} - - '@sinonjs/samsam@5.3.1': - resolution: {integrity: sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==} - - '@sinonjs/text-encoding@0.7.3': - resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} - deprecated: |- - Deprecated: no longer maintained and no longer used by Sinon packages. See - https://github.com/sinonjs/nise/issues/243 for replacement details. - '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -1906,9 +1764,6 @@ packages: '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@types/chai@4.3.20': - resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1936,21 +1791,12 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/karma-sinon-chai@2.0.6': - resolution: {integrity: sha512-7bfh0DuuFFd8OotzhARvekmBBSMwc+bzbiQjvS/Ja4T0WhhFo5ava9hMVL6Z7YZdDyeTlckHdCuWJhNXQrEpFQ==} - - '@types/karma@6.3.9': - resolution: {integrity: sha512-sjE/MHnoAZAQYAKRXAbjTOiBKyGGErEM725bruRcmDdMa2vp1bjWPhApI7/i564PTyHlzc3vIGXLL6TFIpAxFg==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/minimatch@3.0.5': resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} - '@types/mocha@10.0.10': - resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} - '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1981,15 +1827,6 @@ packages: '@types/shelljs@0.10.0': resolution: {integrity: sha512-OEfyhE5Ox+FeoHbhrEDwm0kXxntO6nsyMRCFvNsIBHPZu5rV1w2OjPcLclaC/IZ1TlzZPgbeMfwAZEi5N238yQ==} - '@types/sinon-chai@2.7.42': - resolution: {integrity: sha512-6M+l7agAuaS4iFwC9KtmcGznH4WYTcF3/Jq/m4jZ5/Gm1Rlufc7o7rl1Sb9++U81NliT+mV2Ri6UQziaJi6opw==} - - '@types/sinon@10.0.20': - resolution: {integrity: sha512-2APKKruFNCAZgx3daAyACGzWuJ028VVCUDk6o2rw/Z4PXT0ogwdV4KUegW0MwVs0Zu59auPXbbuBJHF12Sx1Eg==} - - '@types/sinonjs__fake-timers@15.0.1': - resolution: {integrity: sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==} - '@types/ssri@7.1.5': resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} @@ -2245,10 +2082,6 @@ packages: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} - ansi-regex@3.0.1: - resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} - engines: {node: '>=4'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2257,10 +2090,6 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -2273,10 +2102,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2292,9 +2117,6 @@ packages: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2317,23 +2139,6 @@ packages: react-native-b4a: optional: true - babel-loader@10.1.1: - resolution: {integrity: sha512-JwKSzk2kjIe7mgPK+/lyZ2QAaJcpahNAdM+hgR2HI8D0OJVkdj8Rl6J3kaLYki9pwF7P2iWnD8qVv80Lq1ABtg==} - engines: {node: ^18.20.0 || ^20.10.0 || >=22.0.0} - peerDependencies: - '@babel/core': ^7.12.0 || ^8.0.0-beta.1 - '@rspack/core': ^1.0.0 || ^2.0.0-0 - webpack: '>=5.61.0' - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - - babel-plugin-istanbul@7.0.1: - resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} - engines: {node: '>=12'} - bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2407,14 +2212,6 @@ packages: big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - body-parser@1.20.5: - resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2436,9 +2233,6 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -2453,10 +2247,6 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} @@ -2469,10 +2259,6 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsite@1.0.0: resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} @@ -2480,10 +2266,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -2501,18 +2283,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2533,13 +2307,6 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2592,16 +2359,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -2655,14 +2416,6 @@ packages: config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - content-type@2.0.0: resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} engines: {node: '>=18'} @@ -2768,9 +2521,6 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - custom-event@1.0.1: - resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} - data-uri-to-buffer@6.0.2: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} @@ -2778,18 +2528,6 @@ packages: date-fns@4.3.0: resolution: {integrity: sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ==} - date-format@4.0.14: - resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} - engines: {node: '>=4.0'} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2799,17 +2537,9 @@ packages: supports-color: optional: true - decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2838,10 +2568,6 @@ packages: engines: {node: '>=10'} hasBin: true - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - deps-regex@0.2.0: resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} @@ -2849,10 +2575,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-file@1.0.0: resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} engines: {node: '>=0.10.0'} @@ -2870,17 +2592,10 @@ packages: devtools-protocol@0.0.1608973: resolution: {integrity: sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==} - di@0.0.1: - resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} - diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - diff@8.0.4: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} @@ -2888,9 +2603,6 @@ packages: dom-combiner@0.1.3: resolution: {integrity: sha512-RXFGB8Jr4ScM9HE8tj4jkt/wkvB8WuHCJJSs/8BnL8E11pjv2H1cRY/HTzXrvg0vrw18Xj61oxtB1ijxgqNvzg==} - dom-serialize@2.2.1: - resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==} - dom-serializer@0.2.2: resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} @@ -2925,9 +2637,6 @@ packages: engines: {node: '>=14'} hasBin: true - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.361: resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} @@ -2944,10 +2653,6 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -2963,10 +2668,6 @@ packages: resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} engines: {node: '>=10.13.0'} - ent@2.2.2: - resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} - engines: {node: '>= 0.4'} - entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -3036,13 +2737,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -3137,9 +2831,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -3222,14 +2913,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3242,22 +2925,9 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - follow-redirects@1.16.0: - resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -3274,17 +2944,10 @@ packages: resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} engines: {node: '>=14.14'} - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - fs-minipass@3.0.3: resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3293,10 +2956,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3305,17 +2964,10 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3358,10 +3010,6 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} @@ -3410,13 +3058,6 @@ packages: resolution: {integrity: sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - growly@1.3.0: - resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3442,10 +3083,6 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - homedir-polyfill@1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} @@ -3463,18 +3100,10 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-proxy@1.18.1: - resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} - engines: {node: '>=8.0.0'} - https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -3488,10 +3117,6 @@ packages: engines: {node: '>=18'} hasBin: true - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -3528,10 +3153,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3558,24 +3179,10 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-core-module@2.16.2: resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -3600,11 +3207,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -3617,34 +3219,18 @@ packages: resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-path-inside@4.0.0: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} - is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -3657,21 +3243,6 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - - is-wsl@3.1.1: - resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} - engines: {node: '>=16'} - - isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - - isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3683,22 +3254,10 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} - istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} @@ -3784,9 +3343,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} @@ -3794,61 +3350,6 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} - just-extend@4.2.1: - resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==} - - karma-chai@0.1.0: - resolution: {integrity: sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==} - peerDependencies: - chai: '*' - karma: '>=0.10.9' - - karma-chrome-launcher@3.2.0: - resolution: {integrity: sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==} - - karma-coverage@2.2.1: - resolution: {integrity: sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==} - engines: {node: '>=10.0.0'} - - karma-firefox-launcher@2.1.3: - resolution: {integrity: sha512-LMM2bseebLbYjODBOVt7TCPP9OI2vZIXCavIXhkO9m+10Uj5l7u/SKoeRmYx8FYHTVGZSpk6peX+3BMHC1WwNw==} - - karma-mocha-reporter@2.2.5: - resolution: {integrity: sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==} - peerDependencies: - karma: '>=0.13' - - karma-mocha@2.0.1: - resolution: {integrity: sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==} - - karma-sinon-chai@2.0.2: - resolution: {integrity: sha512-SDgh6V0CUd+7ruL1d3yG6lFzmJNGRNQuEuCYXLaorruNP9nwQfA7hpsp4clx4CbOo5Gsajh3qUOT7CrVStUKMw==} - peerDependencies: - chai: '>=3.5.0' - sinon: '>=2.1.0' - sinon-chai: '>=2.9.0' - - karma-sinon@1.0.5: - resolution: {integrity: sha512-wrkyAxJmJbn75Dqy17L/8aILJWFm7znd1CE8gkyxTBFnjMSOe2XTJ3P30T8SkxWZHmoHX0SCaUJTDBEoXs25Og==} - engines: {node: '>= 0.10.0'} - peerDependencies: - karma: '>=0.10' - sinon: '*' - - karma-sourcemap-loader@0.4.0: - resolution: {integrity: sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==} - - karma-webpack@5.0.1: - resolution: {integrity: sha512-oo38O+P3W2mSPCSUrQdySSPv1LvPpXP+f+bBimNomS5sW+1V4SuhCuW8TfJzV+rDv921w2fDSDw0xJbPe6U+kQ==} - engines: {node: '>= 18'} - peerDependencies: - webpack: ^5.0.0 - - karma@6.4.4: - resolution: {integrity: sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==} - engines: {node: '>= 10'} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -3971,18 +3472,10 @@ packages: localforage@1.10.0: resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -3995,14 +3488,6 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - log-symbols@2.2.0: - resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} - engines: {node: '>=4'} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -4011,16 +3496,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - log4js@6.9.1: - resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} - engines: {node: '>=8.0'} - longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -4028,9 +3506,6 @@ packages: resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} engines: {node: 20 || >=22} - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} @@ -4124,10 +3599,6 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -4238,11 +3709,6 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4310,30 +3776,13 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - mlly@1.8.2: resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} - mocha@11.7.6: - resolution: {integrity: sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - mock-fs@5.5.0: resolution: {integrity: sha512-d/P1M/RacgM3dB0sJ8rjeRNXxtapkPCUnMGmIN0ixJ16F/E4GUZCvWcSGfWGz8eaXYvn1s9baUwNjI4LOPEjiA==} engines: {node: '>=12.0.0'} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4372,17 +3821,11 @@ packages: resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} engines: {node: '>= 0.4.0'} - nise@4.1.0: - resolution: {integrity: sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==} - node-gyp@12.3.0: resolution: {integrity: sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==} engines: {node: ^20.17.0 || >=22.9.0} hasBin: true - node-notifier@10.0.1: - resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==} - node-releases@2.0.46: resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} engines: {node: '>=18'} @@ -4397,10 +3840,6 @@ packages: engines: {node: ^20.17.0 || >=22.9.0} hasBin: true - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - npm-bundled@5.0.0: resolution: {integrity: sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==} engines: {node: ^20.17.0 || >=22.9.0} @@ -4440,10 +3879,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -4451,14 +3886,6 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4487,18 +3914,10 @@ packages: peerDependencies: oxc-parser: '>=0.72.0' - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -4507,10 +3926,6 @@ packages: resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - pac-proxy-agent@7.2.0: resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} engines: {node: '>= 14'} @@ -4545,18 +3960,10 @@ packages: parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4572,9 +3979,6 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - path-to-regexp@1.9.0: - resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4586,9 +3990,6 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -4856,9 +4257,6 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4881,25 +4279,9 @@ packages: resolution: {integrity: sha512-QFJyps9y5oHeXnNA3Ql1EaAqWBivNwQn19Pw1lt9RxfB+4e+bIyqCyuombk79D6Fxe+lPXggVfI1WtRGEBwgbQ==} hasBin: true - qjobs@1.2.0: - resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==} - engines: {node: '>=0.9'} - - qs@6.15.2: - resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} - engines: {node: '>=0.6'} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@2.5.3: - resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} - engines: {node: '>= 0.8'} - raw-loader@4.0.2: resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==} engines: {node: '>= 10.13.0'} @@ -4948,9 +4330,6 @@ packages: require-package-name@2.0.1: resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-dir@1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} engines: {node: '>=0.10.0'} @@ -4986,11 +4365,6 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@6.1.3: resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} engines: {node: 20 || >=22} @@ -5028,10 +4402,6 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -5054,10 +4424,6 @@ packages: semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - semver@7.8.1: resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} engines: {node: '>=10'} @@ -5067,13 +4433,6 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} - serialize-javascript@7.0.5: - resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} - engines: {node: '>=20.0.0'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5089,27 +4448,8 @@ packages: resolution: {integrity: sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==} engines: {node: '>=18'} - shellwords@0.1.1: - resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -5125,16 +4465,6 @@ packages: simple-git@3.36.0: resolution: {integrity: sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q==} - sinon-chai@3.7.0: - resolution: {integrity: sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==} - peerDependencies: - chai: ^4.0.0 - sinon: '>=4.0.0' - - sinon@9.2.4: - resolution: {integrity: sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==} - deprecated: 16.1.1 - slack-notify@2.0.7: resolution: {integrity: sha512-DZ4J3RVszHUaJf5zXtAocxEhZRAvwWoswB6a/8sAG/QMWkuZdvk3e8d2YQQlPJNYNSbfak+rCtn3zrZ5UmMnYg==} engines: {node: '>=13.2.x'} @@ -5220,14 +4550,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} @@ -5235,10 +4557,6 @@ packages: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} - streamroller@3.1.5: - resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} - engines: {node: '>=8.0'} - streamx@2.25.0: resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} @@ -5268,10 +4586,6 @@ packages: stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - strip-ansi@4.0.0: - resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} - engines: {node: '>=4'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -5300,10 +4614,6 @@ packages: peerDependencies: postcss: ^8.5.13 - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -5391,10 +4701,6 @@ packages: engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} @@ -5416,18 +4722,10 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tmp@0.2.7: - resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} - engines: {node: '>=14.14'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -5451,14 +4749,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -5467,10 +4757,6 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - type-level-regexp@0.1.17: resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} @@ -5501,10 +4787,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - ua-parser-js@0.7.41: - resolution: {integrity: sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==} - hasBin: true - uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} @@ -5543,18 +4825,10 @@ packages: universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} @@ -5575,14 +4849,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@14.0.0: - resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} - hasBin: true - validate-npm-package-name@6.0.2: resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -5690,10 +4956,6 @@ packages: jsdom: optional: true - void-elements@2.0.1: - resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==} - engines: {node: '>=0.10.0'} - vue@3.5.34: resolution: {integrity: sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==} peerDependencies: @@ -5709,9 +4971,6 @@ packages: webdriver-bidi-protocol@0.4.1: resolution: {integrity: sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==} - webpack-merge@4.2.2: - resolution: {integrity: sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==} - webpack-sources@3.5.0: resolution: {integrity: sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==} engines: {node: '>=10.13.0'} @@ -5738,11 +4997,6 @@ packages: engines: {node: '>= 8'} hasBin: true - which@3.0.1: - resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - hasBin: true - which@6.0.1: resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -5757,9 +5011,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerpool@9.3.4: - resolution: {integrity: sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -5795,9 +5046,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -5822,10 +5070,6 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -5864,28 +5108,6 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.7': {} - - '@babel/core@7.29.7(supports-color@8.1.1)': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) - '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/generator@7.29.7': dependencies: '@babel/parser': 7.29.7 @@ -5894,45 +5116,12 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.29.7': - dependencies: - '@babel/compat-data': 7.29.7 - '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.29.7': - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/helper-module-imports': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-string-parser@7.29.7': {} '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.29.7': {} - - '@babel/helpers@7.29.7': - dependencies: - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - '@babel/parser@7.29.7': dependencies: '@babel/types': 7.29.7 @@ -5966,8 +5155,6 @@ snapshots: '@colordx/core@5.4.3': {} - '@colors/colors@1.5.0': {} - '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -6330,16 +5517,6 @@ snapshots: dependencies: minipass: 7.1.3 - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 4.2.0 - resolve-from: 5.0.0 - - '@istanbuljs/schema@0.1.6': {} - '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.10 @@ -6884,22 +6061,6 @@ snapshots: '@sindresorhus/merge-streams@2.3.0': {} - '@sinonjs/commons@1.8.6': - dependencies: - type-detect: 4.0.8 - - '@sinonjs/fake-timers@6.0.1': - dependencies: - '@sinonjs/commons': 1.8.6 - - '@sinonjs/samsam@5.3.1': - dependencies: - '@sinonjs/commons': 1.8.6 - lodash.get: 4.4.2 - type-detect: 4.1.0 - - '@sinonjs/text-encoding@0.7.3': {} - '@socket.io/component-emitter@3.1.2': {} '@standard-schema/spec@1.1.0': {} @@ -6930,8 +6091,6 @@ snapshots: tslib: 2.8.1 optional: true - '@types/chai@4.3.20': {} - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -6960,30 +6119,12 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/karma-sinon-chai@2.0.6': - dependencies: - '@types/chai': 4.3.20 - '@types/karma': 6.3.9 - '@types/sinon': 10.0.20 - '@types/sinon-chai': 2.7.42 - transitivePeerDependencies: - - supports-color - - '@types/karma@6.3.9': - dependencies: - '@types/node': 22.19.19 - log4js: 6.9.1(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 '@types/minimatch@3.0.5': {} - '@types/mocha@10.0.10': {} - '@types/ms@2.1.0': {} '@types/node-fetch@2.6.13': @@ -7025,17 +6166,6 @@ snapshots: '@types/node': 22.19.19 fast-glob: 3.3.3 - '@types/sinon-chai@2.7.42': - dependencies: - '@types/chai': 4.3.20 - '@types/sinon': 10.0.20 - - '@types/sinon@10.0.20': - dependencies: - '@types/sinonjs__fake-timers': 15.0.1 - - '@types/sinonjs__fake-timers@15.0.1': {} - '@types/ssri@7.1.5': dependencies: '@types/node': 22.19.19 @@ -7389,16 +6519,10 @@ snapshots: dependencies: environment: 1.1.0 - ansi-regex@3.0.1: {} - ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -7407,11 +6531,6 @@ snapshots: ansi-styles@6.2.3: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - argparse@2.0.1: {} array-differ@3.0.0: {} @@ -7420,8 +6539,6 @@ snapshots: arrify@2.0.1: {} - assertion-error@1.1.0: {} - assertion-error@2.0.1: {} ast-types@0.13.4: @@ -7438,23 +6555,6 @@ snapshots: b4a@1.8.1: {} - babel-loader@10.1.1(@babel/core@7.29.7)(webpack@5.107.2(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.15)): - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - find-up: 5.0.0 - optionalDependencies: - webpack: 5.107.2(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.15) - - babel-plugin-istanbul@7.0.1: - dependencies: - '@babel/helper-plugin-utils': 7.29.7 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.6 - istanbul-lib-instrument: 6.0.3 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - bail@2.0.2: {} balanced-match@1.0.2: {} @@ -7505,25 +6605,6 @@ snapshots: big.js@5.2.2: {} - binary-extensions@2.3.0: {} - - body-parser@1.20.5: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.15.2 - raw-body: 2.5.3 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - boolbase@1.0.0: {} boolean@3.2.0: {} @@ -7545,8 +6626,6 @@ snapshots: dependencies: fill-range: 7.1.1 - browser-stdout@1.3.1: {} - browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.32 @@ -7564,8 +6643,6 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bytes@3.1.2: {} - cac@7.0.0: {} cacache@20.0.4: @@ -7586,17 +6663,10 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsite@1.0.0: {} callsites@3.1.0: {} - camelcase@5.3.1: {} - camelcase@6.3.0: {} camelcase@8.0.0: {} @@ -7612,24 +6682,8 @@ snapshots: ccount@2.0.1: {} - chai@4.5.0: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - chai@6.2.2: {} - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -7645,22 +6699,6 @@ snapshots: chardet@2.1.1: {} - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -7712,16 +6750,10 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} colorette@2.0.20: {} @@ -7761,17 +6793,6 @@ snapshots: ini: 1.3.8 proto-list: 1.2.4 - connect@3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - transitivePeerDependencies: - - supports-color - - content-type@1.0.5: {} - content-type@2.0.0: {} convert-source-map@2.0.0: {} @@ -7908,34 +6929,20 @@ snapshots: csstype@3.2.3: {} - custom-event@1.0.1: {} - data-uri-to-buffer@6.0.2: {} date-fns@4.3.0: {} - date-format@4.0.14: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 optionalDependencies: supports-color: 8.1.1 - decamelize@4.0.0: {} - decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 - deep-eql@4.1.4: - dependencies: - type-detect: 4.1.0 - deep-is@0.1.4: {} define-data-property@1.1.4: @@ -7996,14 +7003,10 @@ snapshots: transitivePeerDependencies: - supports-color - depd@2.0.0: {} - deps-regex@0.2.0: {} dequal@2.0.3: {} - destroy@1.2.0: {} - detect-file@1.0.0: {} detect-libc@2.1.2: {} @@ -8016,12 +7019,8 @@ snapshots: devtools-protocol@0.0.1608973: {} - di@0.0.1: {} - diff-sequences@29.6.3: {} - diff@4.0.4: {} - diff@8.0.4: {} dom-combiner@0.1.3: @@ -8030,13 +7029,6 @@ snapshots: lodash: 4.18.1 parse5: 1.0.0 - dom-serialize@2.2.1: - dependencies: - custom-event: 1.0.1 - ent: 2.2.2 - extend: 3.0.2 - void-elements: 2.0.1 - dom-serializer@0.2.2: dependencies: domelementtype: 2.3.0 @@ -8082,8 +7074,6 @@ snapshots: minimatch: 9.0.9 semver: 7.8.1 - ee-first@1.1.1: {} - electron-to-chromium@1.5.361: {} emoji-regex@10.6.0: {} @@ -8094,15 +7084,13 @@ snapshots: emojis-list@3.0.0: {} - encodeurl@1.0.2: {} - end-of-stream@1.4.5: dependencies: once: 1.4.0 engine.io-parser@5.2.3: {} - engine.io@6.6.8: + engine.io@6.6.8(supports-color@8.1.1): dependencies: '@types/cors': 2.8.19 '@types/node': 22.19.19 @@ -8124,13 +7112,6 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 - ent@2.2.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - punycode: 1.4.1 - safe-regex-test: 1.1.0 - entities@2.2.0: {} entities@3.0.1: {} @@ -8209,10 +7190,6 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -8337,8 +7314,6 @@ snapshots: esutils@2.0.3: {} - eventemitter3@4.0.7: {} - eventemitter3@5.0.4: {} events-universal@1.0.1: @@ -8427,23 +7402,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -8461,12 +7419,8 @@ snapshots: flatted: 3.4.2 keyv: 4.5.4 - flat@5.0.2: {} - flatted@3.4.2: {} - follow-redirects@1.16.0: {} - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -8488,31 +7442,19 @@ snapshots: jsonfile: 6.2.1 universalify: 2.0.1 - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - fs-minipass@3.0.3: dependencies: minipass: 7.1.3 - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true function-bind@1.1.2: {} - gensync@1.0.0-beta.2: {} - get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} - get-func-name@2.0.2: {} - get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -8526,8 +7468,6 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 - get-package-type@0.1.0: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -8578,15 +7518,6 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - global-agent@3.0.0: dependencies: boolean: 3.2.0 @@ -8641,10 +7572,6 @@ snapshots: graphql@16.14.0: {} - growly@1.3.0: {} - - has-flag@3.0.0: {} - has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -8679,8 +7606,6 @@ snapshots: dependencies: '@types/hast': 3.0.4 - he@1.2.0: {} - homedir-polyfill@1.0.3: dependencies: parse-passwd: 1.0.0 @@ -8695,14 +7620,6 @@ snapshots: http-cache-semantics@4.2.0: {} - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -8710,14 +7627,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy@1.18.1: - dependencies: - eventemitter3: 4.0.7 - follow-redirects: 1.16.0 - requires-port: 1.0.0 - transitivePeerDependencies: - - debug - https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -8729,10 +7638,6 @@ snapshots: husky@9.1.7: {} - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -8760,11 +7665,6 @@ snapshots: imurmurhash@0.1.4: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@1.3.8: {} @@ -8787,18 +7687,10 @@ snapshots: is-arrayish@0.2.1: {} - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-core-module@2.16.2: dependencies: hasown: 2.0.4 - is-docker@2.2.1: {} - - is-docker@3.0.0: {} - is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -8815,93 +7707,36 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - is-interactive@2.0.0: {} is-number@7.0.0: {} is-path-cwd@3.0.0: {} - is-path-inside@3.0.3: {} - is-path-inside@4.0.0: {} - is-plain-obj@2.1.0: {} - is-plain-obj@4.1.0: {} - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.4 - is-stream@2.0.1: {} - is-unicode-supported@0.1.0: {} - is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} is-windows@1.0.2: {} - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - - is-wsl@3.1.1: - dependencies: - is-inside-container: 1.0.0 - - isarray@0.0.1: {} - - isbinaryfile@4.0.10: {} - isexe@2.0.0: {} isexe@4.0.0: {} istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/parser': 7.29.7 - '@istanbuljs/schema': 0.1.6 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - istanbul-lib-instrument@6.0.3: - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/parser': 7.29.7 - '@istanbuljs/schema': 0.1.6 - istanbul-lib-coverage: 3.2.2 - semver: 7.8.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1(supports-color@8.1.1): - dependencies: - debug: 4.4.3(supports-color@8.1.1) - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 @@ -8972,10 +7807,6 @@ snapshots: json5@2.2.3: {} - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - jsonfile@6.2.1: dependencies: universalify: 2.0.1 @@ -8984,98 +7815,6 @@ snapshots: jsonparse@1.3.1: {} - just-extend@4.2.1: {} - - karma-chai@0.1.0(chai@4.5.0)(karma@6.4.4(supports-color@8.1.1)): - dependencies: - chai: 4.5.0 - karma: 6.4.4(supports-color@8.1.1) - - karma-chrome-launcher@3.2.0: - dependencies: - which: 1.3.1 - - karma-coverage@2.2.1(supports-color@8.1.1): - dependencies: - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) - istanbul-reports: 3.2.0 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - karma-firefox-launcher@2.1.3: - dependencies: - is-wsl: 2.2.0 - which: 3.0.1 - - karma-mocha-reporter@2.2.5(karma@6.4.4(supports-color@8.1.1)): - dependencies: - chalk: 2.4.2 - karma: 6.4.4(supports-color@8.1.1) - log-symbols: 2.2.0 - strip-ansi: 4.0.0 - - karma-mocha@2.0.1: - dependencies: - minimist: 1.2.8 - - karma-sinon-chai@2.0.2(chai@4.5.0)(sinon-chai@3.7.0(chai@4.5.0)(sinon@9.2.4))(sinon@9.2.4): - dependencies: - chai: 4.5.0 - sinon: 9.2.4 - sinon-chai: 3.7.0(chai@4.5.0)(sinon@9.2.4) - - karma-sinon@1.0.5(karma@6.4.4(supports-color@8.1.1))(sinon@9.2.4): - dependencies: - karma: 6.4.4(supports-color@8.1.1) - sinon: 9.2.4 - - karma-sourcemap-loader@0.4.0: - dependencies: - graceful-fs: 4.2.11 - - karma-webpack@5.0.1(webpack@5.107.2(esbuild@0.28.1)): - dependencies: - glob: 7.2.3 - minimatch: 9.0.9 - webpack: 5.107.2(esbuild@0.28.1) - webpack-merge: 4.2.2 - - karma@6.4.4(supports-color@8.1.1): - dependencies: - '@colors/colors': 1.5.0 - body-parser: 1.20.5 - braces: 3.0.3 - chokidar: 3.6.0 - connect: 3.7.0 - di: 0.0.1 - dom-serialize: 2.2.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - http-proxy: 1.18.1 - isbinaryfile: 4.0.10 - lodash: 4.18.1 - log4js: 6.9.1(supports-color@8.1.1) - mime: 2.6.0 - minimatch: 3.1.5 - mkdirp: 0.5.6 - qjobs: 1.2.0 - range-parser: 1.2.1 - rimraf: 3.0.2 - socket.io: 4.8.3 - source-map: 0.6.1 - tmp: 0.2.7 - ua-parser-js: 0.7.41 - yargs: 16.2.0 - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -9187,16 +7926,10 @@ snapshots: dependencies: lie: 3.1.1 - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 - lodash.get@4.4.2: {} - lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} @@ -9205,15 +7938,6 @@ snapshots: lodash@4.18.1: {} - log-symbols@2.2.0: - dependencies: - chalk: 2.4.2 - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - log-symbols@6.0.0: dependencies: chalk: 5.6.2 @@ -9227,30 +7951,12 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 - log4js@6.9.1(supports-color@8.1.1): - dependencies: - date-format: 4.0.14 - debug: 4.4.3(supports-color@8.1.1) - flatted: 3.4.2 - rfdc: 1.4.1 - streamroller: 3.1.5(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - longest-streak@3.1.0: {} - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - lru-cache@10.4.3: {} lru-cache@11.5.0: {} - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - lru-cache@7.18.3: {} lunr@2.3.9: {} @@ -9448,8 +8154,6 @@ snapshots: mdurl@2.0.0: {} - media-typer@0.3.0: {} - merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -9665,8 +8369,6 @@ snapshots: dependencies: mime-db: 1.52.0 - mime@2.6.0: {} - mimic-fn@2.1.0: {} mimic-function@5.0.1: {} @@ -9731,12 +8433,6 @@ snapshots: mitt@3.0.1: {} - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - - mkdirp@3.0.1: {} - mlly@1.8.2: dependencies: acorn: 8.16.0 @@ -9744,34 +8440,8 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.4 - mocha@11.7.6: - dependencies: - browser-stdout: 1.3.1 - chokidar: 4.0.3 - debug: 4.4.3(supports-color@8.1.1) - diff: 8.0.4 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 10.5.0 - he: 1.2.0 - is-path-inside: 3.0.3 - js-yaml: 4.2.0 - log-symbols: 4.1.0 - minimatch: 9.0.9 - ms: 2.1.3 - picocolors: 1.1.1 - serialize-javascript: 7.0.5 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 9.3.4 - yargs: 17.7.2 - yargs-parser: 21.1.1 - yargs-unparser: 2.0.0 - mock-fs@5.5.0: {} - ms@2.0.0: {} - ms@2.1.3: {} multimatch@5.0.0: @@ -9798,14 +8468,6 @@ snapshots: netmask@2.1.1: {} - nise@4.1.0: - dependencies: - '@sinonjs/commons': 1.8.6 - '@sinonjs/fake-timers': 6.0.1 - '@sinonjs/text-encoding': 0.7.3 - just-extend: 4.2.1 - path-to-regexp: 1.9.0 - node-gyp@12.3.0: dependencies: env-paths: 2.2.1 @@ -9819,15 +8481,6 @@ snapshots: undici: 6.27.0 which: 6.0.1 - node-notifier@10.0.1: - dependencies: - growly: 1.3.0 - is-wsl: 2.2.0 - semver: 7.8.1 - shellwords: 0.1.1 - uuid: 14.0.0 - which: 2.0.2 - node-releases@2.0.46: {} nopt@7.2.1: @@ -9838,8 +8491,6 @@ snapshots: dependencies: abbrev: 4.0.0 - normalize-path@3.0.0: {} - npm-bundled@5.0.0: dependencies: npm-normalize-package-bin: 5.0.0 @@ -9892,20 +8543,10 @@ snapshots: object-assign@4.1.1: {} - object-inspect@1.13.4: {} - object-keys@1.1.1: {} obug@2.1.1: {} - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -9964,26 +8605,16 @@ snapshots: magic-regexp: 0.10.0 oxc-parser: 0.72.3 - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 p-map@7.0.4: {} - p-try@2.2.0: {} - pac-proxy-agent@7.2.0: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 @@ -10045,12 +8676,8 @@ snapshots: dependencies: entities: 8.0.0 - parseurl@1.3.3: {} - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -10065,18 +8692,12 @@ snapshots: lru-cache: 11.5.0 minipass: 7.1.3 - path-to-regexp@1.9.0: - dependencies: - isarray: 0.0.1 - path-type@4.0.0: {} path-type@6.0.0: {} pathe@2.0.3: {} - pathval@1.1.1: {} - pend@1.2.0: {} picocolors@1.1.1: {} @@ -10326,8 +8947,6 @@ snapshots: punycode.js@2.3.1: {} - punycode@1.4.1: {} - punycode@2.3.1: {} puppeteer-cluster@0.24.0(puppeteer@24.43.1(supports-color@8.1.1)(typescript@5.5.4))(supports-color@8.1.1): @@ -10378,23 +8997,8 @@ snapshots: postcss: 8.5.15 postcss-selector-parser: 7.1.1 - qjobs@1.2.0: {} - - qs@6.15.2: - dependencies: - side-channel: 1.1.0 - queue-microtask@1.2.3: {} - range-parser@1.2.1: {} - - raw-body@2.5.3: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-loader@4.0.2(webpack@5.107.2(esbuild@0.28.1)(lightningcss@1.32.0)(postcss@8.5.15)): dependencies: loader-utils: 2.0.4 @@ -10457,8 +9061,6 @@ snapshots: require-package-name@2.0.1: {} - requires-port@1.0.0: {} - resolve-dir@1.0.1: dependencies: expand-tilde: 2.0.2 @@ -10488,10 +9090,6 @@ snapshots: rfdc@1.4.1: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rimraf@6.1.3: dependencies: glob: 13.0.6 @@ -10592,12 +9190,6 @@ snapshots: safe-buffer@5.2.1: {} - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - safer-buffer@2.1.2: {} sax@1.6.0: {} @@ -10622,18 +9214,12 @@ snapshots: semver-compare@1.0.0: {} - semver@6.3.1: {} - semver@7.8.1: {} serialize-error@7.0.1: dependencies: type-fest: 0.13.1 - serialize-javascript@7.0.5: {} - - setprototypeof@1.2.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -10647,36 +9233,6 @@ snapshots: execa: 5.1.1 fast-glob: 3.3.3 - shellwords@0.1.1: {} - - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -10704,20 +9260,6 @@ snapshots: transitivePeerDependencies: - supports-color - sinon-chai@3.7.0(chai@4.5.0)(sinon@9.2.4): - dependencies: - chai: 4.5.0 - sinon: 9.2.4 - - sinon@9.2.4: - dependencies: - '@sinonjs/commons': 1.8.6 - '@sinonjs/fake-timers': 6.0.1 - '@sinonjs/samsam': 5.3.1 - diff: 4.0.4 - nise: 4.1.0 - supports-color: 7.2.0 - slack-notify@2.0.7: {} slash@5.1.0: {} @@ -10744,7 +9286,7 @@ snapshots: '@sentry/node': 7.120.4 global-agent: 3.0.0 - socket.io-adapter@2.5.7: + socket.io-adapter@2.5.7(supports-color@8.1.1): dependencies: debug: 4.4.3(supports-color@8.1.1) ws: 8.21.0 @@ -10753,22 +9295,22 @@ snapshots: - supports-color - utf-8-validate - socket.io-parser@4.2.6: + socket.io-parser@4.2.6(supports-color@8.1.1): dependencies: '@socket.io/component-emitter': 3.1.2 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - socket.io@4.8.3: + socket.io@4.8.3(supports-color@8.1.1): dependencies: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.6 debug: 4.4.3(supports-color@8.1.1) - engine.io: 6.6.8 - socket.io-adapter: 2.5.7 - socket.io-parser: 4.2.6 + engine.io: 6.6.8(supports-color@8.1.1) + socket.io-adapter: 2.5.7(supports-color@8.1.1) + socket.io-parser: 4.2.6(supports-color@8.1.1) transitivePeerDependencies: - bufferutil - supports-color @@ -10817,22 +9359,10 @@ snapshots: stackback@0.0.2: {} - statuses@1.5.0: {} - - statuses@2.0.2: {} - std-env@4.1.0: {} stdin-discarder@0.2.2: {} - streamroller@3.1.5(supports-color@8.1.1): - dependencies: - date-format: 4.0.14 - debug: 4.4.3(supports-color@8.1.1) - fs-extra: 8.1.0 - transitivePeerDependencies: - - supports-color - streamx@2.25.0: dependencies: events-universal: 1.0.1 @@ -10876,10 +9406,6 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 - strip-ansi@4.0.0: - dependencies: - ansi-regex: 3.0.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -10902,10 +9428,6 @@ snapshots: postcss: 8.5.15 postcss-selector-parser: 7.1.1 - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -11005,12 +9527,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: - dependencies: - '@istanbuljs/schema': 0.1.6 - glob: 7.2.3 - minimatch: 3.1.5 - text-decoder@1.2.7: dependencies: b4a: 1.8.1 @@ -11032,14 +9548,10 @@ snapshots: tinyrainbow@3.1.0: {} - tmp@0.2.7: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - trim-lines@3.0.1: {} trough@2.2.0: {} @@ -11062,19 +9574,10 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-detect@4.0.8: {} - - type-detect@4.1.0: {} - type-fest@0.13.1: {} type-fest@4.41.0: {} - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - type-level-regexp@0.1.17: {} typed-query-selector@2.12.2: {} @@ -11106,8 +9609,6 @@ snapshots: typescript@5.5.4: {} - ua-parser-js@0.7.41: {} - uc.micro@2.1.0: {} ufo@1.6.4: {} @@ -11153,12 +9654,8 @@ snapshots: universal-user-agent@7.0.3: {} - universalify@0.1.2: {} - universalify@2.0.1: {} - unpipe@1.0.0: {} - unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -11180,10 +9677,6 @@ snapshots: util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - - uuid@14.0.0: {} - validate-npm-package-name@6.0.2: {} validate-npm-package-name@7.0.2: {} @@ -11250,8 +9743,6 @@ snapshots: transitivePeerDependencies: - msw - void-elements@2.0.1: {} - vue@3.5.34(typescript@5.5.4): dependencies: '@vue/compiler-dom': 3.5.34 @@ -11269,10 +9760,6 @@ snapshots: webdriver-bidi-protocol@0.4.1: {} - webpack-merge@4.2.2: - dependencies: - lodash: 4.18.1 - webpack-sources@3.5.0: {} webpack-virtual-modules@0.6.2: {} @@ -11363,10 +9850,6 @@ snapshots: dependencies: isexe: 2.0.0 - which@3.0.1: - dependencies: - isexe: 2.0.0 - which@6.0.1: dependencies: isexe: 4.0.0 @@ -11378,8 +9861,6 @@ snapshots: word-wrap@1.2.5: {} - workerpool@9.3.4: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -11410,8 +9891,6 @@ snapshots: y18n@5.0.8: {} - yallist@3.1.1: {} - yallist@4.0.0: {} yallist@5.0.0: {} @@ -11424,13 +9903,6 @@ snapshots: yargs-parser@21.1.1: {} - yargs-unparser@2.0.0: - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - yargs@16.2.0: dependencies: cliui: 7.0.4 diff --git a/scripts/postinstall.js b/scripts/postinstall.js index 8f5af8f35..945448d48 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -16,7 +16,8 @@ if ( fs.existsSync( path.join( ROOT_DIRECTORY, '.git' ) ) ) { husky(); - execSync( 'pnpm run -r postinstall', { + // The `--if-present` flag prevents an error when no workspace package defines the script. + execSync( 'pnpm run -r --if-present postinstall', { cwd: ROOT_DIRECTORY, stdio: 'inherit' } ); diff --git a/scripts/validate-licenses.mjs b/scripts/validate-licenses.mjs index 5e973bb38..29c8c7e11 100644 --- a/scripts/validate-licenses.mjs +++ b/scripts/validate-licenses.mjs @@ -70,10 +70,8 @@ validateLicenseFiles( { }, { packageName: '@ckeditor/ckeditor5-dev-tests', dependencies: [ - { license: 'MIT', name: 'karma-sinon', copyright: 'Copyright (c) Janusz J (https://github.com/yanoosh).' }, { license: 'MIT', name: 'chokidar', copyright: 'Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker.' }, { license: 'Apache-2.0', name: 'typescript', copyright: 'Copyright (c) Microsoft Corporation. All rights reserved.' }, - { license: 'BSD-2-Clause', name: 'sinon-chai', copyright: 'Copyright © 2012–2017 Domenic Denicola .' }, minimistOverride ] }, {