feat(documents): bulk upload — split-panel with file switcher #329

Merged
marcel merged 46 commits from feat/issue-317-bulk-upload into main 2026-04-25 12:24:25 +02:00
2 changed files with 43 additions and 0 deletions
Showing only changes of commit 811baf78da - Show all commits

View File

@@ -152,6 +152,7 @@ async function save() {
</span>
<button
type="button"
data-testid="discard-all-btn"
onclick={discardAll}
class="text-xs font-medium text-red-600/70 hover:text-red-700"
>

View File

@@ -96,4 +96,46 @@ describe('BulkDocumentEditLayout', () => {
// Wait for async save to complete
await vi.waitFor(() => expect(mockFetch).toHaveBeenCalledTimes(2), { timeout: 3000 });
});
it('save marks file as error when server returns non-ok response', async () => {
const mockFetch = vi.fn().mockResolvedValue({
ok: false,
json: async () => ({ errors: [{ filename: 'f0.pdf', code: 'FILE_UPLOAD_FAILED' }] })
});
vi.stubGlobal('fetch', mockFetch);
vi.mock('$app/navigation', () => ({ goto: vi.fn() }));
const { container } = render(BulkDocumentEditLayout, {});
await addFilesViaInput(container, [makeFile('f0.pdf')]);
const saveBtn = container.querySelector(
'button[data-testid="bulk-save-btn"]'
) as HTMLButtonElement;
saveBtn.click();
await vi.waitFor(() => expect(mockFetch).toHaveBeenCalledTimes(1), { timeout: 3000 });
});
it('discard-all resets to N=0 state and shows drop zone', async () => {
const { container } = render(BulkDocumentEditLayout, {});
await addFilesViaInput(container, [makeFile('a.pdf'), makeFile('b.pdf')]);
// Confirm N=2 state — switcher is visible
expect(container.querySelector('[data-testid="file-switcher-strip"]')).not.toBeNull();
// Click the topbar discard-all button (only visible in isMulti state)
const discardBtn = container.querySelector(
'button[data-testid="discard-all-btn"]'
) as HTMLButtonElement;
expect(discardBtn).not.toBeNull();
discardBtn.click();
await vi.waitFor(
() => {
expect(container.querySelector('[data-testid="bulk-drop-zone"]')).not.toBeNull();
expect(container.querySelector('[data-testid="file-switcher-strip"]')).toBeNull();
},
{ timeout: 1000 }
);
});
});