diff --git a/angular.json b/angular.json index 3ac5b911..d9ea9512 100644 --- a/angular.json +++ b/angular.json @@ -79,20 +79,10 @@ } }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "tsconfig.spec.json", - "inlineStyleLanguage": "scss", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "@angular/material/prebuilt-themes/purple-green.css", - "src/styles.scss" - ], - "scripts": [] + "runnerConfig": "vitest.config.ts", + "tsConfig": "tsconfig.spec.json" } }, "lint": { @@ -128,10 +118,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-async/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-async/tsconfig.spec.json" } }, "lint": { @@ -167,10 +157,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-common/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-common/tsconfig.spec.json" } }, "lint": { @@ -206,10 +196,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-utils/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-utils/tsconfig.spec.json" } }, "lint": { @@ -245,10 +235,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-wireframe/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-wireframe/tsconfig.spec.json" } }, "lint": { @@ -284,10 +274,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-router/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-router/tsconfig.spec.json" } }, "lint": { @@ -323,10 +313,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-state-management/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-state-management/tsconfig.spec.json" } }, "lint": { @@ -362,10 +352,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-dialogs/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-dialogs/tsconfig.spec.json" } }, "lint": { @@ -401,10 +391,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-forms/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-forms/tsconfig.spec.json" } }, "lint": { @@ -440,10 +430,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-common-components/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-common-components/tsconfig.spec.json" } } } @@ -470,10 +460,10 @@ "defaultConfiguration": "production" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "karmaConfig": "karma.conf.js", - "tsConfig": "projects/ppwcode/ng-unit-testing/tsconfig.spec.json", + "runnerConfig": "vitest.config.ts", + "tsConfig": "projects/ppwcode/ng-unit-testing/tsconfig.spec.json" } } } diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index 65fe032e..00000000 --- a/karma.conf.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = function (config) { - // Get project name from environment variable, fallback to default - let subdir = process.env.ANGULAR_PROJECT_NAME || '+application+' - - // Try to determine the project from the karma config if available (as backup) - if (config.projectName) { - subdir = config.projectName - } - - console.log('TEST RESULTS SUBDIR', subdir) - - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-coverage'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-junit-reporter') - ], - client: { - clearContext: false - }, - failOnEmptyTestSuite: false, - reporters: ['kjhtml', 'progress', 'coverage', 'junit'], - dir: 'coverage', - coverageReporter: { - dir: require('path').join(__dirname, `./coverage/${subdir}`), - reporters: [ - { type: 'text-summary', subdir: 'text-summary' }, - { type: 'html', subdir: 'html' }, - { type: 'cobertura', subdir: 'cobertura' } - ], - combineBrowserReports: true, - fixWebpackSourcePaths: true, - skipFilesWithNoCoverage: true - }, - junitReporter: { - outputDir: `test-results/${subdir}` - }, - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - customLaunchers: { - ChromiumNoSandbox: { - base: 'ChromeHeadless', - flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-translate', '--disable-extensions'] - } - }, - singleRun: false, - restartOnFileChange: true, - browserNoActivityTimeout: 999999 - }) -} diff --git a/package-lock.json b/package-lock.json index e89023e0..c2e7e6f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,6 @@ "@angular/cli": "21.0.6", "@angular/compiler-cli": "21.0.9", "@types/file-saver-es": "2.0.1", - "@types/jasmine": "4.3.5", "@types/node": "22.13.14", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", @@ -47,19 +46,22 @@ "eslint-plugin-depend": "1.2.0", "eslint-plugin-no-secrets": "2.2.1", "jasmine-core": "4.6.0", - "karma": "6.4.2", - "karma-chrome-launcher": "3.2.0", - "karma-coverage": "2.2.1", - "karma-jasmine": "5.1.0", - "karma-jasmine-html-reporter": "2.1.0", - "karma-junit-reporter": "2.0.1", + "jsdom": "28.0.0", "ng-packagr": "21.0.0", "prettier": "3.1.1", "prettier-config-standard": "7.0.0", "retire": "5.2.5", - "typescript": "5.9.3" + "typescript": "5.9.3", + "vitest": "4.0.18" } }, + "node_modules/@acemir/cssom": { + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@algolia/abtesting": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.6.1.tgz", @@ -1016,6 +1018,61 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", + "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "lru-cache": "^11.2.4" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.7.tgz", + "integrity": "sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.5" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", @@ -1326,10 +1383,145 @@ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.1.90" } }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.26.tgz", + "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@emnapi/core": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", @@ -2016,6 +2208,24 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@exodus/bytes": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.11.0.tgz", + "integrity": "sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@fortawesome/fontawesome-free": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz", @@ -4681,7 +4891,8 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/@standard-schema/spec": { "version": "1.1.0", @@ -4747,16 +4958,35 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -4778,13 +5008,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jasmine": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.3.5.tgz", - "integrity": "sha512-9YHUdvuNDDRJYXZwHqSsO72Ok0vmqoJbNn73ttyITQp/VA60SarnZ+MPLD37rJAhVoKp+9BWOvJP5tHIRfZylQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4804,7 +5027,6 @@ "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -5337,6 +5559,127 @@ "vite": "^6.0.0 || ^7.0.0" } }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -5524,6 +5867,7 @@ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -5538,6 +5882,7 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -5562,6 +5907,16 @@ "node": ">= 0.4" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types": { "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", @@ -5608,6 +5963,7 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": "^4.5.0 || >= 5.9" } @@ -5652,12 +6008,23 @@ "node": ">=14.0.0" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8" }, @@ -5914,6 +6281,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6283,6 +6660,7 @@ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -6299,6 +6677,7 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "ms": "2.0.0" } @@ -6309,6 +6688,7 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.8" } @@ -6319,6 +6699,7 @@ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -6337,7 +6718,8 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/connect/node_modules/on-finished": { "version": "2.3.0", @@ -6345,6 +6727,7 @@ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "ee-first": "1.1.1" }, @@ -6358,6 +6741,7 @@ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -6491,25 +6875,66 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-what": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", - "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, - "license": "BSD-2-Clause", - "engines": { + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { "node": ">= 6" }, "funding": { "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cssstyle": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", + "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^4.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", @@ -6521,6 +6946,20 @@ "node": ">= 14" } }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -6544,6 +6983,7 @@ "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=4.0" } @@ -6566,6 +7006,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -6614,6 +7061,7 @@ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -6635,7 +7083,8 @@ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/dom-serialize": { "version": "2.2.1", @@ -6643,6 +7092,7 @@ "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -6786,6 +7236,7 @@ "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", @@ -6807,6 +7258,7 @@ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=10.0.0" } @@ -6817,6 +7269,7 @@ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -6831,6 +7284,7 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -6841,6 +7295,7 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6854,6 +7309,7 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -6864,6 +7320,7 @@ "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -6951,6 +7408,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -7390,7 +7854,8 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/eventsource": { "version": "3.0.7", @@ -7415,6 +7880,16 @@ "node": ">=18.0.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -7488,7 +7963,8 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -7730,6 +8206,7 @@ } ], "license": "MIT", + "optional": true, "engines": { "node": ">=4.0" }, @@ -7765,6 +8242,7 @@ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -7792,7 +8270,8 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -7913,6 +8392,7 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7954,6 +8434,7 @@ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7965,6 +8446,7 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8041,6 +8523,7 @@ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -8098,12 +8581,18 @@ "node": "20 || >=22" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } }, "node_modules/htmlparser2": { "version": "10.1.0", @@ -8172,6 +8661,7 @@ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -8320,6 +8810,7 @@ "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.", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -8378,6 +8869,7 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -8463,6 +8955,13 @@ "node": ">=0.12.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -8476,6 +8975,7 @@ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -8515,6 +9015,7 @@ "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 8.0.0" }, @@ -8556,80 +9057,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jasmine-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jose": { "version": "6.1.3", @@ -8661,6 +9094,56 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.0.0.tgz", + "integrity": "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.7.6", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^5.3.7", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "undici": "^7.20.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/undici": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.20.0.tgz", + "integrity": "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -8738,6 +9221,7 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", + "optional": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -8758,7 +9242,7 @@ "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", "dev": true, "license": "MIT", - "peer": true, + "optional": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -8785,149 +9269,11 @@ "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/karma-coverage": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", - "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.0.5", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/karma-coverage/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/karma-coverage/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/karma-coverage/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/karma-jasmine": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", - "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "jasmine-core": "^4.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "karma": "^6.0.0" - } - }, - "node_modules/karma-jasmine-html-reporter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", - "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "jasmine-core": "^4.0.0 || ^5.0.0", - "karma": "^6.0.0", - "karma-jasmine": "^5.0.0" - } - }, - "node_modules/karma-junit-reporter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", - "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-is-absolute": "^1.0.0", - "xmlbuilder": "12.0.0" - }, - "engines": { - "node": ">= 8" + "bin": { + "karma": "bin/karma" }, - "peerDependencies": { - "karma": ">=0.9" + "engines": { + "node": ">= 10" } }, "node_modules/karma/node_modules/ansi-regex": { @@ -8936,6 +9282,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8" } @@ -8946,6 +9293,7 @@ "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", @@ -8971,6 +9319,7 @@ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8982,6 +9331,7 @@ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -9007,6 +9357,7 @@ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -9019,6 +9370,7 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "ms": "2.0.0" } @@ -9028,7 +9380,8 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/karma/node_modules/glob-parent": { "version": "5.1.2", @@ -9036,6 +9389,7 @@ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -9049,6 +9403,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -9062,6 +9417,7 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8" } @@ -9072,6 +9428,7 @@ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -9082,6 +9439,7 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -9092,6 +9450,7 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "mime-db": "1.52.0" }, @@ -9105,6 +9464,7 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9117,7 +9477,8 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/karma/node_modules/picomatch": { "version": "2.3.1", @@ -9125,6 +9486,7 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -9138,6 +9500,7 @@ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -9154,6 +9517,7 @@ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -9167,6 +9531,7 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -9177,6 +9542,7 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9192,6 +9558,7 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9205,6 +9572,7 @@ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -9219,6 +9587,7 @@ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9237,6 +9606,7 @@ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -9256,6 +9626,7 @@ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", + "optional": true, "engines": { "node": ">=10" } @@ -9589,6 +9960,7 @@ "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "license": "Apache-2.0", + "optional": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -9629,22 +10001,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/make-fetch-happen": { "version": "15.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz", @@ -9701,6 +10057,13 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -9777,6 +10140,7 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "license": "MIT", + "optional": true, "bin": { "mime": "cli.js" }, @@ -9846,6 +10210,7 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", + "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10009,6 +10374,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "minimist": "^1.2.6" }, @@ -10841,6 +11207,7 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -11013,6 +11380,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -11340,6 +11718,7 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -11399,6 +11778,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -11630,7 +12016,8 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/qjobs": { "version": "1.2.0", @@ -11638,6 +12025,7 @@ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.9" } @@ -11737,7 +12125,8 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/resolve": { "version": "1.22.11", @@ -11864,6 +12253,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -12033,6 +12423,7 @@ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -12058,7 +12449,6 @@ "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -12115,6 +12505,19 @@ "node": ">=11.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -12294,6 +12697,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -12372,6 +12782,7 @@ "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -12391,6 +12802,7 @@ "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "debug": "~4.4.1", "ws": "~8.18.3" @@ -12402,6 +12814,7 @@ "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" @@ -12416,6 +12829,7 @@ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -12430,6 +12844,7 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -12440,6 +12855,7 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "mime-db": "1.52.0" }, @@ -12453,6 +12869,7 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.6" } @@ -12583,6 +13000,13 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -12593,6 +13017,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/stdin-discarder": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", @@ -12612,6 +13043,7 @@ "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -12696,6 +13128,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tar": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", @@ -12723,6 +13162,23 @@ "node": ">=18" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -12740,12 +13196,43 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.22", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.22.tgz", + "integrity": "sha512-nqpKFC53CgopKPjT6Wfb6tpIcZXHcI6G37hesvikhx0EmUGPkZrujRyAjgnmp1SHNgpQfKVanZ+KfpANFt2Hxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.22" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.22", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.22.tgz", + "integrity": "sha512-KgbTDC5wzlL6j/x6np6wCnDSMUq4kucHNm00KXPbfNzmllCmtmvtykJHfmgdHntwIeupW04y8s1N/43S1PkQDw==", + "dev": true, + "license": "MIT" + }, "node_modules/tmp": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=14.14" } @@ -12773,6 +13260,42 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", + "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tr46/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -12881,6 +13404,7 @@ } ], "license": "MIT", + "optional": true, "bin": { "ua-parser-js": "script/cli.js" }, @@ -12937,6 +13461,7 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 4.0.0" } @@ -13008,6 +13533,7 @@ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4.0" } @@ -13617,16 +14143,109 @@ "@esbuild/win32-x64": "0.25.12" } }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/walk-up-path": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", @@ -13666,6 +14285,41 @@ "license": "MIT", "optional": true }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.0.tgz", + "integrity": "sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -13682,6 +14336,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -13775,6 +14446,7 @@ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=10.0.0" }, @@ -13791,16 +14463,23 @@ } } }, - "node_modules/xmlbuilder": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", - "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6.0" + "node": ">=18" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 8ab5e359..5f9ad4c0 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "@angular/cli": "21.0.6", "@angular/compiler-cli": "21.0.9", "@types/file-saver-es": "2.0.1", - "@types/jasmine": "4.3.5", "@types/node": "22.13.14", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", @@ -59,17 +58,13 @@ "eslint-plugin-depend": "1.2.0", "eslint-plugin-no-secrets": "2.2.1", "jasmine-core": "4.6.0", - "karma": "6.4.2", - "karma-chrome-launcher": "3.2.0", - "karma-coverage": "2.2.1", - "karma-jasmine": "5.1.0", - "karma-jasmine-html-reporter": "2.1.0", - "karma-junit-reporter": "2.0.1", + "jsdom": "28.0.0", "ng-packagr": "21.0.0", "prettier": "3.1.1", "prettier-config-standard": "7.0.0", "retire": "5.2.5", - "typescript": "5.9.3" + "typescript": "5.9.3", + "vitest": "4.0.18" }, "overrides": { "deep-equal": { diff --git a/projects/ppwcode/ng-async/src/lib/async-result/async-result.component.spec.ts b/projects/ppwcode/ng-async/src/lib/async-result/async-result.component.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-async/src/lib/default-handling.spec.ts b/projects/ppwcode/ng-async/src/lib/default-handling.spec.ts index 9ece0a6a..682304cd 100644 --- a/projects/ppwcode/ng-async/src/lib/default-handling.spec.ts +++ b/projects/ppwcode/ng-async/src/lib/default-handling.spec.ts @@ -33,15 +33,13 @@ describe('default async result handling', () => { const httpErrorResponse = new HttpErrorResponse({ status: 400 }) const source$ = throwError(() => httpErrorResponse) - await expectAsync(firstValueFrom(handleAsyncResult(source$, [409]))).toBeRejectedWith(httpErrorResponse) + await expect(firstValueFrom(handleAsyncResult(source$, [409]))).rejects.toEqual(httpErrorResponse) }) it('should pass on unexpected errors', async () => { const source$ = throwError(() => new Error('ERROR_MESSAGE')) - await expectAsync(firstValueFrom(handleAsyncResult(source$, [409]))).toBeRejectedWith( - new Error('ERROR_MESSAGE') - ) + await expect(firstValueFrom(handleAsyncResult(source$, [409]))).rejects.toEqual(new Error('ERROR_MESSAGE')) }) }) @@ -73,7 +71,7 @@ describe('default async result handling', () => { const httpErrorResponse = new HttpErrorResponse({ status: 400 }) const source$ = throwError(() => httpErrorResponse) - await expectAsync(firstValueFrom(handleAsyncResultIgnoreEntity(source$, [409]))).toBeRejectedWith( + await expect(firstValueFrom(handleAsyncResultIgnoreEntity(source$, [409]))).rejects.toEqual( httpErrorResponse ) }) @@ -81,7 +79,7 @@ describe('default async result handling', () => { it('should pass on unexpected errors', async () => { const source$ = throwError(() => new Error('ERROR_MESSAGE')) - await expectAsync(firstValueFrom(handleAsyncResultIgnoreEntity(source$, [409]))).toBeRejectedWith( + await expect(firstValueFrom(handleAsyncResultIgnoreEntity(source$, [409]))).rejects.toEqual( new Error('ERROR_MESSAGE') ) }) @@ -115,15 +113,13 @@ describe('default async result handling', () => { const httpErrorResponse = new HttpErrorResponse({ status: 400 }) const source$ = throwError(() => httpErrorResponse) - await expectAsync(firstValueFrom(handlePagedAsyncResult(source$, [409]))).toBeRejectedWith( - httpErrorResponse - ) + await expect(firstValueFrom(handlePagedAsyncResult(source$, [409]))).rejects.toEqual(httpErrorResponse) }) it('should pass on unexpected errors', async () => { const source$ = throwError(() => new Error('ERROR_MESSAGE')) - await expectAsync(firstValueFrom(handlePagedAsyncResult(source$, [409]))).toBeRejectedWith( + await expect(firstValueFrom(handlePagedAsyncResult(source$, [409]))).rejects.toEqual( new Error('ERROR_MESSAGE') ) }) diff --git a/projects/ppwcode/ng-async/src/lib/error-handling.spec.ts b/projects/ppwcode/ng-async/src/lib/error-handling.spec.ts index 6e2d5d71..c15ea034 100644 --- a/projects/ppwcode/ng-async/src/lib/error-handling.spec.ts +++ b/projects/ppwcode/ng-async/src/lib/error-handling.spec.ts @@ -12,7 +12,7 @@ const constructErrorResponse = (status: number, error: unknown = null, statusTex describe('extractHttpError', () => { it('should run the global extractor when defined', () => { - window.ppwcodeHttpErrorExtractor = jasmine.createSpy('ppwcodeHttpErrorExtractor') + window.ppwcodeHttpErrorExtractor = vi.fn() const httpError = constructErrorResponse(400) extractHttpError(httpError) @@ -23,7 +23,7 @@ describe('extractHttpError', () => { }) it('should not run the global extractor when skipCustomExtractor is true', () => { - window.ppwcodeHttpErrorExtractor = jasmine.createSpy('ppwcodeHttpErrorExtractor') + window.ppwcodeHttpErrorExtractor = vi.fn() const httpError = constructErrorResponse(400) extractHttpError(httpError, true) @@ -115,7 +115,7 @@ describe('extractHttpError', () => { describe('expectHttpError', () => { it('should pass on the received value', async () => { - const handler = jasmine.createSpy('handler', () => new Error()).and.callThrough() + const handler = vi.fn(() => new Error()) const source$ = of('source value') const result = await firstValueFrom(source$.pipe(expectHttpError([409], handler))) @@ -126,10 +126,10 @@ describe('expectHttpError', () => { }) it('should pass on exceptions that are not an HttpErrorResponse', async () => { - const handler = jasmine.createSpy('handler', () => new Error()).and.callThrough() + const handler = vi.fn(() => new Error()) const source$ = throwError(() => new Error('ERROR_MESSAGE')) - await expectAsync(firstValueFrom(source$.pipe(expectHttpError([409], handler)))).toBeRejectedWith( + await expect(firstValueFrom(source$.pipe(expectHttpError([409], handler)))).rejects.toEqual( new Error('ERROR_MESSAGE') ) @@ -137,10 +137,10 @@ describe('expectHttpError', () => { }) it(`should pass on http errors that don't match the expected status code`, async () => { - const handler = jasmine.createSpy('handler', () => new Error()).and.callThrough() + const handler = vi.fn(() => new Error()) const source$ = throwError(() => new HttpErrorResponse({ status: 400 })) - await expectAsync(firstValueFrom(source$.pipe(expectHttpError([409], handler)))).toBeRejectedWith( + await expect(firstValueFrom(source$.pipe(expectHttpError([409], handler)))).rejects.toEqual( new HttpErrorResponse({ status: 400 }) ) @@ -148,7 +148,7 @@ describe('expectHttpError', () => { }) it('should handle http errors with the expected status code', async () => { - const handler = jasmine.createSpy('handler', () => new Error()).and.callThrough() + const handler = vi.fn(() => new Error()) const source$ = throwError(() => new HttpErrorResponse({ status: 409 })) const result = await firstValueFrom(source$.pipe(expectHttpError([409], handler))) diff --git a/projects/ppwcode/ng-async/src/lib/models/async-result.spec.ts b/projects/ppwcode/ng-async/src/lib/models/async-result.spec.ts index 287811ba..871b7679 100644 --- a/projects/ppwcode/ng-async/src/lib/models/async-result.spec.ts +++ b/projects/ppwcode/ng-async/src/lib/models/async-result.spec.ts @@ -29,8 +29,8 @@ describe('executeAsyncOperation', () => { it('should execute success handler on successful async operation', async () => { const operation$ = new Subject>() const isExecuting$ = new BehaviorSubject(false) - const onSuccess = jasmine.createSpy('onSuccess') - const onError = jasmine.createSpy('onError') + const onSuccess = vi.fn() + const onError = vi.fn() const operationValue = createSuccessAsyncResult('operation result') const promise = executeAsyncOperation( @@ -42,11 +42,11 @@ describe('executeAsyncOperation', () => { isExecuting$ ) - expect(isExecuting$.value).toBeTrue() + expect(isExecuting$.value).toBe(true) operation$.next(operationValue) await promise - expect(isExecuting$.value).toBeFalse() + expect(isExecuting$.value).toBe(false) expect(onSuccess).toHaveBeenCalledWith(operationValue) expect(onError).not.toHaveBeenCalled() }) @@ -54,8 +54,8 @@ describe('executeAsyncOperation', () => { it('should execute error handler on failed async operation', async () => { const operation$ = new Subject>() const isExecuting$ = new BehaviorSubject(false) - const onSuccess = jasmine.createSpy('onSuccess') - const onError = jasmine.createSpy('onError') + const onSuccess = vi.fn() + const onError = vi.fn() const operationValue: AsyncResult = createFailedAsyncResult(new Error('operation failed'), 'it failed') @@ -68,11 +68,11 @@ describe('executeAsyncOperation', () => { isExecuting$ ) - expect(isExecuting$.value).toBeTrue() + expect(isExecuting$.value).toBe(true) operation$.next(operationValue) await promise - expect(isExecuting$.value).toBeFalse() + expect(isExecuting$.value).toBe(false) expect(onError).toHaveBeenCalledWith(operationValue) expect(onSuccess).not.toHaveBeenCalled() }) diff --git a/projects/ppwcode/ng-async/src/lib/models/paged-async-result.spec.ts b/projects/ppwcode/ng-async/src/lib/models/paged-async-result.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-async/src/lib/models/paged-entities.spec.ts b/projects/ppwcode/ng-async/src/lib/models/paged-entities.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-async/tsconfig.spec.json b/projects/ppwcode/ng-async/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-async/tsconfig.spec.json +++ b/projects/ppwcode/ng-async/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-common-components/src/lib/search-filter/search-filter.component.spec.ts b/projects/ppwcode/ng-common-components/src/lib/search-filter/search-filter.component.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-common-components/src/lib/table/table.component.spec.ts b/projects/ppwcode/ng-common-components/src/lib/table/table.component.spec.ts index 8f243a50..8d695760 100644 --- a/projects/ppwcode/ng-common-components/src/lib/table/table.component.spec.ts +++ b/projects/ppwcode/ng-common-components/src/lib/table/table.component.spec.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, Component, signal, ViewChild, WritableSignal } from '@angular/core' import { ComponentFixture, TestBed } from '@angular/core/testing' -import { NoopAnimationsModule } from '@angular/platform-browser/animations' import { ColumnType } from './columns/column' import { TableComponent } from './table.component' @@ -106,7 +105,7 @@ export function getJsDateFormatter(): (value: Date) => string { } `, - standalone: false, + imports: [PpwTableModule], changeDetection: ChangeDetectionStrategy.OnPush }) class TestTableComponent { @@ -136,8 +135,7 @@ describe('TableComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TestTableComponent], - imports: [PpwTableModule, NoopAnimationsModule] + imports: [TestTableComponent] }) fixture = TestBed.createComponent(TestTableComponent) diff --git a/projects/ppwcode/ng-common-components/tsconfig.spec.json b/projects/ppwcode/ng-common-components/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-common-components/tsconfig.spec.json +++ b/projects/ppwcode/ng-common-components/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-common/src/lib/mixins/constructor.spec.ts b/projects/ppwcode/ng-common/src/lib/mixins/constructor.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-common/src/lib/mixins/handle-subscriptions.spec.ts b/projects/ppwcode/ng-common/src/lib/mixins/handle-subscriptions.spec.ts index b0ef4d7f..8d5a742f 100644 --- a/projects/ppwcode/ng-common/src/lib/mixins/handle-subscriptions.spec.ts +++ b/projects/ppwcode/ng-common/src/lib/mixins/handle-subscriptions.spec.ts @@ -8,8 +8,8 @@ describe('Handle subscriptions mixin', () => { let component: TestComponent beforeEach(() => { - jasmine.clock().install() - jasmine.clock().mockDate(new Date()) + vi.useFakeTimers() + vi.setSystemTime(new Date()) TestBed.configureTestingModule({ declarations: [TestComponent] @@ -20,7 +20,7 @@ describe('Handle subscriptions mixin', () => { }) afterEach(() => { - jasmine.clock().uninstall() + vi.useRealTimers() }) it('should extend the given class definitions', () => { @@ -34,14 +34,14 @@ describe('Handle subscriptions mixin', () => { const subscription = component.stopOnDestroy(interval$).subscribe(() => subscriptionHits++) expect(subscriptionHits).toBe(0) - jasmine.clock().tick(999) + vi.advanceTimersByTime(999) expect(subscriptionHits).toBe(0) - jasmine.clock().tick(2) + vi.advanceTimersByTime(2) expect(subscriptionHits).toBe(1) fixture.destroy() - jasmine.clock().tick(1000) + vi.advanceTimersByTime(1000) expect(subscriptionHits).toBe(1) subscription.unsubscribe() diff --git a/projects/ppwcode/ng-common/src/lib/mixins/track-pending.spec.ts b/projects/ppwcode/ng-common/src/lib/mixins/track-pending.spec.ts index ce39794b..554bb5ef 100644 --- a/projects/ppwcode/ng-common/src/lib/mixins/track-pending.spec.ts +++ b/projects/ppwcode/ng-common/src/lib/mixins/track-pending.spec.ts @@ -10,15 +10,15 @@ describe('Track pending mixin', () => { let instanceOfExtendedClass: BaseClass & CanTrackPending beforeEach(() => { - jasmine.clock().install() - jasmine.clock().mockDate(new Date()) + vi.useFakeTimers() + vi.setSystemTime(new Date()) extendedClass = mixinTrackPending(false, BaseClass) instanceOfExtendedClass = new extendedClass() }) afterEach(() => { - jasmine.clock().uninstall() + vi.useRealTimers() }) it('should extend the base implementation', () => { @@ -35,12 +35,12 @@ describe('Track pending mixin', () => { const trackedStream$ = instanceOfExtendedClass.trackPending(stream$) const subscription = trackedStream$.subscribe() - expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBeTrue() - expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBeTrue() + expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBe(true) + expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBe(true) - jasmine.clock().tick(100) - expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBeFalse() - expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBeFalse() + vi.advanceTimersByTime(100) + expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBe(false) + expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBe(false) subscription.unsubscribe() }) @@ -55,12 +55,12 @@ describe('Track pending mixin', () => { const subscription1 = trackedStream1$.subscribe() const subscription2 = trackedStream2$.subscribe() - expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream1'))).toBeTrue() - expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream2'))).toBeTrue() + expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream1'))).toBe(true) + expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream2'))).toBe(true) - jasmine.clock().tick(100) - expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream1'))).toBeFalse() - expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream2'))).toBeFalse() + vi.advanceTimersByTime(100) + expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream1'))).toBe(false) + expect(await firstValueFrom(instanceOfExtendedClass.isPending('stream2'))).toBe(false) subscription1.unsubscribe() subscription2.unsubscribe() @@ -75,12 +75,12 @@ describe('Track pending mixin', () => { const subscription = trackedStream$.subscribe() const namedSubscription = trackedNamedStream$.subscribe() - expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBeTrue() - expect(await firstValueFrom(instanceOfExtendedClass.isPending('named'))).toBeTrue() + expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBe(true) + expect(await firstValueFrom(instanceOfExtendedClass.isPending('named'))).toBe(true) - jasmine.clock().tick(100) - expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBeFalse() - expect(await firstValueFrom(instanceOfExtendedClass.isPending('named'))).toBeFalse() + vi.advanceTimersByTime(100) + expect(await firstValueFrom(instanceOfExtendedClass.isPending())).toBe(false) + expect(await firstValueFrom(instanceOfExtendedClass.isPending('named'))).toBe(false) subscription.unsubscribe() namedSubscription.unsubscribe() @@ -89,31 +89,31 @@ describe('Track pending mixin', () => { it('should support manual pending tracking on the default name', async () => { const isPending$ = instanceOfExtendedClass.pending$ - expect(await firstValueFrom(isPending$)).toBeFalse() + expect(await firstValueFrom(isPending$)).toBe(false) await firstValueFrom(of(null).pipe(instanceOfExtendedClass.startPending())) - expect(await firstValueFrom(isPending$)).toBeTrue() + expect(await firstValueFrom(isPending$)).toBe(true) await firstValueFrom(of(null).pipe(instanceOfExtendedClass.stopPending())) - expect(await firstValueFrom(isPending$)).toBeFalse() + expect(await firstValueFrom(isPending$)).toBe(false) }) it('should support manual pending tracking on a custom name', async () => { const isPending$ = instanceOfExtendedClass.isPending('custom') - expect(await firstValueFrom(isPending$)).toBeFalse() + expect(await firstValueFrom(isPending$)).toBe(false) await firstValueFrom(of(null).pipe(instanceOfExtendedClass.startPending('custom'))) - expect(await firstValueFrom(isPending$)).toBeTrue() + expect(await firstValueFrom(isPending$)).toBe(true) await firstValueFrom(of(null).pipe(instanceOfExtendedClass.stopPending('custom'))) - expect(await firstValueFrom(isPending$)).toBeFalse() + expect(await firstValueFrom(isPending$)).toBe(false) }) it('should have true as the default pending state', async () => { const extendedClass = mixinTrackPending() const instanceOfExtendedClass = new extendedClass() - expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBeTrue() + expect(await firstValueFrom(instanceOfExtendedClass.pending$)).toBe(true) }) }) diff --git a/projects/ppwcode/ng-common/src/lib/utilities/value-reducers.spec.ts b/projects/ppwcode/ng-common/src/lib/utilities/value-reducers.spec.ts index abb17499..e671da85 100644 --- a/projects/ppwcode/ng-common/src/lib/utilities/value-reducers.spec.ts +++ b/projects/ppwcode/ng-common/src/lib/utilities/value-reducers.spec.ts @@ -1,13 +1,15 @@ import { signal } from '@angular/core' import { TestBed } from '@angular/core/testing' import { combineLatest, firstValueFrom, Observable, of } from 'rxjs' -import { first } from 'rxjs/operators' import { invert, ObservableConvertableValue, oneTrue } from './value-reducers' describe('Value combiners', () => { describe('invert', () => { - it('should invert boolean values', (done) => { - const testCases: Array<{ initialValue: ObservableConvertableValue; inverted: boolean }> = [ + it('should invert boolean values', async () => { + const testCases: Array<{ + initialValue: ObservableConvertableValue + inverted: boolean + }> = [ { initialValue: false, inverted: true }, { initialValue: signal(false), inverted: true }, { initialValue: of(false), inverted: true }, @@ -22,12 +24,8 @@ describe('Value combiners', () => { observables = testCases.map((testCase) => invert(testCase.initialValue)) }) - combineLatest(observables) - .pipe(first()) - .subscribe((result) => { - expect(result).toEqual(testCases.map((testCase) => testCase.inverted)) - done() - }) + const result = await firstValueFrom(combineLatest(observables)) + expect(result).toEqual(testCases.map((testCase) => testCase.inverted)) }) }) diff --git a/projects/ppwcode/ng-common/tsconfig.spec.json b/projects/ppwcode/ng-common/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-common/tsconfig.spec.json +++ b/projects/ppwcode/ng-common/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-dialogs/tsconfig.spec.json b/projects/ppwcode/ng-dialogs/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-dialogs/tsconfig.spec.json +++ b/projects/ppwcode/ng-dialogs/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-forms/src/lib/controls-of.spec.ts b/projects/ppwcode/ng-forms/src/lib/controls-of.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-forms/tsconfig.spec.json b/projects/ppwcode/ng-forms/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-forms/tsconfig.spec.json +++ b/projects/ppwcode/ng-forms/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-router/src/lib/mixins/pagination.spec.ts b/projects/ppwcode/ng-router/src/lib/mixins/pagination.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-router/src/lib/relative-navigation.spec.ts b/projects/ppwcode/ng-router/src/lib/relative-navigation.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-router/src/lib/routing.spec.ts b/projects/ppwcode/ng-router/src/lib/routing.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-router/tsconfig.spec.json b/projects/ppwcode/ng-router/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-router/tsconfig.spec.json +++ b/projects/ppwcode/ng-router/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-state-management/src/lib/signal-store/signal-store.spec.ts b/projects/ppwcode/ng-state-management/src/lib/signal-store/signal-store.spec.ts index e69de29b..a47cfb53 100644 --- a/projects/ppwcode/ng-state-management/src/lib/signal-store/signal-store.spec.ts +++ b/projects/ppwcode/ng-state-management/src/lib/signal-store/signal-store.spec.ts @@ -0,0 +1,8 @@ +import { SignalStore } from './signal-store' + +describe('SignalStore', () => { + it('should create', () => { + const store = new SignalStore() + expect(store).toBeTruthy() + }) +}) diff --git a/projects/ppwcode/ng-state-management/tsconfig.spec.json b/projects/ppwcode/ng-state-management/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-state-management/tsconfig.spec.json +++ b/projects/ppwcode/ng-state-management/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.spec.ts b/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.spec.ts index d5058b62..fc391527 100644 --- a/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.spec.ts +++ b/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.spec.ts @@ -58,7 +58,7 @@ describe('http-call-tester', () => { it('should verify a call to the fake backend', () => { const httpTestingController = TestBed.inject(HttpTestingController) - spyOn(httpTestingController, 'expectOne').and.callThrough() + vi.spyOn(httpTestingController, 'expectOne') const response: Array = [] @@ -96,7 +96,7 @@ describe('http-call-tester', () => { it('should support failures', () => { const httpTestingController = TestBed.inject(HttpTestingController) - spyOn(httpTestingController, 'expectOne').and.callThrough() + vi.spyOn(httpTestingController, 'expectOne') const response: Array = [] @@ -117,7 +117,7 @@ describe('http-call-tester', () => { it('should support checking the failure', () => { const httpTestingController = TestBed.inject(HttpTestingController) - spyOn(httpTestingController, 'expectOne').and.callThrough() + vi.spyOn(httpTestingController, 'expectOne') const response: Array = [] diff --git a/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.ts b/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.ts index d351ccee..56ed155d 100644 --- a/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.ts +++ b/projects/ppwcode/ng-unit-testing/src/lib/http/http-call-tester.ts @@ -203,13 +203,13 @@ export class HttpCallTester { expectOneCallToUrl(this.url, response, this.expectRequestFn, this.responseOptions) subscription.unsubscribe() - expect(subscriptionHits) - .withContext( - `Expected ${expectedSubscriptionHits} successful http stream results but got ${subscriptionHits}` - ) - .toEqual(expectedSubscriptionHits) - expect(failureHits) - .withContext(`Expected ${expectedFailureHits} failed http stream results but got ${failureHits}`) - .toEqual(expectedFailureHits) + expect( + subscriptionHits, + `Expected ${expectedSubscriptionHits} successful http stream results but got ${subscriptionHits}` + ).toEqual(expectedSubscriptionHits) + expect( + failureHits, + `Expected ${expectedFailureHits} failed http stream results but got ${failureHits}` + ).toEqual(expectedFailureHits) } } diff --git a/projects/ppwcode/ng-unit-testing/src/lib/http/http-client-testing-controller.spec.ts b/projects/ppwcode/ng-unit-testing/src/lib/http/http-client-testing-controller.spec.ts index 5feecc42..b6ae0bcb 100644 --- a/projects/ppwcode/ng-unit-testing/src/lib/http/http-client-testing-controller.spec.ts +++ b/projects/ppwcode/ng-unit-testing/src/lib/http/http-client-testing-controller.spec.ts @@ -16,13 +16,12 @@ describe('http-client-testing-controller', () => { httpClient = TestBed.inject(HttpClient) }) - it('should support expecting a call to a url and send a fake response', (done: DoneFn) => { + it('should support expecting a call to a url and send a fake response', async () => { const httpCall = httpClient.get('/api') const response = [{ id: 1 }] const subscription = httpCall.subscribe((callResponse) => { expect(callResponse).toBe(response) - done() }) expectOneCallToUrl('/api', response) diff --git a/projects/ppwcode/ng-unit-testing/tsconfig.lib.json b/projects/ppwcode/ng-unit-testing/tsconfig.lib.json index ee82da63..4ab948ac 100644 --- a/projects/ppwcode/ng-unit-testing/tsconfig.lib.json +++ b/projects/ppwcode/ng-unit-testing/tsconfig.lib.json @@ -6,7 +6,7 @@ "declaration": true, "declarationMap": true, "inlineSources": true, - "types": ["jasmine"] + "types": ["vitest/globals"] }, "exclude": ["**/*.spec.ts"] } diff --git a/projects/ppwcode/ng-unit-testing/tsconfig.spec.json b/projects/ppwcode/ng-unit-testing/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-unit-testing/tsconfig.spec.json +++ b/projects/ppwcode/ng-unit-testing/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-utils/src/lib/conditional-assert.spec.ts b/projects/ppwcode/ng-utils/src/lib/conditional-assert.spec.ts index 3299105b..1150b82a 100644 --- a/projects/ppwcode/ng-utils/src/lib/conditional-assert.spec.ts +++ b/projects/ppwcode/ng-utils/src/lib/conditional-assert.spec.ts @@ -1,3 +1,4 @@ +import type { Mock } from 'vitest' import { natural } from './assertion' import { assert, @@ -10,23 +11,18 @@ import { settings, violationMessage } from './conditional-assert' -import Spy = jasmine.Spy - -interface Fixture { - originalConditionalAssertEnabled: boolean - originalLogViolations: boolean - spy: Spy -} describe('Conditional Assert ', () => { - beforeEach(function (this: Fixture): void { - this.originalConditionalAssertEnabled = settings.enabled - this.originalLogViolations = settings.logViolations + let originalConditionalAssertEnabled: boolean, originalLogViolations: boolean + + beforeEach(() => { + originalConditionalAssertEnabled = settings.enabled + originalLogViolations = settings.logViolations }) - afterEach(function (this: Fixture): void { - settings.enabled = this.originalConditionalAssertEnabled - settings.logViolations = this.originalLogViolations + afterEach(() => { + settings.enabled = originalConditionalAssertEnabled + settings.logViolations = originalLogViolations }) describe('#violationMessage', () => { @@ -126,43 +122,50 @@ describe('Conditional Assert ', () => { it('throws when the assertion fails, with the default message', () => { const expectedMessage = violationMessage(subject, alwaysFalse) - expect(assert.bind(undefined, subject, alwaysFalse)).toThrowError(ConditionViolation, expectedMessage) + expect(assert.bind(undefined, subject, alwaysFalse)).toThrowError(ConditionViolation) + expect(assert.bind(undefined, subject, alwaysFalse)).toThrowError(expectedMessage) }) it('throws when the assertion fails, with a custom message', () => { const expectedMessage = violationMessage(subject, alwaysFalse, customMessage) - expect(assert.bind(undefined, subject, alwaysFalse, customMessage)).toThrowError( - ConditionViolation, - expectedMessage - ) + expect(assert.bind(undefined, subject, alwaysFalse, customMessage)).toThrowError(ConditionViolation) + expect(assert.bind(undefined, subject, alwaysFalse, customMessage)).toThrowError(expectedMessage) }) describe('log violations', () => { - beforeEach(function (this: Fixture): void { - this.spy = spyOn(console, 'error') // spy released by Jasmine automatically + let spy: Mock + let originalConsoleError: Console['error'] + + beforeEach(() => { + originalConsoleError = console.error + spy = vi.spyOn(console, 'error').mockImplementation(() => {}) }) - it('does not log violations to the console when requested', function (this: Fixture): void { + afterEach(() => { + console.error = originalConsoleError + }) + + it('does not log violations to the console when requested', () => { settings.logViolations = false try { assert(5, (t) => t === 3) // should have failed and have written to console - fail() + throw new Error() } catch (err) { expect(err).toBeDefined() - expect(this.spy).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() } }) - it('logs violations to the console when requested', function (this: Fixture): void { + it('logs violations to the console when requested', () => { settings.logViolations = true try { assert(5, (t) => t === 3) // should have failed and have written to console - fail() + throw new Error() } catch (err) { expect(err).toBeDefined() - expect(this.spy).toHaveBeenCalledWith(err) + expect(spy).toHaveBeenCalledWith(err) } }) }) @@ -211,8 +214,8 @@ describe('Conditional Assert ', () => { it('throws when t is undefined', () => { const t: number | undefined = undefined + expect(notUndefined.bind(undefined, t)).toThrowError(ConditionViolation) expect(notUndefined.bind(undefined, t)).toThrowError( - ConditionViolation, violationMessage(undefined, () => true, notUndefinedViolationMessage) ) }) @@ -257,10 +260,8 @@ describe('Conditional Assert ', () => { it('throws when t is null', () => { const t: number | null = null - expect(notNull.bind(null, t)).toThrowError( - ConditionViolation, - violationMessage(null, () => true, notNullViolationMessage) - ) + expect(notNull.bind(null, t)).toThrowError(ConditionViolation) + expect(notNull.bind(null, t)).toThrowError(violationMessage(null, () => true, notNullViolationMessage)) }) }) diff --git a/projects/ppwcode/ng-utils/tsconfig.spec.json b/projects/ppwcode/ng-utils/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-utils/tsconfig.spec.json +++ b/projects/ppwcode/ng-utils/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/projects/ppwcode/ng-wireframe/src/lib/left-sidenav/left-sidenav.component.spec.ts b/projects/ppwcode/ng-wireframe/src/lib/left-sidenav/left-sidenav.component.spec.ts index fb13193e..c8ce07f4 100644 --- a/projects/ppwcode/ng-wireframe/src/lib/left-sidenav/left-sidenav.component.spec.ts +++ b/projects/ppwcode/ng-wireframe/src/lib/left-sidenav/left-sidenav.component.spec.ts @@ -1,145 +1,149 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' -import { Router, RouterModule } from '@angular/router' -import { provideTranslateService } from '@ngx-translate/core' -import { NavigationItem } from '../navigation-item/navigation-item.model' -import { LeftSidenavComponent } from './left-sidenav.component' - -describe('Left sidenav component', () => { - let router: Router - let component: LeftSidenavComponent - let fixture: ComponentFixture - const disabledNavigationItem: NavigationItem = { - label: 'Navigation item 1', - isEnabled: false, - icon: 'fa-solid fa-cogs', - fullRouterPath: '/item-1' - } - const enabledNavigationItem: NavigationItem = { - label: 'Navigation item 2', - isEnabled: true, - icon: 'fa-solid fa-cogs', - fullRouterPath: '/item-2' - } - const implicitEnabledNavigationItem: NavigationItem = { - label: 'Navigation item 3', - icon: 'fa-solid fa-cogs', - fullRouterPath: '/item-3' - } - const invalidNavigationItem: NavigationItem = { label: 'Navigation item 4', icon: 'fa-solid fa-cogs' } - const emptyChildrenNavigationItem = { label: 'Navigation item 5', icon: 'fa-solid fa-cogs', children: [] } - const childrenNavigationItem = { - label: 'Navigation item 6', - icon: 'fa-solid fa-cogs', - children: [{ label: 'Navigation item 2', isEnabled: true, icon: 'fa-solid fa-cogs', fullRouterPath: '/item-2' }] - } - const navigationItems: Array = [ - disabledNavigationItem, - enabledNavigationItem, - implicitEnabledNavigationItem, - invalidNavigationItem, - emptyChildrenNavigationItem, - childrenNavigationItem - ] - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [LeftSidenavComponent, RouterModule], - providers: [provideTranslateService({})] - }) - - router = TestBed.inject(Router) - - fixture = TestBed.createComponent(LeftSidenavComponent) - component = fixture.componentInstance - fixture.componentRef.setInput('navigationItems', navigationItems) - fixture.detectChanges() - }) - - it('should do nothing when clicking disabled navigation items', () => { - expect(component.navigationItemIsOpened(disabledNavigationItem)).toBeFalse() - - component.onClickNavigationItem(disabledNavigationItem) - - expect(component.navigationItemIsOpened(disabledNavigationItem)).toBeFalse() - }) - - it('should navigate to explicitly enabled routes with a router path', () => { - spyOn(router, 'navigateByUrl') - - component.onClickNavigationItem(enabledNavigationItem) - - expect(router.navigateByUrl).toHaveBeenCalledOnceWith('/item-2') - expect(component.navigationItemIsOpened(enabledNavigationItem)).toBeFalse() - }) - - it('should navigate to implicitly enabled routes with a router path', () => { - spyOn(router, 'navigateByUrl') - - component.onClickNavigationItem(implicitEnabledNavigationItem) - - expect(router.navigateByUrl).toHaveBeenCalledOnceWith('/item-3') - expect(component.navigationItemIsOpened(implicitEnabledNavigationItem)).toBeFalse() - }) - - it('should error when the navigation item has no children or router path', () => { - const expectedError = new Error('Could not handle navigation item with no children or router path.') - - expect(() => component.onClickNavigationItem(invalidNavigationItem)).toThrow(expectedError) - expect(component.navigationItemIsOpened(invalidNavigationItem)).toBeFalse() - - expect(() => component.onClickNavigationItem(emptyChildrenNavigationItem)).toThrow(expectedError) - expect(component.navigationItemIsOpened(emptyChildrenNavigationItem)).toBeFalse() - }) - - it('should toggle the state of collapsible navigation items', () => { - expect(component.navigationItemIsOpened(childrenNavigationItem)).toBeFalse() - - component.onClickNavigationItem(childrenNavigationItem) - expect(component.navigationItemIsOpened(childrenNavigationItem)).toBeTrue() - - component.onClickNavigationItem(childrenNavigationItem) - expect(component.navigationItemIsOpened(childrenNavigationItem)).toBeFalse() - }) - - it('should throw when an external link navigation item contains children', () => { - const navigationItemsWithExternalLink: Array = [ - ...navigationItems, - { - icon: 'fa-solid fa-globe', - label: 'external', - fullRouterPath: 'https://peopleware.be', - isExternalLink: true, - children: [...navigationItems] - } - ] - - expect(() => { - fixture.componentRef.setInput('navigationItems', navigationItemsWithExternalLink) - fixture.detectChanges() - }).toThrowError('External link navigation items cannot have children.') - }) - - it('should throw when an external link navigation item as a child contains children on itself', () => { - const navigationItemsWithExternalLink: Array = [...navigationItems].map((item, index) => - index === 0 - ? { - ...item, - children: [ - { - icon: 'fa-solid fa-globe', - label: 'external', - fullRouterPath: 'https://peopleware.be', - isExternalLink: true, - children: [...navigationItems] - } - ] - } - : { ...item } - ) - - expect(() => { - fixture.componentRef.setInput('navigationItems', navigationItemsWithExternalLink) - fixture.detectChanges() - }).toThrowError('External link navigation items cannot have children.') - }) -}) +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { Router, RouterModule } from '@angular/router' +import { provideTranslateService } from '@ngx-translate/core' +import { NavigationItem } from '../navigation-item/navigation-item.model' +import { LeftSidenavComponent } from './left-sidenav.component' + +describe('Left sidenav component', () => { + let router: Router + let component: LeftSidenavComponent + let fixture: ComponentFixture + const disabledNavigationItem: NavigationItem = { + label: 'Navigation item 1', + isEnabled: false, + icon: 'fa-solid fa-cogs', + fullRouterPath: '/item-1' + } + const enabledNavigationItem: NavigationItem = { + label: 'Navigation item 2', + isEnabled: true, + icon: 'fa-solid fa-cogs', + fullRouterPath: '/item-2' + } + const implicitEnabledNavigationItem: NavigationItem = { + label: 'Navigation item 3', + icon: 'fa-solid fa-cogs', + fullRouterPath: '/item-3' + } + const invalidNavigationItem: NavigationItem = { label: 'Navigation item 4', icon: 'fa-solid fa-cogs' } + const emptyChildrenNavigationItem = { label: 'Navigation item 5', icon: 'fa-solid fa-cogs', children: [] } + const childrenNavigationItem = { + label: 'Navigation item 6', + icon: 'fa-solid fa-cogs', + children: [{ label: 'Navigation item 2', isEnabled: true, icon: 'fa-solid fa-cogs', fullRouterPath: '/item-2' }] + } + const navigationItems: Array = [ + disabledNavigationItem, + enabledNavigationItem, + implicitEnabledNavigationItem, + invalidNavigationItem, + emptyChildrenNavigationItem, + childrenNavigationItem + ] + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [LeftSidenavComponent, RouterModule], + providers: [provideTranslateService({})] + }) + + router = TestBed.inject(Router) + + fixture = TestBed.createComponent(LeftSidenavComponent) + component = fixture.componentInstance + fixture.componentRef.setInput('navigationItems', navigationItems) + fixture.detectChanges() + }) + + it('should do nothing when clicking disabled navigation items', () => { + expect(component.navigationItemIsOpened(disabledNavigationItem)).toBe(false) + + component.onClickNavigationItem(disabledNavigationItem) + + expect(component.navigationItemIsOpened(disabledNavigationItem)).toBe(false) + }) + + it('should navigate to explicitly enabled routes with a router path', () => { + vi.spyOn(router, 'navigateByUrl') + + component.onClickNavigationItem(enabledNavigationItem) + + expect(router.navigateByUrl).toHaveBeenCalledTimes(1) + + expect(router.navigateByUrl).toHaveBeenCalledWith('/item-2') + expect(component.navigationItemIsOpened(enabledNavigationItem)).toBe(false) + }) + + it('should navigate to implicitly enabled routes with a router path', () => { + vi.spyOn(router, 'navigateByUrl') + + component.onClickNavigationItem(implicitEnabledNavigationItem) + + expect(router.navigateByUrl).toHaveBeenCalledTimes(1) + + expect(router.navigateByUrl).toHaveBeenCalledWith('/item-3') + expect(component.navigationItemIsOpened(implicitEnabledNavigationItem)).toBe(false) + }) + + it('should error when the navigation item has no children or router path', () => { + const expectedError = new Error('Could not handle navigation item with no children or router path.') + + expect(() => component.onClickNavigationItem(invalidNavigationItem)).toThrow(expectedError) + expect(component.navigationItemIsOpened(invalidNavigationItem)).toBe(false) + + expect(() => component.onClickNavigationItem(emptyChildrenNavigationItem)).toThrow(expectedError) + expect(component.navigationItemIsOpened(emptyChildrenNavigationItem)).toBe(false) + }) + + it('should toggle the state of collapsible navigation items', () => { + expect(component.navigationItemIsOpened(childrenNavigationItem)).toBe(false) + + component.onClickNavigationItem(childrenNavigationItem) + expect(component.navigationItemIsOpened(childrenNavigationItem)).toBe(true) + + component.onClickNavigationItem(childrenNavigationItem) + expect(component.navigationItemIsOpened(childrenNavigationItem)).toBe(false) + }) + + it('should throw when an external link navigation item contains children', () => { + const navigationItemsWithExternalLink: Array = [ + ...navigationItems, + { + icon: 'fa-solid fa-globe', + label: 'external', + fullRouterPath: 'https://peopleware.be', + isExternalLink: true, + children: [...navigationItems] + } + ] + + expect(() => { + fixture.componentRef.setInput('navigationItems', navigationItemsWithExternalLink) + fixture.detectChanges() + }).toThrowError('External link navigation items cannot have children.') + }) + + it('should throw when an external link navigation item as a child contains children on itself', () => { + const navigationItemsWithExternalLink: Array = [...navigationItems].map((item, index) => + index === 0 + ? { + ...item, + children: [ + { + icon: 'fa-solid fa-globe', + label: 'external', + fullRouterPath: 'https://peopleware.be', + isExternalLink: true, + children: [...navigationItems] + } + ] + } + : { ...item } + ) + + expect(() => { + fixture.componentRef.setInput('navigationItems', navigationItemsWithExternalLink) + fixture.detectChanges() + }).toThrowError('External link navigation items cannot have children.') + }) +}) diff --git a/projects/ppwcode/ng-wireframe/src/lib/navigation-item/navigation-item.model.spec.ts b/projects/ppwcode/ng-wireframe/src/lib/navigation-item/navigation-item.model.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-wireframe/src/lib/pagination-bar/pagination-bar.component.spec.ts b/projects/ppwcode/ng-wireframe/src/lib/pagination-bar/pagination-bar.component.spec.ts index 9b218786..963ffaa1 100644 --- a/projects/ppwcode/ng-wireframe/src/lib/pagination-bar/pagination-bar.component.spec.ts +++ b/projects/ppwcode/ng-wireframe/src/lib/pagination-bar/pagination-bar.component.spec.ts @@ -6,8 +6,7 @@ import { PaginationBarComponent } from './pagination-bar.component' describe('Pagination bar component', () => { const createTestComponent = async (value: PagedAsyncResult | PagedEntities) => { TestBed.configureTestingModule({ - declarations: [TestComponent], - imports: [PaginationBarComponent] + imports: [TestComponent] }) const fixture = TestBed.createComponent(TestComponent) fixture.componentRef.setInput('value', value) @@ -37,8 +36,7 @@ describe('Pagination bar component', () => { @Component({ template: '', - /* eslint-disable @angular-eslint/prefer-standalone */ - standalone: false, + imports: [PaginationBarComponent], changeDetection: ChangeDetectionStrategy.OnPush }) class TestComponent { diff --git a/projects/ppwcode/ng-wireframe/src/lib/toolbar/toolbar.component.spec.ts b/projects/ppwcode/ng-wireframe/src/lib/toolbar/toolbar.component.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-wireframe/src/lib/wireframe/wireframe.component.spec.ts b/projects/ppwcode/ng-wireframe/src/lib/wireframe/wireframe.component.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/projects/ppwcode/ng-wireframe/tsconfig.spec.json b/projects/ppwcode/ng-wireframe/tsconfig.spec.json index 80f875ef..66ab0878 100644 --- a/projects/ppwcode/ng-wireframe/tsconfig.spec.json +++ b/projects/ppwcode/ng-wireframe/tsconfig.spec.json @@ -4,7 +4,7 @@ "compilerOptions": { "outDir": "../../../out-tsc/spec", "types": [ - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/scripts/ci/test-libs.js b/scripts/ci/test-libs.js index ebf26ed4..285b27b8 100644 --- a/scripts/ci/test-libs.js +++ b/scripts/ci/test-libs.js @@ -16,7 +16,7 @@ const projects = [ const commands = projects.map((project) => ({ name: project, - command: `ng test ${project} --browsers ChromeHeadless --watch=false --code-coverage`, + command: `ng test ${project} --watch=false`, env: { ANGULAR_PROJECT_NAME: project } })) diff --git a/tsconfig.angular.json b/tsconfig.angular.json index 55d02ca8..377a9aad 100644 --- a/tsconfig.angular.json +++ b/tsconfig.angular.json @@ -31,7 +31,7 @@ "target": "ES2022", "module": "ES2022", "useDefineForClassFields": false, - "lib": ["ES2022", "dom"] + "lib": ["ES2022", "dom", "esnext.disposable"] }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, diff --git a/tsconfig.spec.json b/tsconfig.spec.json index 5b8946f6..d890fd17 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -5,7 +5,7 @@ "outDir": "./out-tsc/spec", "types": [ "node", - "jasmine" + "vitest/globals" ] }, "include": [ diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..8cdee2d6 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + globals: true + } +})