Changeset 0.37.17 (#229)
Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
153
packages/sdk-test-runner/js/domains/admin.js
Normal file
153
packages/sdk-test-runner/js/domains/admin.js
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: admin
|
||||
*
|
||||
* Tests admin-scoped endpoints. Requires admin role.
|
||||
* KNOWN ISSUES: some admin list endpoints use non-standard envelope
|
||||
* keys (§E in ICD drift audit).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('admin', async function () {
|
||||
|
||||
// Guard: skip if not admin
|
||||
if (!window.sw || !sw.isAdmin) {
|
||||
await T.test('admin', 'guard', 'skip — not admin', async function () {
|
||||
T.assert(true, 'skipped (user is not admin)');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Users ──
|
||||
|
||||
await T.test('admin', 'users', 'sw.api.admin.users.list()', {
|
||||
sdk: function () { return sw.api.admin.users.list(); },
|
||||
raw: { method: 'GET', path: '/admin/users' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {users: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.users) arr = r.users;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array (maybe wrapped in non-standard key)');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Configs (provider configs) ──
|
||||
|
||||
await T.test('admin', 'configs', 'sw.api.admin.configs.list()', {
|
||||
sdk: function () { return sw.api.admin.configs.list(); },
|
||||
raw: { method: 'GET', path: '/admin/configs' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {configs: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.configs) arr = r.configs;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Models ──
|
||||
|
||||
await T.test('admin', 'models', 'sw.api.admin.models.list()', {
|
||||
sdk: function () { return sw.api.admin.models.list(); },
|
||||
raw: { method: 'GET', path: '/admin/models' },
|
||||
validate: function (r) {
|
||||
// KNOWN: backend returns {models: [...]} not {data: [...]}
|
||||
var arr = r;
|
||||
if (r && r.models) arr = r.models;
|
||||
if (r && r.data) arr = r.data;
|
||||
T.assert(Array.isArray(arr), 'expected array');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Settings ──
|
||||
|
||||
await T.test('admin', 'settings', 'sw.api.admin.settings.get()', {
|
||||
sdk: function () { return sw.api.admin.settings.get(); },
|
||||
raw: { method: 'GET', path: '/admin/settings' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Packages ──
|
||||
|
||||
await T.test('admin', 'packages', 'sw.api.admin.packages.list()', {
|
||||
sdk: function () { return sw.api.admin.packages.list(); },
|
||||
raw: { method: 'GET', path: '/admin/packages' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Surfaces ──
|
||||
|
||||
await T.test('admin', 'surfaces', 'sw.api.admin.surfaces.list()', {
|
||||
sdk: function () { return sw.api.admin.surfaces.list(); },
|
||||
raw: { method: 'GET', path: '/admin/surfaces' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Extensions ──
|
||||
|
||||
await T.test('admin', 'extensions', 'sw.api.admin.extensions.list()', {
|
||||
sdk: function () { return sw.api.admin.extensions.list(); },
|
||||
raw: { method: 'GET', path: '/admin/extensions' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Tasks ──
|
||||
|
||||
await T.test('admin', 'tasks', 'sw.api.admin.tasks.list()', {
|
||||
sdk: function () { return sw.api.admin.tasks.list(); },
|
||||
raw: { method: 'GET', path: '/admin/tasks' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Routing ──
|
||||
|
||||
await T.test('admin', 'routing', 'sw.api.admin.routing.policies()', {
|
||||
sdk: function () { return sw.api.admin.routing.policies(); },
|
||||
raw: { method: 'GET', path: '/admin/routing/policies' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Provider health ──
|
||||
|
||||
await T.test('admin', 'providers', 'sw.api.admin.providers.health()', {
|
||||
sdk: function () { return sw.api.admin.providers.health(); },
|
||||
raw: { method: 'GET', path: '/admin/providers/health' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array'); }
|
||||
});
|
||||
|
||||
// ── Storage ──
|
||||
|
||||
await T.test('admin', 'storage', 'sw.api.admin.storage.status()', {
|
||||
sdk: function () { return sw.api.admin.storage.status(); },
|
||||
raw: { method: 'GET', path: '/admin/storage/status' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Vault ──
|
||||
|
||||
await T.test('admin', 'vault', 'sw.api.admin.vault.status()', {
|
||||
sdk: function () { return sw.api.admin.vault.status(); },
|
||||
raw: { method: 'GET', path: '/admin/vault/status' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Channels (archived) ──
|
||||
|
||||
await T.test('admin', 'channels', 'sw.api.admin.channels.archived()', {
|
||||
sdk: function () { return sw.api.admin.channels.archived(); },
|
||||
raw: { method: 'GET', path: '/admin/channels/archived' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Projects ──
|
||||
|
||||
await T.test('admin', 'projects', 'sw.api.admin.projects.list()', {
|
||||
sdk: function () { return sw.api.admin.projects.list(); },
|
||||
raw: { method: 'GET', path: '/admin/projects' },
|
||||
validate: function (r) { T.assert(Array.isArray(r) || (r && Array.isArray(r.data)), 'expected array'); }
|
||||
});
|
||||
});
|
||||
})();
|
||||
158
packages/sdk-test-runner/js/domains/channels.js
Normal file
158
packages/sdk-test-runner/js/domains/channels.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: channels
|
||||
*
|
||||
* Tests: list, create, get, update, delete, messages, participants,
|
||||
* models, kbs, files, markRead, generateTitle, path, siblings.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('channels', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var channelId = null;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('channels', 'list', 'sw.api.channels.list() returns array', {
|
||||
sdk: function () { return sw.api.channels.list(); },
|
||||
raw: { method: 'GET', path: '/channels' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('channels', 'crud', 'sw.api.channels.create() returns channel shape', {
|
||||
sdk: function () {
|
||||
return sw.api.channels.create({ title: tag + '-ch', type: 'direct' });
|
||||
},
|
||||
raw: { method: 'POST', path: '/channels', body: { title: tag + '-ch-raw', type: 'direct' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.channel, 'channel');
|
||||
channelId = r.id;
|
||||
T.registerCleanup(function () { if (channelId) return T.safeDelete('/channels/' + channelId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!channelId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('channels', 'crud', 'sw.api.channels.get(id) returns full shape', {
|
||||
sdk: function () { return sw.api.channels.get(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.channelFull, 'channelFull');
|
||||
T.assert(r.id === channelId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update ──
|
||||
|
||||
await T.test('channels', 'crud', 'sw.api.channels.update(id, data)', {
|
||||
sdk: function () { return sw.api.channels.update(channelId, { title: tag + '-updated' }); },
|
||||
raw: { method: 'PUT', path: '/channels/' + channelId, body: { title: tag + '-updated' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.channelFull, 'channel');
|
||||
T.assert(r.title === tag + '-updated', 'title not updated');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Messages ──
|
||||
|
||||
await T.test('channels', 'messages', 'sw.api.channels.messages(id) returns array', {
|
||||
sdk: function () { return sw.api.channels.messages(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/messages' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Send message ──
|
||||
|
||||
var msgId = null;
|
||||
await T.test('channels', 'messages', 'sw.api.channels.send(id, data)', {
|
||||
sdk: function () {
|
||||
return sw.api.channels.send(channelId, { content: 'sdk-test-msg', role: 'user' });
|
||||
},
|
||||
raw: { method: 'POST', path: '/channels/' + channelId + '/messages',
|
||||
body: { content: 'sdk-test-msg', role: 'user' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.message, 'message');
|
||||
msgId = r.id;
|
||||
}
|
||||
});
|
||||
|
||||
// ── Siblings ──
|
||||
|
||||
if (msgId) {
|
||||
await T.test('channels', 'messages', 'sw.api.channels.siblings(id, msgId)', {
|
||||
sdk: function () { return sw.api.channels.siblings(channelId, msgId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/messages/' + msgId + '/siblings' },
|
||||
validate: function (r) {
|
||||
// Siblings returns { siblings: [...], current_index, total }
|
||||
var arr = r.siblings || T.unwrapList(r);
|
||||
T.assert(Array.isArray(arr), 'expected siblings array');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── Path ──
|
||||
|
||||
await T.test('channels', 'tree', 'sw.api.channels.path(id)', {
|
||||
sdk: function () { return sw.api.channels.path(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/path' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Mark Read ──
|
||||
|
||||
await T.test('channels', 'read', 'sw.api.channels.markRead(id)', {
|
||||
sdk: function () { return sw.api.channels.markRead(channelId); },
|
||||
raw: { method: 'POST', path: '/channels/' + channelId + '/mark-read', body: {} },
|
||||
validate: function () { /* 200 OK is sufficient */ }
|
||||
});
|
||||
|
||||
// ── KBs ──
|
||||
|
||||
await T.test('channels', 'kbs', 'sw.api.channels.kbs(id) returns array', {
|
||||
sdk: function () { return sw.api.channels.kbs(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/knowledge-bases' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Files ──
|
||||
|
||||
await T.test('channels', 'files', 'sw.api.channels.files(id)', {
|
||||
sdk: function () { return sw.api.channels.files(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/files' },
|
||||
validate: function (r) {
|
||||
// May be array or {files: [], count: N}
|
||||
T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Participants ──
|
||||
|
||||
await T.test('channels', 'participants', 'sw.api.channels.participants(id)', {
|
||||
sdk: function () { return sw.api.channels.participants(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/participants' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Models ──
|
||||
|
||||
await T.test('channels', 'models', 'sw.api.channels.models(id)', {
|
||||
sdk: function () { return sw.api.channels.models(channelId); },
|
||||
raw: { method: 'GET', path: '/channels/' + channelId + '/models' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('channels', 'crud', 'sw.api.channels.del(id)', {
|
||||
sdk: function () { return sw.api.channels.del(channelId); },
|
||||
raw: { method: 'DELETE', path: '/channels/' + channelId },
|
||||
validate: function () { channelId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
82
packages/sdk-test-runner/js/domains/knowledge.js
Normal file
82
packages/sdk-test-runner/js/domains/knowledge.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: knowledge
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('knowledge', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var kbId = null;
|
||||
|
||||
await T.test('knowledge', 'list', 'sw.api.knowledge.list()', {
|
||||
sdk: function () { return sw.api.knowledge.list(); },
|
||||
raw: { method: 'GET', path: '/knowledge-bases' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
await T.test('knowledge', 'crud', 'sw.api.knowledge.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.knowledge.create({ name: tag + '-kb', scope: 'personal' });
|
||||
},
|
||||
raw: { method: 'POST', path: '/knowledge-bases', body: { name: tag + '-kb', scope: 'personal' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.kb, 'kb');
|
||||
kbId = r.id;
|
||||
T.registerCleanup(function () { if (kbId) return T.safeDelete('/knowledge-bases/' + kbId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!kbId) return;
|
||||
|
||||
await T.test('knowledge', 'crud', 'sw.api.knowledge.get(id)', {
|
||||
sdk: function () { return sw.api.knowledge.get(kbId); },
|
||||
raw: { method: 'GET', path: '/knowledge-bases/' + kbId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.kb, 'kb');
|
||||
T.assert(r.id === kbId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
await T.test('knowledge', 'crud', 'sw.api.knowledge.update(id, data)', {
|
||||
sdk: function () { return sw.api.knowledge.update(kbId, { name: tag + '-kb-upd' }); },
|
||||
raw: { method: 'PUT', path: '/knowledge-bases/' + kbId, body: { name: tag + '-kb-upd' } },
|
||||
validate: function (r) { T.assertShape(r, T.S.kb, 'kb'); }
|
||||
});
|
||||
|
||||
// ── Discoverable ──
|
||||
|
||||
await T.test('knowledge', 'discover', 'sw.api.knowledge.discoverable()', {
|
||||
sdk: function () { return sw.api.knowledge.discoverable(); },
|
||||
raw: { method: 'GET', path: '/knowledge-bases-discoverable' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Documents ──
|
||||
|
||||
await T.test('knowledge', 'docs', 'sw.api.knowledge.documents(id)', {
|
||||
sdk: function () { return sw.api.knowledge.documents(kbId); },
|
||||
raw: { method: 'GET', path: '/knowledge-bases/' + kbId + '/documents' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Search ──
|
||||
|
||||
// Search requires an embedding provider — only run if fixture provisioned one
|
||||
var hasEmbedding = T.fixtures && T.fixtures.embeddingModel;
|
||||
await T.test('knowledge', 'search', 'sw.api.knowledge.search(id, query)', {
|
||||
sdk: function () { return sw.api.knowledge.search(kbId, 'test', 5); },
|
||||
raw: { method: 'POST', path: '/knowledge-bases/' + kbId + '/search',
|
||||
body: { query: 'test', limit: 5 } },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); },
|
||||
skip: hasEmbedding ? null : 'no embedding provider configured — set up a provider with embedding models'
|
||||
});
|
||||
|
||||
await T.test('knowledge', 'crud', 'sw.api.knowledge.del(id)', {
|
||||
sdk: function () { return sw.api.knowledge.del(kbId); },
|
||||
raw: { method: 'DELETE', path: '/knowledge-bases/' + kbId },
|
||||
validate: function () { kbId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
196
packages/sdk-test-runner/js/domains/misc.js
Normal file
196
packages/sdk-test-runner/js/domains/misc.js
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: misc
|
||||
*
|
||||
* Covers smaller domains: notifications, folders, profile,
|
||||
* data portability, health, models, users, presence, usage, groups,
|
||||
* tools, git.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('misc', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// HEALTH
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'health', 'sw.api.health()', {
|
||||
sdk: function () { return sw.api.health(); },
|
||||
raw: { method: 'GET', path: '/health' },
|
||||
validate: function (r) { T.assert(r.status === 'ok', 'status should be ok'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// PROFILE
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'profile', 'sw.api.profile.get()', {
|
||||
sdk: function () { return sw.api.profile.get(); },
|
||||
raw: { method: 'GET', path: '/profile' },
|
||||
validate: function (r) { T.assertShape(r, T.S.profile, 'profile'); }
|
||||
});
|
||||
|
||||
await T.test('misc', 'profile', 'sw.api.profile.permissions()', {
|
||||
sdk: function () {
|
||||
if (sw.api.profile.permissions) return sw.api.profile.permissions();
|
||||
throw new Error('sw.api.profile.permissions not defined');
|
||||
},
|
||||
raw: { method: 'GET', path: '/profile/permissions' },
|
||||
validate: function (r) {
|
||||
T.assert(Array.isArray(r.permissions), 'permissions should be array');
|
||||
}
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// MODELS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'models', 'sw.api.models.enabled()', {
|
||||
sdk: function () {
|
||||
if (sw.api.models && sw.api.models.enabled) return sw.api.models.enabled();
|
||||
throw new Error('sw.api.models.enabled not defined');
|
||||
},
|
||||
raw: { method: 'GET', path: '/models/enabled' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// FOLDERS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
var folderId = null;
|
||||
|
||||
await T.test('misc', 'folders', 'sw.api.folders.list()', {
|
||||
sdk: function () { return sw.api.folders.list(); },
|
||||
raw: { method: 'GET', path: '/folders' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
await T.test('misc', 'folders', 'sw.api.folders.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.folders.create(tag + '-folder');
|
||||
},
|
||||
raw: { method: 'POST', path: '/folders', body: { name: tag + '-folder', parent_id: null, sort_order: 0 } },
|
||||
validate: function (r) {
|
||||
// Backend returns { folder: {...} } — SDK passes envelope through
|
||||
var obj = r.folder || r;
|
||||
T.assertShape(obj, T.S.folder, 'folder');
|
||||
folderId = obj.id;
|
||||
T.registerCleanup(function () { if (folderId) return T.safeDelete('/folders/' + folderId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (folderId) {
|
||||
await T.test('misc', 'folders', 'sw.api.folders.update(id, data)', {
|
||||
sdk: function () { return sw.api.folders.update(folderId, { name: tag + '-fold-upd' }); },
|
||||
raw: { method: 'PUT', path: '/folders/' + folderId, body: { name: tag + '-fold-upd' } },
|
||||
validate: function (r) { T.assert(r && (r.ok || r.id || r.folder), 'expected ok or folder'); }
|
||||
});
|
||||
|
||||
await T.test('misc', 'folders', 'sw.api.folders.del(id)', {
|
||||
sdk: function () { return sw.api.folders.del(folderId); },
|
||||
raw: { method: 'DELETE', path: '/folders/' + folderId },
|
||||
validate: function () { folderId = null; }
|
||||
});
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// NOTIFICATIONS (duplicate key bug fixed — prefs/setPref/delPref restored)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'notifications', 'sw.api.notifications.list()', {
|
||||
sdk: function () { return sw.api.notifications.list(); },
|
||||
raw: { method: 'GET', path: '/notifications' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
await T.test('misc', 'notifications', 'sw.api.notifications.unreadCount()', {
|
||||
sdk: function () { return sw.api.notifications.unreadCount(); },
|
||||
raw: { method: 'GET', path: '/notifications/unread-count' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
await T.test('misc', 'notifications', 'sw.api.notifications.prefs()', {
|
||||
sdk: function () {
|
||||
if (typeof sw.api.notifications.prefs === 'function') return sw.api.notifications.prefs();
|
||||
throw new Error('sw.api.notifications.prefs is ' + typeof sw.api.notifications.prefs);
|
||||
},
|
||||
raw: { method: 'GET', path: '/notifications/preferences' },
|
||||
validate: function () { /* existence is sufficient */ }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// USERS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'users', 'sw.api.users.search(q)', {
|
||||
sdk: function () { return sw.api.users.search('admin'); },
|
||||
raw: { method: 'GET', path: '/users/search?q=admin' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// PRESENCE
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'presence', 'sw.api.presence.heartbeat()', {
|
||||
sdk: function () { return sw.api.presence.heartbeat(); },
|
||||
raw: { method: 'POST', path: '/presence/heartbeat', body: {} },
|
||||
validate: function () { /* 200 OK is sufficient */ }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// USAGE
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'usage', 'sw.api.usage.mine()', {
|
||||
sdk: function () { return sw.api.usage.mine(); },
|
||||
raw: { method: 'GET', path: '/usage' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// GROUPS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'groups', 'sw.api.groups.mine()', {
|
||||
sdk: function () { return sw.api.groups.mine(); },
|
||||
raw: { method: 'GET', path: '/groups/mine' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// TOOLS
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'tools', 'sw.api.tools.list()', {
|
||||
sdk: function () { return sw.api.tools.list(); },
|
||||
raw: { method: 'GET', path: '/tools' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// DATA PORTABILITY (KNOWN BUG: deleteAccount wrong method+path)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
await T.test('misc', 'export', 'sw.api.dataPortability.exportMe()', {
|
||||
sdk: function () { return sw.api.dataPortability.exportMe(); },
|
||||
raw: { method: 'GET', path: '/export/me' },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); },
|
||||
skip: 'empty DB export may 500 — expected in dev'
|
||||
});
|
||||
|
||||
// deleteAccount: SDK uses POST /profile/delete, backend is DELETE /me
|
||||
// We don't actually call delete — just verify the method exists
|
||||
await T.test('misc', 'export', 'sw.api.dataPortability.deleteAccount exists', async function () {
|
||||
T.assert(typeof sw.api.dataPortability.deleteAccount === 'function',
|
||||
'deleteAccount should be a function');
|
||||
// NOTE: SDK calls POST /profile/delete — backend is DELETE /me.
|
||||
// This is a known SDK_BUG from the ICD drift audit (§A).
|
||||
// We don't actually invoke it because it would delete the account.
|
||||
});
|
||||
});
|
||||
})();
|
||||
106
packages/sdk-test-runner/js/domains/notes.js
Normal file
106
packages/sdk-test-runner/js/domains/notes.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: notes
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('notes', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var noteId = null;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('notes', 'list', 'sw.api.notes.list()', {
|
||||
sdk: function () { return sw.api.notes.list(); },
|
||||
raw: { method: 'GET', path: '/notes' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('notes', 'crud', 'sw.api.notes.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.notes.create({ title: tag + '-note', content: '# Test\nBody text' });
|
||||
},
|
||||
raw: { method: 'POST', path: '/notes', body: { title: tag + '-note', content: '# Test\nBody text' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.note, 'note');
|
||||
noteId = r.id;
|
||||
T.registerCleanup(function () { if (noteId) return T.safeDelete('/notes/' + noteId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!noteId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('notes', 'crud', 'sw.api.notes.get(id)', {
|
||||
sdk: function () { return sw.api.notes.get(noteId); },
|
||||
raw: { method: 'GET', path: '/notes/' + noteId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.note, 'note');
|
||||
T.assert(r.id === noteId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update ──
|
||||
|
||||
await T.test('notes', 'crud', 'sw.api.notes.update(id, data)', {
|
||||
sdk: function () { return sw.api.notes.update(noteId, { title: tag + '-note-upd', content: 'updated' }); },
|
||||
raw: { method: 'PUT', path: '/notes/' + noteId, body: { title: tag + '-note-upd', content: 'updated' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.note, 'note');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Search ──
|
||||
|
||||
await T.test('notes', 'search', 'sw.api.notes.search(query)', {
|
||||
sdk: function () { return sw.api.notes.search(tag, 5); },
|
||||
raw: { method: 'GET', path: '/notes/search?q=' + encodeURIComponent(tag) + '&limit=5' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Search Titles ──
|
||||
|
||||
await T.test('notes', 'search', 'sw.api.notes.searchTitles(query)', {
|
||||
sdk: function () { return sw.api.notes.searchTitles(tag, 5); },
|
||||
raw: { method: 'GET', path: '/notes/search-titles?q=' + encodeURIComponent(tag) + '&limit=5' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Folders ──
|
||||
|
||||
await T.test('notes', 'folders', 'sw.api.notes.folders()', {
|
||||
sdk: function () { return sw.api.notes.folders(); },
|
||||
raw: { method: 'GET', path: '/notes/folders' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Backlinks ──
|
||||
|
||||
await T.test('notes', 'links', 'sw.api.notes.backlinks(id)', {
|
||||
sdk: function () { return sw.api.notes.backlinks(noteId); },
|
||||
raw: { method: 'GET', path: '/notes/' + noteId + '/backlinks' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Graph ──
|
||||
|
||||
await T.test('notes', 'graph', 'sw.api.notes.graph()', {
|
||||
sdk: function () { return sw.api.notes.graph(); },
|
||||
raw: { method: 'GET', path: '/notes/graph' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('notes', 'crud', 'sw.api.notes.del(id)', {
|
||||
sdk: function () { return sw.api.notes.del(noteId); },
|
||||
raw: { method: 'DELETE', path: '/notes/' + noteId },
|
||||
validate: function () { noteId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
66
packages/sdk-test-runner/js/domains/personas.js
Normal file
66
packages/sdk-test-runner/js/domains/personas.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: personas
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('personas', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var personaId = null;
|
||||
|
||||
// Policy: allow_user_personas is toggled by fixtures.js.
|
||||
// If fixtures didn't run (or user isn't admin), create will 403.
|
||||
|
||||
await T.test('personas', 'list', 'sw.api.personas.list()', {
|
||||
sdk: function () { return sw.api.personas.list(); },
|
||||
raw: { method: 'GET', path: '/personas' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
await T.test('personas', 'crud', 'sw.api.personas.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.personas.create({
|
||||
name: tag + '-persona', system_prompt: 'You are a test bot.',
|
||||
scope: 'personal'
|
||||
});
|
||||
},
|
||||
raw: { method: 'POST', path: '/personas', body: {
|
||||
name: tag + '-persona', system_prompt: 'You are a test bot.',
|
||||
scope: 'personal'
|
||||
}},
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.persona, 'persona');
|
||||
personaId = r.id;
|
||||
T.registerCleanup(function () { if (personaId) return T.safeDelete('/personas/' + personaId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!personaId) return;
|
||||
|
||||
// NOTE: User-scoped personas only have LIST + CREATE routes.
|
||||
// GET/PUT/DELETE /personas/:id are admin-only (ICD gap).
|
||||
// Use admin endpoints for full CRUD testing.
|
||||
|
||||
await T.test('personas', 'crud', 'sw.api.admin.personas.update(id, data)', {
|
||||
sdk: function () { return sw.api.admin.personas.update(personaId, { name: tag + '-pers-upd' }); },
|
||||
raw: { method: 'PUT', path: '/admin/personas/' + personaId, body: { name: tag + '-pers-upd' } },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── KBs ──
|
||||
|
||||
await T.test('personas', 'kbs', 'sw.api.admin.personas.kbs(id)', {
|
||||
sdk: function () { return sw.api.admin.personas.kbs(personaId); },
|
||||
raw: { method: 'GET', path: '/admin/personas/' + personaId + '/knowledge-bases' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
await T.test('personas', 'crud', 'sw.api.admin.personas.del(id)', {
|
||||
sdk: function () { return sw.api.admin.personas.del(personaId); },
|
||||
raw: { method: 'DELETE', path: '/admin/personas/' + personaId },
|
||||
validate: function () { personaId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
134
packages/sdk-test-runner/js/domains/projects.js
Normal file
134
packages/sdk-test-runner/js/domains/projects.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: projects
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('projects', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var projectId = null;
|
||||
var channelId = null;
|
||||
var noteId = null;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('projects', 'list', 'sw.api.projects.list()', {
|
||||
sdk: function () { return sw.api.projects.list(); },
|
||||
raw: { method: 'GET', path: '/projects' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('projects', 'crud', 'sw.api.projects.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.projects.create({ name: tag + '-proj', description: 'sdk test' });
|
||||
},
|
||||
raw: { method: 'POST', path: '/projects', body: { name: tag + '-proj', description: 'sdk test' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.project, 'project');
|
||||
projectId = r.id;
|
||||
T.registerCleanup(function () { if (projectId) return T.safeDelete('/projects/' + projectId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!projectId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('projects', 'crud', 'sw.api.projects.get(id)', {
|
||||
sdk: function () { return sw.api.projects.get(projectId); },
|
||||
raw: { method: 'GET', path: '/projects/' + projectId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.project, 'project');
|
||||
T.assert(r.id === projectId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update ──
|
||||
|
||||
await T.test('projects', 'crud', 'sw.api.projects.update(id, data)', {
|
||||
sdk: function () { return sw.api.projects.update(projectId, { name: tag + '-proj-upd' }); },
|
||||
raw: { method: 'PUT', path: '/projects/' + projectId, body: { name: tag + '-proj-upd' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.project, 'project');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Channel association ──
|
||||
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.addChannel()', async function () {
|
||||
var ch = await T.raw.post('/channels', { title: tag + '-proj-ch', type: 'direct' });
|
||||
channelId = ch.id;
|
||||
T.registerCleanup(function () { if (channelId) return T.safeDelete('/channels/' + channelId); });
|
||||
});
|
||||
|
||||
if (channelId) {
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.addChannel(id, chId)', {
|
||||
sdk: function () { return sw.api.projects.addChannel(projectId, channelId, 0); },
|
||||
raw: { method: 'POST', path: '/projects/' + projectId + '/channels',
|
||||
body: { channel_id: channelId, position: 0 } },
|
||||
validate: function () { /* ok */ }
|
||||
});
|
||||
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.channels(id)', {
|
||||
sdk: function () { return sw.api.projects.channels(projectId); },
|
||||
raw: { method: 'GET', path: '/projects/' + projectId + '/channels' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.removeChannel()', {
|
||||
sdk: function () { return sw.api.projects.removeChannel(projectId, channelId); },
|
||||
raw: { method: 'DELETE', path: '/projects/' + projectId + '/channels/' + channelId },
|
||||
validate: function () { /* ok */ }
|
||||
});
|
||||
}
|
||||
|
||||
// ── Note association ──
|
||||
|
||||
await T.test('projects', 'assoc', 'create scratch note for project', async function () {
|
||||
var n = await T.raw.post('/notes', { title: tag + '-proj-note', content: 'test' });
|
||||
noteId = n.id;
|
||||
T.registerCleanup(function () { if (noteId) return T.safeDelete('/notes/' + noteId); });
|
||||
});
|
||||
|
||||
if (noteId) {
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.addNote()', {
|
||||
sdk: function () { return sw.api.projects.addNote(projectId, noteId); },
|
||||
raw: { method: 'POST', path: '/projects/' + projectId + '/notes',
|
||||
body: { note_id: noteId } },
|
||||
validate: function () { /* ok */ }
|
||||
});
|
||||
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.notes(id)', {
|
||||
sdk: function () { return sw.api.projects.notes(projectId); },
|
||||
raw: { method: 'GET', path: '/projects/' + projectId + '/notes' },
|
||||
validate: function (r) { T.assert(Array.isArray(r), 'expected array'); }
|
||||
});
|
||||
|
||||
await T.test('projects', 'assoc', 'sw.api.projects.removeNote()', {
|
||||
sdk: function () { return sw.api.projects.removeNote(projectId, noteId); },
|
||||
raw: { method: 'DELETE', path: '/projects/' + projectId + '/notes/' + noteId },
|
||||
validate: function () { /* ok */ }
|
||||
});
|
||||
}
|
||||
|
||||
// ── Files ──
|
||||
|
||||
await T.test('projects', 'files', 'sw.api.projects.files(id)', {
|
||||
sdk: function () { return sw.api.projects.files(projectId); },
|
||||
raw: { method: 'GET', path: '/projects/' + projectId + '/files' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected obj/arr'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('projects', 'crud', 'sw.api.projects.del(id)', {
|
||||
sdk: function () { return sw.api.projects.del(projectId); },
|
||||
raw: { method: 'DELETE', path: '/projects/' + projectId },
|
||||
validate: function () { projectId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
107
packages/sdk-test-runner/js/domains/tasks.js
Normal file
107
packages/sdk-test-runner/js/domains/tasks.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: tasks
|
||||
*
|
||||
* KNOWN BUGS:
|
||||
* sw.api.tasks.start(id) → POST /tasks/:id/start (backend: /tasks/:id/run)
|
||||
* sw.api.tasks.stop(id) → POST /tasks/:id/stop (backend: /tasks/:id/kill)
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('tasks', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var taskId = null;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('tasks', 'list', 'sw.api.tasks.list()', {
|
||||
sdk: function () { return sw.api.tasks.list(); },
|
||||
raw: { method: 'GET', path: '/tasks' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('tasks', 'crud', 'sw.api.tasks.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.tasks.create({
|
||||
name: tag + '-task', task_type: 'prompt',
|
||||
schedule: '@daily', user_prompt: 'SDK test prompt', is_active: false
|
||||
});
|
||||
},
|
||||
raw: { method: 'POST', path: '/tasks', body: {
|
||||
name: tag + '-task', task_type: 'prompt',
|
||||
schedule: '@daily', user_prompt: 'SDK test prompt', is_active: false
|
||||
}},
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.task, 'task');
|
||||
taskId = r.id;
|
||||
T.registerCleanup(function () { if (taskId) return T.safeDelete('/tasks/' + taskId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!taskId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('tasks', 'crud', 'sw.api.tasks.get(id)', {
|
||||
sdk: function () { return sw.api.tasks.get(taskId); },
|
||||
raw: { method: 'GET', path: '/tasks/' + taskId },
|
||||
validate: function (r) {
|
||||
T.assert(r.id === taskId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update ──
|
||||
|
||||
await T.test('tasks', 'crud', 'sw.api.tasks.update(id, data)', {
|
||||
sdk: function () { return sw.api.tasks.update(taskId, { name: tag + '-task-upd' }); },
|
||||
raw: { method: 'PUT', path: '/tasks/' + taskId, body: { name: tag + '-task-upd' } },
|
||||
validate: function (r) { T.assert(typeof r === 'object', 'expected object'); }
|
||||
});
|
||||
|
||||
// ── Start ──
|
||||
|
||||
await T.test('tasks', 'lifecycle', 'sw.api.tasks.start(id)', {
|
||||
sdk: function () {
|
||||
if (sw.api.tasks.start) return sw.api.tasks.start(taskId);
|
||||
throw new Error('sw.api.tasks.start not defined');
|
||||
},
|
||||
raw: { method: 'POST', path: '/tasks/' + taskId + '/run', body: {} },
|
||||
validate: function () { /* 200/202 is sufficient */ }
|
||||
});
|
||||
|
||||
// ── Stop ── (404 expected when no active run)
|
||||
|
||||
await T.test('tasks', 'lifecycle', 'sw.api.tasks.stop(id)', {
|
||||
sdk: function () {
|
||||
if (sw.api.tasks.stop) return sw.api.tasks.stop(taskId);
|
||||
throw new Error('sw.api.tasks.stop not defined');
|
||||
},
|
||||
raw: { method: 'POST', path: '/tasks/' + taskId + '/kill', body: {} },
|
||||
validate: function () { /* 200/202 is sufficient */ },
|
||||
skip: 'no active run to cancel — 404 expected without task execution'
|
||||
});
|
||||
|
||||
// ── Runs ──
|
||||
|
||||
await T.test('tasks', 'runs', 'sw.api.tasks.runs(id)', {
|
||||
sdk: function () {
|
||||
if (sw.api.tasks.runs) return sw.api.tasks.runs(taskId);
|
||||
throw new Error('sw.api.tasks.runs not defined');
|
||||
},
|
||||
raw: { method: 'GET', path: '/tasks/' + taskId + '/runs' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('tasks', 'crud', 'sw.api.tasks.del(id)', {
|
||||
sdk: function () { return sw.api.tasks.del(taskId); },
|
||||
raw: { method: 'DELETE', path: '/tasks/' + taskId },
|
||||
validate: function () { taskId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
93
packages/sdk-test-runner/js/domains/workflows.js
Normal file
93
packages/sdk-test-runner/js/domains/workflows.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: workflows
|
||||
*
|
||||
* Tests: list, create, get, update, delete, stages.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('workflows', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var wfId = null;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('workflows', 'list', 'sw.api.workflows.list() returns array', {
|
||||
sdk: function () { return sw.api.workflows.list(); },
|
||||
raw: { method: 'GET', path: '/workflows' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('workflows', 'crud', 'sw.api.workflows.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.workflows.create({
|
||||
name: tag + '-wf', slug: tag + '-wf',
|
||||
entry_mode: 'team_only', scope: 'personal'
|
||||
});
|
||||
},
|
||||
raw: { method: 'POST', path: '/workflows', body: {
|
||||
name: tag + '-wf', slug: tag + '-wf',
|
||||
entry_mode: 'team_only', scope: 'personal'
|
||||
}},
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workflow, 'workflow');
|
||||
wfId = r.id;
|
||||
T.registerCleanup(function () { if (wfId) return T.safeDelete('/workflows/' + wfId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!wfId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('workflows', 'crud', 'sw.api.workflows.get(id)', {
|
||||
sdk: function () { return sw.api.workflows.get(wfId); },
|
||||
raw: { method: 'GET', path: '/workflows/' + wfId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workflow, 'workflow');
|
||||
T.assert(r.id === wfId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update (KNOWN BUG: SDK uses PUT, backend expects PATCH) ──
|
||||
|
||||
await T.test('workflows', 'crud', 'sw.api.workflows.update(id, data)', {
|
||||
sdk: function () {
|
||||
return sw.api.workflows.update(wfId, { name: tag + '-wf-updated' });
|
||||
},
|
||||
raw: { method: 'PATCH', path: '/workflows/' + wfId,
|
||||
body: { name: tag + '-wf-updated' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workflow, 'workflow');
|
||||
T.assert(r.name === tag + '-wf-updated', 'name not updated');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Stages ──
|
||||
|
||||
var stageId = null;
|
||||
|
||||
// stages.list via SDK (if wired) vs raw
|
||||
await T.test('workflows', 'stages', 'GET /workflows/:id/stages (raw — SDK may not have this)', {
|
||||
sdk: function () {
|
||||
// SDK may or may not expose stages — test raw path
|
||||
if (sw.api.workflows.stages) return sw.api.workflows.stages(wfId);
|
||||
throw new Error('sw.api.workflows.stages not defined');
|
||||
},
|
||||
raw: { method: 'GET', path: '/workflows/' + wfId + '/stages' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('workflows', 'crud', 'sw.api.workflows.del(id)', {
|
||||
sdk: function () { return sw.api.workflows.del(wfId); },
|
||||
raw: { method: 'DELETE', path: '/workflows/' + wfId },
|
||||
validate: function () { wfId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
83
packages/sdk-test-runner/js/domains/workspaces.js
Normal file
83
packages/sdk-test-runner/js/domains/workspaces.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* SDK Test Runner — Domain: workspaces
|
||||
*
|
||||
* Tests: list, create, get, update, delete, files.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.SDKR;
|
||||
if (!T) return;
|
||||
|
||||
T.registerDomain('workspaces', async function () {
|
||||
var tag = 'sdkr-' + Date.now();
|
||||
var wsId = null;
|
||||
|
||||
// Get current user for owner_type/owner_id
|
||||
var me = await sw.api.profile.get();
|
||||
var userId = me.id;
|
||||
|
||||
// ── List ──
|
||||
|
||||
await T.test('workspaces', 'list', 'sw.api.workspaces.list()', {
|
||||
sdk: function () { return sw.api.workspaces.list(); },
|
||||
raw: { method: 'GET', path: '/workspaces' },
|
||||
validate: function (r) { var arr = T.unwrapList(r); T.assert(arr.length >= 0, 'expected list'); }
|
||||
});
|
||||
|
||||
// ── Create ──
|
||||
|
||||
await T.test('workspaces', 'crud', 'sw.api.workspaces.create()', {
|
||||
sdk: function () {
|
||||
return sw.api.workspaces.create({ name: tag + '-ws', owner_type: 'user', owner_id: userId });
|
||||
},
|
||||
raw: { method: 'POST', path: '/workspaces', body: { name: tag + '-ws', owner_type: 'user', owner_id: userId } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workspace, 'workspace');
|
||||
wsId = r.id;
|
||||
T.registerCleanup(function () { if (wsId) return T.safeDelete('/workspaces/' + wsId); });
|
||||
}
|
||||
});
|
||||
|
||||
if (!wsId) return;
|
||||
|
||||
// ── Get ──
|
||||
|
||||
await T.test('workspaces', 'crud', 'sw.api.workspaces.get(id)', {
|
||||
sdk: function () { return sw.api.workspaces.get(wsId); },
|
||||
raw: { method: 'GET', path: '/workspaces/' + wsId },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workspace, 'workspace');
|
||||
T.assert(r.id === wsId, 'id mismatch');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Update (KNOWN BUG: SDK uses PUT, backend expects PATCH) ──
|
||||
|
||||
await T.test('workspaces', 'crud', 'sw.api.workspaces.update(id, data)', {
|
||||
sdk: function () {
|
||||
return sw.api.workspaces.update(wsId, { name: tag + '-ws-updated' });
|
||||
},
|
||||
raw: { method: 'PATCH', path: '/workspaces/' + wsId,
|
||||
body: { name: tag + '-ws-updated' } },
|
||||
validate: function (r) {
|
||||
T.assertShape(r, T.S.workspace, 'workspace');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Files list ──
|
||||
|
||||
await T.test('workspaces', 'files', 'sw.api.workspaces.files(id)', {
|
||||
sdk: function () { return sw.api.workspaces.files(wsId); },
|
||||
raw: { method: 'GET', path: '/workspaces/' + wsId + '/files' },
|
||||
validate: function (r) { T.assert(typeof r === 'object' || Array.isArray(r), 'expected object or array'); }
|
||||
});
|
||||
|
||||
// ── Delete ──
|
||||
|
||||
await T.test('workspaces', 'crud', 'sw.api.workspaces.del(id)', {
|
||||
sdk: function () { return sw.api.workspaces.del(wsId); },
|
||||
raw: { method: 'DELETE', path: '/workspaces/' + wsId },
|
||||
validate: function () { wsId = null; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user