feat(planner): integrate C4 RecipePicker with PanelState machine + slot actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,10 @@ vi.mock('$env/dynamic/private', () => ({
|
||||
|
||||
const mockGet = vi.fn();
|
||||
const mockPost = vi.fn();
|
||||
const mockPatch = vi.fn();
|
||||
const mockDelete = vi.fn();
|
||||
vi.mock('$lib/server/api', () => ({
|
||||
apiClient: () => ({ GET: mockGet, POST: mockPost })
|
||||
apiClient: () => ({ GET: mockGet, POST: mockPost, PATCH: mockPatch, DELETE: mockDelete })
|
||||
}));
|
||||
|
||||
describe('planner page — load', () => {
|
||||
@@ -193,3 +195,89 @@ describe('planner page — variety score partial failure', () => {
|
||||
expect(result.varietyScore).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('planner page — slot actions', () => {
|
||||
let actions: any;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockGet.mockReset();
|
||||
mockPost.mockReset();
|
||||
mockPatch.mockReset();
|
||||
mockDelete.mockReset();
|
||||
vi.resetModules();
|
||||
const mod = await import('./+page.server');
|
||||
actions = mod.actions;
|
||||
});
|
||||
|
||||
it('addSlot calls POST /v1/week-plans/{id}/slots and returns success with slot', async () => {
|
||||
const formData = new FormData();
|
||||
formData.set('planId', 'plan-1');
|
||||
formData.set('slotDate', '2026-04-01');
|
||||
formData.set('recipeId', 'r1');
|
||||
mockPost.mockResolvedValue({ data: { id: 's1', slotDate: '2026-04-01' }, error: undefined });
|
||||
const result = await actions.addSlot({
|
||||
fetch: vi.fn(),
|
||||
request: { formData: async () => formData }
|
||||
} as any);
|
||||
expect(mockPost).toHaveBeenCalledWith(
|
||||
'/v1/week-plans/{id}/slots',
|
||||
expect.objectContaining({
|
||||
params: { path: { id: 'plan-1' } },
|
||||
body: { slotDate: '2026-04-01', recipeId: 'r1' }
|
||||
})
|
||||
);
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.slot?.id).toBe('s1');
|
||||
});
|
||||
|
||||
it('addSlot returns failure when API errors', async () => {
|
||||
const formData = new FormData();
|
||||
formData.set('planId', 'plan-1');
|
||||
formData.set('slotDate', '2026-04-01');
|
||||
formData.set('recipeId', 'r1');
|
||||
mockPost.mockResolvedValue({ data: undefined, error: { status: 500 } });
|
||||
const result = await actions.addSlot({
|
||||
fetch: vi.fn(),
|
||||
request: { formData: async () => formData }
|
||||
} as any);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('updateSlot calls PATCH /v1/week-plans/{planId}/slots/{slotId} and returns success', async () => {
|
||||
const formData = new FormData();
|
||||
formData.set('planId', 'plan-1');
|
||||
formData.set('slotId', 's1');
|
||||
formData.set('recipeId', 'r2');
|
||||
mockPatch.mockResolvedValue({ data: { id: 's1' }, error: undefined });
|
||||
const result = await actions.updateSlot({
|
||||
fetch: vi.fn(),
|
||||
request: { formData: async () => formData }
|
||||
} as any);
|
||||
expect(mockPatch).toHaveBeenCalledWith(
|
||||
'/v1/week-plans/{planId}/slots/{slotId}',
|
||||
expect.objectContaining({
|
||||
params: { path: { planId: 'plan-1', slotId: 's1' } },
|
||||
body: { recipeId: 'r2' }
|
||||
})
|
||||
);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('deleteSlot calls DELETE /v1/week-plans/{planId}/slots/{slotId} and returns success', async () => {
|
||||
const formData = new FormData();
|
||||
formData.set('planId', 'plan-1');
|
||||
formData.set('slotId', 's1');
|
||||
mockDelete.mockResolvedValue({ error: undefined });
|
||||
const result = await actions.deleteSlot({
|
||||
fetch: vi.fn(),
|
||||
request: { formData: async () => formData }
|
||||
} as any);
|
||||
expect(mockDelete).toHaveBeenCalledWith(
|
||||
'/v1/week-plans/{planId}/slots/{slotId}',
|
||||
expect.objectContaining({
|
||||
params: { path: { planId: 'plan-1', slotId: 's1' } }
|
||||
})
|
||||
);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user