diff --git a/maintenance.sh b/maintenance.sh
index ba3d92c..78bcbe9 100755
--- a/maintenance.sh
+++ b/maintenance.sh
@@ -23,8 +23,9 @@ if [ -f package.json ]; then
# npm ci will reconcile. We do a cheap check by comparing mtime.
if [ -f package-lock.json ]; then
if [ package-lock.json -nt node_modules ]; then
- echo "package-lock.json newer than node_modules; running npm ci..."
- npm ci
+ echo "package-lock.json newer than node_modules; running npm install & npm prune..."
+ npm install
+ npm prune
else
echo "npm deps look current; skipping install."
fi
@@ -36,6 +37,8 @@ else
echo "-> No package.json; skipping Node maintenance."
fi
+npx npm-check-updates -u
+
# ----------------------------
# 2) Refresh Playwright Chromium if Playwright version changed
# ----------------------------
diff --git a/package-lock.json b/package-lock.json
index 46f8afd..0d5d31d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"date-fns": "^4.1.0",
"dexie": "^4.2.1",
"jszip": "^3.10.1",
+ "npm-check-updates": "^19.1.2",
"papaparse": "^5.5.3",
"react": "^19.2.0",
"react-dom": "^19.2.0",
@@ -24,7 +25,7 @@
"uuid": "^13.0.0"
},
"devDependencies": {
- "@playwright/test": "^1.56.1",
+ "@playwright/test": "^1.57.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
@@ -32,11 +33,11 @@
"@types/papaparse": "^5.5.0",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
- "@typescript-eslint/eslint-plugin": "^8.47.0",
- "@typescript-eslint/parser": "^8.47.0",
+ "@typescript-eslint/eslint-plugin": "^8.48.0",
+ "@typescript-eslint/parser": "^8.48.0",
"@vitejs/plugin-react": "^5.1.1",
- "@vitest/coverage-v8": "^4.0.13",
- "@vitest/ui": "^4.0.13",
+ "@vitest/coverage-v8": "^4.0.14",
+ "@vitest/ui": "^4.0.14",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
@@ -44,9 +45,9 @@
"msw": "^2.12.3",
"rollup-plugin-visualizer": "^6.0.5",
"typescript": "^5.9.3",
- "typescript-eslint": "^8.47.0",
- "vite": "^7.2.4",
- "vitest": "^4.0.13"
+ "typescript-eslint": "^8.48.0",
+ "vite": "^7.2.6",
+ "vitest": "^4.0.14"
}
},
"node_modules/@acemir/cssom": {
@@ -78,19 +79,19 @@
}
},
"node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
- "version": "11.2.2",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
- "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==",
+ "version": "11.2.4",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz",
+ "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==",
"dev": true,
- "license": "ISC",
+ "license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@asamuzakjp/dom-selector": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.4.tgz",
- "integrity": "sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==",
+ "version": "6.7.5",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.5.tgz",
+ "integrity": "sha512-Eks6dY8zau4m4wNRQjRVaKQRTalNcPcBvU1ZQ35w5kKRk1gUeNCkVLsRiATurjASTp3TKM4H10wsI50nx3NZdw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -102,11 +103,11 @@
}
},
"node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": {
- "version": "11.2.2",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
- "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==",
+ "version": "11.2.4",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz",
+ "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==",
"dev": true,
- "license": "ISC",
+ "license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
}
@@ -532,9 +533,9 @@
}
},
"node_modules/@csstools/css-syntax-patches-for-csstree": {
- "version": "1.0.17",
- "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.17.tgz",
- "integrity": "sha512-LCC++2h8pLUSPY+EsZmrrJ1EOUu+5iClpEiDhhdw3zRJpPbABML/N5lmRuBHjxtKm9VnRcsUzioyD0sekFMF0A==",
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.20.tgz",
+ "integrity": "sha512-8BHsjXfSciZxjmHQOuVdW2b8WLUPts9a+mfL13/PzEviufUEW2xnvQuOlKs9dRBHgRqJ53SF/DUoK9+MZk72oQ==",
"dev": true,
"funding": [
{
@@ -1254,9 +1255,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
- "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
+ "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1266,7 +1267,7 @@
"globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
+ "js-yaml": "^4.1.1",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
@@ -1795,44 +1796,6 @@
}
}
},
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/@open-draft/deferred-promise": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz",
@@ -1859,13 +1822,13 @@
"license": "MIT"
},
"node_modules/@playwright/test": {
- "version": "1.56.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
- "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
+ "version": "1.57.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz",
+ "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.56.1"
+ "playwright": "1.57.0"
},
"bin": {
"playwright": "cli.js"
@@ -2456,17 +2419,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.47.0.tgz",
- "integrity": "sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz",
+ "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.47.0",
- "@typescript-eslint/type-utils": "8.47.0",
- "@typescript-eslint/utils": "8.47.0",
- "@typescript-eslint/visitor-keys": "8.47.0",
+ "@typescript-eslint/scope-manager": "8.48.0",
+ "@typescript-eslint/type-utils": "8.48.0",
+ "@typescript-eslint/utils": "8.48.0",
+ "@typescript-eslint/visitor-keys": "8.48.0",
"graphemer": "^1.4.0",
"ignore": "^7.0.0",
"natural-compare": "^1.4.0",
@@ -2480,22 +2443,22 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.47.0",
+ "@typescript-eslint/parser": "^8.48.0",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.47.0.tgz",
- "integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz",
+ "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.47.0",
- "@typescript-eslint/types": "8.47.0",
- "@typescript-eslint/typescript-estree": "8.47.0",
- "@typescript-eslint/visitor-keys": "8.47.0",
+ "@typescript-eslint/scope-manager": "8.48.0",
+ "@typescript-eslint/types": "8.48.0",
+ "@typescript-eslint/typescript-estree": "8.48.0",
+ "@typescript-eslint/visitor-keys": "8.48.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2511,14 +2474,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.47.0.tgz",
- "integrity": "sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz",
+ "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.47.0",
- "@typescript-eslint/types": "^8.47.0",
+ "@typescript-eslint/tsconfig-utils": "^8.48.0",
+ "@typescript-eslint/types": "^8.48.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2533,14 +2496,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.47.0.tgz",
- "integrity": "sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz",
+ "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.47.0",
- "@typescript-eslint/visitor-keys": "8.47.0"
+ "@typescript-eslint/types": "8.48.0",
+ "@typescript-eslint/visitor-keys": "8.48.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2551,9 +2514,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.47.0.tgz",
- "integrity": "sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz",
+ "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2568,15 +2531,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.47.0.tgz",
- "integrity": "sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz",
+ "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.47.0",
- "@typescript-eslint/typescript-estree": "8.47.0",
- "@typescript-eslint/utils": "8.47.0",
+ "@typescript-eslint/types": "8.48.0",
+ "@typescript-eslint/typescript-estree": "8.48.0",
+ "@typescript-eslint/utils": "8.48.0",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -2593,9 +2556,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.47.0.tgz",
- "integrity": "sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz",
+ "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2607,21 +2570,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.47.0.tgz",
- "integrity": "sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz",
+ "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.47.0",
- "@typescript-eslint/tsconfig-utils": "8.47.0",
- "@typescript-eslint/types": "8.47.0",
- "@typescript-eslint/visitor-keys": "8.47.0",
+ "@typescript-eslint/project-service": "8.48.0",
+ "@typescript-eslint/tsconfig-utils": "8.48.0",
+ "@typescript-eslint/types": "8.48.0",
+ "@typescript-eslint/visitor-keys": "8.48.0",
"debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
+ "tinyglobby": "^0.2.15",
"ts-api-utils": "^2.1.0"
},
"engines": {
@@ -2636,16 +2598,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.47.0.tgz",
- "integrity": "sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz",
+ "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.47.0",
- "@typescript-eslint/types": "8.47.0",
- "@typescript-eslint/typescript-estree": "8.47.0"
+ "@typescript-eslint/scope-manager": "8.48.0",
+ "@typescript-eslint/types": "8.48.0",
+ "@typescript-eslint/typescript-estree": "8.48.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2660,13 +2622,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.47.0.tgz",
- "integrity": "sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz",
+ "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.47.0",
+ "@typescript-eslint/types": "8.48.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -2712,21 +2674,21 @@
}
},
"node_modules/@vitest/coverage-v8": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.13.tgz",
- "integrity": "sha512-w77N6bmtJ3CFnL/YHiYotwW/JI3oDlR3K38WEIqegRfdMSScaYxwYKB/0jSNpOTZzUjQkG8HHEz4sdWQMWpQ5g==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.14.tgz",
+ "integrity": "sha512-EYHLqN/BY6b47qHH7gtMxAg++saoGmsjWmAq9MlXxAz4M0NcHh9iOyKhBZyU4yxZqOd8Xnqp80/5saeitz4Cng==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bcoe/v8-coverage": "^1.0.2",
- "@vitest/utils": "4.0.13",
+ "@vitest/utils": "4.0.14",
"ast-v8-to-istanbul": "^0.3.8",
- "debug": "^4.4.3",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1",
"istanbul-lib-source-maps": "^5.0.6",
"istanbul-reports": "^3.2.0",
"magicast": "^0.5.1",
+ "obug": "^2.1.1",
"std-env": "^3.10.0",
"tinyrainbow": "^3.0.3"
},
@@ -2734,8 +2696,8 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "@vitest/browser": "4.0.13",
- "vitest": "4.0.13"
+ "@vitest/browser": "4.0.14",
+ "vitest": "4.0.14"
},
"peerDependenciesMeta": {
"@vitest/browser": {
@@ -2744,16 +2706,16 @@
}
},
"node_modules/@vitest/expect": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.13.tgz",
- "integrity": "sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.14.tgz",
+ "integrity": "sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"@types/chai": "^5.2.2",
- "@vitest/spy": "4.0.13",
- "@vitest/utils": "4.0.13",
+ "@vitest/spy": "4.0.14",
+ "@vitest/utils": "4.0.14",
"chai": "^6.2.1",
"tinyrainbow": "^3.0.3"
},
@@ -2762,13 +2724,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.13.tgz",
- "integrity": "sha512-eNCwzrI5djoauklwP1fuslHBjrbR8rqIVbvNlAnkq1OTa6XT+lX68mrtPirNM9TnR69XUPt4puBCx2Wexseylg==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.14.tgz",
+ "integrity": "sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "4.0.13",
+ "@vitest/spy": "4.0.14",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
@@ -2789,9 +2751,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.13.tgz",
- "integrity": "sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.14.tgz",
+ "integrity": "sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2802,13 +2764,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.13.tgz",
- "integrity": "sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.14.tgz",
+ "integrity": "sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "4.0.13",
+ "@vitest/utils": "4.0.14",
"pathe": "^2.0.3"
},
"funding": {
@@ -2816,13 +2778,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.13.tgz",
- "integrity": "sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.14.tgz",
+ "integrity": "sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.0.13",
+ "@vitest/pretty-format": "4.0.14",
"magic-string": "^0.30.21",
"pathe": "^2.0.3"
},
@@ -2831,9 +2793,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.13.tgz",
- "integrity": "sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.14.tgz",
+ "integrity": "sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -2841,13 +2803,13 @@
}
},
"node_modules/@vitest/ui": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.13.tgz",
- "integrity": "sha512-MFV6GhTflgBj194+vowTB2iLI5niMZhqiW7/NV7U4AfWbX/IAtsq4zA+gzCLyGzpsQUdJlX26hrQ1vuWShq2BQ==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.14.tgz",
+ "integrity": "sha512-fvDz8o7SQpFLoSBo6Cudv+fE85/fPCkwTnLAN85M+Jv7k59w2mSIjT9Q5px7XwGrmYqqKBEYxh/09IBGd1E7AQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "4.0.13",
+ "@vitest/utils": "4.0.14",
"fflate": "^0.8.2",
"flatted": "^3.3.3",
"pathe": "^2.0.3",
@@ -2859,17 +2821,17 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "vitest": "4.0.13"
+ "vitest": "4.0.14"
}
},
"node_modules/@vitest/utils": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.13.tgz",
- "integrity": "sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.14.tgz",
+ "integrity": "sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.0.13",
+ "@vitest/pretty-format": "4.0.14",
"tinyrainbow": "^3.0.3"
},
"funding": {
@@ -3055,9 +3017,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.8.30",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.30.tgz",
- "integrity": "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA==",
+ "version": "2.8.32",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz",
+ "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -3084,19 +3046,6 @@
"balanced-match": "^1.0.0"
}
},
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/browserslist": {
"version": "4.28.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz",
@@ -3147,9 +3096,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001756",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz",
- "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==",
+ "version": "1.0.30001757",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz",
+ "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==",
"dev": true,
"funding": [
{
@@ -3286,12 +3235,16 @@
"license": "MIT"
},
"node_modules/cookie": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
- "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
"license": "MIT",
"engines": {
"node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/core-util-is": {
@@ -3482,9 +3435,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.259",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz",
- "integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==",
+ "version": "1.5.262",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz",
+ "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==",
"dev": true,
"license": "ISC"
},
@@ -3859,36 +3812,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3903,14 +3826,22 @@
"dev": true,
"license": "MIT"
},
- "node_modules/fastq": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4"
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
}
},
"node_modules/fflate": {
@@ -3933,19 +3864,6 @@
"node": ">=16.0.0"
}
},
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -3991,9 +3909,9 @@
"license": "ISC"
},
"node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -4334,16 +4252,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.12.0"
- }
- },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -4694,30 +4602,6 @@
"dev": true,
"license": "CC0-1.0"
},
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -4848,6 +4732,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/npm-check-updates": {
+ "version": "19.1.2",
+ "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.2.tgz",
+ "integrity": "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==",
+ "license": "Apache-2.0",
+ "bin": {
+ "ncu": "build/cli.js",
+ "npm-check-updates": "build/cli.js"
+ },
+ "engines": {
+ "node": ">=20.0.0",
+ "npm": ">=8.12.1"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4857,6 +4755,17 @@
"node": ">=0.10.0"
}
},
+ "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/open": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
@@ -5043,26 +4952,26 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=8.6"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/playwright": {
- "version": "1.56.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
- "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
+ "version": "1.57.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
+ "integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.56.1"
+ "playwright-core": "1.57.0"
},
"bin": {
"playwright": "cli.js"
@@ -5075,9 +4984,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.56.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
- "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
+ "version": "1.57.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz",
+ "integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -5087,21 +4996,6 @@
"node": ">=18"
}
},
- "node_modules/playwright/node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -5212,27 +5106,6 @@
"node": ">=6"
}
},
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
"node_modules/react": {
"version": "19.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
@@ -5409,17 +5282,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
"node_modules/rollup": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
@@ -5493,19 +5355,6 @@
}
}
},
- "node_modules/rollup-plugin-visualizer/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/rollup-plugin-visualizer/node_modules/source-map": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
@@ -5516,30 +5365,6 @@
"node": ">= 12"
}
},
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -5887,37 +5712,6 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/tinyrainbow": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
@@ -5929,38 +5723,25 @@
}
},
"node_modules/tldts": {
- "version": "7.0.18",
- "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.18.tgz",
- "integrity": "sha512-lCcgTAgMxQ1JKOWrVGo6E69Ukbnx4Gc1wiYLRf6J5NN4HRYJtCby1rPF8rkQ4a6qqoFBK5dvjJ1zJ0F7VfDSvw==",
+ "version": "7.0.19",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz",
+ "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "tldts-core": "^7.0.18"
+ "tldts-core": "^7.0.19"
},
"bin": {
"tldts": "bin/cli.js"
}
},
"node_modules/tldts-core": {
- "version": "7.0.18",
- "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.18.tgz",
- "integrity": "sha512-jqJC13oP4FFAahv4JT/0WTDrCF9Okv7lpKtOZUGPLiAnNbACcSg8Y8T+Z9xthOmRBqi/Sob4yi0TE0miRCvF7Q==",
+ "version": "7.0.19",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz",
+ "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==",
"dev": true,
"license": "MIT"
},
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
@@ -6064,16 +5845,16 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.47.0.tgz",
- "integrity": "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz",
+ "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.47.0",
- "@typescript-eslint/parser": "8.47.0",
- "@typescript-eslint/typescript-estree": "8.47.0",
- "@typescript-eslint/utils": "8.47.0"
+ "@typescript-eslint/eslint-plugin": "8.48.0",
+ "@typescript-eslint/parser": "8.48.0",
+ "@typescript-eslint/typescript-estree": "8.48.0",
+ "@typescript-eslint/utils": "8.48.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -6165,9 +5946,9 @@
}
},
"node_modules/vite": {
- "version": "7.2.4",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz",
- "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==",
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz",
+ "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6239,55 +6020,39 @@
}
}
},
- "node_modules/vite/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "node_modules/vite/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
+ "hasInstallScript": true,
"license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/vite/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/vitest": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.13.tgz",
- "integrity": "sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==",
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.14.tgz",
+ "integrity": "sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/expect": "4.0.13",
- "@vitest/mocker": "4.0.13",
- "@vitest/pretty-format": "4.0.13",
- "@vitest/runner": "4.0.13",
- "@vitest/snapshot": "4.0.13",
- "@vitest/spy": "4.0.13",
- "@vitest/utils": "4.0.13",
- "debug": "^4.4.3",
+ "@vitest/expect": "4.0.14",
+ "@vitest/mocker": "4.0.14",
+ "@vitest/pretty-format": "4.0.14",
+ "@vitest/runner": "4.0.14",
+ "@vitest/snapshot": "4.0.14",
+ "@vitest/spy": "4.0.14",
+ "@vitest/utils": "4.0.14",
"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.3",
"std-env": "^3.10.0",
@@ -6310,12 +6075,11 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
- "@types/debug": "^4.1.12",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "@vitest/browser-playwright": "4.0.13",
- "@vitest/browser-preview": "4.0.13",
- "@vitest/browser-webdriverio": "4.0.13",
- "@vitest/ui": "4.0.13",
+ "@vitest/browser-playwright": "4.0.14",
+ "@vitest/browser-preview": "4.0.14",
+ "@vitest/browser-webdriverio": "4.0.14",
+ "@vitest/ui": "4.0.14",
"happy-dom": "*",
"jsdom": "*"
},
@@ -6326,9 +6090,6 @@
"@opentelemetry/api": {
"optional": true
},
- "@types/debug": {
- "optional": true
- },
"@types/node": {
"optional": true
},
@@ -6352,19 +6113,6 @@
}
}
},
- "node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
@@ -6540,9 +6288,9 @@
"license": "ISC"
},
"node_modules/yaml": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
- "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
+ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"dev": true,
"license": "ISC",
"optional": true,
@@ -6552,6 +6300,9 @@
},
"engines": {
"node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/yargs": {
diff --git a/package.json b/package.json
index 75c2fc7..cfba686 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"date-fns": "^4.1.0",
"dexie": "^4.2.1",
"jszip": "^3.10.1",
+ "npm-check-updates": "^19.1.2",
"papaparse": "^5.5.3",
"react": "^19.2.0",
"react-dom": "^19.2.0",
@@ -29,7 +30,7 @@
"uuid": "^13.0.0"
},
"devDependencies": {
- "@playwright/test": "^1.56.1",
+ "@playwright/test": "^1.57.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
@@ -37,11 +38,11 @@
"@types/papaparse": "^5.5.0",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
- "@typescript-eslint/eslint-plugin": "^8.47.0",
- "@typescript-eslint/parser": "^8.47.0",
+ "@typescript-eslint/eslint-plugin": "^8.48.0",
+ "@typescript-eslint/parser": "^8.48.0",
"@vitejs/plugin-react": "^5.1.1",
- "@vitest/coverage-v8": "^4.0.13",
- "@vitest/ui": "^4.0.13",
+ "@vitest/coverage-v8": "^4.0.14",
+ "@vitest/ui": "^4.0.14",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
@@ -49,8 +50,8 @@
"msw": "^2.12.3",
"rollup-plugin-visualizer": "^6.0.5",
"typescript": "^5.9.3",
- "typescript-eslint": "^8.47.0",
- "vite": "^7.2.4",
- "vitest": "^4.0.13"
+ "typescript-eslint": "^8.48.0",
+ "vite": "^7.2.6",
+ "vitest": "^4.0.14"
}
}
diff --git a/src/screens/ActivePickListScreen.more.test.tsx b/src/screens/ActivePickListScreen.more.test.tsx
new file mode 100644
index 0000000..888478f
--- /dev/null
+++ b/src/screens/ActivePickListScreen.more.test.tsx
@@ -0,0 +1,133 @@
+// src/screens/ActivePickListScreen.more.test.tsx
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { render, screen, within, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { describe, expect, it, vi, beforeEach } from 'vitest';
+import ActivePickListScreen from './ActivePickListScreen';
+import { PickItem } from '../models/PickItem';
+import { Product } from '../models/Product';
+
+const addMock = vi.fn();
+const updateMock = vi.fn();
+const deleteMock = vi.fn();
+const pickItemsMock = vi.fn<() => PickItem[]>();
+const productsMock = vi.fn<() => Product[]>();
+const pickListMock = vi.fn();
+
+vi.mock('../hooks/dataHooks', () => ({
+ usePickItems: () => pickItemsMock(),
+ useProducts: () => productsMock(),
+ usePickList: () => pickListMock(),
+ useAreas: () => [{ id: 'a1', name: 'Front', created_at: 0, updated_at: 0 }],
+ useCategories: () => [{ id: 'c1', name: 'Drinks', created_at: 0, updated_at: 0 }],
+}));
+
+vi.mock('../context/DBProvider', () => ({
+ useDatabase: () => ({
+ pickItems: {
+ add: addMock,
+ update: updateMock,
+ get: vi.fn(async (id: string) => (pickItemsMock() || []).find((it) => it.id === id)),
+ delete: deleteMock,
+ where: (_f: string) => ({
+ equals: (val: any) => ({
+ toArray: async () => (pickItemsMock() || []).filter((it) => it.pick_list_id === val),
+ count: async () => (pickItemsMock() || []).filter((it) => it.pick_list_id === val).length,
+ }),
+ }),
+ },
+ }),
+}));
+
+const products = [
+ { id: 'prod-1', name: 'Cola', category: 'c1', unit_type: 'unit', bulk_name: 'box', barcode: '111', archived: false, created_at: 0, updated_at: 0 },
+];
+
+beforeEach(() => {
+ addMock.mockReset();
+ updateMock.mockReset();
+ deleteMock.mockReset();
+ pickItemsMock.mockReset();
+ productsMock.mockReset();
+ pickListMock.mockReset();
+
+ productsMock.mockReturnValue(products);
+ pickListMock.mockReturnValue({ id: 'list-1', area_id: 'a1', created_at: 0, categories: ['c1'], auto_add_new_products: false });
+});
+
+describe('ActivePickListScreen extra branches', () => {
+ it('adds a pick item when a product is selected (listbox opens)', async () => {
+ // Ensure the product is available (not already on the pick list)
+ pickItemsMock.mockReturnValue([]);
+
+ const user = userEvent.setup();
+ render(
+
+
+ } />
+
+ ,
+ );
+
+ // Get the combobox (product input), open it and select the option
+ const combobox = screen.getByRole('combobox', { name: /search products/i }) || screen.getByTestId('product-search-input');
+ await user.click(combobox);
+
+ // Wait for the listbox to appear and click the option
+ const listbox = await screen.findByRole('listbox');
+ await user.click(within(listbox).getByRole('option', { name: /cola/i }));
+
+ // Assert add was called
+ await waitFor(() => {
+ expect(addMock).toHaveBeenCalled();
+ const added = addMock.mock.calls[0][0];
+ expect(added).toEqual(expect.objectContaining({ product_id: 'prod-1', quantity: 1, is_carton: false }));
+ });
+ });
+
+ it('shows "No items match the filter" when visible items exist but none match search', async () => {
+ pickItemsMock.mockReturnValue([
+ { id: 'item-1', pick_list_id: 'list-1', product_id: 'prod-1', quantity: 1, is_carton: false, status: 'pending', created_at: 0, updated_at: 0 },
+ ]);
+
+ const user = userEvent.setup();
+ render(
+
+
+ } />
+
+ ,
+ );
+
+ const listSearch = screen.getByPlaceholderText(/search list/i) || screen.getByRole('textbox', { name: /search list/i });
+ await user.type(listSearch, 'nomatchtext');
+
+ expect(await screen.findByText(/no items match the filter/i)).toBeVisible();
+ });
+
+ it('categoryFilter restricts visible items to selected category', async () => {
+ productsMock.mockReturnValue([
+ ...products,
+ { id: 'prod-2', name: 'Chips', category: 'other', unit_type: 'unit', bulk_name: 'box', created_at: 0, updated_at: 0, archived: false },
+ ]);
+ pickItemsMock.mockReturnValue([
+ { id: 'item-1', pick_list_id: 'list-1', product_id: 'prod-1', quantity: 1, is_carton: false, status: 'pending', created_at: 0, updated_at: 0 },
+ { id: 'item-2', pick_list_id: 'list-1', product_id: 'prod-2', quantity: 1, is_carton: false, status: 'pending', created_at: 0, updated_at: 0 },
+ ]);
+
+ const user = userEvent.setup();
+ render(
+
+
+ } />
+
+ ,
+ );
+
+ const select = screen.getByLabelText(/filter by category/i) as HTMLSelectElement;
+ await user.selectOptions(select, ['c1']);
+
+ expect(screen.getByText(/cola/i)).toBeVisible();
+ expect(screen.queryByText(/chips/i)).not.toBeInTheDocument();
+ });
+});
diff --git a/src/screens/ManageCategoriesScreen.additional.test.tsx b/src/screens/ManageCategoriesScreen.additional.test.tsx
new file mode 100644
index 0000000..df9e5e8
--- /dev/null
+++ b/src/screens/ManageCategoriesScreen.additional.test.tsx
@@ -0,0 +1,122 @@
+// src/screens/ManageCategoriesScreen.additional.test.tsx
+import { MemoryRouter } from 'react-router-dom';
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import ManageCategoriesScreen from './ManageCategoriesScreen';
+
+const categories = [
+ { id: 'cat-1', name: 'Snacks', created_at: 0, updated_at: 0 },
+ { id: 'cat-2', name: 'Drinks', created_at: 0, updated_at: 0 },
+];
+
+const products = [
+ { id: 'prod-1', name: 'Chips', category: 'Snacks', archived: false, created_at: 0, updated_at: 0 },
+];
+
+const categoryAddMock = vi.fn();
+const categoryUpdateMock = vi.fn();
+const categoryDeleteMock = vi.fn();
+const productModifyMock = vi.fn();
+const pickListsUpdateMock = vi.fn();
+
+// Mock hooks
+vi.mock('../hooks/dataHooks', () => ({
+ useCategories: () => categories,
+ useProducts: () => products,
+}));
+
+// Mock DBProvider to catch pickLists.update and categories.update/delete
+vi.mock('../context/DBProvider', () => ({
+ useDatabase: () => ({
+ transaction: async (...args: unknown[]) => {
+ const cb = args[args.length - 1];
+ if (typeof cb === 'function') await (cb as () => Promise)();
+ },
+ categories: { add: categoryAddMock, update: categoryUpdateMock, delete: categoryDeleteMock },
+ products: {
+ where: () => ({
+ equals: (_: string) => ({
+ count: async () => 0,
+ modify: async (changes: any) => productModifyMock(changes),
+ }),
+ }),
+ },
+ pickLists: {
+ toArray: async () => [{ id: 'pl-1', categories: ['Snacks'], created_at: 0, updated_at: 0 }],
+ update: pickListsUpdateMock,
+ },
+ }),
+}));
+
+describe('ManageCategoriesScreen additional', () => {
+ beforeEach(() => {
+ categoryAddMock.mockReset();
+ categoryUpdateMock.mockReset();
+ categoryDeleteMock.mockReset();
+ productModifyMock.mockReset();
+ pickListsUpdateMock.mockReset();
+ });
+
+ it('updates pickLists when category name is changed (legacy name in pickLists.categories)', async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ await user.click(screen.getByRole('button', { name: /edit snacks/i }));
+ const editField = screen.getByDisplayValue(/snacks/i);
+ await user.clear(editField);
+ await user.type(editField, 'Treats');
+ await user.click(screen.getByRole('button', { name: /save category/i }));
+
+ // categories.update should have been called
+ expect(categoryUpdateMock).toHaveBeenCalled();
+
+ // and pickLists.update should have been called to update the categories array
+ expect(pickListsUpdateMock).toHaveBeenCalled();
+ expect(await screen.findByText(/category updated/i)).toBeVisible();
+ });
+
+ it('deletes category when no products reference it', async () => {
+ // products.where().equals().count() is 0 in our mock, so delete should proceed
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ // Click the "Delete Snacks" icon/button (specific aria-label)
+ await user.click(screen.getByRole('button', { name: /delete snacks/i }));
+
+ // Wait for the delete mock to be called (component calls the onDelete handler)
+ await waitFor(() => {
+ expect(categoryDeleteMock).toHaveBeenCalled();
+ });
+
+ // And assert the success alert is shown
+ expect(await screen.findByText(/category deleted/i)).toBeVisible();
+ });
+
+ it('prevents renaming to an existing name', async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ await user.click(screen.getByRole('button', { name: /edit snacks/i }));
+ const editField = screen.getByDisplayValue(/snacks/i);
+ await user.clear(editField);
+ await user.type(editField, 'Drinks'); // name that already exists
+ await user.click(screen.getByRole('button', { name: /save category/i }));
+
+ // Should show "already exists" and NOT call update
+ expect(categoryUpdateMock).not.toHaveBeenCalled();
+ expect(await screen.findByText(/already exists/i)).toBeVisible();
+ });
+});
diff --git a/src/testUtils/mockDb.test.ts b/src/testUtils/mockDb.test.ts
new file mode 100644
index 0000000..2ed8ca1
--- /dev/null
+++ b/src/testUtils/mockDb.test.ts
@@ -0,0 +1,75 @@
+// src/testUtils/mockDb.test.ts
+import { describe, it, expect } from 'vitest';
+import { MockTable, createMockDb } from './mockDb';
+
+type Item = { id: string; category?: string; name?: string };
+
+describe('MockTable basic operations', () => {
+ it('supports toArray, add, get, put (update + insert) and delete', async () => {
+ const t = new MockTable- ([{ id: 'a', name: 'alpha' }]);
+
+ // toArray
+ expect(await t.toArray()).toHaveLength(1);
+
+ // add
+ await t.add({ id: 'b', name: 'beta' });
+ expect((await t.toArray()).map((i) => i.id)).toContain('b');
+
+ // get
+ expect((await t.get('b'))?.name).toBe('beta');
+
+ // put (update)
+ await t.put({ id: 'a', name: 'alpha-updated' });
+ expect((await t.get('a'))?.name).toBe('alpha-updated');
+
+ // put (insert)
+ await t.put({ id: 'c', name: 'gamma' });
+ expect((await t.toArray()).map((i) => i.id)).toContain('c');
+
+ // delete
+ await t.delete('b');
+ expect(await t.get('b')).toBeUndefined();
+ });
+
+ it('where().equals().first / count / filter works and filter.delete removes items', async () => {
+ const t = new MockTable
- ([
+ { id: '1', category: 'x' },
+ { id: '2', category: 'x' },
+ { id: '3', category: 'y' },
+ ]);
+
+ // first
+ const firstX = await t.where('category').equals('x').first();
+ expect(firstX?.id).toBe('1');
+
+ // count
+ const countX = await t.where('category').equals('x').count();
+ expect(countX).toBe(2);
+
+ // equals(...).filter(...).first()
+ const filteredFirst = await t.where('category').equals('x').filter((it: any) => it.id === '2').first();
+ expect(filteredFirst?.id).toBe('2');
+
+ // filter(pred).delete() and filter(...).first()
+ const before = await t.toArray();
+ expect(before.some((i) => i.category === 'y')).toBeTruthy();
+
+ const f = t.filter((it: any) => it.category === 'y');
+ await f.delete();
+ const after = await t.toArray();
+ expect(after.some((i) => i.category === 'y')).toBeFalsy();
+ });
+
+ it('transaction executes callback when provided and returns undefined otherwise', async () => {
+ const db = createMockDb({});
+ let called = false;
+ await db.transaction('rw', async () => {
+ called = true;
+ });
+ expect(called).toBe(true);
+
+ // when last arg isn't a function, it should resolve and return undefined
+ const res = await db.transaction('rw');
+ expect(res).toBeUndefined();
+ });
+});