test: frontend test suite — Vitest infrastructure, auth/connection stores, vault composable, admin middleware
28 tests across 4 spec files. Vitest + happy-dom configured with Nuxt auto-import shims ($$fetch, navigateTo, defineNuxtRouteMiddleware) so stores and composables resolve cleanly outside the Nuxt runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5abbffca9b
commit
f01e357647
678
frontend/package-lock.json
generated
678
frontend/package-lock.json
generated
@ -23,9 +23,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.0.0",
|
||||
"@pinia/testing": "^0.1.7",
|
||||
"@primevue/nuxt-module": "^4.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"happy-dom": "^20.8.4",
|
||||
"nuxt": "^3.10.0",
|
||||
"typescript": "^5.3.0"
|
||||
"typescript": "^5.3.0",
|
||||
"vitest": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@ -1706,23 +1710,6 @@
|
||||
"nuxt": "^3.21.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/schema": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-4.4.2.tgz",
|
||||
"integrity": "sha512-/q6C7Qhiricgi+PKR7ovBnJlKTL0memCbA1CzRT+itCW/oeYzUfeMdQ35mGntlBoyRPNrMXbzuSUhfDbSCU57w==",
|
||||
"extraneous": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/shared": "^3.5.30",
|
||||
"defu": "^6.1.4",
|
||||
"pathe": "^2.0.3",
|
||||
"pkg-types": "^2.3.0",
|
||||
"std-env": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/telemetry": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.7.0.tgz",
|
||||
@ -1849,6 +1836,13 @@
|
||||
"unctx": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@one-ini/wasm": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@oxc-minify/binding-android-arm-eabi": {
|
||||
"version": "0.117.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.117.0.tgz",
|
||||
@ -3229,6 +3223,22 @@
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinia/testing": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.7.tgz",
|
||||
"integrity": "sha512-xcDq6Ry/kNhZ5bsUMl7DeoFXwdume1NYzDggCiDUDKoPQ6Mo0eH9VU7bJvBtlurqe6byAntWoX5IhVFqWzRz/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vue-demi": "^0.14.10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pinia": ">=2.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@ -4022,6 +4032,13 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
@ -4033,12 +4050,40 @@
|
||||
"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/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/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
|
||||
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||
@ -4046,6 +4091,23 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/whatwg-mimetype": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz",
|
||||
"integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@unhead/vue": {
|
||||
"version": "2.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.1.12.tgz",
|
||||
@ -4135,6 +4197,129 @@
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz",
|
||||
"integrity": "sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.0",
|
||||
"@vitest/utils": "4.1.0",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz",
|
||||
"integrity": "sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.0",
|
||||
"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 || ^8.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.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz",
|
||||
"integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz",
|
||||
"integrity": "sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.0",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz",
|
||||
"integrity": "sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.0",
|
||||
"@vitest/utils": "4.1.0",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz",
|
||||
"integrity": "sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz",
|
||||
"integrity": "sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.4.28",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz",
|
||||
@ -4399,6 +4584,17 @@
|
||||
"integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/test-utils": {
|
||||
"version": "2.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz",
|
||||
"integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-beautify": "^1.14.9",
|
||||
"vue-component-type-helpers": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
@ -4747,6 +4943,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"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-kit": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz",
|
||||
@ -5312,6 +5518,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",
|
||||
@ -5444,16 +5660,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
||||
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/commondir": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||
@ -5511,6 +5717,24 @@
|
||||
"integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/config-chain": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
||||
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ini": "^1.3.4",
|
||||
"proto-list": "~1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/config-chain/node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/consola": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
|
||||
@ -6184,6 +6408,68 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/editorconfig": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz",
|
||||
"integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@one-ini/wasm": "0.1.1",
|
||||
"commander": "^10.0.0",
|
||||
"minimatch": "^9.0.1",
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"bin": {
|
||||
"editorconfig": "bin/editorconfig"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/editorconfig/node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -6439,6 +6725,16 @@
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"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/exsolve": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
|
||||
@ -6889,6 +7185,24 @@
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/happy-dom": {
|
||||
"version": "20.8.4",
|
||||
"resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.8.4.tgz",
|
||||
"integrity": "sha512-GKhjq4OQCYB4VLFBzv8mmccUadwlAusOZOI7hC1D9xDIT5HhzkJK17c4el2f6R6C715P9xB4uiMxeKUa2nHMwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": ">=20.0.0",
|
||||
"@types/whatwg-mimetype": "^3.0.2",
|
||||
"@types/ws": "^8.18.1",
|
||||
"entities": "^7.0.1",
|
||||
"whatwg-mimetype": "^3.0.0",
|
||||
"ws": "^8.18.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@ -7457,6 +7771,143 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify": {
|
||||
"version": "1.15.4",
|
||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz",
|
||||
"integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"config-chain": "^1.1.13",
|
||||
"editorconfig": "^1.0.4",
|
||||
"glob": "^10.4.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"nopt": "^7.2.1"
|
||||
},
|
||||
"bin": {
|
||||
"css-beautify": "js/bin/css-beautify.js",
|
||||
"html-beautify": "js/bin/html-beautify.js",
|
||||
"js-beautify": "js/bin/js-beautify.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/abbrev": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
||||
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/glob": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
"integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
|
||||
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/nopt": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
|
||||
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"abbrev": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify/node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -9867,6 +10318,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/quansync": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
|
||||
@ -10549,6 +11007,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",
|
||||
@ -10676,6 +11141,13 @@
|
||||
"node": ">=20.16.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/standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
@ -10922,6 +11394,16 @@
|
||||
"url": "https://opencollective.com/svgo"
|
||||
}
|
||||
},
|
||||
"node_modules/svgo/node_modules/commander": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
||||
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/system-architecture": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz",
|
||||
@ -11300,6 +11782,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"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/tinyclip": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.12.tgz",
|
||||
@ -11335,6 +11824,16 @@
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyrainbow": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
||||
"integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -11530,6 +12029,13 @@
|
||||
"node": ">=18.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unenv": {
|
||||
"version": "2.0.0-rc.24",
|
||||
"resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
|
||||
@ -12409,6 +12915,88 @@
|
||||
"@types/estree": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz",
|
||||
"integrity": "sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.0",
|
||||
"@vitest/mocker": "4.1.0",
|
||||
"@vitest/pretty-format": "4.1.0",
|
||||
"@vitest/runner": "4.1.0",
|
||||
"@vitest/snapshot": "4.1.0",
|
||||
"@vitest/spy": "4.1.0",
|
||||
"@vitest/utils": "4.1.0",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
"obug": "^2.1.1",
|
||||
"pathe": "^2.0.3",
|
||||
"picomatch": "^4.0.3",
|
||||
"std-env": "^4.0.0-rc.1",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^1.0.2",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"tinyrainbow": "^3.0.3",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.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.1.0",
|
||||
"@vitest/browser-preview": "4.1.0",
|
||||
"@vitest/browser-webdriverio": "4.1.0",
|
||||
"@vitest/ui": "4.1.0",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
||||
},
|
||||
"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
|
||||
},
|
||||
"vite": {
|
||||
"optional": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
||||
@ -12447,6 +13035,13 @@
|
||||
"ufo": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-component-type-helpers": {
|
||||
"version": "2.2.12",
|
||||
"resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz",
|
||||
"integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vue-demi": {
|
||||
"version": "0.14.10",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
|
||||
@ -12509,6 +13104,16 @@
|
||||
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/whatwg-mimetype": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
|
||||
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
@ -12536,6 +13141,23 @@
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
},
|
||||
"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/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
||||
@ -5,26 +5,33 @@
|
||||
"scripts": {
|
||||
"dev": "nuxi dev",
|
||||
"build": "nuxi generate",
|
||||
"preview": "nuxi preview"
|
||||
"preview": "nuxi preview",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:cov": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.5.0",
|
||||
"@primevue/themes": "^4.0.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-search": "^0.15.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/addon-webgl": "^0.18.0",
|
||||
"@xterm/xterm": "^5.4.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"lucide-vue-next": "^0.300.0",
|
||||
"monaco-editor": "^0.45.0",
|
||||
"pinia": "^2.1.0",
|
||||
"primevue": "^4.0.0",
|
||||
"@xterm/xterm": "^5.4.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-search": "^0.15.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/addon-webgl": "^0.18.0"
|
||||
"primevue": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.0.0",
|
||||
"@pinia/testing": "^0.1.7",
|
||||
"@primevue/nuxt-module": "^4.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"happy-dom": "^20.8.4",
|
||||
"nuxt": "^3.10.0",
|
||||
"typescript": "^5.3.0"
|
||||
"typescript": "^5.3.0",
|
||||
"vitest": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
99
frontend/tests/composables/useVault.spec.ts
Normal file
99
frontend/tests/composables/useVault.spec.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { useVault } from '../../composables/useVault'
|
||||
|
||||
const mockFetch = vi.mocked($fetch as ReturnType<typeof vi.fn>)
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: assert no Authorization header was sent
|
||||
// ---------------------------------------------------------------------------
|
||||
function assertNoAuthHeader(callIndex = 0) {
|
||||
const callArgs = mockFetch.mock.calls[callIndex]
|
||||
const options = callArgs[1] as Record<string, unknown> | undefined
|
||||
if (options && options.headers) {
|
||||
const headers = options.headers as Record<string, unknown>
|
||||
expect(headers).not.toHaveProperty('Authorization')
|
||||
}
|
||||
// If no options object at all — cookie-only, no auth header by definition
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SSH Keys
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('listKeys()', () => {
|
||||
it('fetches /api/ssh-keys without Authorization header', async () => {
|
||||
mockFetch.mockResolvedValueOnce([])
|
||||
const { listKeys } = useVault()
|
||||
await listKeys()
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ssh-keys')
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
describe('importKey()', () => {
|
||||
it('posts key data to /api/ssh-keys', async () => {
|
||||
mockFetch.mockResolvedValueOnce({ id: 1 })
|
||||
const { importKey } = useVault()
|
||||
const payload = { name: 'my-key', privateKey: '-----BEGIN RSA PRIVATE KEY-----' }
|
||||
await importKey(payload)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ssh-keys', { method: 'POST', body: payload })
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteKey()', () => {
|
||||
it('sends DELETE to /api/ssh-keys/:id', async () => {
|
||||
mockFetch.mockResolvedValueOnce(undefined)
|
||||
const { deleteKey } = useVault()
|
||||
await deleteKey(7)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ssh-keys/7', { method: 'DELETE' })
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Credentials
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('listCredentials()', () => {
|
||||
it('fetches /api/credentials without Authorization header', async () => {
|
||||
mockFetch.mockResolvedValueOnce([])
|
||||
const { listCredentials } = useVault()
|
||||
await listCredentials()
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/credentials')
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
describe('createCredential()', () => {
|
||||
it('posts credential data to /api/credentials', async () => {
|
||||
const cred = { label: 'prod-db', username: 'admin', password: 'hunter2' }
|
||||
mockFetch.mockResolvedValueOnce({ id: 5, ...cred })
|
||||
const { createCredential } = useVault()
|
||||
await createCredential(cred)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/credentials', { method: 'POST', body: cred })
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateCredential()', () => {
|
||||
it('sends PUT to /api/credentials/:id', async () => {
|
||||
mockFetch.mockResolvedValueOnce(undefined)
|
||||
const { updateCredential } = useVault()
|
||||
await updateCredential(5, { password: 'new-pass' })
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/credentials/5', { method: 'PUT', body: { password: 'new-pass' } })
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteCredential()', () => {
|
||||
it('sends DELETE to /api/credentials/:id', async () => {
|
||||
mockFetch.mockResolvedValueOnce(undefined)
|
||||
const { deleteCredential } = useVault()
|
||||
await deleteCredential(5)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/credentials/5', { method: 'DELETE' })
|
||||
assertNoAuthHeader()
|
||||
})
|
||||
})
|
||||
52
frontend/tests/middleware/admin.spec.ts
Normal file
52
frontend/tests/middleware/admin.spec.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useAuthStore } from '../../stores/auth.store'
|
||||
|
||||
// The middleware calls useAuthStore() and navigateTo() as Nuxt auto-imports.
|
||||
// We override the global.useAuthStore shim (set in setup.ts) with the real
|
||||
// store factory so it resolves against the active Pinia instance.
|
||||
// navigateTo is already vi.fn() from setup.ts.
|
||||
|
||||
const mockNavigateTo = vi.mocked(navigateTo as ReturnType<typeof vi.fn>)
|
||||
|
||||
// Load the middleware factory.
|
||||
// defineNuxtRouteMiddleware is a pass-through shim that just returns the fn.
|
||||
// So `adminMiddleware` will be the inner route handler function.
|
||||
let adminMiddleware: () => unknown
|
||||
|
||||
beforeEach(async () => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
|
||||
// Bind useAuthStore to the global so middleware can call it as an auto-import
|
||||
global.useAuthStore = useAuthStore as any
|
||||
|
||||
// Re-import the middleware fresh each test to get the current global binding
|
||||
const mod = await import('../../middleware/admin?t=' + Date.now())
|
||||
adminMiddleware = mod.default
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// admin middleware
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('admin middleware', () => {
|
||||
it('redirects non-admin users to "/"', () => {
|
||||
const auth = useAuthStore()
|
||||
// Non-admin user
|
||||
auth.user = { id: 2, email: 'bob@example.com', displayName: 'Bob', role: 'user' }
|
||||
|
||||
adminMiddleware()
|
||||
|
||||
expect(mockNavigateTo).toHaveBeenCalledWith('/')
|
||||
})
|
||||
|
||||
it('allows admin users through without redirecting', () => {
|
||||
const auth = useAuthStore()
|
||||
// Admin user
|
||||
auth.user = { id: 1, email: 'alice@example.com', displayName: 'Alice', role: 'admin' }
|
||||
|
||||
adminMiddleware()
|
||||
|
||||
expect(mockNavigateTo).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
38
frontend/tests/setup.ts
Normal file
38
frontend/tests/setup.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { vi } from 'vitest'
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Nuxt auto-import globals
|
||||
// These are injected by Nuxt at runtime but Vitest doesn't run Nuxt,
|
||||
// so we shim them here so test files can import store/composable modules
|
||||
// without hitting "X is not defined" errors.
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// $fetch — Nuxt's isomorphic fetch wrapper
|
||||
global.$fetch = vi.fn()
|
||||
|
||||
// navigateTo — Nuxt router utility
|
||||
global.navigateTo = vi.fn()
|
||||
|
||||
// Route middleware helpers
|
||||
global.defineNuxtRouteMiddleware = vi.fn((fn: Function) => fn)
|
||||
|
||||
// Plugin helper (used in some plugin files, not in tests directly)
|
||||
global.defineNuxtPlugin = vi.fn((fn: Function) => fn)
|
||||
|
||||
// Page meta (used in page components)
|
||||
global.definePageMeta = vi.fn()
|
||||
|
||||
// Vue Composition API — re-export from Vue so stores using these
|
||||
// via Nuxt auto-imports resolve correctly in Vitest
|
||||
global.ref = ref
|
||||
global.computed = computed
|
||||
global.onMounted = onMounted
|
||||
global.watch = watch
|
||||
|
||||
// useAuthStore — needed by middleware; forward-declared here so
|
||||
// admin.ts middleware can resolve it. Individual test files override
|
||||
// this with the real Pinia store instance.
|
||||
// (Set to undefined by default — tests that import middleware must
|
||||
// call setActivePinia first and then the real store will resolve.)
|
||||
global.useAuthStore = undefined as any
|
||||
165
frontend/tests/stores/auth.store.spec.ts
Normal file
165
frontend/tests/stores/auth.store.spec.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useAuthStore } from '../../stores/auth.store'
|
||||
|
||||
// $fetch and navigateTo are shimmed in tests/setup.ts as globals.
|
||||
// We re-cast them here so vi.mocked() provides typed mock utilities.
|
||||
const mockFetch = vi.mocked($fetch as ReturnType<typeof vi.fn>)
|
||||
const mockNavigateTo = vi.mocked(navigateTo as ReturnType<typeof vi.fn>)
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// login()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('login()', () => {
|
||||
it('stores the user and returns the response on success', async () => {
|
||||
const user = { id: 1, email: 'alice@example.com', displayName: 'Alice', role: 'user' }
|
||||
mockFetch.mockResolvedValueOnce({ user })
|
||||
|
||||
const auth = useAuthStore()
|
||||
const result = await auth.login('alice@example.com', 'secret')
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/auth/login', {
|
||||
method: 'POST',
|
||||
body: { email: 'alice@example.com', password: 'secret' },
|
||||
})
|
||||
expect(auth.user).toEqual(user)
|
||||
expect(result).toEqual({ user })
|
||||
})
|
||||
|
||||
it('includes totpCode in body when provided', async () => {
|
||||
const user = { id: 1, email: 'alice@example.com', displayName: 'Alice', role: 'user' }
|
||||
mockFetch.mockResolvedValueOnce({ user })
|
||||
|
||||
const auth = useAuthStore()
|
||||
await auth.login('alice@example.com', 'secret', '123456')
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/auth/login', {
|
||||
method: 'POST',
|
||||
body: { email: 'alice@example.com', password: 'secret', totpCode: '123456' },
|
||||
})
|
||||
})
|
||||
|
||||
it('returns requires_totp and does NOT set user when TOTP is required', async () => {
|
||||
mockFetch.mockResolvedValueOnce({ requires_totp: true })
|
||||
|
||||
const auth = useAuthStore()
|
||||
const result = await auth.login('alice@example.com', 'secret')
|
||||
|
||||
expect(result).toEqual({ requires_totp: true })
|
||||
expect(auth.user).toBeNull()
|
||||
})
|
||||
|
||||
it('does NOT include an Authorization header (cookie-only auth)', async () => {
|
||||
mockFetch.mockResolvedValueOnce({ user: { id: 1, email: 'a@b.com', displayName: null, role: 'user' } })
|
||||
|
||||
const auth = useAuthStore()
|
||||
await auth.login('a@b.com', 'pass')
|
||||
|
||||
const callArgs = mockFetch.mock.calls[0]
|
||||
const options = callArgs[1] as Record<string, unknown>
|
||||
expect(options).not.toHaveProperty('headers')
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// logout()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('logout()', () => {
|
||||
it('clears user state and calls navigateTo("/login")', async () => {
|
||||
mockFetch.mockResolvedValueOnce({}) // logout POST succeeds
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'alice@example.com', displayName: 'Alice', role: 'user' }
|
||||
|
||||
await auth.logout()
|
||||
|
||||
expect(auth.user).toBeNull()
|
||||
expect(mockNavigateTo).toHaveBeenCalledWith('/login')
|
||||
})
|
||||
|
||||
it('clears user state even when the logout request fails', async () => {
|
||||
mockFetch.mockRejectedValueOnce(new Error('network error'))
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'alice@example.com', displayName: 'Alice', role: 'user' }
|
||||
|
||||
await auth.logout()
|
||||
|
||||
expect(auth.user).toBeNull()
|
||||
expect(mockNavigateTo).toHaveBeenCalledWith('/login')
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// fetchProfile()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('fetchProfile()', () => {
|
||||
it('sets user on success', async () => {
|
||||
const user = { id: 2, email: 'bob@example.com', displayName: 'Bob', role: 'admin' }
|
||||
mockFetch.mockResolvedValueOnce(user)
|
||||
|
||||
const auth = useAuthStore()
|
||||
await auth.fetchProfile()
|
||||
|
||||
expect(auth.user).toEqual(user)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/auth/profile')
|
||||
})
|
||||
|
||||
it('sets user to null on failure', async () => {
|
||||
mockFetch.mockRejectedValueOnce(new Error('401'))
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'a@b.com', displayName: null, role: 'user' }
|
||||
|
||||
await auth.fetchProfile()
|
||||
|
||||
expect(auth.user).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getWsTicket()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('getWsTicket()', () => {
|
||||
it('returns the ticket string from the API', async () => {
|
||||
mockFetch.mockResolvedValueOnce({ ticket: 'abc-xyz-ticket' })
|
||||
|
||||
const auth = useAuthStore()
|
||||
const ticket = await auth.getWsTicket()
|
||||
|
||||
expect(ticket).toBe('abc-xyz-ticket')
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/auth/ws-ticket', { method: 'POST' })
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getters
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('isAuthenticated getter', () => {
|
||||
it('returns false when user is null', () => {
|
||||
const auth = useAuthStore()
|
||||
expect(auth.isAuthenticated).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true when user is set', () => {
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'a@b.com', displayName: null, role: 'user' }
|
||||
expect(auth.isAuthenticated).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isAdmin getter', () => {
|
||||
it('returns false for non-admin role', () => {
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'a@b.com', displayName: null, role: 'user' }
|
||||
expect(auth.isAdmin).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true for admin role', () => {
|
||||
const auth = useAuthStore()
|
||||
auth.user = { id: 1, email: 'a@b.com', displayName: null, role: 'admin' }
|
||||
expect(auth.isAdmin).toBe(true)
|
||||
})
|
||||
})
|
||||
124
frontend/tests/stores/connection.store.spec.ts
Normal file
124
frontend/tests/stores/connection.store.spec.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useConnectionStore } from '../../stores/connection.store'
|
||||
|
||||
const mockFetch = vi.mocked($fetch as ReturnType<typeof vi.fn>)
|
||||
|
||||
const makeHost = (id: number) => ({
|
||||
id,
|
||||
name: `host-${id}`,
|
||||
hostname: `192.168.1.${id}`,
|
||||
port: 22,
|
||||
protocol: 'ssh' as const,
|
||||
groupId: null,
|
||||
credentialId: null,
|
||||
tags: [],
|
||||
notes: null,
|
||||
color: null,
|
||||
lastConnectedAt: null,
|
||||
group: null,
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// fetchHosts()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('fetchHosts()', () => {
|
||||
it('populates hosts array and resets loading flag', async () => {
|
||||
const hosts = [makeHost(1), makeHost(2)]
|
||||
mockFetch.mockResolvedValueOnce(hosts)
|
||||
|
||||
const store = useConnectionStore()
|
||||
await store.fetchHosts()
|
||||
|
||||
expect(store.hosts).toEqual(hosts)
|
||||
expect(store.loading).toBe(false)
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/hosts')
|
||||
})
|
||||
|
||||
it('does NOT include Authorization headers (cookie-only auth)', async () => {
|
||||
mockFetch.mockResolvedValueOnce([])
|
||||
const store = useConnectionStore()
|
||||
await store.fetchHosts()
|
||||
|
||||
const callArgs = mockFetch.mock.calls[0]
|
||||
// fetchHosts passes no options — only the URL
|
||||
expect(callArgs.length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// createHost()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('createHost()', () => {
|
||||
it('posts to /api/hosts and refreshes the list', async () => {
|
||||
const newHost = makeHost(10)
|
||||
// First call: POST to create, second call: GET for fetchHosts
|
||||
mockFetch
|
||||
.mockResolvedValueOnce(newHost) // POST
|
||||
.mockResolvedValueOnce([newHost]) // GET (fetchHosts)
|
||||
|
||||
const store = useConnectionStore()
|
||||
const result = await store.createHost({ name: 'host-10', hostname: '10.0.0.10', port: 22, protocol: 'ssh' })
|
||||
|
||||
expect(result).toEqual(newHost)
|
||||
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/hosts', {
|
||||
method: 'POST',
|
||||
body: { name: 'host-10', hostname: '10.0.0.10', port: 22, protocol: 'ssh' },
|
||||
})
|
||||
expect(store.hosts).toEqual([newHost])
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// deleteHost()
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('deleteHost()', () => {
|
||||
it('sends DELETE and refreshes the list', async () => {
|
||||
mockFetch
|
||||
.mockResolvedValueOnce(undefined) // DELETE
|
||||
.mockResolvedValueOnce([]) // fetchHosts
|
||||
|
||||
const store = useConnectionStore()
|
||||
await store.deleteHost(5)
|
||||
|
||||
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/hosts/5', { method: 'DELETE' })
|
||||
expect(store.hosts).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Group CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('createGroup()', () => {
|
||||
it('posts to /api/groups and refreshes the tree', async () => {
|
||||
mockFetch
|
||||
.mockResolvedValueOnce(undefined) // POST
|
||||
.mockResolvedValueOnce([]) // fetchTree
|
||||
|
||||
const store = useConnectionStore()
|
||||
await store.createGroup({ name: 'Dev Servers' })
|
||||
|
||||
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/groups', {
|
||||
method: 'POST',
|
||||
body: { name: 'Dev Servers' },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteGroup()', () => {
|
||||
it('sends DELETE and refreshes the tree', async () => {
|
||||
mockFetch
|
||||
.mockResolvedValueOnce(undefined) // DELETE
|
||||
.mockResolvedValueOnce([]) // fetchTree
|
||||
|
||||
const store = useConnectionStore()
|
||||
await store.deleteGroup(3)
|
||||
|
||||
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/groups/3', { method: 'DELETE' })
|
||||
})
|
||||
})
|
||||
18
frontend/vitest.config.ts
Normal file
18
frontend/vitest.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'happy-dom',
|
||||
setupFiles: ['./tests/setup.ts'],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': resolve(__dirname, '.'),
|
||||
'@': resolve(__dirname, '.'),
|
||||
},
|
||||
},
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user