diff --git a/frontend/e2e/.auth/user-cc.json b/frontend/e2e/.auth/user-cc.json index 2d750a2..fb4fcf8 100644 --- a/frontend/e2e/.auth/user-cc.json +++ b/frontend/e2e/.auth/user-cc.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "vB_LRXjnl0ucrR2XdmRzT2hdBCb656qv75SB6s3yuCM", + "value": "oxkpzGInQ4shJIvaKgzPTk-G1g-yuISm-eWLWAHCz8c", "domain": "localhost", "path": "/api/auth", - "expires": 1786851645.664007, + "expires": 1786910690.97027, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI0YjlmNGE2NS0xM2JmLTRkZDEtYTE3Mi1hODFmYzNkNjQ3ZWQiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzkwODY0NDV9.hxhTHPEnMJagMq3tUpW5qIon3qgx1u77TikMwrXfM3s", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiIzMDgxMGE1MS0xOGRkLTRjOGEtOWU2MS0xZGRjMGM5NGQ2ODAiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzkxNDU0OTB9.wgl1nIrfwav8NhRqXaqglqbtwZ-W6M3FfR2_J00v_lw", "domain": "localhost", "path": "/", - "expires": 1779086445.663928, + "expires": 1779145490.969587, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1779075645509}" + "value": "{\"type\":\"logout\",\"at\":1779134690681}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1779248445817}" + "value": "{\"expiresAt\":1779307491379}" } ] } diff --git a/frontend/e2e/.auth/user-delete.json b/frontend/e2e/.auth/user-delete.json index e7d070a..2a8bd36 100644 --- a/frontend/e2e/.auth/user-delete.json +++ b/frontend/e2e/.auth/user-delete.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "gboIPp5ceYO1Kb0CtJoBNLLEB_aqa9hpmWeQcYU5ts0", + "value": "n_EftQzpLANJ_pI4xwg6LQDCDds9Ufvy1GcnnYJQ00A", "domain": "localhost", "path": "/api/auth", - "expires": 1786851645.795109, + "expires": 1786910690.820234, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiYzBlNTdhNzktZTU2OS00Y2RmLTk0MDQtYzdiYjI3ZmRkMjAyIiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc5MDg2NDQ1fQ.WXFDSpITZGB74reIt7-NMFdS40oxrUhqhkQdqDdCrK4", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiNDE3OWYwNzItYTM3MC00NGY1LTg1YmMtZmU1ZDIwNzY3NWE3IiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc5MTQ1NDkwfQ.1uhXDEXNncubgx4D8XnFI6KWxXT4wvvvGrXQfHvjnhU", "domain": "localhost", "path": "/", - "expires": 1779086445.79506, + "expires": 1779145490.819506, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1779075645659}" + "value": "{\"type\":\"logout\",\"at\":1779134690558}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1779248445953}" + "value": "{\"expiresAt\":1779307491309}" } ] } diff --git a/frontend/e2e/.auth/user.json b/frontend/e2e/.auth/user.json index 21e6c00..17f91eb 100644 --- a/frontend/e2e/.auth/user.json +++ b/frontend/e2e/.auth/user.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "vp9tOOruGSijnoaSX6nKSaRCEsSzsiln0Jt1sSaaVtg", + "value": "QCuLIgmPV2vnDfzmgvptt-mZAW1jh8UML_wwAee4OTQ", "domain": "localhost", "path": "/api/auth", - "expires": 1786851643.974239, + "expires": 1786912678.702645, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiJjYjU5ZWU1Ni1iNDJkLTQ2NDctOTQ0MC1lNzYwYmJlMjg2ZDYiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzkwODY0NDN9.8xB5EOIA_PBXC3KwajHcAfpZVC8c78OP0HaExyrYRV8", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiJlM2VmNGE2OC0zZWI3LTQ2MjQtYTI0Mi0yNmY1OTgyZDIwOWEiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzkxNDc0Nzh9.P7CDplAG3MBXgtEpuYFtp6gOV5pi-6QeAYRqmE-Dkys", "domain": "localhost", "path": "/", - "expires": 1779086443.974189, + "expires": 1779147478.701971, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1779075643795}" + "value": "{\"type\":\"logout\",\"at\":1779136678495}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1779248444100}" + "value": "{\"expiresAt\":1779309478870}" } ] } diff --git a/frontend/src/components/routine/RoutineEditView.vue b/frontend/src/components/routine/RoutineEditView.vue index d8b0df7..dbe3994 100644 --- a/frontend/src/components/routine/RoutineEditView.vue +++ b/frontend/src/components/routine/RoutineEditView.vue @@ -372,12 +372,23 @@ async function handleSubmit(form: { name: string; points: number; image_id: stri }) if (!resp.ok) throw new Error('Failed to save routine') const routineData = await resp.json() - const routineId = routineData.id || props.id + const routineId = + props.id || + (typeof routineData?.id === 'string' && routineData.id) || + (typeof routineData?.routine?.id === 'string' && routineData.routine.id) || + '' + + if (!routineId) { + throw new Error('Failed to resolve routine id after save') + } for (const itemId of removedItemIds.value) { - await fetch(`/api/routine/${routineId}/item/${itemId}`, { + const deleteResp = await fetch(`/api/routine/${routineId}/item/${itemId}`, { method: 'DELETE', }) + if (!deleteResp.ok) { + throw new Error('Failed to delete routine item') + } } for (const item of items.value) { @@ -385,17 +396,23 @@ async function handleSubmit(form: { name: string; points: number; image_id: stri const payload = { name: item.name, image_id: resolvedImageId, order: item.order } if (item.id?.startsWith('temp-') || !item.id) { - await fetch(`/api/routine/${routineId}/item/add`, { + const addItemResp = await fetch(`/api/routine/${routineId}/item/add`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }) + if (!addItemResp.ok) { + throw new Error('Failed to add routine item') + } } else { - await fetch(`/api/routine/${routineId}/item/${item.id}/edit`, { + const editItemResp = await fetch(`/api/routine/${routineId}/item/${item.id}/edit`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }) + if (!editItemResp.ok) { + throw new Error('Failed to edit routine item') + } } } diff --git a/frontend/src/components/routine/__tests__/RoutineEditView.spec.ts b/frontend/src/components/routine/__tests__/RoutineEditView.spec.ts index 59ddcde..119eb9f 100644 --- a/frontend/src/components/routine/__tests__/RoutineEditView.spec.ts +++ b/frontend/src/components/routine/__tests__/RoutineEditView.spec.ts @@ -3,13 +3,15 @@ import { defineComponent, nextTick } from 'vue' import { mount } from '@vue/test-utils' import RoutineEditView from '../RoutineEditView.vue' +const mockPush = vi.fn() + vi.mock('vue-router', () => ({ useRoute: vi.fn(() => ({ params: {}, query: { name: 'Timmy' }, })), useRouter: vi.fn(() => ({ - push: vi.fn(), + push: mockPush, back: vi.fn(), })), })) @@ -35,7 +37,7 @@ const EntityEditFormStub = defineComponent({ emits: ['submit', 'cancel', 'add-image'], template: `