add istanbul for coverage, unit tests for resposne bodies, add coverage here and there

This commit is contained in:
2025-05-31 11:48:00 -07:00
parent c08a15f01f
commit 6d6d6801db
10 changed files with 626 additions and 46 deletions

3
.gitignore vendored
View File

@ -24,4 +24,5 @@ vite.config.ts.timestamp-*
# Development
cert
.vscode
.vscode
coverage

463
package-lock.json generated
View File

@ -21,6 +21,7 @@
"@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^22.10.7",
"@vitest/coverage-istanbul": "^2.1.8",
"@vitest/coverage-v8": "^2.1.8",
"eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0",
@ -50,10 +51,169 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/code-frame": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz",
"integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz",
"integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.27.1",
"@babel/helper-compilation-targets": "^7.27.1",
"@babel/helper-module-transforms": "^7.27.1",
"@babel/helpers": "^7.27.1",
"@babel/parser": "^7.27.1",
"@babel/template": "^7.27.1",
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
"json5": "^2.2.3",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/babel"
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/generator": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz",
"integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.27.1",
"@babel/types": "^7.27.1",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.27.2",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"license": "ISC"
},
"node_modules/@babel/helper-module-imports": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz",
"integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
"@babel/traverse": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"license": "MIT",
"engines": {
@ -61,23 +221,47 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz",
"integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==",
"node_modules/@babel/helper-validator-option": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz",
"integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.7"
"@babel/template": "^7.27.1",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz",
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.27.1"
},
"bin": {
"parser": "bin/babel-parser.js"
@ -86,15 +270,59 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz",
"integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==",
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9"
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz",
"integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.27.1",
"@babel/parser": "^7.27.1",
"@babel/template": "^7.27.1",
"@babel/types": "^7.27.1",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse/node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/types": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@ -1567,6 +1795,31 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@vitest/coverage-istanbul": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.8.tgz",
"integrity": "sha512-cSaCd8KcWWvgDwEJSXm0NEWZ1YTiJzjicKHy+zOEbUm0gjbbkz+qJf1p8q71uBzSlS7vdnZA8wRLeiwVE3fFTA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@istanbuljs/schema": "^0.1.3",
"debug": "^4.3.7",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-instrument": "^6.0.3",
"istanbul-lib-report": "^3.0.1",
"istanbul-lib-source-maps": "^5.0.6",
"istanbul-reports": "^3.1.7",
"magicast": "^0.3.5",
"test-exclude": "^7.0.1",
"tinyrainbow": "^1.2.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"vitest": "2.1.8"
}
},
"node_modules/@vitest/coverage-v8": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz",
@ -1906,6 +2159,39 @@
"node": ">=8"
}
},
"node_modules/browserslist": {
"version": "4.24.5",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz",
"integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001716",
"electron-to-chromium": "^1.5.149",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3"
},
"bin": {
"browserslist": "cli.js"
},
"engines": {
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/bson": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz",
@ -1941,6 +2227,27 @@
"node": ">=6"
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001718",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz",
"integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "CC-BY-4.0"
},
"node_modules/chai": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
@ -2061,6 +2368,13 @@
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"license": "ISC"
},
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true,
"license": "MIT"
},
"node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
@ -2181,6 +2495,13 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.152",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz",
"integrity": "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==",
"dev": true,
"license": "ISC"
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -2233,6 +2554,16 @@
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -2737,6 +3068,16 @@
"node": ">=10"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -2975,6 +3316,23 @@
"node": ">=8"
}
},
"node_modules/istanbul-lib-instrument": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@babel/core": "^7.23.9",
"@babel/parser": "^7.23.9",
"@istanbuljs/schema": "^0.1.3",
"istanbul-lib-coverage": "^3.2.0",
"semver": "^7.5.4"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-lib-report": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
@ -3051,6 +3409,13 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@ -3064,6 +3429,19 @@
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@ -3085,6 +3463,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
@ -3568,6 +3959,13 @@
"webidl-conversions": "^3.0.0"
}
},
"node_modules/node-releases": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true,
"license": "MIT"
},
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -4689,6 +5087,37 @@
"dev": true,
"license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"escalade": "^3.2.0",
"picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
},
"peerDependencies": {
"browserslist": ">= 4.21.0"
}
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",

View File

@ -23,6 +23,7 @@
"@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^22.10.7",
"@vitest/coverage-istanbul": "^2.1.8",
"@vitest/coverage-v8": "^2.1.8",
"eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0",

View File

