diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5a63dc50..a1bdb192 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -21,11 +21,14 @@ jobs: - name: Install dependencies run: npm ci + - name: Run Vitest Tests + run: npm run test:vi + - name: Build run: npm run build - name: Run Cypress Tests - run: npm run test + run: npm run test:cy - name: Upload Cypress Screenshots if: always() # Run this step even if tests fail @@ -36,4 +39,3 @@ jobs: cypress/screenshots/ retention-days: 7 # Keep artifacts for 7 days if-no-files-found: warn # Warn instead of fail if no screenshots found - diff --git a/cypress.config.ts b/cypress.config.ts index e891d118..4b84eeff 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,13 +1,11 @@ -import {defineConfig} from "cypress"; +import { defineConfig } from 'cypress'; -import {defineConfig as defineViteConfig} from 'vite'; +import { defineConfig as defineViteConfig } from 'vite'; import react from '@vitejs/plugin-react'; const viteConfig = defineViteConfig({ - plugins: [ - react(), - ], + plugins: [react()], }); export default defineConfig({ includeShadowDom: true, @@ -15,17 +13,10 @@ export default defineConfig({ viewportHeight: 1080, component: { devServer: { - framework: "react", - bundler: "vite", + framework: 'react', + bundler: 'vite', viteConfig: viteConfig, }, - specPattern: "**/*.test.{js,ts,jsx,tsx}", - }, - - e2e: { - baseUrl: "http://localhost:5173/", - setupNodeEvents() { - // implement node event listeners here - }, + specPattern: '**/*.cy.{js,ts,jsx,tsx}', }, }); diff --git a/package-lock.json b/package-lock.json index 174359de..3f518ca7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,8 @@ "sass-embedded": "^1.86.0", "typescript": "^5.7.3", "typescript-eslint": "^8.26.1", - "vite": "^6.3.4" + "vite": "^6.3.4", + "vitest": "^3.1.4" }, "engines": { "node": "^22.0.0", @@ -3973,6 +3974,119 @@ } } }, + "node_modules/@vitest/expect": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.4.tgz", + "integrity": "sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.4", + "@vitest/utils": "3.1.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.4.tgz", + "integrity": "sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.4.tgz", + "integrity": "sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.4.tgz", + "integrity": "sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.1.4", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.4.tgz", + "integrity": "sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.4.tgz", + "integrity": "sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.4.tgz", + "integrity": "sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.4", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@whatwg-node/disposablestack": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz", @@ -4526,6 +4640,16 @@ "node": ">=0.8" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -4986,6 +5110,16 @@ "node": ">= 0.8" } }, + "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/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -5106,6 +5240,23 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/chai": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "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": ">=12" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5200,6 +5351,16 @@ "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -5880,6 +6041,16 @@ } } }, + "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", @@ -6304,6 +6475,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -6943,6 +7121,16 @@ "node": ">=4.0" } }, + "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/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7033,6 +7221,16 @@ "node": ">=4" } }, + "node_modules/expect-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", + "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", @@ -9882,6 +10080,13 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true, + "license": "MIT" + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -9926,6 +10131,16 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -10774,6 +10989,23 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -12606,6 +12838,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": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -12744,6 +12983,13 @@ "dev": true, "license": "MIT" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -12753,6 +12999,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -13145,6 +13398,20 @@ "node": ">=16" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -13187,6 +13454,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "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": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/title-case": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz", @@ -13879,6 +14176,29 @@ } } }, + "node_modules/vite-node": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.4.tgz", + "integrity": "sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.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.4.4", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", @@ -13905,6 +14225,77 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vitest": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.4.tgz", + "integrity": "sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.1.4", + "@vitest/mocker": "3.1.4", + "@vitest/pretty-format": "^3.1.4", + "@vitest/runner": "3.1.4", + "@vitest/snapshot": "3.1.4", + "@vitest/spy": "3.1.4", + "@vitest/utils": "3.1.4", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.13", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.1.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.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.1.4", + "@vitest/ui": "3.1.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -14064,6 +14455,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 89a8e887..958ad021 100644 --- a/package.json +++ b/package.json @@ -12,15 +12,22 @@ "build": "tsc && vite build", "lint": "eslint ./src --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "test": "cypress run --component --browser chrome", - "testE2E": "cypress run --e2e --browser chrome", - "test:open": "cypress open --component --browser chrome", - "testE2E:open": "cypress open --e2e --browser chrome", + "test:vi": "vitest", + "test:cy": "cypress run --component --browser chrome", + "test:cy:open": "cypress open --component --browser chrome", "generate-graphql-types": "graphql-codegen --config graphql.config.yaml", "generate-graphql-types:watch": "graphql-codegen --config graphql.config.yaml --watch" }, "dependencies": { "@apollo/client": "^3.13.6", + "@fastify/autoload": "^6.3.0", + "@fastify/cookie": "^11.0.2", + "@fastify/env": "^5.0.2", + "@fastify/http-proxy": "^11.1.2", + "@fastify/secure-session": "^8.2.0", + "@fastify/sensible": "^6.0.3", + "@fastify/static": "^8.1.1", + "@fastify/vite": "^8.1.3", "@hookform/resolvers": "^5.0.0", "@ui5/webcomponents": "^2.7.2", "@ui5/webcomponents-fiori": "^2.7.2", @@ -30,14 +37,6 @@ "dotenv": "^16.5.0", "fastify": "^5.3.3", "fastify-plugin": "^5.0.1", - "@fastify/autoload": "^6.3.0", - "@fastify/cookie": "^11.0.2", - "@fastify/env": "^5.0.2", - "@fastify/http-proxy": "^11.1.2", - "@fastify/secure-session": "^8.2.0", - "@fastify/sensible": "^6.0.3", - "@fastify/static": "^8.1.1", - "@fastify/vite": "^8.1.3", "graphql": "^16.10.0", "graphql-config": "^5.1.3", "i18next": "^25.0.0", @@ -82,6 +81,7 @@ "sass-embedded": "^1.86.0", "typescript": "^5.7.3", "typescript-eslint": "^8.26.1", - "vite": "^6.3.4" + "vite": "^6.3.4", + "vitest": "^3.1.4" } } diff --git a/src/components/ControlPlanes/List/MembersAvatarView.tsx b/src/components/ControlPlanes/List/MembersAvatarView.tsx index e95520f7..27e4dca8 100644 --- a/src/components/ControlPlanes/List/MembersAvatarView.tsx +++ b/src/components/ControlPlanes/List/MembersAvatarView.tsx @@ -4,7 +4,7 @@ import PopoverPlacement from '@ui5/webcomponents/dist/types/PopoverPlacement.js' import { useRef, useState } from 'react'; import { MemberTable } from '../../Members/MemberTable.tsx'; import { Member } from '../../../lib/api/types/shared/members'; -import { generateInitialsForEmail } from '../../Helper/GenerateInitialsForEmail.ts'; +import { generateInitialsForEmail } from '../../Helper/generateInitialsForEmail.ts'; interface Props { project?: string; diff --git a/src/components/Core/ShellBar.tsx b/src/components/Core/ShellBar.tsx index d07940e7..df6cc3bb 100644 --- a/src/components/Core/ShellBar.tsx +++ b/src/components/Core/ShellBar.tsx @@ -16,7 +16,7 @@ import { RefObject, useEffect, useRef, useState } from 'react'; import { ShellBarProfileClickEventDetail } from '@ui5/webcomponents-fiori/dist/ShellBar.js'; import PopoverPlacement from '@ui5/webcomponents/dist/types/PopoverPlacement.js'; import { useTranslation } from 'react-i18next'; -import { generateInitialsForEmail } from '../Helper/GenerateInitialsForEmail'; +import { generateInitialsForEmail } from '../Helper/generateInitialsForEmail.ts'; import styles from './ShellBar.module.css'; import { ThemingParameters } from '@ui5/webcomponents-react-base'; diff --git a/src/components/Dialogs/CreateProjectDialog.test.tsx b/src/components/Dialogs/CreateProjectDialog.cy.tsx similarity index 100% rename from src/components/Dialogs/CreateProjectDialog.test.tsx rename to src/components/Dialogs/CreateProjectDialog.cy.tsx diff --git a/src/components/Dialogs/DeleteConfirmationDialog.test.tsx b/src/components/Dialogs/DeleteConfirmationDialog.cy.tsx similarity index 100% rename from src/components/Dialogs/DeleteConfirmationDialog.test.tsx rename to src/components/Dialogs/DeleteConfirmationDialog.cy.tsx diff --git a/src/components/Helper/generateInitialsForEmail.spec.ts b/src/components/Helper/generateInitialsForEmail.spec.ts new file mode 100644 index 00000000..ba2418d3 --- /dev/null +++ b/src/components/Helper/generateInitialsForEmail.spec.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from 'vitest'; +import { generateInitialsForEmail } from './generateInitialsForEmail.ts'; + +describe('generateInitialsForEmail', () => { + it('should generate initials from a standard email', () => { + expect(generateInitialsForEmail('first.last@example.com')).toBe('FL'); + }); + + it('should generate initials from an email with a single-part name', () => { + expect(generateInitialsForEmail('firstlast@example.com')).toBe('F'); + }); + + it('should generate initials from an email with multiple name parts', () => { + expect(generateInitialsForEmail('first.middle.last@example.com')).toBe( + 'FML', + ); + }); + + it('should truncate to 3 initials if more than 3 name parts exist', () => { + expect( + generateInitialsForEmail('first.second.third.extra@example.com'), + ).toBe('FST'); + }); + + it('should handle emails where the name part is short', () => { + expect(generateInitialsForEmail('a.b@example.com')).toBe('AB'); + expect(generateInitialsForEmail('x@example.com')).toBe('X'); + }); + + it('should convert initials to uppercase', () => { + expect(generateInitialsForEmail('first.last@example.com')).toBe('FL'); + expect(generateInitialsForEmail('FiRsT.lAsT@example.com')).toBe('FL'); + }); + + it('should handle emails with numbers in the name part', () => { + expect(generateInitialsForEmail('first1.last2@example.com')).toBe('FL'); + expect(generateInitialsForEmail('1first.2last@example.com')).toBe('12'); + }); + + it('should handle emails with leading/trailing dots in the name part gracefully', () => { + expect(generateInitialsForEmail('.leading.dot@example.com')).toBe('LD'); + expect(generateInitialsForEmail('trailing.dot.@example.com')).toBe('TD'); + expect(generateInitialsForEmail('double..dot@example.com')).toBe('DD'); + }); + + it('should return an empty string for undefined input', () => { + expect(generateInitialsForEmail(undefined)).toBe(''); + }); + + it('should return an empty string for an empty string input', () => { + expect(generateInitialsForEmail('')).toBe(''); + }); +}); diff --git a/src/components/Helper/GenerateInitialsForEmail.ts b/src/components/Helper/generateInitialsForEmail.ts similarity index 100% rename from src/components/Helper/GenerateInitialsForEmail.ts rename to src/components/Helper/generateInitialsForEmail.ts diff --git a/src/components/Members/EditMembers.test.tsx b/src/components/Members/EditMembers.cy.tsx similarity index 100% rename from src/components/Members/EditMembers.test.tsx rename to src/components/Members/EditMembers.cy.tsx diff --git a/src/components/Members/MemberRoleSelect.test.tsx b/src/components/Members/MemberRoleSelect.cy.tsx similarity index 100% rename from src/components/Members/MemberRoleSelect.test.tsx rename to src/components/Members/MemberRoleSelect.cy.tsx diff --git a/src/components/Ui/IllustratedBanner/IllustratedBanner.test.tsx b/src/components/Ui/IllustratedBanner/IllustratedBanner.cy.tsx similarity index 100% rename from src/components/Ui/IllustratedBanner/IllustratedBanner.test.tsx rename to src/components/Ui/IllustratedBanner/IllustratedBanner.cy.tsx