All checks were successful
CI/CD / detect-changes (pull_request) Successful in 23s
CI/CD / test-frontend (pull_request) Successful in 26s
CI/CD / test-go-pg (pull_request) Successful in 2m35s
CI/CD / test-sqlite (pull_request) Successful in 3m19s
CI/CD / build-and-deploy (pull_request) Successful in 1m46s
sw.testing SDK module — structured test framework for surface runners: - suite/test registration, lifecycle hooks (beforeAll/afterAll/beforeEach/afterEach) - Assertion library (ok/eq/neq/gt/match/throws/status/shape/arrayOf) - Auto-cleanup via track(type, id) with LIFO deletion - Three result statuses: passed/failed/warned - Structured JSON results with timing, warnings, cleanup stats test-runner manifest type: - ValidateManifest accepts "test-runner" packages - Excluded from sidebar nav (extensionNavItems filters surface/full only) - DB migrations: SQLite 013, Postgres 014 (CHECK constraint) ICD runner migration (kernel-only): - Migrated from T.test()/T.assert() to sw.testing.suite() - Stripped extension-dependent tests (channels, notes, personas, etc.) - Kernel suites: smoke, crud, authz, security, providers, packaging, sdk - Deleted ui.js + css (rendering delegated to registry surface) SDK runner migration (kernel-only): - Migrated from T.dualTest()/T.domains to sw.testing.suite() - Stripped extension domains (belong in v0.7.2 package runners) - Kernel suites: misc, workflows, admin, packages, connections, deps, composition Runner registry surface (/s/test-runners): - Admin-only dashboard discovering test-runner packages - Run All / per-runner Run buttons, real-time results - Export Failures / Export Full Results (JSON download) - Dark mode styling using kernel CSS variables - Suite count polling for async runner script loading 141 passed, 0 failed on fresh minimal install. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
4.3 KiB
JavaScript
100 lines
4.3 KiB
JavaScript
/**
|
|
* ICD Test Runner — Fixtures
|
|
* Creates and tears down test users, teams, and groups for AuthZ tests.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
var T = window.ICD;
|
|
if (!T) return;
|
|
|
|
function genPassword() {
|
|
var chars = 'ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$';
|
|
var pw = '';
|
|
for (var i = 0; i < 16; i++) pw += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
return pw;
|
|
}
|
|
|
|
T.provisionFixtures = async function () {
|
|
var fixtures = T.fixtures;
|
|
if (fixtures.ready) {
|
|
console.log('[ICD] Fixtures already provisioned — tear down first');
|
|
return;
|
|
}
|
|
if (T.user.role !== 'admin') {
|
|
console.log('[ICD] Admin required to provision fixtures');
|
|
return;
|
|
}
|
|
|
|
var tag = 'icd-' + Date.now();
|
|
var errors = [];
|
|
|
|
var userDefs = [
|
|
{ username: tag + '-user', display_name: 'ICD Test User', role: 'user' },
|
|
{ username: tag + '-tadmin', display_name: 'ICD Test Team Admin', role: 'user' },
|
|
{ username: tag + '-admin2', display_name: 'ICD Test Admin', role: 'admin' }
|
|
];
|
|
|
|
for (var i = 0; i < userDefs.length; i++) {
|
|
var def = userDefs[i];
|
|
var pw = genPassword();
|
|
try {
|
|
var created = await T.apiPost('/admin/users', {
|
|
username: def.username, password: pw,
|
|
email: def.username + '@example.com', role: def.role
|
|
});
|
|
try { await T.apiPut('/admin/users/' + created.id + '/active', { is_active: true }); } catch (e) { /* may already be active */ }
|
|
var login = await T.publicPost('/auth/login', { login: def.username, password: pw });
|
|
fixtures.users.push({
|
|
username: def.username, password: pw, display_name: def.display_name,
|
|
role: def.role, id: created.id, token: login.access_token || ''
|
|
});
|
|
} catch (e) {
|
|
errors.push('User ' + def.username + ': ' + e.message);
|
|
}
|
|
}
|
|
|
|
try {
|
|
var team = await T.apiPost('/admin/teams', { name: tag + '-team', description: 'ICD test team' });
|
|
fixtures.team = { id: team.id, name: team.name };
|
|
try { await T.apiPost('/admin/teams/' + team.id + '/members', { user_id: T.user.id, role: 'admin' }); } catch (e) { /* auto-add */ }
|
|
var tadmin = fixtures.users.find(function (u) { return u.username.indexOf('-tadmin') !== -1; });
|
|
if (tadmin) await T.apiPost('/admin/teams/' + team.id + '/members', { user_id: tadmin.id, role: 'admin' });
|
|
var regUser = fixtures.users.find(function (u) { return u.username.indexOf('-user') !== -1 && u.username.indexOf('-tadmin') === -1; });
|
|
if (regUser) await T.apiPost('/admin/teams/' + team.id + '/members', { user_id: regUser.id, role: 'member' });
|
|
} catch (e) { errors.push('Team: ' + e.message); }
|
|
|
|
try {
|
|
var grp = await T.apiPost('/admin/groups', { name: tag + '-group', scope: 'global' });
|
|
fixtures.group = { id: grp.id, name: grp.name };
|
|
await T.apiPut('/admin/groups/' + grp.id, { permissions: ['model.use', 'kb.read'] });
|
|
var regUser2 = fixtures.users.find(function (u) { return u.username.indexOf('-user') !== -1 && u.username.indexOf('-tadmin') === -1; });
|
|
if (regUser2) await T.apiPost('/admin/groups/' + grp.id + '/members', { user_id: regUser2.id });
|
|
} catch (e) { errors.push('Group: ' + e.message); }
|
|
|
|
fixtures.ready = true;
|
|
|
|
if (errors.length > 0) {
|
|
console.warn('[ICD] Fixtures created with ' + errors.length + ' errors', errors);
|
|
} else {
|
|
console.log('[ICD] Fixtures provisioned (' + fixtures.users.length + ' users, team, group)');
|
|
}
|
|
};
|
|
|
|
T.teardownFixtures = async function () {
|
|
var fixtures = T.fixtures;
|
|
if (!fixtures.ready) return;
|
|
if (fixtures.group) { try { await T.safeDelete('/admin/groups/' + fixtures.group.id); } catch (e) { /* ok */ } }
|
|
if (fixtures.team) { try { await T.safeDelete('/admin/teams/' + fixtures.team.id); } catch (e) { /* ok */ } }
|
|
for (var i = fixtures.users.length - 1; i >= 0; i--) {
|
|
try { await T.safeDelete('/admin/users/' + fixtures.users[i].id); } catch (e) { /* ok */ }
|
|
}
|
|
T.fixtures = { ready: false, users: [], team: null, group: null };
|
|
console.log('[ICD] Test fixtures torn down');
|
|
};
|
|
|
|
T.getFixtureUser = function (suffix) {
|
|
return T.fixtures.users.find(function (u) { return u.username.indexOf(suffix) !== -1; });
|
|
};
|
|
|
|
})();
|