Files
bitvid/tests/edit-modal-upload-field.test.mjs
thePR0M3TH3ANandClaude Opus 4.8 c8a63c57c6 feat(edit): thumbnail + video file upload in Edit modal (steps 2-3/3)
Brings the Edit modal to upload parity with the Upload modal: re-upload a
thumbnail or video file instead of only pasting URLs.

- Wire storage services (r2/s3/storageService) + pubkey/npub accessors into
  EditModal via ModalManager/initEditModal; EditModal constructs a shared
  MediaUploader.
- New editModalUpload.js holds all the upload glue (file-picker wiring, progress,
  storage-unlock checks, field write-back) to keep EditModal under its file-size
  budget. EditModal calls initEditModalUpload(this, context) in one line.
- edit-video-modal.html: "Replace video file…" (under the URL field) and
  "Replace thumbnail file…" (under the thumbnail field), each with a hidden file
  input + status line.
- On thumbnail upload: writes the new URL into the thumbnail field. On video
  upload: writes url + magnet (+ ws/xs hints). All written via setFieldUnlocked,
  which marks the field edited so EditModal.collect actually persists it (gated
  behind storage being configured + unlocked).

setFieldUnlocked is unit-tested (mutation-verified): without the unlock, the
re-upload would silently not save. Build + full lint + unit suite green.

NOTE: the upload/storage flow itself can't be unit-tested (browser + R2/S3);
pending manual verification of editing a video's thumbnail/file.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-20 09:09:07 -04:00

50 lines
1.7 KiB
JavaScript

// When the Edit modal re-uploads a thumbnail/video file, the new URL/magnet must
// be written into the field AND the field marked "edited" — otherwise
// EditModal.collect (which gates each field on isEditing: readOnly===false ||
// dataset.isEditing==="true") would keep the ORIGINAL value and the re-upload
// would silently not save. setFieldUnlocked encodes that contract.
import "./test-helpers/setup-localstorage.mjs";
import assert from "node:assert/strict";
import test from "node:test";
import { setFieldUnlocked } from "../js/ui/components/editModalUpload.js";
// Minimal input-element stand-in matching what setFieldUnlocked touches.
function makeInput() {
return {
value: "original",
readOnly: true,
dataset: {},
removeAttribute(name) {
this._removed = this._removed || [];
this._removed.push(name);
},
};
}
// Mirror of EditModal.collect's isEditing() gate.
function isEditing(input) {
if (!input) return true;
if (input.dataset?.isEditing === "true") return true;
return input.readOnly === false;
}
test("setFieldUnlocked sets the value and marks the field edited so it persists", () => {
const input = makeInput();
setFieldUnlocked(input, "https://cdn.example.com/new.mp4");
assert.equal(input.value, "https://cdn.example.com/new.mp4", "value updated");
assert.equal(input.readOnly, false, "field unlocked");
assert.equal(input.dataset.isEditing, "true", "marked as user-edited");
assert.equal(
isEditing(input),
true,
"EditModal.collect would treat it as edited (so the upload persists)",
);
});
test("setFieldUnlocked is a no-op on a missing field", () => {
assert.doesNotThrow(() => setFieldUnlocked(null, "x"));
assert.doesNotThrow(() => setFieldUnlocked(undefined, "x"));
});