This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/surfaces/icd-test-runner/js/crud/surfaces.js
2026-03-14 19:36:33 +00:00

205 lines
9.4 KiB
JavaScript

/**
* ICD Test Runner — CRUD: Surfaces
* Surface install lifecycle (install → read → admin list → user list →
* disable → hidden from user → still in admin → enable → visible again →
* core disable rejection → not found → disable not found → missing manifest →
* core conflict → reseed preserves enabled → delete → delete not found).
* Uses T.crud.buildTestZip() from _helpers.js.
*/
(function () {
'use strict';
var T = window.ICD;
if (!T) return;
if (!T.crud) T.crud = {};
var buildTestZip = T.crud.buildTestZip;
T.crud.surfaces = async function (testTag) {
// ── Surfaces CRUD ──
var surfaceId = null;
await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (happy path)', async function () {
surfaceId = 'icd-test-' + Date.now();
var manifest = JSON.stringify({
id: surfaceId,
title: 'ICD Test Surface',
route: '/s/' + surfaceId
});
var zipBlob = buildTestZip({ 'manifest.json': manifest });
await T.apiUpload('/admin/surfaces/install', zipBlob, surfaceId + '.surface');
// Verify it exists
var d = await T.apiGet('/admin/surfaces/' + surfaceId);
T.assert(d.id === surfaceId, 'installed surface id mismatch');
T.assert(d.title === 'ICD Test Surface', 'title mismatch');
T.registerCleanup(async function () {
if (surfaceId) {
var token = await T.getAuthToken();
return T.authFetch(token, 'DELETE', '/admin/surfaces/' + surfaceId);
}
});
});
if (surfaceId) {
await T.test('crud', 'surfaces', 'GET /admin/surfaces/:id (read)', async function () {
var d = await T.apiGet('/admin/surfaces/' + surfaceId);
T.assertShape(d, T.S.surfaceAdmin, 'surface detail');
T.assert(d.id === surfaceId, 'id mismatch');
T.assert(d.source === 'extension', 'source should be extension');
T.assert(d.enabled === true, 'newly installed surface should be enabled');
});
await T.test('crud', 'surfaces', 'GET /admin/surfaces (list includes new)', async function () {
var d = await T.apiGet('/admin/surfaces');
T.assertHasKey(d, 'surfaces', '/admin/surfaces');
var found = d.surfaces.some(function (s) { return s.id === surfaceId; });
T.assert(found, 'installed surface should appear in admin list');
});
await T.test('crud', 'surfaces', 'GET /surfaces (user list includes new)', async function () {
var d = await T.apiGet('/surfaces');
T.assertHasKey(d, 'surfaces', '/surfaces');
var found = d.surfaces.some(function (s) { return s.id === surfaceId; });
T.assert(found, 'enabled extension surface should appear in user nav list');
// Verify nav shape: id + title + route, NOT source/enabled
var entry = d.surfaces.find(function (s) { return s.id === surfaceId; });
T.assert(entry.route !== undefined, 'nav entry should have route');
T.assert(entry.source === undefined, 'nav entry should NOT have source');
T.assert(entry.enabled === undefined, 'nav entry should NOT have enabled');
});
await T.test('crud', 'surfaces', 'PUT /admin/surfaces/:id/disable', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/' + surfaceId + '/disable');
T.assertStatus(d, 200, 'disable');
T.assert(d.enabled === false, 'should report disabled');
});
await T.test('crud', 'surfaces', 'GET /surfaces (disabled hidden from user)', async function () {
var d = await T.apiGet('/surfaces');
var found = d.surfaces.some(function (s) { return s.id === surfaceId; });
T.assert(!found, 'disabled surface should NOT appear in user nav list');
});
await T.test('crud', 'surfaces', 'GET /admin/surfaces (disabled still in admin)', async function () {
var d = await T.apiGet('/admin/surfaces');
var entry = d.surfaces.find(function (s) { return s.id === surfaceId; });
T.assert(entry, 'disabled surface should still appear in admin list');
T.assert(entry.enabled === false, 'should show as disabled in admin list');
});
await T.test('crud', 'surfaces', 'PUT /admin/surfaces/:id/enable', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/' + surfaceId + '/enable');
T.assertStatus(d, 200, 'enable');
T.assert(d.enabled === true, 'should report enabled');
});
await T.test('crud', 'surfaces', 'GET /surfaces (re-enabled visible)', async function () {
var d = await T.apiGet('/surfaces');
var found = d.surfaces.some(function (s) { return s.id === surfaceId; });
T.assert(found, 're-enabled surface should appear in user nav list');
});
await T.test('crud', 'surfaces', 'PUT /admin/surfaces/chat/disable (reject → 400)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/chat/disable');
T.assert(d._status === 400, 'disabling chat should return 400, got ' + d._status);
});
await T.test('crud', 'surfaces', 'PUT /admin/surfaces/admin/disable (reject → 400)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/admin/disable');
T.assert(d._status === 400, 'disabling admin should return 400, got ' + d._status);
});
await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/chat (core reject → 400)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'DELETE',
'/admin/surfaces/chat');
T.assert(d._status === 400, 'deleting core surface should return 400, got ' + d._status);
});
await T.test('crud', 'surfaces', 'GET /admin/surfaces/:id (not found → 404)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'GET',
'/admin/surfaces/nonexistent-surface-id');
T.assert(d._status === 404, 'nonexistent should return 404, got ' + d._status);
});
await T.test('crud', 'surfaces', 'PUT /admin/surfaces/nonexistent/disable (404)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/nonexistent-surface-id/disable');
T.assert(d._status === 404, 'disable nonexistent should return 404, got ' + d._status);
});
await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (missing manifest → 400)', async function () {
var zipBlob = buildTestZip({ 'readme.txt': 'no manifest here' });
var d;
try {
d = await T.apiUpload('/admin/surfaces/install', zipBlob, 'bad.surface');
T.assert(false, 'should have thrown');
} catch (e) {
T.assert(e.message.indexOf('400') !== -1, 'missing manifest should 400: ' + e.message);
}
});
await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (core conflict → 409)', async function () {
var manifest = JSON.stringify({ id: 'chat', title: 'Evil Chat', route: '/s/chat' });
var zipBlob = buildTestZip({ 'manifest.json': manifest });
var d;
try {
d = await T.apiUpload('/admin/surfaces/install', zipBlob, 'chat.surface');
// If no throw, check status manually
T.assert(false, 'overwriting core surface should have thrown');
} catch (e) {
T.assert(e.message.indexOf('409') !== -1, 'core conflict should 409: ' + e.message);
}
});
await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (reseed preserves enabled)', async function () {
// Surface was re-enabled above. Disable it, then re-install.
await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/' + surfaceId + '/disable');
// Re-install same ID
var manifest = JSON.stringify({
id: surfaceId,
title: 'ICD Test Surface v2',
route: '/s/' + surfaceId
});
var zipBlob = buildTestZip({ 'manifest.json': manifest });
await T.apiUpload('/admin/surfaces/install', zipBlob, surfaceId + '.surface');
// Verify title updated but enabled preserved as false
var d = await T.apiGet('/admin/surfaces/' + surfaceId);
T.assert(d.title === 'ICD Test Surface v2', 'title should be updated after reseed');
T.assert(d.enabled === false, 'enabled should be preserved as false after reseed');
// Re-enable for cleanup
await T.authFetch(await T.getAuthToken(), 'PUT',
'/admin/surfaces/' + surfaceId + '/enable');
});
await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/:id', async function () {
var token = await T.getAuthToken();
var d = await T.authFetch(token, 'DELETE', '/admin/surfaces/' + surfaceId);
T.assertStatus(d, 200, 'delete');
T.assert(d.deleted === true, 'should report deleted');
// Verify gone
var check = await T.authFetch(token, 'GET', '/admin/surfaces/' + surfaceId);
T.assert(check._status === 404, 'deleted surface should 404 on get');
surfaceId = null;
});
await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/nonexistent (404)', async function () {
var d = await T.authFetch(await T.getAuthToken(), 'DELETE',
'/admin/surfaces/nonexistent-surface-id');
T.assert(d._status === 404, 'delete nonexistent should return 404, got ' + d._status);
});
}
};
})();