fix: clear alt text when the upload dialog is handed a different file
The file input's `onChange` reset `state` to `IDLE` and left `altText` untouched. On success that is harmless -- the dialog unmounts. But REJECTED, QUARANTINED and TRANSPORT_FAILED all leave it mounted with the file input re-enabled, and that is precisely the retry path: upload `db-schema.png` described as "DB 스키마", have it quarantined, pick `sequence.png`, upload -- and `sequence.png` shipped described as "DB 스키마", passing EVIDENCE_ALT_REQUIRED and publishing with a caption about a different image. Cleared on every file selection rather than only after a failure: alt text describes one image, and "which file is this describing" has one honest answer per selection. `submit()`'s existing ALT_REQUIRED refusal turns the emptied field into a stop rather than a silent omission. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f69edb633d
commit
1f2cba79e9
@@ -1835,3 +1835,76 @@ test("mergeAssetCatalog can only grow: an empty arrival keeps everything", () =>
|
||||
|
||||
assert.deepEqual(mergeAssetCatalog([known], []).map((asset) => asset.id), [known.id]);
|
||||
});
|
||||
|
||||
// --- Alignment follow-up, item 3: alt text must not outlive its file ---
|
||||
//
|
||||
// The file input's `onChange` reset `state` to `IDLE` and left `altText`
|
||||
// alone. On success that is harmless -- the dialog unmounts. But REJECTED,
|
||||
// QUARANTINED and TRANSPORT_FAILED all leave it mounted with the file input
|
||||
// re-enabled, which is exactly the retry path: upload `db-schema.png`
|
||||
// described as "DB 스키마", get it quarantined, pick `sequence.png`, upload --
|
||||
// and `sequence.png` shipped described as "DB 스키마", validating as
|
||||
// publishable the whole way.
|
||||
|
||||
test("picking a different file after a quarantined upload clears the previous image's alt text", async () => {
|
||||
const user = userEvent.setup();
|
||||
const forms: Array<{ altText?: string; filename: string }> = [];
|
||||
const gateway = uploadOnlyGateway(async (form) => {
|
||||
forms.push({ altText: form.altText, filename: form.file.name });
|
||||
return (forms.length === 1
|
||||
? { ...READY, managementStatus: "QUARANTINED" }
|
||||
: READY) as never;
|
||||
});
|
||||
render(<AssetUploadDialog gateway={gateway} kind="IMAGE" onUploaded={() => {}} onClose={() => {}} />);
|
||||
|
||||
chooseAndUpload(new File(["a"], "db-schema.png", { type: "image/png" }), "DB 스키마");
|
||||
await waitFor(() =>
|
||||
assert.equal(
|
||||
screen.getByRole("status", { name: "업로드 상태" }).textContent,
|
||||
"보안 검사에서 격리되어 사용할 수 없습니다.",
|
||||
),
|
||||
);
|
||||
|
||||
chooseFile(new File(["b"], "sequence.png", { type: "image/png" }));
|
||||
|
||||
assert.equal((screen.getByLabelText("대체 텍스트") as HTMLInputElement).value, "");
|
||||
// And the emptied field is enforced, not merely displayed: uploading now
|
||||
// refuses instead of shipping an undescribed image.
|
||||
await user.click(screen.getByRole("button", { name: "업로드" }));
|
||||
assert.equal(
|
||||
screen.getByRole("status", { name: "업로드 상태" }).textContent,
|
||||
"대체 텍스트를 입력하거나 장식용으로 표시하세요.",
|
||||
);
|
||||
assert.equal(forms.length, 1);
|
||||
});
|
||||
|
||||
test("the retry after a transport failure ships its own alt text, never the first attempt's", async () => {
|
||||
const forms: Array<{ altText?: string; filename: string }> = [];
|
||||
const gateway = uploadOnlyGateway(async (form) => {
|
||||
forms.push({ altText: form.altText, filename: form.file.name });
|
||||
if (forms.length === 1) throw new Error("offline");
|
||||
return READY as never;
|
||||
});
|
||||
render(<AssetUploadDialog gateway={gateway} kind="IMAGE" onUploaded={() => {}} onClose={() => {}} />);
|
||||
|
||||
chooseAndUpload(new File(["a"], "db-schema.png", { type: "image/png" }), "DB 스키마");
|
||||
await waitFor(() =>
|
||||
assert.equal(
|
||||
screen.getByRole("status", { name: "업로드 상태" }).textContent,
|
||||
"업로드를 전송하지 못했습니다.",
|
||||
),
|
||||
);
|
||||
|
||||
chooseAndUpload(new File(["b"], "sequence.png", { type: "image/png" }), "시퀀스 다이어그램");
|
||||
await waitFor(() =>
|
||||
assert.equal(
|
||||
screen.getByRole("status", { name: "업로드 상태" }).textContent,
|
||||
"업로드했습니다.",
|
||||
),
|
||||
);
|
||||
|
||||
assert.deepEqual(forms, [
|
||||
{ altText: "DB 스키마", filename: "db-schema.png" },
|
||||
{ altText: "시퀀스 다이어그램", filename: "sequence.png" },
|
||||
]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user