Files
tessera-ctl/apps/web/src/components/nextcloud-files/use-transfers.test.ts
T
schalli 486819f80b fix(nextcloud-files): WR-07 Merkzettel angelegter Ordner gilt nur fuer eine Ablage
- der Merkzettel wird geleert, wenn neu abgelegt wird und nichts mehr laeuft, nach jedem
  Loeschen, Verschieben und Umbenennen in der Ansicht und wenn ein Hochladen mit
  pathConflict/notFound scheitert (dann legt "Erneut versuchen" den Ordner wieder an)
- innerhalb einer Ablage wird jeder Ordner weiter nur einmal angelegt
- Hook-Tests fuer alle drei Wege

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 22:43:32 +02:00

90 lines
3.7 KiB
TypeScript

import { act, renderHook, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { NextcloudFilesRequestError } from '@/lib/nextcloud-files-api';
import { useTransfers } from './use-transfers';
const mockCreate = vi.fn();
const mockUpload = vi.fn();
vi.mock('@/lib/nextcloud-files-api', async (importOriginal) => {
const actual = await importOriginal<typeof import('@/lib/nextcloud-files-api')>();
return {
...actual,
createFolder: (...a: unknown[]) => mockCreate(...a),
listFolder: vi.fn(),
};
});
vi.mock('@/lib/nextcloud-files-upload', () => ({
uploadFile: (...a: unknown[]) => mockUpload(...a),
}));
const file = (name: string) => new File(['x'], name);
beforeEach(() => {
mockCreate.mockReset().mockResolvedValue({ path: '/A' });
mockUpload.mockReset().mockResolvedValue({ path: '/A/a.txt', size: 1 });
});
describe('useTransfers — Ordner-Merkzettel (WR-07)', () => {
it('eine neue Ablage nach dem Ende der vorigen legt den Ordner erneut an (er kann inzwischen geloescht sein)', async () => {
const { result } = renderHook(() => useTransfers({ quotaAvailable: null }));
act(() => result.current.enqueue([{ file: file('a.txt'), relativeDir: 'A' }], '/'));
await waitFor(() => expect(result.current.transfers[0]?.status).toBe('done'));
expect(mockCreate).toHaveBeenCalledTimes(1);
expect(mockCreate).toHaveBeenLastCalledWith('/A');
act(() => result.current.enqueue([{ file: file('b.txt'), relativeDir: 'A' }], '/'));
await waitFor(() => expect(result.current.transfers[1]?.status).toBe('done'));
expect(mockCreate).toHaveBeenCalledTimes(2);
});
it('innerhalb einer Ablage wird jeder Ordner nur einmal angelegt', async () => {
const { result } = renderHook(() => useTransfers({ quotaAvailable: null }));
act(() =>
result.current.enqueue(
[
{ file: file('a.txt'), relativeDir: 'A' },
{ file: file('b.txt'), relativeDir: 'A' },
{ file: file('c.txt'), relativeDir: 'A' },
],
'/',
),
);
await waitFor(() =>
expect(result.current.transfers.every((t) => t.status === 'done')).toBe(true),
);
expect(mockCreate).toHaveBeenCalledTimes(1);
});
it('forgetFolders und ein Hochladen mit pathConflict leeren den Merkzettel', async () => {
let release!: () => void;
const hold = new Promise<void>((r) => {
release = r;
});
mockUpload
.mockImplementationOnce(async () => {
await hold;
return { path: '/A/a.txt', size: 1 };
})
.mockRejectedValueOnce(new NextcloudFilesRequestError(409, 'pathConflict', 'fehlt'))
.mockResolvedValue({ path: '/A/c.txt', size: 1 });
const { result } = renderHook(() => useTransfers({ quotaAvailable: null }));
// Die erste Datei laeuft noch: die zweite Ablage nutzt den Merkzettel.
act(() => result.current.enqueue([{ file: file('a.txt'), relativeDir: 'A' }], '/'));
await waitFor(() => expect(mockUpload).toHaveBeenCalledTimes(1));
act(() => result.current.enqueue([{ file: file('b.txt'), relativeDir: 'A' }], '/'));
await waitFor(() => expect(result.current.transfers[1]?.status).toBe('error'));
expect(mockCreate).toHaveBeenCalledTimes(1);
// pathConflict: "Erneut versuchen" legt den Ordner wieder an.
act(() => result.current.retry(result.current.transfers[1].id));
await waitFor(() => expect(result.current.transfers[1]?.status).toBe('done'));
expect(mockCreate).toHaveBeenCalledTimes(2);
act(() => result.current.forgetFolders());
act(() => result.current.enqueue([{ file: file('c.txt'), relativeDir: 'A' }], '/'));
await waitFor(() => expect(result.current.transfers[2]?.status).toBe('done'));
expect(mockCreate).toHaveBeenCalledTimes(3);
release();
});
});