Compare commits
5 Commits
6b10daeeac
...
9aed929b67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aed929b67 | ||
|
|
cb9962f0c2 | ||
|
|
262c792654 | ||
|
|
60f1db1f99 | ||
|
|
8cf4f7c2e4 |
@@ -140,6 +140,25 @@ describe('BulkDocumentEditLayout', () => {
|
|||||||
expect(metadataJson).toHaveProperty('tagNames');
|
expect(metadataJson).toHaveProperty('tagNames');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('save() navigates to /documents when all chunks succeed', async () => {
|
||||||
|
const mockFetch = vi.fn().mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({ created: [], updated: [], errors: [] })
|
||||||
|
});
|
||||||
|
vi.stubGlobal('fetch', mockFetch);
|
||||||
|
|
||||||
|
const { container } = render(BulkDocumentEditLayout, {});
|
||||||
|
await addFilesViaInput(container, [makeFile('doc.pdf')]);
|
||||||
|
|
||||||
|
const saveBtn = container.querySelector(
|
||||||
|
'button[data-testid="bulk-save-btn"]'
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
saveBtn.click();
|
||||||
|
|
||||||
|
await vi.waitFor(() => expect(mockFetch).toHaveBeenCalledTimes(1), { timeout: 3000 });
|
||||||
|
await vi.waitFor(() => expect(goto).toHaveBeenCalledWith('/documents'), { timeout: 3000 });
|
||||||
|
});
|
||||||
|
|
||||||
it('save() does not navigate when chunk returns non-ok response', async () => {
|
it('save() does not navigate when chunk returns non-ok response', async () => {
|
||||||
const mockFetch = vi.fn().mockResolvedValue({
|
const mockFetch = vi.fn().mockResolvedValue({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ $effect(() => {
|
|||||||
>
|
>
|
||||||
<span class="max-w-[8rem] truncate" title={entry.title}>{entry.title}</span>
|
<span class="max-w-[8rem] truncate" title={entry.title}>{entry.title}</span>
|
||||||
{#if entry.status === 'error'}
|
{#if entry.status === 'error'}
|
||||||
|
<span class="sr-only">{m.bulk_file_error_chip_label()}</span>
|
||||||
<span aria-hidden="true" class="ml-0.5 font-extrabold text-red-600">!</span>
|
<span aria-hidden="true" class="ml-0.5 font-extrabold text-red-600">!</span>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -78,6 +78,27 @@ describe('FileSwitcherStrip', () => {
|
|||||||
expect(errBtn).not.toBeNull();
|
expect(errBtn).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('error chip contains a screen-reader-only error label', async () => {
|
||||||
|
const files: FileEntry[] = [
|
||||||
|
{
|
||||||
|
id: 'e1',
|
||||||
|
file: new File([''], 'bad.pdf'),
|
||||||
|
title: 'Bad file',
|
||||||
|
status: 'error',
|
||||||
|
previewUrl: ''
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const { container } = render(FileSwitcherStrip, {
|
||||||
|
files,
|
||||||
|
activeId: 'e1',
|
||||||
|
onSelect: vi.fn(),
|
||||||
|
onRemove: vi.fn()
|
||||||
|
});
|
||||||
|
const errBtn = container.querySelector('[data-status="error"]');
|
||||||
|
const srOnly = errBtn?.querySelector('.sr-only');
|
||||||
|
expect(srOnly).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('ArrowRight moves focus to next chip without leaving strip', async () => {
|
it('ArrowRight moves focus to next chip without leaving strip', async () => {
|
||||||
const files = makeFiles(3);
|
const files = makeFiles(3);
|
||||||
const { container } = render(FileSwitcherStrip, {
|
const { container } = render(FileSwitcherStrip, {
|
||||||
|
|||||||
@@ -6,21 +6,21 @@ import ScopeCard from './ScopeCard.svelte';
|
|||||||
afterEach(cleanup);
|
afterEach(cleanup);
|
||||||
|
|
||||||
describe('ScopeCard', () => {
|
describe('ScopeCard', () => {
|
||||||
it('per-file variant has mint background class', async () => {
|
it('per-file variant has accent background class', async () => {
|
||||||
const { container } = render(ScopeCard, { variant: 'per-file', count: 1 });
|
const { container } = render(ScopeCard, { variant: 'per-file', count: 1 });
|
||||||
const card = container.querySelector('[data-testid="scope-card"]');
|
const card = container.querySelector('[data-testid="scope-card"]');
|
||||||
expect(card?.className).toMatch(/brand-mint/);
|
expect(card?.className).toMatch(/bg-accent-bg/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shared variant does not have mint background', async () => {
|
it('shared variant does not have accent background', async () => {
|
||||||
const { container } = render(ScopeCard, { variant: 'shared', count: 3 });
|
const { container } = render(ScopeCard, { variant: 'shared', count: 3 });
|
||||||
const card = container.querySelector('[data-testid="scope-card"]');
|
const card = container.querySelector('[data-testid="scope-card"]');
|
||||||
expect(card?.className).not.toMatch(/bg-brand-mint/);
|
expect(card?.className).not.toMatch(/bg-accent-bg/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shared variant renders count badge with file count', async () => {
|
it('shared variant renders count badge with file count', async () => {
|
||||||
render(ScopeCard, { variant: 'shared', count: 5 });
|
render(ScopeCard, { variant: 'shared', count: 5 });
|
||||||
await expect.element(page.getByText('5')).toBeInTheDocument();
|
await expect.element(page.getByText('5', { exact: true })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('per-file variant renders slot content', async () => {
|
it('per-file variant renders slot content', async () => {
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ let {
|
|||||||
></progress>
|
></progress>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex items-center justify-between gap-3">
|
<div class="flex items-center justify-between gap-3">
|
||||||
<button type="button" onclick={onDiscard} class="text-sm text-red-600/70 hover:text-red-700">
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={onDiscard}
|
||||||
|
class="flex min-h-[44px] items-center px-2 text-sm text-red-600/70 hover:text-red-700"
|
||||||
|
>
|
||||||
{m.bulk_discard_all()}
|
{m.bulk_discard_all()}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1695,7 +1695,7 @@ export interface components {
|
|||||||
/** Format: date */
|
/** Format: date */
|
||||||
documentDate?: string;
|
documentDate?: string;
|
||||||
location?: string;
|
location?: string;
|
||||||
tags?: string;
|
tagNames?: string[];
|
||||||
metadataComplete?: boolean;
|
metadataComplete?: boolean;
|
||||||
};
|
};
|
||||||
QuickUploadResult: {
|
QuickUploadResult: {
|
||||||
|
|||||||
Reference in New Issue
Block a user