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
2026-03-15 15:45:00 +00:00

143 lines
6.2 KiB
JavaScript

/**
* ICD Test Runner — CRUD: Admin
* Admin user lifecycle (create → deactivate → login reject → activate →
* login success → role change → password reset → vault reset → delete),
* admin settings roundtrip, channel purge.
*/
(function () {
'use strict';
var T = window.ICD;
if (!T) return;
if (!T.crud) T.crud = {};
T.crud.admin = async function (testTag) {
// ── Admin User Lifecycle (create → login fails → activate → login succeeds → cleanup) ──
if (T.user.role === 'admin') {
var testUserId = null;
var testUsername = 'icdtest' + (Date.now() % 100000);
var testPassword = 'IcdT3st!Pw' + (Date.now() % 10000);
await T.test('crud', 'admin', 'POST /admin/users (create)', async function () {
var d = await T.apiPost('/admin/users', {
username: testUsername,
password: testPassword,
email: testUsername + '@example.com',
role: 'user'
});
T.assertShape(d, T.S.adminUser, 'admin-user');
testUserId = d.id;
T.registerCleanup(function () { if (testUserId) return T.safeDelete('/admin/users/' + testUserId); });
});
if (testUserId) {
// Users start active (CreateUser sets IsActive=true).
// Deactivate first, then test inactive login rejection.
await T.test('crud', 'admin', 'PUT /admin/users/:id/active (deactivate)', async function () {
var d = await T.apiPut('/admin/users/' + testUserId + '/active', { is_active: false });
T.assert(typeof d === 'object', 'expected object');
});
await T.test('crud', 'admin', 'POST /auth/login (inactive user → reject)', async function () {
var d = await T.publicPost('/auth/login', {
login: testUsername,
password: testPassword
});
T.assert(d._status === 401 || d._status === 403,
'expected 401/403 for inactive user, got ' + d._status);
});
await T.test('crud', 'admin', 'PUT /admin/users/:id/active (activate)', async function () {
var d = await T.apiPut('/admin/users/' + testUserId + '/active', { is_active: true });
T.assert(typeof d === 'object', 'expected object');
});
var testUserToken = null;
await T.test('crud', 'admin', 'POST /auth/login (active user → success)', async function () {
var d = await T.publicPost('/auth/login', {
login: testUsername,
password: testPassword
});
T.assert(d._status === 200, 'expected 200, got ' + d._status +
(d.error ? ' (' + d.error + ')' : ''));
T.assertHasKey(d, 'access_token', 'login');
T.assertHasKey(d, 'refresh_token', 'login');
T.assertHasKey(d, 'user', 'login');
T.assert(d.user.username === testUsername, 'username mismatch');
testUserToken = d.access_token;
});
if (testUserToken) {
await T.test('crud', 'admin', 'GET /profile (as test user)', async function () {
var d = await T.authFetch(testUserToken, 'GET', '/profile');
T.assertStatus(d, 200, 'profile');
T.assert(d.username === testUsername, 'username mismatch');
});
await T.test('crud', 'admin', 'POST /auth/logout (test user)', async function () {
var d = await T.publicPost('/auth/logout', { refresh_token: '' });
T.assert(d._status === 200 || d._status === 401 || d._status === 204,
'expected 200/204/401, got ' + d._status);
});
}
await T.test('crud', 'admin', 'PUT /admin/users/:id/role (set admin)', async function () {
var d = await T.apiPut('/admin/users/' + testUserId + '/role', { role: 'admin' });
T.assert(typeof d === 'object', 'expected object');
});
await T.test('crud', 'admin', 'POST /admin/users/:id/reset-password', async function () {
var d = await T.apiPost('/admin/users/' + testUserId + '/reset-password', {
password: 'ResetPw!' + Date.now()
});
T.assert(typeof d === 'object', 'expected object');
T.assert(!d.error, 'unexpected error: ' + (d.error || ''));
});
await T.test('crud', 'admin', 'POST /admin/users/:id/vault/reset', async function () {
var d = await T.apiPost('/admin/users/' + testUserId + '/vault/reset', {});
// May return 200 with message, or 400 if vault not configured
T.assert(d._status === undefined || !d.error || d.error === 'vault not configured',
'unexpected error: ' + (d.error || ''));
});
await T.test('crud', 'admin', 'DELETE /admin/users/:id', async function () {
await T.safeDelete('/admin/users/' + testUserId);
testUserId = null;
});
}
// ── Admin Settings Roundtrip ──
await T.test('crud', 'admin', 'PUT /admin/settings/:key (policy roundtrip)', async function () {
// Read current value
var before = await T.apiGet('/admin/settings/allow_registration');
var originalVal = before.value;
// Write a known value
await T.apiPut('/admin/settings/allow_registration', { value: 'false' });
var after = await T.apiGet('/admin/settings/allow_registration');
T.assert(after.value === 'false', 'expected policy value "false"');
// Restore
if (originalVal !== undefined) {
await T.apiPut('/admin/settings/allow_registration', { value: String(originalVal) });
} else {
await T.apiPut('/admin/settings/allow_registration', { value: 'true' });
}
});
// ── Channel Purge ──
await T.test('crud', 'admin', 'DELETE /admin/channels/:id/purge (lifecycle)', async function () {
// Create a throwaway channel
var ch = await T.apiPost('/channels', { title: 'icd-purge-test', type: 'direct' });
T.assert(ch.id, 'expected channel id');
// Archive it
await T.apiPut('/channels/' + ch.id, { is_archived: true });
// Purge rejects non-archived channel attempts — ours is archived, so purge should succeed
var del = await T.apiDelete('/admin/channels/' + ch.id + '/purge');
T.assert(del.ok === true, 'expected { ok: true }');
});
}
};
})();