Refine guest gallery UI and add multi-photo upload flow
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-02-09 18:01:01 +01:00
parent e3bb1642db
commit 1f9a43806a
9 changed files with 369 additions and 159 deletions

View File

@@ -1,10 +1,14 @@
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { EventDataProvider } from '../context/EventDataContext';
const navigateMock = vi.fn();
const uploadPhotoMock = vi.fn();
const addToQueueMock = vi.fn();
vi.mock('react-router-dom', () => ({
useNavigate: () => vi.fn(),
useNavigate: () => navigateMock,
useSearchParams: () => [new URLSearchParams('taskId=12')],
}));
@@ -18,8 +22,8 @@ vi.mock('@tamagui/text', () => ({
}));
vi.mock('@tamagui/button', () => ({
Button: ({ children, ...rest }: { children: React.ReactNode }) => (
<button type="button" {...rest}>
Button: ({ children, onPress, ...rest }: { children: React.ReactNode; onPress?: () => void }) => (
<button type="button" onClick={onPress} {...rest}>
{children}
</button>
),
@@ -30,8 +34,8 @@ vi.mock('../components/AppShell', () => ({
}));
vi.mock('../services/uploadApi', () => ({
uploadPhoto: vi.fn(),
useUploadQueue: () => ({ items: [], add: vi.fn() }),
uploadPhoto: (...args: unknown[]) => uploadPhotoMock(...args),
useUploadQueue: () => ({ items: [], add: addToQueueMock }),
}));
vi.mock('../services/tasksApi', () => ({
@@ -64,7 +68,22 @@ vi.mock('@/hooks/use-appearance', () => ({
import UploadScreen from '../screens/UploadScreen';
Object.defineProperty(URL, 'createObjectURL', {
writable: true,
value: vi.fn(() => 'blob:preview'),
});
Object.defineProperty(URL, 'revokeObjectURL', {
writable: true,
value: vi.fn(),
});
describe('UploadScreen', () => {
beforeEach(() => {
navigateMock.mockReset();
uploadPhotoMock.mockReset();
addToQueueMock.mockReset();
});
it('renders queue entry point', () => {
render(
<EventDataProvider token="token">
@@ -84,4 +103,48 @@ describe('UploadScreen', () => {
expect(await screen.findByText('Capture the dancefloor')).toBeInTheDocument();
});
it('redirects to queue with notice when upload fails because of network', async () => {
uploadPhotoMock.mockRejectedValueOnce({ code: 'network_error' });
addToQueueMock.mockResolvedValueOnce(undefined);
const { container } = render(
<EventDataProvider token="token">
<UploadScreen />
</EventDataProvider>
);
const input = container.querySelector('input[type="file"]') as HTMLInputElement;
const file = new File(['demo'], 'demo.jpg', { type: 'image/jpeg' });
fireEvent.change(input, { target: { files: [file] } });
fireEvent.click(await screen.findByText('Foto verwenden'));
await waitFor(() => {
expect(addToQueueMock).toHaveBeenCalled();
expect(navigateMock).toHaveBeenCalledWith('../queue?notice=network-retry');
});
});
it('uploads all selected photos when multiple files are picked', async () => {
uploadPhotoMock.mockResolvedValueOnce(101).mockResolvedValueOnce(102);
const { container } = render(
<EventDataProvider token="token">
<UploadScreen />
</EventDataProvider>
);
const input = container.querySelector('input[type="file"]') as HTMLInputElement;
const first = new File(['one'], 'one.jpg', { type: 'image/jpeg' });
const second = new File(['two'], 'two.jpg', { type: 'image/jpeg' });
fireEvent.change(input, { target: { files: [first, second] } });
fireEvent.click(await screen.findByText('Upload {count} photos'));
await waitFor(() => {
expect(uploadPhotoMock).toHaveBeenCalledTimes(2);
});
expect(addToQueueMock).not.toHaveBeenCalled();
});
});