@ -1,4 +1,4 @@
import { hasProperty } from "./validation";
import { hasProperty, hasOnlyKeys } from "./validation";
export interface Me {
id: string;
@ -10,5 +10,6 @@ export function isMe(target: unknown): target is Me {
if (!hasProperty(target, "id", "string")) return false;
if (!hasProperty(target, "role", "string")) return false;
if (!hasProperty(target, "username", "string")) return false;
if (!hasOnlyKeys(target, ["id", "role", "username"])) return false;
return true;
}

View File

@ -1,19 +1,21 @@
import { describe, it } from "vitest";
import { Game } from "$lib/server/Game";
import { deepEqual, ok, throws } from "node:assert/strict";
import { createId, idFromString, stringFromId } from "$lib/Id";
import { equal } from "node:assert";
import { ok, throws } from "node:assert/strict";
import { createId } from "$lib/Id";
import { equal, deepEqual } from "node:assert";
describe("Game", () => {
const idString = stringFromId(createId());
const idString = createId();
describe("addPlayer", () => {
it("should push a player id into the player array", () => {
const game = new Game();
deepEqual(game.players, []);
const user = "Mr. User";
game.addPlayer(idFromString(idString));
equal(game.players.length, 0);
game.addPlayer(idString, user);
equal(game.players.length, 1);
equal(stringFromId(game.players[0]), idString);
deepEqual(game.players[0], { id: idString, username: user });
});
});

View File

@ -0,0 +1,98 @@
import { describe, it } from "vitest";
import {
listResponse,
singleResponse,
createdResponse,
tokenResponse,
badRequestResponse,
notFoundResponse,
serverErrorResponse,
unauthorizedResponse,
forbiddenResponse,
} from "../responseBodies";
import { deepEqual, equal } from "assert";
import { createId } from "$lib/Id";
describe("responseBodies", () => {
describe("the following response body functions return expected response", () => {
it("listResponse", async () => {
const expected = [{ some: "item", another: "thing" }];
const { body, status } = await unwrapResponse(listResponse, expected);
deepEqual(body, { items: expected });
equal(status, 200);
});
it("singleResponse", async () => {
const expected = { some: "item" };
const { body, status } = await unwrapResponse(singleResponse, expected);
deepEqual(body, { item: expected });
equal(status, 200);
});
it("createdResponse", async () => {
const expectedId = createId();
const { body, status } = await unwrapResponse(createdResponse, expectedId);
deepEqual(body, { item: expectedId });
equal(status, 201);
});
it("tokenResponse", async () => {
const token = "some-generated-token";
const { body, status } = await unwrapResponse(tokenResponse, token);
deepEqual(body, { access_token: token });
equal(status, 200);
});
it("badRequestResponse", async () => {
const errorString = "something bad happened";
let { body, status } = await unwrapResponse(badRequestResponse, errorString);
deepEqual(body, { error: errorString });
equal(status, 400);
const res = await unwrapResponse(badRequestResponse);
body = res.body;
status = res.status;
deepEqual(body, { error: "Bad Request" });
equal(status, 400);
});
it("notFoundResponse", async () => {
const { body, status } = await unwrapResponse(notFoundResponse);
deepEqual(body, { error: "Not Found" });
equal(status, 404);
});
it("serverErrorResponse", async () => {
const { body, status } = await unwrapResponse(serverErrorResponse);
deepEqual(body, { error: "Unexpected Server Error" });
equal(status, 500);
});
it("unauthorizedResponse", async () => {
const { body, status } = await unwrapResponse(unauthorizedResponse);
deepEqual(body, { error: "Unauthorized" });
equal(status, 401);
});
it("forbiddenResponse", async () => {
const { body, status } = await unwrapResponse(forbiddenResponse);
deepEqual(body, { error: "Forbidden" });
equal(status, 403);
});
});
});
async function unwrapResponse(fn: Function, body?: unknown) {
const res = fn(body);
return { status: res.status, body: await res.json() };
}

View File

@ -1,34 +1,44 @@
import { describe, it } from "vitest";
import { type GameData, isGameData } from "$lib/GameData";
import { isGameData } from "$lib/GameData";
import { equal, ok } from "node:assert/strict";
import { createId, idFromString, stringFromId } from "$lib/Id";
import { createId } from "$lib/Id";
describe("GameData", () => {
const idString = stringFromId(createId());
const idString = createId();
describe("isGameData", () => {
it("rejects a malformed object", () => {
let data: unknown = {
players: [idFromString(idString), idString],
players: [idString, idString],
isStarted: false,
state: {},
};
equal(isGameData(data), false);
data = {
players: [idFromString(idString)],
players: [idString],
isStarted: null,
state: {},
};
equal(isGameData(data), false);
data = {
players: [idFromString(idString)],
players: [{ username: "Mr. User", id: idString }],
isStarted: false,
};
equal(isGameData(data), false);
});
it("rejects an object with a malformed players array", () => {
const data: unknown = {
players: [{ id: idString }],
state: {},
isStarted: false,
};
equal(isGameData(data), false);
});
it("rejects an object without a players property", () => {
const data: unknown = {
state: {},
@ -40,7 +50,7 @@ describe("GameData", () => {
it("rejects an object with extra properties", () => {
const data: unknown = {
players: [idFromString(idString)],
players: [{ username: "Mr. User", id: idString }],
isStarted: false,
state: {},
extra: true,
@ -50,8 +60,8 @@ describe("GameData", () => {
});
it("should accept a proper GameData object", () => {
const data: GameData = {
players: [idFromString(idString)],
const data: unknown = {
players: [{ username: "Mr. User", id: idString }],
state: {},
isStarted: false,
};

View File

@ -15,7 +15,7 @@ import type { GameData } from "$lib/GameData";
import { describe, it } from "vitest";
import type { State } from "$lib/State";
import { doesNotThrow, deepStrictEqual, equal, ok, throws } from "assert";
import { createId, idFromString, stringFromId } from "$lib/Id";
import { createId } from "$lib/Id";
describe("Game Events", () => {
describe("isGameEventData", () => {
@ -55,13 +55,20 @@ describe("Game Events", () => {
});
describe("getGameEvent", () => {
const idString = stringFromId(createId());
const anotherIdString = stringFromId(createId());
const playerOne = {
id: createId(),
username: "Player One",
};
const playerTwo = {
id: createId(),
username: "Player Two",
};
it("should throw if the kind is unkown", () => {
const data: GameData = {
isStarted: false,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -77,7 +84,7 @@ describe("Game Events", () => {
it("should throw when SeatPlayers has the wrong number of players", () => {
const data: GameData = {
isStarted: true,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -92,7 +99,7 @@ describe("Game Events", () => {
it("should return a SeatPlayers object when the number of players is correct", () => {
const data: GameData = {
isStarted: true,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -107,7 +114,7 @@ describe("Game Events", () => {
it("should throw an error if the player passes a full roll with Roll", () => {
const data: GameData = {
isStarted: true,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -123,7 +130,7 @@ describe("Game Events", () => {
it("should return a Roll object with dice values when the player passes a die count as a value", () => {
const data: GameData = {
isStarted: true,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -143,7 +150,7 @@ describe("Game Events", () => {
it("should return the class that corresponds with a given kind", () => {
const data: GameData = {
isStarted: true,
players: [idFromString(idString), idFromString(anotherIdString)],
players: [playerOne, playerTwo],
state: {},
};
@ -754,7 +761,7 @@ describe("Game Events", () => {
});
});
it("should allow the player to hold 2 threes of a kind for 1,500 points", () => {
it("should allow the player to hold 2 threes of a kind for 1,600 points", () => {
const state: State = {
dice: [2, 2, 2, 3, 3, 3],
playing: 0,
@ -770,7 +777,7 @@ describe("Game Events", () => {
deepStrictEqual(state, {
dieCount: 6,
heldScore: 1_500,
heldScore: 1_600,
playing: 0,
scores: [0, 0, 0],
});

30
src/lib/test/me.spec.ts Normal file
View File

@ -0,0 +1,30 @@
import { createId } from "$lib/Id";
import { isMe, type Me } from "$lib/me";
import { equal, ok } from "assert";
import { describe, it } from "vitest";
describe("me", () => {
describe("isMe", () => {
const target: Me = {
id: createId(),
role: "test-role",
username: "Ms. User",
};
it("returns true when the target is shaped like a 'Me'", () => {
ok(isMe(target));
});
it("returns false when the target is missing a property", () => {
const { id, role, username } = target;
equal(isMe({ role, username }), false);
equal(isMe({ id, username }), false);
equal(isMe({ id, role }), false);
});
it("returns false when the target has an extra property", () => {
const { id, role, username } = target;
equal(isMe({ id, role, username, extra: "something" }), false);
});
});
});

View File

@ -16,6 +16,7 @@ export default defineConfig({
test: {
include: ["src/**/*.{test,spec}.{js,ts}"],
coverage: {
provider: "istanbul",
exclude: [...coverageConfigDefaults.exclude, "svelte.config.js"],
},
environment: "jsdom",