chore(website): remove tests and update SvelteKit
This commit is contained in:
@@ -5,7 +5,6 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||||||
cd "$ROOT_DIR/website"
|
cd "$ROOT_DIR/website"
|
||||||
|
|
||||||
bun install --frozen-lockfile
|
bun install --frozen-lockfile
|
||||||
bun test
|
|
||||||
bun run check
|
bun run check
|
||||||
bun run build
|
bun run build
|
||||||
python3 "$ROOT_DIR/scripts/test_check_bun_audit.py"
|
python3 "$ROOT_DIR/scripts/test_check_bun_audit.py"
|
||||||
|
|||||||
+13
-7
@@ -11,7 +11,7 @@
|
|||||||
"@iconify/json": "^2.2.474",
|
"@iconify/json": "^2.2.474",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/enhanced-img": "^0.10.4",
|
"@sveltejs/enhanced-img": "^0.10.4",
|
||||||
"@sveltejs/kit": "^2.50.1",
|
"@sveltejs/kit": "^2.70.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||||
"google-play-scraper": "^10.1.2",
|
"google-play-scraper": "^10.1.2",
|
||||||
"svelte": "^5.48.2",
|
"svelte": "^5.48.2",
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.8", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA=="],
|
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.11", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-LFuZUkjJ9iF7JZye/aG5XM0SFcQ5VyL0oVX4WJ9dc0Va3R3s0OauX1BESVCb+YN/ol8TAfqGDDAQsTG627Y5kw=="],
|
||||||
|
|
||||||
"@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@7.0.0", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-ImDWaErTOCkRS4Gt+5gZuymKFBobnhChXUZ9lhUZLahUgvA4OOvRzi3sahzYgbxGj5nkA6OV0GAW378+dl/gyw=="],
|
"@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@7.0.0", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-ImDWaErTOCkRS4Gt+5gZuymKFBobnhChXUZ9lhUZLahUgvA4OOvRzi3sahzYgbxGj5nkA6OV0GAW378+dl/gyw=="],
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
|
|
||||||
"@sveltejs/enhanced-img": ["@sveltejs/enhanced-img@0.10.4", "", { "dependencies": { "magic-string": "^0.30.5", "sharp": "^0.34.1", "svelte-parse-markup": "^0.1.5", "vite-imagetools": "^9.0.3", "zimmerframe": "^1.1.2" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0 || ^7.0.0", "svelte": "^5.0.0", "vite": "^6.3.0 || >=7.0.0" } }, "sha512-Am5nmAKUo7Nboqq7Dhtfn7dcXA087d7gIz6Vecn1opB41aJ680+0q9U9KvEcMgduOyeiwckTIOQOx4Mmq9GcvA=="],
|
"@sveltejs/enhanced-img": ["@sveltejs/enhanced-img@0.10.4", "", { "dependencies": { "magic-string": "^0.30.5", "sharp": "^0.34.1", "svelte-parse-markup": "^0.1.5", "vite-imagetools": "^9.0.3", "zimmerframe": "^1.1.2" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0 || ^7.0.0", "svelte": "^5.0.0", "vite": "^6.3.0 || >=7.0.0" } }, "sha512-Am5nmAKUo7Nboqq7Dhtfn7dcXA087d7gIz6Vecn1opB41aJ680+0q9U9KvEcMgduOyeiwckTIOQOx4Mmq9GcvA=="],
|
||||||
|
|
||||||
"@sveltejs/kit": ["@sveltejs/kit@2.50.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.6.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-875hTUkEbz+MyJIxWbQjfMaekqdmEKUUfR7JyKcpfMRZqcGyrO9Gd+iS1D/Dx8LpE5FEtutWGOtlAh4ReSAiOA=="],
|
"@sveltejs/kit": ["@sveltejs/kit@2.70.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.9", "@types/cookie": "^0.6.0", "acorn": "^8.16.0", "cookie": "^0.6.0", "devalue": "^5.8.1", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-nY9SPHGOZro3doud9vZXDBwl9tCZIouuJztjgSHs6PAIrv9M/z5O7eOhPV5xU7CgVHA976Jwu3BA1hIFvXztkA=="],
|
||||||
|
|
||||||
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.4", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", "magic-string": "^0.30.21", "obug": "^2.1.0", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA=="],
|
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@6.2.4", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", "magic-string": "^0.30.21", "obug": "^2.1.0", "vitefu": "^1.1.1" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA=="],
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
|
|
||||||
"@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="],
|
"@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
||||||
|
|
||||||
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||||
|
|
||||||
"devalue": ["devalue@5.6.2", "", {}, "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg=="],
|
"devalue": ["devalue@5.8.2", "", {}, "sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA=="],
|
||||||
|
|
||||||
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
||||||
|
|
||||||
@@ -503,12 +503,18 @@
|
|||||||
|
|
||||||
"htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
|
"htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
|
||||||
|
|
||||||
"mlly/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
|
||||||
|
|
||||||
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||||
|
|
||||||
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
||||||
|
|
||||||
|
"svelte/@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.8", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA=="],
|
||||||
|
|
||||||
|
"svelte/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
|
"svelte/devalue": ["devalue@5.6.2", "", {}, "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg=="],
|
||||||
|
|
||||||
|
"unplugin/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,7 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"reviewedOn": "2026-07-21",
|
"reviewedOn": "2026-07-24",
|
||||||
"accepted": [
|
"accepted": [
|
||||||
{
|
|
||||||
"id": 1113317,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "moderate",
|
|
||||||
"vulnerableRange": ">=2.49.0 <=2.52.1",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-88qp-p4qg-rqm6: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1113318,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "moderate",
|
|
||||||
"vulnerableRange": ">=2.49.0 <=2.52.1",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-vrhm-gvg7-fpcf: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1113631,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "low",
|
|
||||||
"vulnerableRange": ">=2.49.0 <=2.53.2",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-fpg4-jhqr-589c: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1116432,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "moderate",
|
|
||||||
"vulnerableRange": "<=2.57.0",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-3f6h-2hrp-w5wx: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1116433,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "high",
|
|
||||||
"vulnerableRange": "<=2.57.0",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-2crg-3p73-43xp: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 1122155,
|
|
||||||
"package": "@sveltejs/kit",
|
|
||||||
"severity": "moderate",
|
|
||||||
"vulnerableRange": ">=2.38.0 <=2.60.0",
|
|
||||||
"expiresOn": "2026-10-19",
|
|
||||||
"rationale": "GHSA-hgv7-v322-mmgr: Static adapter/prerender site has no remote functions or forms, query.batch, hooks/redirects, or adapter-node body handling."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 1103907,
|
"id": 1103907,
|
||||||
"package": "cookie",
|
"package": "cookie",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"audit": "python3 ../scripts/check_bun_audit.py --project . --baseline bun_audit_baseline.json",
|
"audit": "python3 ../scripts/check_bun_audit.py --project . --baseline bun_audit_baseline.json",
|
||||||
"test": "bun test",
|
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"prepare": "svelte-kit sync || echo ''",
|
"prepare": "svelte-kit sync || echo ''",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
"@iconify/json": "^2.2.474",
|
"@iconify/json": "^2.2.474",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/enhanced-img": "^0.10.4",
|
"@sveltejs/enhanced-img": "^0.10.4",
|
||||||
"@sveltejs/kit": "^2.50.1",
|
"@sveltejs/kit": "^2.70.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||||
"google-play-scraper": "^10.1.2",
|
"google-play-scraper": "^10.1.2",
|
||||||
"svelte": "^5.48.2",
|
"svelte": "^5.48.2",
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
|
||||||
import { createServer, type ViteDevServer } from 'vite';
|
|
||||||
|
|
||||||
let vite: ViteDevServer;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
vite = await createServer({
|
|
||||||
root: process.cwd(),
|
|
||||||
appType: 'custom',
|
|
||||||
server: { middlewareMode: true },
|
|
||||||
});
|
|
||||||
}, 30_000);
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await vite?.close();
|
|
||||||
}, 30_000);
|
|
||||||
|
|
||||||
async function renderComponent(path: string): Promise<string> {
|
|
||||||
const [{ default: component }, { render: renderOnViteGraph }] = await Promise.all([
|
|
||||||
vite.ssrLoadModule(path),
|
|
||||||
vite.ssrLoadModule('svelte/server'),
|
|
||||||
]);
|
|
||||||
return renderOnViteGraph(component).body;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('SSR component contracts', () => {
|
|
||||||
test('Logo renders the one managed asset as a decorative non-draggable image', async () => {
|
|
||||||
const html = await renderComponent('/src/lib/components/Logo.svelte');
|
|
||||||
expect(html).toContain('<img');
|
|
||||||
expect(html).toContain('alt=""');
|
|
||||||
expect(html).toContain('aria-hidden="true"');
|
|
||||||
expect(html).toContain('draggable="false"');
|
|
||||||
expect(html).not.toContain('<path');
|
|
||||||
}, 30_000);
|
|
||||||
|
|
||||||
test('Linux downloads prerender as an ordinary inert disclosure', async () => {
|
|
||||||
const html = await renderComponent('/src/lib/components/DownloadButtons.svelte');
|
|
||||||
expect(html).toContain('aria-expanded="false"');
|
|
||||||
expect(html).toContain('aria-controls="');
|
|
||||||
expect(html).toContain('aria-hidden="true"');
|
|
||||||
expect(html).toContain('inert');
|
|
||||||
expect(html).not.toContain('aria-haspopup');
|
|
||||||
expect(html).not.toContain('role="menu"');
|
|
||||||
expect(html).not.toContain('role="menuitem"');
|
|
||||||
expect(html.match(/plezy-linux-(?:x64|arm64)\.(?:deb|rpm|pkg\.tar\.zst|tar\.gz)/g)).toHaveLength(8);
|
|
||||||
}, 30_000);
|
|
||||||
test('Screenshots prerender stable regions but only the initial lazy phone images', async () => {
|
|
||||||
const html = await renderComponent('/src/lib/components/Screenshots.svelte');
|
|
||||||
for (const device of ['phone', 'tablet', 'desktop', 'tv']) {
|
|
||||||
expect(html).toContain(`id="screenshots-${device}-panel"`);
|
|
||||||
}
|
|
||||||
expect(html.match(/<picture\b/g)).toHaveLength(4);
|
|
||||||
expect(html.match(/loading="lazy"/g)).toHaveLength(4);
|
|
||||||
expect(html.match(/width="\d+" height="\d+"/g)).toHaveLength(4);
|
|
||||||
expect(html).toContain('alt="Plezy home screen"');
|
|
||||||
expect(html).toContain('style="opacity: 1; transform: translateY(0px);');
|
|
||||||
expect(html).not.toContain('alt="Plezy on tablet - home"');
|
|
||||||
expect(html).not.toContain('alt="Plezy on desktop - home"');
|
|
||||||
expect(html).not.toContain('alt="Plezy on TV - home"');
|
|
||||||
}, 120_000);
|
|
||||||
});
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
|
||||||
import { createServer, type ViteDevServer } from 'vite';
|
|
||||||
|
|
||||||
import { faqs, faqSchemaMainEntity, watchTogetherFaqAnswer } from '../src/lib/content/faqs';
|
|
||||||
import { csr, prerender } from '../src/routes/privacy/+page';
|
|
||||||
|
|
||||||
let vite: ViteDevServer;
|
|
||||||
let renderedPrivacyHead: string;
|
|
||||||
let renderedPrivacyHtml: string;
|
|
||||||
let privacySource: string;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
vite = await createServer({
|
|
||||||
root: process.cwd(),
|
|
||||||
appType: 'custom',
|
|
||||||
server: { middlewareMode: true },
|
|
||||||
});
|
|
||||||
const [{ default: privacyPage }, { render }] = await Promise.all([
|
|
||||||
vite.ssrLoadModule('/src/routes/privacy/+page.svelte'),
|
|
||||||
vite.ssrLoadModule('svelte/server'),
|
|
||||||
]);
|
|
||||||
const rendered = render(privacyPage);
|
|
||||||
renderedPrivacyHead = rendered.head;
|
|
||||||
renderedPrivacyHtml = rendered.body;
|
|
||||||
privacySource = await Bun.file('src/routes/privacy/+page.svelte').text();
|
|
||||||
}, 90_000);
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await vite?.close();
|
|
||||||
}, 30_000);
|
|
||||||
|
|
||||||
function visibleText(html: string): string {
|
|
||||||
return html
|
|
||||||
.replace(/<[^>]+>/g, ' ')
|
|
||||||
.replaceAll('&', '&')
|
|
||||||
.replaceAll(''', "'")
|
|
||||||
.replace(/\s+/g, ' ')
|
|
||||||
.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('privacy page', () => {
|
|
||||||
test('remains a prerendered, server-rendered route', () => {
|
|
||||||
expect(prerender).toBe(true);
|
|
||||||
expect(csr).toBe(false);
|
|
||||||
expect(renderedPrivacyHead).toContain('<title>Privacy Policy - Plezy</title>');
|
|
||||||
expect(renderedPrivacyHead).toContain('<link rel="canonical" href="https://plezy.app/privacy"');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('renders a concise semantic policy without inventory cards or grids', () => {
|
|
||||||
for (const heading of [
|
|
||||||
'Overview',
|
|
||||||
'Data on your device',
|
|
||||||
'Connections and third parties',
|
|
||||||
'Optional Plezy services',
|
|
||||||
'Your choices',
|
|
||||||
'Retention and security',
|
|
||||||
'Contact and changes',
|
|
||||||
]) {
|
|
||||||
expect(renderedPrivacyHtml).toContain(`>${heading}</h2>`);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(renderedPrivacyHtml.match(/<section/g)).toHaveLength(7);
|
|
||||||
expect(renderedPrivacyHtml).not.toContain('flow-card');
|
|
||||||
expect(renderedPrivacyHtml).not.toContain('<dl');
|
|
||||||
expect(renderedPrivacyHtml).not.toContain('<ul');
|
|
||||||
expect(privacySource).not.toContain('display: grid');
|
|
||||||
expect(visibleText(renderedPrivacyHtml).split(' ').length).toBeLessThan(900);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('uses first-party language and preserves the material privacy boundaries', () => {
|
|
||||||
const text = visibleText(renderedPrivacyHtml);
|
|
||||||
|
|
||||||
expect(text).not.toMatch(/\brepositor(?:y|ies)\b/i);
|
|
||||||
expect(text).not.toMatch(/repository-verified/i);
|
|
||||||
expect(text).toContain('We do not sell personal data or use it for advertising');
|
|
||||||
expect(text).toContain('access tokens and other sign-in data');
|
|
||||||
expect(text).toContain('may contain a server access credential');
|
|
||||||
expect(text).toContain('does not carry the media stream or your media-server credentials');
|
|
||||||
expect(text).toContain('Support-log uploads are always explicit');
|
|
||||||
expect(text).toContain('up to 90 days');
|
|
||||||
expect(text).toContain('retrieved for three days');
|
|
||||||
expect(text).toContain('no more than three hours');
|
|
||||||
expect(renderedPrivacyHtml).toContain('rel="noopener noreferrer"');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('keeps the Watch Together disclosure aligned with visible FAQ content', () => {
|
|
||||||
const faqIndex = faqs.findIndex((faq) => faq.id === 'watch-together');
|
|
||||||
expect(faqIndex).toBeGreaterThanOrEqual(0);
|
|
||||||
expect(faqs[faqIndex]!.answer).toBe(watchTogetherFaqAnswer);
|
|
||||||
expect(faqSchemaMainEntity[faqIndex]!.acceptedAnswer.text).toBe(watchTogetherFaqAnswer);
|
|
||||||
expect(watchTogetherFaqAnswer).toContain('server and media identifiers');
|
|
||||||
expect(watchTogetherFaqAnswer).toContain('does not relay the media stream');
|
|
||||||
expect(watchTogetherFaqAnswer).toContain('custom relay');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
||||||
|
|
||||||
import {
|
|
||||||
detectMobileStorePlatform,
|
|
||||||
linuxArchitectures,
|
|
||||||
storeOptionsForPlatform,
|
|
||||||
} from '../src/lib/content/downloads';
|
|
||||||
import {
|
|
||||||
buildSoftwareApplicationOffers,
|
|
||||||
normalizeUsdStorePrice,
|
|
||||||
} from '../src/lib/content/software_app_offers';
|
|
||||||
|
|
||||||
type PlayStoreFixture = {
|
|
||||||
available?: boolean;
|
|
||||||
price?: unknown;
|
|
||||||
currency?: unknown;
|
|
||||||
score?: number;
|
|
||||||
ratings?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
let playStoreFixture: PlayStoreFixture | Error;
|
|
||||||
|
|
||||||
mock.module('google-play-scraper', () => ({
|
|
||||||
default: {
|
|
||||||
app: async () => {
|
|
||||||
if (playStoreFixture instanceof Error) throw playStoreFixture;
|
|
||||||
return playStoreFixture;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Dynamic loading is intentional here: Bun must install the scraper mock before
|
|
||||||
// the route first loads its optional external dependency.
|
|
||||||
const { load } = await import('../src/routes/+page.server');
|
|
||||||
|
|
||||||
function appleFetch(body: unknown, status = 200): typeof fetch {
|
|
||||||
return (async () => new Response(JSON.stringify(body), {
|
|
||||||
status,
|
|
||||||
headers: { 'content-type': 'application/json' },
|
|
||||||
})) as typeof fetch;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadHomepage(fetcher: typeof fetch) {
|
|
||||||
return await (load as (event: { fetch: typeof fetch }) => Promise<{
|
|
||||||
appStorePrice: string | null;
|
|
||||||
playStorePrice: string | null;
|
|
||||||
aggregateRating: { ratingValue: string; ratingCount: number } | null;
|
|
||||||
}>)({ fetch: fetcher });
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
playStoreFixture = {
|
|
||||||
available: true,
|
|
||||||
price: 4.99,
|
|
||||||
currency: 'USD',
|
|
||||||
score: 4.5,
|
|
||||||
ratings: 10,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
mock.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('download component contracts', () => {
|
|
||||||
test('detects mobile stores without browser globals', () => {
|
|
||||||
expect(detectMobileStorePlatform()).toBe('unknown');
|
|
||||||
expect(detectMobileStorePlatform({ userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0)' })).toBe('ios');
|
|
||||||
expect(detectMobileStorePlatform({ userAgent: 'Mozilla/5.0 (Linux; Android 15)' })).toBe('android');
|
|
||||||
expect(detectMobileStorePlatform({
|
|
||||||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)',
|
|
||||||
platform: 'MacIntel',
|
|
||||||
maxTouchPoints: 5,
|
|
||||||
})).toBe('ios');
|
|
||||||
expect(detectMobileStorePlatform({
|
|
||||||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)',
|
|
||||||
platform: 'MacIntel',
|
|
||||||
maxTouchPoints: 0,
|
|
||||||
})).toBe('unknown');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('unknown platforms retain both truthful store choices', () => {
|
|
||||||
expect(storeOptionsForPlatform('unknown').map((option) => option.label)).toEqual(['App Store', 'Google Play']);
|
|
||||||
expect(storeOptionsForPlatform('ios').map((option) => option.label)).toEqual(['App Store']);
|
|
||||||
expect(storeOptionsForPlatform('android').map((option) => option.label)).toEqual(['Google Play']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Linux disclosure data contains both architectures and eight unique native links', () => {
|
|
||||||
expect(linuxArchitectures.map((architecture) => architecture.label)).toEqual(['x64 (Intel/AMD)', 'ARM64']);
|
|
||||||
const links = linuxArchitectures.flatMap((architecture) => architecture.formats.map((format) => format.url));
|
|
||||||
expect(links).toHaveLength(8);
|
|
||||||
expect(new Set(links).size).toBe(8);
|
|
||||||
expect(links.every((url) => url.startsWith('https://github.com/edde746/plezy/releases/latest/download/'))).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('homepage store metadata', () => {
|
|
||||||
test('normalizes only finite nonnegative numeric USD prices', () => {
|
|
||||||
expect(normalizeUsdStorePrice(4.99, 'USD')).toBe('4.99');
|
|
||||||
expect(normalizeUsdStorePrice(0, 'USD')).toBe('0');
|
|
||||||
for (const value of [null, undefined, '4.99', Number.NaN, Number.POSITIVE_INFINITY, -1]) {
|
|
||||||
expect(normalizeUsdStorePrice(value, 'USD')).toBeNull();
|
|
||||||
}
|
|
||||||
expect(normalizeUsdStorePrice(4.99, undefined)).toBeNull();
|
|
||||||
expect(normalizeUsdStorePrice(4.99, 'EUR')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('keeps Google Play metadata when the App Store request fails', async () => {
|
|
||||||
const data = await loadHomepage((async () => {
|
|
||||||
throw new Error('offline');
|
|
||||||
}) as typeof fetch);
|
|
||||||
expect(data.appStorePrice).toBeNull();
|
|
||||||
expect(data.playStorePrice).toBe('4.99');
|
|
||||||
expect(data.aggregateRating).toEqual({ ratingValue: '4.5', ratingCount: 10 });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('keeps App Store metadata when Google Play is unavailable', async () => {
|
|
||||||
playStoreFixture = { available: false, price: 0, currency: 'USD' };
|
|
||||||
const data = await loadHomepage(appleFetch({
|
|
||||||
results: [{ price: 5.99, currency: 'USD', averageUserRating: 4, userRatingCount: 20 }],
|
|
||||||
}));
|
|
||||||
expect(data.appStorePrice).toBe('5.99');
|
|
||||||
expect(data.playStorePrice).toBeNull();
|
|
||||||
expect(data.aggregateRating).toEqual({ ratingValue: '4.0', ratingCount: 20 });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('keeps App Store metadata when Google Play throws', async () => {
|
|
||||||
playStoreFixture = new Error('scraper failed');
|
|
||||||
const data = await loadHomepage(appleFetch({
|
|
||||||
results: [{ price: 5.99, currency: 'USD' }],
|
|
||||||
}));
|
|
||||||
expect(data.appStorePrice).toBe('5.99');
|
|
||||||
expect(data.playStorePrice).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('rejects non-OK and malformed store responses independently', async () => {
|
|
||||||
playStoreFixture = { price: 'free', currency: 'USD' };
|
|
||||||
const data = await loadHomepage(appleFetch({ results: [{ price: 4.99, currency: 'USD' }] }, 503));
|
|
||||||
expect(data.appStorePrice).toBeNull();
|
|
||||||
expect(data.playStorePrice).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('retains paid store URLs when live prices are unavailable', () => {
|
|
||||||
const unavailable = buildSoftwareApplicationOffers({ appStorePrice: null, playStorePrice: null });
|
|
||||||
expect(unavailable.map((offer) => offer.category)).toEqual([
|
|
||||||
'App Store',
|
|
||||||
'Google Play',
|
|
||||||
'Amazon Appstore',
|
|
||||||
'GitHub',
|
|
||||||
]);
|
|
||||||
expect(unavailable.find((offer) => offer.category === 'App Store')).toMatchObject({
|
|
||||||
url: 'https://apps.apple.com/us/app/id6754315964',
|
|
||||||
});
|
|
||||||
expect(unavailable.find((offer) => offer.category === 'Google Play')).toMatchObject({
|
|
||||||
url: 'https://play.google.com/store/apps/details?id=com.edde746.plezy',
|
|
||||||
});
|
|
||||||
expect(unavailable.filter((offer) => offer.price === '0').map((offer) => offer.category)).toEqual(['GitHub']);
|
|
||||||
expect(
|
|
||||||
unavailable
|
|
||||||
.filter((offer) => ['App Store', 'Google Play'].includes(offer.category))
|
|
||||||
.every((offer) => !('price' in offer)),
|
|
||||||
).toBe(true);
|
|
||||||
|
|
||||||
const available = buildSoftwareApplicationOffers({ appStorePrice: '5.99', playStorePrice: '4.99' });
|
|
||||||
expect(available.find((offer) => offer.category === 'App Store')).toMatchObject({ price: '5.99', priceCurrency: 'USD' });
|
|
||||||
expect(available.find((offer) => offer.category === 'Google Play')).toMatchObject({ price: '4.99', priceCurrency: 'USD' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user