/**
* Tests for PendingUploadsPanel — review-card name resolution (#1152 follow-up).
*
* The panel renders ``upload.display_name`` (the resolved name that mirrors
* what the eventual archive's ``print_name`` will be) and falls back to
* ``upload.filename`` when the display_name is missing — guards against a
* pending row created before the column landed (or a serialiser bug) showing
* a blank card.
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { render } from '../utils';
import { PendingUploadsPanel } from '../../components/PendingUploadsPanel';
import { http, HttpResponse } from 'msw';
import { server } from '../mocks/server';
interface MockUpload {
id: number;
filename: string;
display_name: string;
file_size: number;
source_ip: string | null;
status: string;
tags: string | null;
notes: string | null;
project_id: number | null;
uploaded_at: string;
}
const baseUpload: MockUpload = {
id: 1,
filename: 'Plate_1.gcode.3mf',
display_name: 'My Resolved Name',
file_size: 12345,
source_ip: '192.168.1.50',
status: 'pending',
tags: null,
notes: null,
project_id: null,
uploaded_at: '2026-05-01T10:00:00Z',
};
describe('PendingUploadsPanel — display_name', () => {
beforeEach(() => {
server.use(
http.get('/api/v1/projects/', () => HttpResponse.json([])),
);
});
it('renders the resolved display_name on the review card', async () => {
server.use(http.get('/api/v1/pending-uploads/', () => HttpResponse.json([baseUpload])));
const { findByText } = render();
expect(await findByText('My Resolved Name')).toBeInTheDocument();
});
it('falls back to filename when display_name is an empty string', async () => {
// Defensive: a bug in the resolver, a pre-migration row that was somehow
// re-fetched, or a partial JSON deserialisation must not produce a blank
// review card. The frontend keeps showing _something_ the user can click.
server.use(
http.get('/api/v1/pending-uploads/', () =>
HttpResponse.json([{ ...baseUpload, display_name: '' }]),
),
);
const { findByText } = render();
expect(await findByText('Plate_1.gcode.3mf')).toBeInTheDocument();
});
it('exposes the raw filename via tooltip so the user can see what arrived over FTP', async () => {
server.use(http.get('/api/v1/pending-uploads/', () => HttpResponse.json([baseUpload])));
const { findByText } = render();
const nameEl = await findByText('My Resolved Name');
expect(nameEl.getAttribute('title')).toBe('Plate_1.gcode.3mf');
});
});