Commit 652c29ccea7f286a8ef85cdb5bb5c30e33a4b3e0
1 parent
4ccccfc3
Fix: uploads-route.test.js was deleting the real uploads/ directory
Spawned server.js with cwd: __dirname (the real repo path, not an isolated copy), so its own test.after() cleanup — rm -rf on "uploads/" — wiped every real uploaded file in the repo on every `node --test` run, not just what the test itself created. Discovered after running the suite several times today silently deleted this session's real character/garment/dance-ref source images (the generated dance videos in library.json were unaffected — those proxy from H3, not served from disk — but admin/dance.html thumbnails broke until the images were re-uploaded). Now spawns from an fs.mkdtempSync isolated copy and cleans up only that tmpdir, matching the pattern already used correctly in dressup-generate.test.js and dance-channel.test.js. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y
Showing
1 changed file
with
16 additions
and
5 deletions
uploads-route.test.js
| @@ -6,6 +6,7 @@ const test = require("node:test"); | @@ -6,6 +6,7 @@ const test = require("node:test"); | ||
| 6 | const assert = require("node:assert/strict"); | 6 | const assert = require("node:assert/strict"); |
| 7 | const fs = require("node:fs"); | 7 | const fs = require("node:fs"); |
| 8 | const path = require("node:path"); | 8 | const path = require("node:path"); |
| 9 | +const os = require("node:os"); | ||
| 9 | const { spawn } = require("node:child_process"); | 10 | const { spawn } = require("node:child_process"); |
| 10 | const http = require("node:http"); | 11 | const http = require("node:http"); |
| 11 | 12 | ||
| @@ -37,9 +38,22 @@ function waitForServer(url, timeoutMs = 10000) { | @@ -37,9 +38,22 @@ function waitForServer(url, timeoutMs = 10000) { | ||
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | let child; | 40 | let child; |
| 41 | +let cwd; | ||
| 40 | test.before(async () => { | 42 | test.before(async () => { |
| 43 | + // server.js resolves uploads/ relative to its own __dirname, not PORT — | ||
| 44 | + // a past version of this test spawned server.js with cwd: __dirname | ||
| 45 | + // (the real repo) and then rm -rf'd the whole uploads/ directory in | ||
| 46 | + // test.after as "cleanup", which wiped real uploaded content on every | ||
| 47 | + // `node --test` run. Spawn from an isolated tmpdir copy instead, same | ||
| 48 | + // pattern as dressup-generate.test.js / dance-channel.test.js, so this | ||
| 49 | + // test can never touch the real repo's uploads/. | ||
| 50 | + cwd = fs.mkdtempSync(path.join(os.tmpdir(), "uploads-route-test-")); | ||
| 51 | + for (const f of ["server.js", "ingest.js", "uploads.js", "store.js", "dressup-store.js", "prompt-template.js"]) { | ||
| 52 | + fs.copyFileSync(path.join(__dirname, f), path.join(cwd, f)); | ||
| 53 | + } | ||
| 54 | + | ||
| 41 | child = spawn(process.execPath, ["server.js"], { | 55 | child = spawn(process.execPath, ["server.js"], { |
| 42 | - cwd: __dirname, | 56 | + cwd, |
| 43 | // H3_CONSOLE_BASE cleared: this test only exercises the upload route, | 57 | // H3_CONSOLE_BASE cleared: this test only exercises the upload route, |
| 44 | // no need for the spawned copy to also hit the real H3 Console / | 58 | // no need for the spawned copy to also hit the real H3 Console / |
| 45 | // race the live pm2 instance on library.json's periodic sync. | 59 | // race the live pm2 instance on library.json's periodic sync. |
| @@ -58,10 +72,7 @@ test.before(async () => { | @@ -58,10 +72,7 @@ test.before(async () => { | ||
| 58 | 72 | ||
| 59 | test.after(() => { | 73 | test.after(() => { |
| 60 | child.kill(); | 74 | child.kill(); |
| 61 | - // uploads/ written by this test run lands under the real repo path | ||
| 62 | - // (server.js resolves it relative to __dirname, not PORT) — clean it up. | ||
| 63 | - const dir = path.join(__dirname, "uploads"); | ||
| 64 | - fs.rmSync(dir, { recursive: true, force: true }); | 75 | + fs.rmSync(cwd, { recursive: true, force: true }); |
| 65 | }); | 76 | }); |
| 66 | 77 | ||
| 67 | test("uploading a real mp4 via /api/admin/upload-video returns a URL that GET /uploads/* serves back as video/mp4", async () => { | 78 | test("uploading a real mp4 via /api/admin/upload-video returns a URL that GET /uploads/* serves back as video/mp4", async () => { |