Commit 652c29ccea7f286a8ef85cdb5bb5c30e33a4b3e0

Authored by yibo
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(&quot;node:test&quot;);
6 6 const assert = require("node:assert/strict");
7 7 const fs = require("node:fs");
8 8 const path = require("node:path");
  9 +const os = require("node:os");
9 10 const { spawn } = require("node:child_process");
10 11 const http = require("node:http");
11 12  
... ... @@ -37,9 +38,22 @@ function waitForServer(url, timeoutMs = 10000) {
37 38 }
38 39  
39 40 let child;
  41 +let cwd;
40 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 55 child = spawn(process.execPath, ["server.js"], {
42   - cwd: __dirname,
  56 + cwd,
43 57 // H3_CONSOLE_BASE cleared: this test only exercises the upload route,
44 58 // no need for the spawned copy to also hit the real H3 Console /
45 59 // race the live pm2 instance on library.json's periodic sync.
... ... @@ -58,10 +72,7 @@ test.before(async () =&gt; {
58 72  
59 73 test.after(() => {
60 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 78 test("uploading a real mp4 via /api/admin/upload-video returns a URL that GET /uploads/* serves back as video/mp4", async () => {
... ...