feat(bulk-edit): add /documents/bulk-edit route

Server load redirects READ_ALL-only users (or unauthenticated) to /documents.
Page load: onMount reads bulkSelectionStore — redirects to /documents when the
store is empty, otherwise POSTs the IDs to /api/documents/batch-metadata and
hands the resulting summaries to BulkDocumentEditLayout in mode="edit".

Refs #225

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-25 15:18:07 +02:00
parent fa5dc43864
commit 6d3489d035
3 changed files with 109 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest';
import { load } from './+page.server';
describe('/documents/bulk-edit +page.server.ts', () => {
it('redirects to /documents when user lacks WRITE_ALL', async () => {
const locals = { user: { groups: [{ permissions: ['READ_ALL'] }] } };
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
throw new Error('expected redirect to be thrown');
} catch (e) {
const err = e as { status?: number; location?: string };
expect(err.status).toBe(303);
expect(err.location).toBe('/documents');
}
});
it('redirects when user has no groups', async () => {
const locals = { user: { groups: [] } };
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
throw new Error('expected redirect');
} catch (e) {
expect((e as { status?: number }).status).toBe(303);
}
});
it('redirects when no user is logged in', async () => {
const locals = {};
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
throw new Error('expected redirect');
} catch (e) {
expect((e as { status?: number }).status).toBe(303);
}
});
it('returns canWrite=true for a WRITE_ALL user', async () => {
const locals = { user: { groups: [{ permissions: ['WRITE_ALL', 'READ_ALL'] }] } };
// @ts-expect-error — partial event shape sufficient for this guard
const result = await load({ locals });
expect(result).toEqual({ canWrite: true });
});
});