From da798720bf38610505b29dcabf0d863651ac8426 Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Sun, 9 Feb 2025 18:36:57 +0100 Subject: [PATCH 1/6] feat: add vitest coverage --- package.json | 2 + pnpm-lock.yaml | 217 ++++++++++++++++++++++++++++++++++++++-- src/app/layout.test.tsx | 33 ++++++ src/app/lib/utils.ts | 6 -- src/lib/utils.test.ts | 25 +++++ vitest.config.mts | 14 ++- 6 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 src/app/layout.test.tsx delete mode 100644 src/app/lib/utils.ts create mode 100644 src/lib/utils.test.ts diff --git a/package.json b/package.json index f4eb04c..56a97bf 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "@types/react": "19.0.8", "@types/react-dom": "19.0.3", "@vitejs/plugin-react": "4.3.4", + "@vitest/coverage-v8": "3.0.4", + "@vitest/ui": "3.0.4", "autoprefixer": "10.4.20", "commitizen": "4.3.1", "eslint": "9.19.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a03a5b8..b9f736a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,6 +90,12 @@ importers: '@vitejs/plugin-react': specifier: 4.3.4 version: 4.3.4(vite@5.4.11(@types/node@22.13.0)(lightningcss@1.29.1)) + '@vitest/coverage-v8': + specifier: 3.0.4 + version: 3.0.4(vitest@3.0.4) + '@vitest/ui': + specifier: 3.0.4 + version: 3.0.4(vitest@3.0.4) autoprefixer: specifier: 10.4.20 version: 10.4.20(postcss@8.5.1) @@ -158,7 +164,7 @@ importers: version: 5.1.4(typescript@5.7.3)(vite@5.4.11(@types/node@22.13.0)(lightningcss@1.29.1)) vitest: specifier: 3.0.4 - version: 3.0.4(@types/node@22.13.0)(jsdom@26.0.0)(lightningcss@1.29.1) + version: 3.0.4(@types/node@22.13.0)(@vitest/ui@3.0.4)(jsdom@26.0.0)(lightningcss@1.29.1) packages: @@ -307,6 +313,10 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -775,6 +785,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -932,6 +946,9 @@ packages: resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==} engines: {node: '>=12'} + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + '@remcolakens/simple-component-generator@1.0.5': resolution: {integrity: sha512-74eqNRw0mtF0k6L5VDgqm9bpoJuP5Oiw84def3s1GnE7tgQZdFPpdHKx9KhRSDKqACVNAUQDtKrdNpqoEnGz2Q==} hasBin: true @@ -1324,6 +1341,15 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@vitest/coverage-v8@3.0.4': + resolution: {integrity: sha512-f0twgRCHgbs24Dp8cLWagzcObXMcuKtAwgxjJV/nnysPAJJk1JiKu/W0gIehZLmkljhJXU/E0/dmuQzsA/4jhA==} + peerDependencies: + '@vitest/browser': 3.0.4 + vitest: 3.0.4 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@3.0.4': resolution: {integrity: sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==} @@ -1350,6 +1376,11 @@ packages: '@vitest/spy@3.0.4': resolution: {integrity: sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==} + '@vitest/ui@3.0.4': + resolution: {integrity: sha512-e+s2F9e9FUURkZ5aFIe1Fi3Y8M7UF6gEuShcaV/ur7y/Ldri+1tzWQ1TJq9Vas42NXnXvCAIrU39Z4U2RyET6g==} + peerDependencies: + vitest: 3.0.4 + '@vitest/utils@3.0.4': resolution: {integrity: sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==} @@ -2366,10 +2397,21 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@2.0.0: resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} engines: {node: '>=4'} @@ -2427,6 +2469,9 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -2666,6 +2711,9 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -2978,6 +3026,22 @@ packages: resolution: {integrity: sha512-jgAw78HO3gs9UrKqJNQvfDj9Ouy8Mhu40fbEJ8yXff4MW8+/Fcn9iFjyWUQ6SKbX8ipPk3X5A3AyfYHRu6uVLw==} engines: {node: ^18.17 || >=20.6.1} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + iterator.prototype@1.1.4: resolution: {integrity: sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==} engines: {node: '>= 0.4'} @@ -3277,6 +3341,13 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + marked-terminal@7.0.0: resolution: {integrity: sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==} engines: {node: '>=16.0.0'} @@ -3386,6 +3457,10 @@ packages: engines: {node: '>=10'} hasBin: true + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3787,6 +3862,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -4265,6 +4344,10 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -4520,6 +4603,10 @@ packages: resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} engines: {node: '>=14.16'} + test-exclude@7.0.1: + resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} + engines: {node: '>=18'} + text-extensions@2.4.0: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} @@ -4554,6 +4641,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} + tinypool@1.0.2: resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -4584,6 +4675,10 @@ packages: toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + tough-cookie@5.0.0: resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==} engines: {node: '>=16'} @@ -5155,6 +5250,8 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bcoe/v8-coverage@1.0.2': {} + '@colors/colors@1.5.0': optional: true @@ -5612,6 +5709,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@istanbuljs/schema@0.1.3': {} + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -5750,6 +5849,8 @@ snapshots: '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 + '@polka/url@1.0.0-next.28': {} + '@remcolakens/simple-component-generator@1.0.5': dependencies: fs-extra: 9.1.0 @@ -6214,6 +6315,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/coverage-v8@3.0.4(vitest@3.0.4)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.1.7 + magic-string: 0.30.17 + magicast: 0.3.5 + std-env: 3.8.0 + test-exclude: 7.0.1 + tinyrainbow: 2.0.0 + vitest: 3.0.4(@types/node@22.13.0)(@vitest/ui@3.0.4)(jsdom@26.0.0)(lightningcss@1.29.1) + transitivePeerDependencies: + - supports-color + '@vitest/expect@3.0.4': dependencies: '@vitest/spy': 3.0.4 @@ -6248,6 +6367,17 @@ snapshots: dependencies: tinyspy: 3.0.2 + '@vitest/ui@3.0.4(vitest@3.0.4)': + dependencies: + '@vitest/utils': 3.0.4 + fflate: 0.8.2 + flatted: 3.3.2 + pathe: 2.0.2 + sirv: 3.0.0 + tinyglobby: 0.2.10 + tinyrainbow: 2.0.0 + vitest: 3.0.4(@types/node@22.13.0)(@vitest/ui@3.0.4)(jsdom@26.0.0)(lightningcss@1.29.1) + '@vitest/utils@3.0.4': dependencies: '@vitest/pretty-format': 3.0.4 @@ -7154,8 +7284,8 @@ snapshots: '@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) eslint: 9.19.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) eslint-plugin-jsx-a11y: 6.10.1(eslint@9.19.0(jiti@2.4.2)) eslint-plugin-react: 7.37.4(eslint@9.19.0(jiti@2.4.2)) eslint-plugin-react-hooks: 5.0.0(eslint@9.19.0(jiti@2.4.2)) @@ -7178,13 +7308,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)): dependencies: debug: 4.4.0 enhanced-resolve: 5.18.0 eslint: 9.19.0(jiti@2.4.2) - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) fast-glob: 3.3.2 get-tsconfig: 4.7.3 is-core-module: 2.15.1 @@ -7195,18 +7325,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) eslint: 9.19.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -7217,7 +7347,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.19.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -7481,11 +7611,17 @@ snapshots: dependencies: reusify: 1.0.4 + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 + fflate@0.8.2: {} + figures@2.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -7549,6 +7685,8 @@ snapshots: flatted@3.3.1: {} + flatted@3.3.2: {} + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -7814,6 +7952,8 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 + html-escaper@2.0.2: {} + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 @@ -8124,6 +8264,27 @@ snapshots: lodash.isstring: 4.0.1 lodash.uniqby: 4.7.0 + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + iterator.prototype@1.1.4: dependencies: define-data-property: 1.1.4 @@ -8415,6 +8576,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.6.3 + marked-terminal@7.0.0(marked@12.0.2): dependencies: ansi-escapes: 6.2.1 @@ -8494,6 +8665,8 @@ snapshots: mkdirp@2.1.6: {} + mrmime@2.0.0: {} + ms@2.1.3: {} mute-stream@0.0.8: {} @@ -8822,6 +8995,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + pidtree@0.6.0: {} pify@2.3.0: {} @@ -9364,6 +9539,12 @@ snapshots: is-arrayish: 0.3.2 optional: true + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + sisteransi@1.0.5: {} skin-tone@2.0.0: @@ -9659,6 +9840,12 @@ snapshots: type-fest: 2.19.0 unique-string: 3.0.0 + test-exclude@7.0.1: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 10.4.5 + minimatch: 9.0.4 + text-extensions@2.4.0: {} thenify-all@1.6.0: @@ -9688,6 +9875,11 @@ snapshots: tinyexec@0.3.2: {} + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.3(picomatch@4.0.2) + picomatch: 4.0.2 + tinypool@1.0.2: {} tinyrainbow@2.0.0: {} @@ -9710,6 +9902,8 @@ snapshots: toggle-selection@1.0.6: {} + totalist@3.0.1: {} + tough-cookie@5.0.0: dependencies: tldts: 6.1.64 @@ -9898,7 +10092,7 @@ snapshots: fsevents: 2.3.3 lightningcss: 1.29.1 - vitest@3.0.4(@types/node@22.13.0)(jsdom@26.0.0)(lightningcss@1.29.1): + vitest@3.0.4(@types/node@22.13.0)(@vitest/ui@3.0.4)(jsdom@26.0.0)(lightningcss@1.29.1): dependencies: '@vitest/expect': 3.0.4 '@vitest/mocker': 3.0.4(vite@5.4.11(@types/node@22.13.0)(lightningcss@1.29.1)) @@ -9922,6 +10116,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.13.0 + '@vitest/ui': 3.0.4(vitest@3.0.4) jsdom: 26.0.0 transitivePeerDependencies: - less diff --git a/src/app/layout.test.tsx b/src/app/layout.test.tsx new file mode 100644 index 0000000..feb4e37 --- /dev/null +++ b/src/app/layout.test.tsx @@ -0,0 +1,33 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import RootLayout from './layout'; + +vi.mock('next/font/google', () => ({ + Inter: () => ({ + style: { + fontFamily: 'Inter', + }, + }), +})); + +describe('RootLayout', () => { + it('should render children with correct font classes', () => { + // Set up our test content + const testContent =
Wassup World
; + + // Render that layout with our test content + render({testContent}); + + // Check if our test content is in the house + const childElement = screen.getByTestId('test-child'); + expect(childElement).toBeInTheDocument(); + + expect(document.body).toHaveClass('font-sans', 'antialiased'); + }); + + it('should have correct lang attribute on html element', () => { + render(Test Content); + + expect(document.documentElement).toHaveAttribute('lang', 'en'); + }); +}); diff --git a/src/app/lib/utils.ts b/src/app/lib/utils.ts deleted file mode 100644 index 256f86f..0000000 --- a/src/app/lib/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type ClassValue, clsx } from 'clsx'; -import { twMerge } from 'tailwind-merge'; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts new file mode 100644 index 0000000..2a82439 --- /dev/null +++ b/src/lib/utils.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, test } from 'vitest'; +import { cn } from './utils'; + +describe('cn utility', () => { + test('combines class names correctly', () => { + // Test basic combination + expect(cn('flex', 'items-center')).toBe('flex items-center'); + + // Test with conditional classes + const isVisible = true; + const isInvisible = false; + expect( + cn('flex', isVisible ? 'visible' : '', isInvisible ? 'invisible' : ''), + ).toBe('flex visible'); + + // Test with Tailwind conflicts (should merge properly) + expect(cn('px-2 py-1', 'px-4')).toBe('py-1 px-4'); + + // Test with undefined/null values + expect(cn('flex', undefined, null, 'gap-2')).toBe('flex gap-2'); + + // Test with array input + expect(cn(['flex', 'items-center'])).toBe('flex items-center'); + }); +}); diff --git a/vitest.config.mts b/vitest.config.mts index 1ef6966..b2f8371 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -2,13 +2,23 @@ import react from '@vitejs/plugin-react'; import tsconfigPaths from 'vite-tsconfig-paths'; import { defineConfig } from 'vitest/config'; -// https://vitejs.dev/config/ +// https://vitest.dev/config/ export default defineConfig({ plugins: [react(), tsconfigPaths()], test: { globals: true, environment: 'jsdom', - include: ['**/*.test.{ts,tsx}'], + coverage: { + include: ['src/**'], + exclude: ['src/svgs', 'src/e2e'], + // thresholds: { + // statements: 80, + // branches: 70, + // functions: 80, + // lines: 80, + // }, + }, setupFiles: './vitest.setup.ts', + include: ['**/*.test.{ts,tsx}'], }, }); From 185db4c8bf379283f1973c45c3759165c94f7d5a Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Sun, 9 Feb 2025 19:23:19 +0100 Subject: [PATCH 2/6] fix: unit tests --- src/app/layout.test.tsx | 29 +++++++++++++++-------------- src/app/layout.tsx | 4 ++-- vitest.setup.ts | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/app/layout.test.tsx b/src/app/layout.test.tsx index feb4e37..854bb91 100644 --- a/src/app/layout.test.tsx +++ b/src/app/layout.test.tsx @@ -7,27 +7,28 @@ vi.mock('next/font/google', () => ({ style: { fontFamily: 'Inter', }, + variable: 'mocked-variable', }), })); describe('RootLayout', () => { - it('should render children with correct font classes', () => { - // Set up our test content - const testContent =
Wassup World
; + it('renders children correctly', async () => { + const { props } = await RootLayout({ + children:
Hello World
, + }); + render(props.children, { container: document.createElement('html') }); - // Render that layout with our test content - render({testContent}); - - // Check if our test content is in the house - const childElement = screen.getByTestId('test-child'); - expect(childElement).toBeInTheDocument(); - - expect(document.body).toHaveClass('font-sans', 'antialiased'); + const testContent = screen.getByTestId('test-content'); + expect(testContent).toBeInTheDocument(); + expect(testContent).toHaveTextContent('Hello World'); }); - it('should have correct lang attribute on html element', () => { - render(Test Content); + it('applies Inter font variable class', async () => { + const { props } = await RootLayout({ + children: null, + }); + render(props.children, { container: document.createElement('html') }); - expect(document.documentElement).toHaveAttribute('lang', 'en'); + expect(document.body).toHaveClass('font-sans', 'antialiased'); }); }); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f6c4806..37d85b1 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -16,9 +16,9 @@ export const metadata: Metadata = { export default function RootLayout({ children, -}: Readonly<{ +}: { children: React.ReactNode; -}>) { +}) { return ( diff --git a/vitest.setup.ts b/vitest.setup.ts index b3b96fb..a27e1d2 100644 --- a/vitest.setup.ts +++ b/vitest.setup.ts @@ -1,4 +1,4 @@ -import '@testing-library/jest-dom'; +import '@testing-library/jest-dom/vitest'; import { cleanup } from '@testing-library/react'; import { afterEach, vi } from 'vitest'; From e8c4f3b170bbf743f66070f8665864deefa25d92 Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Sun, 9 Feb 2025 20:01:57 +0100 Subject: [PATCH 3/6] fix: add coverage cmd --- .github/workflows/ci.yml | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b47008..2c8a12d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,4 +49,4 @@ jobs: uses: ./.github/actions/setup - name: Test - run: pnpm test + run: pnpm test:coverage diff --git a/package.json b/package.json index 56a97bf..6caf318 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "release": "semantic-release", "start": "next start", "test": "vitest run", + "test:coverage": "vitest run --coverage", "test:e2e": "playwright test" }, "devDependencies": { From 2ed895d70a769bf65761aeff233daa1860b53a08 Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Sun, 9 Feb 2025 20:17:28 +0100 Subject: [PATCH 4/6] fix: unit test --- src/lib/utils.test.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 2a82439..fdabca6 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -7,14 +7,12 @@ describe('cn utility', () => { expect(cn('flex', 'items-center')).toBe('flex items-center'); // Test with conditional classes - const isVisible = true; - const isInvisible = false; - expect( - cn('flex', isVisible ? 'visible' : '', isInvisible ? 'invisible' : ''), - ).toBe('flex visible'); + const isOpen = true; + expect(cn('flex', isOpen && 'visible')).toBe('flex visible'); // Test with Tailwind conflicts (should merge properly) expect(cn('px-2 py-1', 'px-4')).toBe('py-1 px-4'); + expect(cn('text-red-500', 'text-blue-500')).toBe('text-blue-500'); // Test with undefined/null values expect(cn('flex', undefined, null, 'gap-2')).toBe('flex gap-2'); From a5db3f05918f448aca9a1a38230b9967ca7f0fd4 Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Mon, 10 Feb 2025 10:31:32 +0100 Subject: [PATCH 5/6] fix: dont include all in coverage --- vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vitest.config.mts b/vitest.config.mts index b2f8371..169dad5 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -9,7 +9,7 @@ export default defineConfig({ globals: true, environment: 'jsdom', coverage: { - include: ['src/**'], + include: ['src/components/**', 'src/hooks/**', 'src/lib/**'], exclude: ['src/svgs', 'src/e2e'], // thresholds: { // statements: 80, From 09fedcf97a1426e4b7381124fc276f23353c66d2 Mon Sep 17 00:00:00 2001 From: Remco Lakens Date: Sun, 16 Feb 2025 20:50:21 +0100 Subject: [PATCH 6/6] fix: remove test --- src/app/layout.test.tsx | 34 ---------------------------------- src/app/page.test.tsx | 38 -------------------------------------- 2 files changed, 72 deletions(-) delete mode 100644 src/app/layout.test.tsx delete mode 100644 src/app/page.test.tsx diff --git a/src/app/layout.test.tsx b/src/app/layout.test.tsx deleted file mode 100644 index 854bb91..0000000 --- a/src/app/layout.test.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest'; -import RootLayout from './layout'; - -vi.mock('next/font/google', () => ({ - Inter: () => ({ - style: { - fontFamily: 'Inter', - }, - variable: 'mocked-variable', - }), -})); - -describe('RootLayout', () => { - it('renders children correctly', async () => { - const { props } = await RootLayout({ - children:
Hello World
, - }); - render(props.children, { container: document.createElement('html') }); - - const testContent = screen.getByTestId('test-content'); - expect(testContent).toBeInTheDocument(); - expect(testContent).toHaveTextContent('Hello World'); - }); - - it('applies Inter font variable class', async () => { - const { props } = await RootLayout({ - children: null, - }); - render(props.children, { container: document.createElement('html') }); - - expect(document.body).toHaveClass('font-sans', 'antialiased'); - }); -}); diff --git a/src/app/page.test.tsx b/src/app/page.test.tsx deleted file mode 100644 index 66c4304..0000000 --- a/src/app/page.test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Home from '@/app/page'; -import { fireEvent, render, screen } from '@testing-library/react'; -import { describe, expect, it } from 'vitest'; - -describe('Home', () => { - it('renders Next.js logo', async () => { - render(); - const nextSvg = await screen.findByAltText('Next.js logo'); - expect(nextSvg).toBeInTheDocument(); - }); - - it('renders text "Save and see your changes instantly."', async () => { - render(); - const textRow = await screen.findByText( - 'Save and see your changes instantly.', - ); - expect(textRow).toBeInTheDocument(); - }); - - it('renders deploy link with correct href', async () => { - render(); - const deployLink = await screen.findByText('Deploy now'); - fireEvent.click(deployLink); - expect(deployLink).toHaveAttribute( - 'href', - 'https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app', - ); - }); - - it('renders docs link with correct href', async () => { - render(); - const docsLink = await screen.findByText('Read our docs'); - expect(docsLink).toHaveAttribute( - 'href', - 'https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app', - ); - }); -});