feat(quick-261008-who): eigene Module beim Start vorladen — Durchstich

- Spalte User.customModulePreloadIds, PUT /custom-modules/:id/preload (Grenze 8, 404 fuer Fremdes)
- Vorlade-Planer und -Komponente, Speicher preload()/pinned, Ersatzgroesse im Behaelter
- E2E-Skript gegen die API

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-09 09:14:45 +02:00
parent 1bb869a7b5
commit ac104495b4
23 changed files with 1139 additions and 42 deletions
@@ -6,6 +6,7 @@ import {
deleteCustomModule,
getCustomModule,
listCustomModules,
setCustomModulePreload,
updateCustomModule,
} from './custom-modules-api';
@@ -79,3 +80,35 @@ describe('custom-modules-api', () => {
expect(mockFetch.mock.calls[1][1].method).toBe('DELETE');
});
});
describe('setCustomModulePreload (quick-261008-who)', () => {
it('ruft PUT /custom-modules/:id/preload mit JSON-Koerper und credentials include', async () => {
mockFetch.mockResolvedValue({
ok: true,
status: 200,
json: async () => ({ id: 'a b', preload: true, preloadCount: 1 }),
});
const res = await setCustomModulePreload('a b', true);
expect(res).toEqual({ id: 'a b', preload: true, preloadCount: 1 });
const [url, init] = mockFetch.mock.calls[0];
expect(String(url)).toMatch(/\/custom-modules\/a%20b\/preload$/);
expect(init.method).toBe('PUT');
expect(init.credentials).toBe('include');
expect(JSON.parse(init.body)).toEqual({ preload: true });
});
it('409 bleibt als CustomModuleRequestError mit Status erkennbar', async () => {
mockFetch.mockResolvedValue({
ok: false,
status: 409,
json: async () => ({ message: 'Grenze' }),
});
await expect(setCustomModulePreload('a', true)).rejects.toMatchObject({
status: 409,
message: 'Grenze',
});
await expect(setCustomModulePreload('a', true)).rejects.toBeInstanceOf(
CustomModuleRequestError,
);
});
});