mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-18 06:13:52 +02:00
add test
This commit is contained in:
448
package-lock.json
generated
448
package-lock.json
generated
@@ -33,6 +33,7 @@
|
||||
"@vee-validate/zod": "^4.15.1",
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"animate.css": "^4.1.1",
|
||||
@@ -70,7 +71,7 @@
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"vee-validate": "^4.15.1",
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest": "^4.0.18",
|
||||
"vue": "^3.5.29",
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-i18n": "^11.2.8",
|
||||
@@ -590,6 +591,16 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bcoe/v8-coverage": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
|
||||
"integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@bramus/specificity": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz",
|
||||
@@ -3755,6 +3766,13 @@
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"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/@swc/helpers": {
|
||||
"version": "0.5.18",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
|
||||
@@ -4381,40 +4399,72 @@
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
|
||||
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz",
|
||||
"integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^1.0.2",
|
||||
"@vitest/utils": "4.0.18",
|
||||
"ast-v8-to-istanbul": "^0.3.10",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.2.0",
|
||||
"magicast": "^0.5.1",
|
||||
"obug": "^2.1.1",
|
||||
"std-env": "^3.10.0",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/browser": "4.0.18",
|
||||
"vitest": "4.0.18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vitest/browser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": "3.2.4",
|
||||
"@vitest/utils": "3.2.4",
|
||||
"chai": "^5.2.0",
|
||||
"tinyrainbow": "^2.0.0"
|
||||
"@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": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
|
||||
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
|
||||
"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": "3.2.4",
|
||||
"@vitest/spy": "4.0.18",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.17"
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"msw": "^2.4.9",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
||||
"vite": "^6.0.0 || ^7.0.0-0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"msw": {
|
||||
@@ -4446,42 +4496,41 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
|
||||
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
|
||||
"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": "^2.0.0"
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
|
||||
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
|
||||
"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": "3.2.4",
|
||||
"pathe": "^2.0.3",
|
||||
"strip-literal": "^3.0.0"
|
||||
"@vitest/utils": "4.0.18",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
|
||||
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
|
||||
"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": "3.2.4",
|
||||
"magic-string": "^0.30.17",
|
||||
"@vitest/pretty-format": "4.0.18",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -4499,28 +4548,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
|
||||
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"tinyspy": "^4.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
|
||||
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
|
||||
"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": "3.2.4",
|
||||
"loupe": "^3.1.4",
|
||||
"tinyrainbow": "^2.0.0"
|
||||
"@vitest/pretty-format": "4.0.18",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
@@ -5160,6 +5205,35 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-v8-to-istanbul": {
|
||||
"version": "0.3.12",
|
||||
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz",
|
||||
"integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.31",
|
||||
"estree-walker": "^3.0.3",
|
||||
"js-tokens": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-v8-to-istanbul/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/ast-v8-to-istanbul/node_modules/js-tokens": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
|
||||
"integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/astral-regex": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
|
||||
@@ -5526,16 +5600,6 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cac": {
|
||||
"version": "6.7.14",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cacache": {
|
||||
"version": "19.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz",
|
||||
@@ -5650,18 +5714,11 @@
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
|
||||
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
|
||||
"integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"assertion-error": "^2.0.1",
|
||||
"check-error": "^2.1.1",
|
||||
"deep-eql": "^5.0.1",
|
||||
"loupe": "^3.1.0",
|
||||
"pathval": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5683,16 +5740,6 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/check-error": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
|
||||
"integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
@@ -6272,16 +6319,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-eql": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
|
||||
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -8272,6 +8309,13 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"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==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
@@ -8595,6 +8639,45 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/istanbul-lib-coverage": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
|
||||
"integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"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-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/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
@@ -9234,13 +9317,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/loupe": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
|
||||
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||
@@ -9284,6 +9360,34 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/magicast": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz",
|
||||
"integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.29.0",
|
||||
"@babel/types": "^7.29.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"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": "14.0.3",
|
||||
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz",
|
||||
@@ -9886,6 +9990,17 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"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/ohash": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
|
||||
@@ -10173,16 +10288,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pathval": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
|
||||
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.16"
|
||||
}
|
||||
},
|
||||
"node_modules/pe-library": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz",
|
||||
@@ -11701,26 +11806,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-literal": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
|
||||
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^9.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-literal/node_modules/js-tokens": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
|
||||
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sumchecker": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||
@@ -11957,11 +12042,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
||||
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
|
||||
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
@@ -12011,30 +12099,10 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
|
||||
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyrainbow": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
|
||||
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyspy": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
|
||||
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
|
||||
"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": {
|
||||
@@ -12483,29 +12551,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite-node": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
|
||||
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cac": "^6.7.14",
|
||||
"debug": "^4.4.1",
|
||||
"es-module-lexer": "^1.7.0",
|
||||
"pathe": "^2.0.3",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
||||
},
|
||||
"bin": {
|
||||
"vite-node": "vite-node.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
@@ -12538,51 +12583,50 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz",
|
||||
"integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
"@vitest/mocker": "3.2.4",
|
||||
"@vitest/pretty-format": "^3.2.4",
|
||||
"@vitest/runner": "3.2.4",
|
||||
"@vitest/snapshot": "3.2.4",
|
||||
"@vitest/spy": "3.2.4",
|
||||
"@vitest/utils": "3.2.4",
|
||||
"chai": "^5.2.0",
|
||||
"debug": "^4.4.1",
|
||||
"expect-type": "^1.2.1",
|
||||
"magic-string": "^0.30.17",
|
||||
"@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.2",
|
||||
"std-env": "^3.9.0",
|
||||
"picomatch": "^4.0.3",
|
||||
"std-env": "^3.10.0",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^0.3.2",
|
||||
"tinyglobby": "^0.2.14",
|
||||
"tinypool": "^1.1.1",
|
||||
"tinyrainbow": "^2.0.0",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
|
||||
"vite-node": "3.2.4",
|
||||
"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": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"@vitest/browser": "3.2.4",
|
||||
"@vitest/ui": "3.2.4",
|
||||
"@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": "*"
|
||||
},
|
||||
@@ -12590,13 +12634,19 @@
|
||||
"@edge-runtime/vm": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/debug": {
|
||||
"@opentelemetry/api": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser": {
|
||||
"@vitest/browser-playwright": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser-preview": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser-webdriverio": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/ui": {
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"@vee-validate/zod": "^4.15.1",
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"animate.css": "^4.1.1",
|
||||
@@ -90,7 +91,7 @@
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"vee-validate": "^4.15.1",
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest": "^4.0.18",
|
||||
"vue": "^3.5.29",
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-i18n": "^11.2.8",
|
||||
|
||||
@@ -264,6 +264,13 @@
|
||||
} from '../pagination';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
|
||||
import {
|
||||
getColStyle,
|
||||
getToggleableColumns,
|
||||
isReorderable as isReorderableHelper,
|
||||
isSpacer,
|
||||
resolveHeaderLabel
|
||||
} from './dataTableHelpers.js';
|
||||
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuTrigger } from '../context-menu';
|
||||
|
||||
import DataTableEmpty from './DataTableEmpty.vue';
|
||||
@@ -396,20 +403,7 @@
|
||||
return null;
|
||||
};
|
||||
|
||||
const isSpacer = (col) => col?.id === '__spacer';
|
||||
|
||||
const isStretch = (col) => {
|
||||
return !!col?.columnDef?.meta?.stretch;
|
||||
};
|
||||
|
||||
const isReorderable = (header) => {
|
||||
const col = header?.column;
|
||||
if (!col) return false;
|
||||
if (isSpacer(col)) return false;
|
||||
if (getPinnedState(col)) return false;
|
||||
if (col.columnDef?.meta?.disableReorder) return false;
|
||||
return true;
|
||||
};
|
||||
const isReorderable = (header) => isReorderableHelper(header, getPinnedState);
|
||||
|
||||
const reorderableIndex = (headers, actualIndex) => {
|
||||
let sortableIdx = 0;
|
||||
@@ -463,33 +457,9 @@
|
||||
|
||||
const toggleableColumns = computed(() => {
|
||||
const cols = props.table?.getAllLeafColumns?.() ?? [];
|
||||
return cols.filter((col) => {
|
||||
if (isSpacer(col)) return false;
|
||||
if (isStretch(col)) return false;
|
||||
if (col.columnDef?.meta?.disableVisibilityToggle) return false;
|
||||
if (!col.columnDef?.meta?.label) return false;
|
||||
return true;
|
||||
});
|
||||
return getToggleableColumns(cols);
|
||||
});
|
||||
|
||||
const resolveHeaderLabel = (col) => {
|
||||
const label = col?.columnDef?.meta?.label;
|
||||
if (typeof label === 'function') return label();
|
||||
return label ?? col?.id ?? '';
|
||||
};
|
||||
|
||||
const getColStyle = (col) => {
|
||||
if (isSpacer(col)) return { width: '0px' };
|
||||
|
||||
if (isStretch(col)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const size = col?.getSize?.();
|
||||
if (!Number.isFinite(size)) return null;
|
||||
return { width: `${size}px` };
|
||||
};
|
||||
|
||||
const getHeaderClass = (header) => {
|
||||
const columnDef = header?.column?.columnDef;
|
||||
const meta = columnDef?.meta ?? {};
|
||||
|
||||
184
src/components/ui/data-table/__tests__/dataTableHelpers.test.js
Normal file
184
src/components/ui/data-table/__tests__/dataTableHelpers.test.js
Normal file
@@ -0,0 +1,184 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
getColStyle,
|
||||
getToggleableColumns,
|
||||
isReorderable,
|
||||
isSpacer,
|
||||
isStretch,
|
||||
resolveHeaderLabel
|
||||
} from '../dataTableHelpers';
|
||||
|
||||
// Helper to create a mock TanStack column instance
|
||||
const mockCol = (id, meta = {}, overrides = {}) => ({
|
||||
id,
|
||||
columnDef: { meta },
|
||||
...overrides
|
||||
});
|
||||
|
||||
describe('isSpacer', () => {
|
||||
it('returns true for __spacer column', () => {
|
||||
expect(isSpacer({ id: '__spacer' })).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for regular column', () => {
|
||||
expect(isSpacer({ id: 'name' })).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for null/undefined', () => {
|
||||
expect(isSpacer(null)).toBe(false);
|
||||
expect(isSpacer(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isStretch', () => {
|
||||
it('returns true when meta.stretch is true', () => {
|
||||
expect(isStretch(mockCol('detail', { stretch: true }))).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when meta.stretch is absent', () => {
|
||||
expect(isStretch(mockCol('name'))).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for null column', () => {
|
||||
expect(isStretch(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveHeaderLabel', () => {
|
||||
it('returns string label from meta', () => {
|
||||
expect(resolveHeaderLabel(mockCol('name', { label: 'Name' }))).toBe(
|
||||
'Name'
|
||||
);
|
||||
});
|
||||
|
||||
it('calls function label and returns result', () => {
|
||||
const col = mockCol('name', { label: () => 'Translated Name' });
|
||||
expect(resolveHeaderLabel(col)).toBe('Translated Name');
|
||||
});
|
||||
|
||||
it('falls back to column id when no label', () => {
|
||||
expect(resolveHeaderLabel(mockCol('displayName'))).toBe('displayName');
|
||||
});
|
||||
|
||||
it('returns empty string for null column', () => {
|
||||
expect(resolveHeaderLabel(null)).toBe('');
|
||||
});
|
||||
|
||||
it('returns empty string for undefined column', () => {
|
||||
expect(resolveHeaderLabel(undefined)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToggleableColumns', () => {
|
||||
it('includes columns with meta.label', () => {
|
||||
const cols = [mockCol('name', { label: 'Name' })];
|
||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('excludes spacer columns', () => {
|
||||
const cols = [
|
||||
mockCol('name', { label: 'Name' }),
|
||||
{ id: '__spacer', columnDef: { meta: { label: 'Spacer' } } }
|
||||
];
|
||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
||||
expect(getToggleableColumns(cols)[0].id).toBe('name');
|
||||
});
|
||||
|
||||
it('excludes stretch columns', () => {
|
||||
const cols = [
|
||||
mockCol('name', { label: 'Name' }),
|
||||
mockCol('detail', { stretch: true, label: 'Detail' })
|
||||
];
|
||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('excludes columns with disableVisibilityToggle', () => {
|
||||
const cols = [
|
||||
mockCol('name', { label: 'Name' }),
|
||||
mockCol('hidden', {
|
||||
label: 'Hidden',
|
||||
disableVisibilityToggle: true
|
||||
})
|
||||
];
|
||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('excludes columns without meta.label', () => {
|
||||
const cols = [
|
||||
mockCol('name', { label: 'Name' }),
|
||||
mockCol('icon'),
|
||||
mockCol('expand', {})
|
||||
];
|
||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('returns empty array for non-array input', () => {
|
||||
expect(getToggleableColumns(null)).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns empty array when all columns are excluded', () => {
|
||||
const cols = [
|
||||
{ id: '__spacer', columnDef: { meta: {} } },
|
||||
mockCol('icon')
|
||||
];
|
||||
expect(getToggleableColumns(cols)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getColStyle', () => {
|
||||
it('returns width 0px for spacer column', () => {
|
||||
expect(getColStyle({ id: '__spacer' })).toEqual({ width: '0px' });
|
||||
});
|
||||
|
||||
it('returns null for stretch column', () => {
|
||||
expect(getColStyle(mockCol('detail', { stretch: true }))).toBeNull();
|
||||
});
|
||||
|
||||
it('returns width from getSize()', () => {
|
||||
const col = { ...mockCol('name'), getSize: () => 200 };
|
||||
expect(getColStyle(col)).toEqual({ width: '200px' });
|
||||
});
|
||||
|
||||
it('returns null when getSize returns non-finite', () => {
|
||||
const col = { ...mockCol('name'), getSize: () => NaN };
|
||||
expect(getColStyle(col)).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null when getSize is missing', () => {
|
||||
expect(getColStyle(mockCol('name'))).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isReorderable', () => {
|
||||
const noPinning = () => false;
|
||||
|
||||
it('returns true for normal column', () => {
|
||||
const header = { column: mockCol('name') };
|
||||
expect(isReorderable(header, noPinning)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for spacer column', () => {
|
||||
const header = { column: { id: '__spacer', columnDef: { meta: {} } } };
|
||||
expect(isReorderable(header, noPinning)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for pinned column', () => {
|
||||
const header = { column: mockCol('name') };
|
||||
const isPinned = () => true;
|
||||
expect(isReorderable(header, isPinned)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for columns with disableReorder', () => {
|
||||
const header = { column: mockCol('name', { disableReorder: true }) };
|
||||
expect(isReorderable(header, noPinning)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for null header', () => {
|
||||
expect(isReorderable(null, noPinning)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for header without column', () => {
|
||||
expect(isReorderable({}, noPinning)).toBe(false);
|
||||
});
|
||||
});
|
||||
77
src/components/ui/data-table/dataTableHelpers.js
Normal file
77
src/components/ui/data-table/dataTableHelpers.js
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Pure helper functions for DataTableLayout.
|
||||
* Extracted for testability.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {object} col - TanStack column instance
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isSpacer(col) {
|
||||
return col?.id === '__spacer';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} col - TanStack column instance
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isStretch(col) {
|
||||
return !!col?.columnDef?.meta?.stretch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a column's display label for the visibility menu.
|
||||
* Supports both string and function labels (for lazy i18n).
|
||||
* @param {object} col - TanStack column instance
|
||||
* @returns {string}
|
||||
*/
|
||||
export function resolveHeaderLabel(col) {
|
||||
const label = col?.columnDef?.meta?.label;
|
||||
if (typeof label === 'function') return label();
|
||||
return label ?? col?.id ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters columns to determine which are toggleable in the visibility menu.
|
||||
* @param {Array} cols - Array of TanStack column instances
|
||||
* @returns {Array}
|
||||
*/
|
||||
export function getToggleableColumns(cols) {
|
||||
if (!Array.isArray(cols)) return [];
|
||||
return cols.filter((col) => {
|
||||
if (isSpacer(col)) return false;
|
||||
if (isStretch(col)) return false;
|
||||
if (col.columnDef?.meta?.disableVisibilityToggle) return false;
|
||||
if (!col.columnDef?.meta?.label) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the style object for a column's <col> element.
|
||||
* @param {object} col - TanStack column instance
|
||||
* @returns {object|null}
|
||||
*/
|
||||
export function getColStyle(col) {
|
||||
if (isSpacer(col)) return { width: '0px' };
|
||||
if (isStretch(col)) return null;
|
||||
|
||||
const size = col?.getSize?.();
|
||||
if (!Number.isFinite(size)) return null;
|
||||
return { width: `${size}px` };
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a header can be reordered via drag-and-drop.
|
||||
* @param {object} header - TanStack header instance
|
||||
* @param {function} getPinnedState - function to check if column is pinned
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isReorderable(header, getPinnedState) {
|
||||
const col = header?.column;
|
||||
if (!col) return false;
|
||||
if (isSpacer(col)) return false;
|
||||
if (getPinnedState?.(col)) return false;
|
||||
if (col.columnDef?.meta?.disableReorder) return false;
|
||||
return true;
|
||||
}
|
||||
234
src/lib/table/__tests__/useVrcxVueTable.utils.test.js
Normal file
234
src/lib/table/__tests__/useVrcxVueTable.utils.test.js
Normal file
@@ -0,0 +1,234 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
filterOrderByColumns,
|
||||
filterSizingByColumns,
|
||||
filterSortingByColumns,
|
||||
filterVisibilityByColumns,
|
||||
findStretchColumnId,
|
||||
getColumnId,
|
||||
safeJsonParse,
|
||||
withSpacerColumn
|
||||
} from '../useVrcxVueTable';
|
||||
|
||||
const cols = (...ids) => ids.map((id) => ({ id }));
|
||||
|
||||
describe('safeJsonParse', () => {
|
||||
it('parses valid JSON', () => {
|
||||
expect(safeJsonParse('{"a":1}')).toEqual({ a: 1 });
|
||||
});
|
||||
|
||||
it('returns null for invalid JSON', () => {
|
||||
expect(safeJsonParse('not json')).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for empty string', () => {
|
||||
expect(safeJsonParse('')).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for null/undefined', () => {
|
||||
expect(safeJsonParse(null)).toBeNull();
|
||||
expect(safeJsonParse(undefined)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterSizingByColumns', () => {
|
||||
it('keeps only keys matching column IDs', () => {
|
||||
const sizing = { name: 200, date: 150, removed: 100 };
|
||||
expect(filterSizingByColumns(sizing, cols('name', 'date'))).toEqual({
|
||||
name: 200,
|
||||
date: 150
|
||||
});
|
||||
});
|
||||
|
||||
it('returns empty object for null sizing', () => {
|
||||
expect(filterSizingByColumns(null, cols('a'))).toEqual({});
|
||||
});
|
||||
|
||||
it('returns empty object for non-object sizing', () => {
|
||||
expect(filterSizingByColumns('bad', cols('a'))).toEqual({});
|
||||
});
|
||||
|
||||
it('returns empty object for null columns', () => {
|
||||
expect(filterSizingByColumns({ a: 1 }, null)).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterSortingByColumns', () => {
|
||||
it('keeps entries with valid column IDs', () => {
|
||||
const sorting = [
|
||||
{ id: 'name', desc: false },
|
||||
{ id: 'removed', desc: true }
|
||||
];
|
||||
expect(filterSortingByColumns(sorting, cols('name', 'date'))).toEqual([
|
||||
{ id: 'name', desc: false }
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns empty array for non-array input', () => {
|
||||
expect(filterSortingByColumns(null, cols('a'))).toEqual([]);
|
||||
expect(filterSortingByColumns('bad', cols('a'))).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns empty array for null columns', () => {
|
||||
expect(
|
||||
filterSortingByColumns([{ id: 'a', desc: false }], null)
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterOrderByColumns', () => {
|
||||
it('keeps IDs present in columns', () => {
|
||||
expect(
|
||||
filterOrderByColumns(
|
||||
['date', 'removed', 'name'],
|
||||
cols('name', 'date')
|
||||
)
|
||||
).toEqual(['date', 'name']);
|
||||
});
|
||||
|
||||
it('returns empty array for non-array input', () => {
|
||||
expect(filterOrderByColumns(null, cols('a'))).toEqual([]);
|
||||
expect(filterOrderByColumns({}, cols('a'))).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns empty array for null columns', () => {
|
||||
expect(filterOrderByColumns(['a'], null)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterVisibilityByColumns', () => {
|
||||
it('keeps keys matching column IDs', () => {
|
||||
const vis = { name: false, removed: true, date: false };
|
||||
expect(filterVisibilityByColumns(vis, cols('name', 'date'))).toEqual({
|
||||
name: false,
|
||||
date: false
|
||||
});
|
||||
});
|
||||
|
||||
it('returns empty object for null visibility', () => {
|
||||
expect(filterVisibilityByColumns(null, cols('a'))).toEqual({});
|
||||
});
|
||||
|
||||
it('returns empty object for non-object visibility', () => {
|
||||
expect(filterVisibilityByColumns(42, cols('a'))).toEqual({});
|
||||
});
|
||||
|
||||
it('returns empty object for null columns', () => {
|
||||
expect(filterVisibilityByColumns({ a: true }, null)).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getColumnId', () => {
|
||||
it('returns id when present', () => {
|
||||
expect(getColumnId({ id: 'foo' })).toBe('foo');
|
||||
});
|
||||
|
||||
it('falls back to accessorKey', () => {
|
||||
expect(getColumnId({ accessorKey: 'bar' })).toBe('bar');
|
||||
});
|
||||
|
||||
it('prefers id over accessorKey', () => {
|
||||
expect(getColumnId({ id: 'foo', accessorKey: 'bar' })).toBe('foo');
|
||||
});
|
||||
|
||||
it('returns null for null/undefined', () => {
|
||||
expect(getColumnId(null)).toBeNull();
|
||||
expect(getColumnId(undefined)).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for empty object', () => {
|
||||
expect(getColumnId({})).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('findStretchColumnId', () => {
|
||||
it('returns the ID of the stretch column', () => {
|
||||
const columns = [
|
||||
{ id: 'a' },
|
||||
{ id: 'b', meta: { stretch: true } },
|
||||
{ id: 'c' }
|
||||
];
|
||||
expect(findStretchColumnId(columns)).toBe('b');
|
||||
});
|
||||
|
||||
it('returns first stretch column when multiple exist', () => {
|
||||
const columns = [
|
||||
{ id: 'x', meta: { stretch: true } },
|
||||
{ id: 'y', meta: { stretch: true } }
|
||||
];
|
||||
expect(findStretchColumnId(columns)).toBe('x');
|
||||
});
|
||||
|
||||
it('returns null when no stretch column exists', () => {
|
||||
expect(findStretchColumnId([{ id: 'a' }, { id: 'b' }])).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for non-array input', () => {
|
||||
expect(findStretchColumnId(null)).toBeNull();
|
||||
expect(findStretchColumnId('bad')).toBeNull();
|
||||
});
|
||||
|
||||
it('falls back to accessorKey for stretch column', () => {
|
||||
const columns = [{ accessorKey: 'detail', meta: { stretch: true } }];
|
||||
expect(findStretchColumnId(columns)).toBe('detail');
|
||||
});
|
||||
});
|
||||
|
||||
describe('withSpacerColumn', () => {
|
||||
const baseCols = [{ id: 'a' }, { id: 'b' }];
|
||||
|
||||
it('appends spacer column at the end when no stretchAfterId', () => {
|
||||
const result = withSpacerColumn(baseCols, true);
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[2].id).toBe('__spacer');
|
||||
});
|
||||
|
||||
it('uses custom spacerId', () => {
|
||||
const result = withSpacerColumn(baseCols, true, 'custom_spacer');
|
||||
expect(result[2].id).toBe('custom_spacer');
|
||||
});
|
||||
|
||||
it('inserts spacer after stretchAfterId column', () => {
|
||||
const columns = [{ id: 'x' }, { id: 'stretch' }, { id: 'y' }];
|
||||
const result = withSpacerColumn(columns, true, '__spacer', 'stretch');
|
||||
expect(result.map((c) => c.id)).toEqual([
|
||||
'x',
|
||||
'stretch',
|
||||
'__spacer',
|
||||
'y'
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns original columns when disabled', () => {
|
||||
const result = withSpacerColumn(baseCols, false);
|
||||
expect(result).toBe(baseCols);
|
||||
});
|
||||
|
||||
it('does not add duplicate spacer', () => {
|
||||
const columns = [{ id: 'a' }, { id: '__spacer' }];
|
||||
const result = withSpacerColumn(columns, true);
|
||||
expect(result).toBe(columns);
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('returns non-array input as-is', () => {
|
||||
expect(withSpacerColumn(null, true)).toBeNull();
|
||||
});
|
||||
|
||||
it('appends spacer when stretchAfterId not found', () => {
|
||||
const result = withSpacerColumn(baseCols, true, '__spacer', 'missing');
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[2].id).toBe('__spacer');
|
||||
});
|
||||
|
||||
it('spacer column has correct defaults', () => {
|
||||
const result = withSpacerColumn(baseCols, true);
|
||||
const spacer = result[2];
|
||||
expect(spacer.enableSorting).toBe(false);
|
||||
expect(spacer.size).toBe(0);
|
||||
expect(spacer.minSize).toBe(0);
|
||||
expect(spacer.header()).toBeNull();
|
||||
expect(spacer.cell()).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import { computed, ref, unref, watch } from 'vue';
|
||||
*
|
||||
* @param str
|
||||
*/
|
||||
function safeJsonParse(str) {
|
||||
export function safeJsonParse(str) {
|
||||
if (!str) {
|
||||
return null;
|
||||
}
|
||||
@@ -44,7 +44,7 @@ function debounce(fn, wait) {
|
||||
* @param sizing
|
||||
* @param columns
|
||||
*/
|
||||
function filterSizingByColumns(sizing, columns) {
|
||||
export function filterSizingByColumns(sizing, columns) {
|
||||
if (!sizing || typeof sizing !== 'object') {
|
||||
return {};
|
||||
}
|
||||
@@ -63,7 +63,7 @@ function filterSizingByColumns(sizing, columns) {
|
||||
* @param sorting
|
||||
* @param columns
|
||||
*/
|
||||
function filterSortingByColumns(sorting, columns) {
|
||||
export function filterSortingByColumns(sorting, columns) {
|
||||
if (!Array.isArray(sorting)) {
|
||||
return [];
|
||||
}
|
||||
@@ -76,7 +76,7 @@ function filterSortingByColumns(sorting, columns) {
|
||||
* @param order
|
||||
* @param columns
|
||||
*/
|
||||
function filterOrderByColumns(order, columns) {
|
||||
export function filterOrderByColumns(order, columns) {
|
||||
if (!Array.isArray(order)) {
|
||||
return [];
|
||||
}
|
||||
@@ -89,7 +89,7 @@ function filterOrderByColumns(order, columns) {
|
||||
* @param visibility
|
||||
* @param columns
|
||||
*/
|
||||
function filterVisibilityByColumns(visibility, columns) {
|
||||
export function filterVisibilityByColumns(visibility, columns) {
|
||||
if (!visibility || typeof visibility !== 'object') {
|
||||
return {};
|
||||
}
|
||||
@@ -107,7 +107,7 @@ function filterVisibilityByColumns(visibility, columns) {
|
||||
*
|
||||
* @param col
|
||||
*/
|
||||
function getColumnId(col) {
|
||||
export function getColumnId(col) {
|
||||
return col?.id ?? col?.accessorKey ?? null;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ function getColumnId(col) {
|
||||
*
|
||||
* @param columns
|
||||
*/
|
||||
function findStretchColumnId(columns) {
|
||||
export function findStretchColumnId(columns) {
|
||||
if (!Array.isArray(columns)) {
|
||||
return null;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ function resolveMaybeGetter(func) {
|
||||
* @param spacerId
|
||||
* @param stretchAfterId
|
||||
*/
|
||||
function withSpacerColumn(columns, enabled, spacerId, stretchAfterId) {
|
||||
export function withSpacerColumn(columns, enabled, spacerId, stretchAfterId) {
|
||||
if (!enabled) {
|
||||
return columns;
|
||||
}
|
||||
|
||||
45
src/shared/utils/base/__tests__/ui.test.js
Normal file
45
src/shared/utils/base/__tests__/ui.test.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { HSVtoRGB } from '../ui';
|
||||
|
||||
describe('HSVtoRGB', () => {
|
||||
it('converts pure red (h=0, s=1, v=1)', () => {
|
||||
expect(HSVtoRGB(0, 1, 1)).toBe('#ff0000');
|
||||
});
|
||||
|
||||
it('converts pure green (h=0.333, s=1, v=1)', () => {
|
||||
const result = HSVtoRGB(1 / 3, 1, 1);
|
||||
expect(result).toBe('#00ff00');
|
||||
});
|
||||
|
||||
it('converts pure blue (h=0.667, s=1, v=1)', () => {
|
||||
const result = HSVtoRGB(2 / 3, 1, 1);
|
||||
expect(result).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('converts white (s=0, v=1)', () => {
|
||||
expect(HSVtoRGB(0, 0, 1)).toBe('#ffffff');
|
||||
});
|
||||
|
||||
it('converts black (v=0)', () => {
|
||||
expect(HSVtoRGB(0, 1, 0)).toBe('#000000');
|
||||
});
|
||||
|
||||
it('converts yellow (h=1/6, s=1, v=1)', () => {
|
||||
expect(HSVtoRGB(1 / 6, 1, 1)).toBe('#ffff00');
|
||||
});
|
||||
|
||||
it('converts cyan (h=0.5, s=1, v=1)', () => {
|
||||
expect(HSVtoRGB(0.5, 1, 1)).toBe('#00ffff');
|
||||
});
|
||||
|
||||
it('handles object argument { h, s, v }', () => {
|
||||
expect(HSVtoRGB({ h: 0, s: 1, v: 1 })).toBe('#ff0000');
|
||||
});
|
||||
|
||||
it('converts a mid-range value', () => {
|
||||
const result = HSVtoRGB(0, 0, 0.5);
|
||||
// gray: rgb(128,128,128)
|
||||
expect(result).toBe('#808080');
|
||||
});
|
||||
});
|
||||
@@ -75,7 +75,7 @@ export function getColumns({
|
||||
'h-4 w-4',
|
||||
isActive
|
||||
? 'text-primary'
|
||||
: 'text-muted-foreground/0 group-hover/row:text-muted-foreground/40'
|
||||
: 'text-muted-foreground/0 group-hover/row:text-muted-foreground'
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,13 @@ globalThis.LogWatcher = new Proxy({}, { get: () => noopAsync });
|
||||
globalThis.Discord = new Proxy({}, { get: () => noopAsync });
|
||||
globalThis.AssetBundleManager = new Proxy({}, { get: () => noopAsync });
|
||||
|
||||
// ResizeObserver polyfill (needed by @dnd-kit/vue at import time)
|
||||
globalThis.ResizeObserver ??= class {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
};
|
||||
|
||||
// Browser API stubs not available in jsdom
|
||||
globalThis.speechSynthesis = {
|
||||
getVoices: () => [],
|
||||
|
||||
Reference in New Issue
Block a user