/** * ICD Test Runner — CRUD: Profile & Settings * Profile update, settings merge round-trip, avatar lifecycle. */ (function () { 'use strict'; var T = window.ICD; if (!T) return; if (!T.crud) T.crud = {}; T.crud.profile = async function (testTag) { // ── GET /profile — full shape (augments smoke) ── var originalProfile = null; await T.test('crud', 'profile', 'GET /profile (full shape)', async function () { var d = await T.apiGet('/profile'); T.assertShape(d, T.S.profile, 'profile'); T.assert(typeof d.email === 'string' && d.email.length > 0, 'email must be non-empty string'); T.assert(typeof d.settings === 'object' && d.settings !== null, 'settings must be object (not null)'); originalProfile = d; }); // ── PUT /profile — update display_name ── if (originalProfile) { await T.test('crud', 'profile', 'PUT /profile (display_name)', async function () { var newName = testTag + '-display'; var d = await T.apiPut('/profile', { display_name: newName }); T.assertShape(d, T.S.profile, 'profile-after-update'); T.assert(d.display_name === newName, 'display_name not updated: ' + d.display_name); }); // Restore original display_name await T.test('crud', 'profile', 'PUT /profile (restore display_name)', async function () { var d = await T.apiPut('/profile', { display_name: originalProfile.display_name || '' }); T.assertShape(d, T.S.profile, 'profile-restored'); }); } // ── GET /settings — envelope with empty object for clean user ── await T.test('crud', 'profile', 'GET /settings (envelope)', async function () { var d = await T.apiGet('/settings'); T.assertHasKey(d, 'settings', 'GET /settings'); T.assert(typeof d.settings === 'object' && d.settings !== null, 'settings must be object'); }); // ── PUT /settings — create, then merge, then verify ── await T.test('crud', 'profile', 'PUT /settings (initial)', async function () { var d = await T.apiPut('/settings', { icd_test_key: 'alpha', icd_test_other: 'keep-me' }); T.assertHasKey(d, 'settings', 'PUT /settings response'); T.assert(d.settings.icd_test_key === 'alpha', 'icd_test_key should be alpha'); T.assert(d.settings.icd_test_other === 'keep-me', 'icd_test_other should be set'); }); await T.test('crud', 'profile', 'PUT /settings (merge overwrites + preserves)', async function () { var d = await T.apiPut('/settings', { icd_test_key: 'beta' }); T.assertHasKey(d, 'settings', 'PUT /settings merge'); T.assert(d.settings.icd_test_key === 'beta', 'icd_test_key should be overwritten to beta'); T.assert(d.settings.icd_test_other === 'keep-me', 'icd_test_other should be preserved'); }); await T.test('crud', 'profile', 'GET /settings (round-trip verify)', async function () { var d = await T.apiGet('/settings'); T.assert(d.settings.icd_test_key === 'beta', 'GET round-trip: icd_test_key should be beta'); T.assert(d.settings.icd_test_other === 'keep-me', 'GET round-trip: icd_test_other preserved'); }); // ── Avatar lifecycle: upload → verify in profile → delete → verify gone ── // Build a minimal 1x1 red PNG as base64 var tinyPNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=='; await T.test('crud', 'profile', 'POST /profile/avatar (upload)', async function () { var d = await T.apiPost('/profile/avatar', { image: tinyPNG }); T.assertHasKey(d, 'avatar', 'avatar-upload'); T.assert(typeof d.avatar === 'string' && d.avatar.indexOf('data:image/png') === 0, 'avatar should be data URI'); }); await T.test('crud', 'profile', 'GET /profile (avatar present)', async function () { var d = await T.apiGet('/profile'); T.assert(d.avatar && typeof d.avatar === 'string', 'profile should have avatar after upload'); }); await T.test('crud', 'profile', 'DELETE /profile/avatar', async function () { await T.safeDelete('/profile/avatar'); }); await T.test('crud', 'profile', 'GET /profile (avatar cleared)', async function () { var d = await T.apiGet('/profile'); T.assert(!d.avatar, 'avatar should be null/absent after delete'); }); // ── Clean up test settings keys ── // Overwrite with empty values — there's no DELETE for individual keys // so just leave them; they're namespaced with icd_test_ prefix. }; })();