Changeset 0.37.14 (#226)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-23 16:47:48 +00:00
committed by xcaliber
parent fcb998bff9
commit b7746c3004
164 changed files with 6972 additions and 3527 deletions

View File

@@ -1,8 +1,9 @@
/**
* ICD Test Runner — SDK Tier
* Validates switchboard-sdk.js contract: boot, identity, REST client,
* events, theme, pipe registration, execution ordering, scoping,
* halt semantics, error isolation, extension compat shim, introspection.
* Validates Preact SDK (sw/sdk/index.js) contract: boot, identity,
* REST client, events, theme, pipe registration, execution ordering,
* scoping, halt semantics, error isolation, introspection.
* v0.37.14: Updated from Switchboard.init() to boot() API.
*/
(function () {
'use strict';
@@ -35,16 +36,16 @@
// BOOT
// ═══════════════════════════════════════════════════════════
await T.test('sdk', 'boot', 'Switchboard.init() returns sw object', async function () {
T.assert(typeof Switchboard !== 'undefined', 'Switchboard global missing');
var inst = Switchboard.init();
T.assert(inst !== null && typeof inst === 'object', 'init() should return object');
T.assert(inst === window.sw, 'window.sw should be the same instance');
await T.test('sdk', 'boot', 'window.sw exists after boot()', async function () {
T.assert(window.sw !== null && typeof window.sw === 'object', 'window.sw should be an object');
T.assert(window.sw._sdk, 'window.sw._sdk version marker should exist');
});
await T.test('sdk', 'boot', 'Double init returns same instance', async function () {
var a = Switchboard.init();
var b = Switchboard.init();
await T.test('sdk', 'boot', 'boot() is idempotent', async function () {
var a = window.sw;
// Import and call boot() again — should return same instance
var mod = await import(window.__BASE__ + '/js/sw/sdk/index.js');
var b = await mod.boot();
T.assert(a === b, 'idempotent: must return same object');
});
@@ -52,16 +53,16 @@
// IDENTITY
// ═══════════════════════════════════════════════════════════
await T.test('sdk', 'identity', 'sw.user populated', async function () {
T.assert(sw.user !== null, 'sw.user should not be null');
T.assert(typeof sw.user.id === 'string' && sw.user.id.length > 0, 'user.id');
T.assert(typeof sw.user.username === 'string', 'user.username');
T.assert(typeof sw.user.role === 'string', 'user.role');
await T.test('sdk', 'identity', 'sw.auth.user populated', async function () {
T.assert(sw.auth.user !== null, 'sw.auth.user should not be null');
T.assert(typeof sw.auth.user.id === 'string' && sw.auth.user.id.length > 0, 'user.id');
T.assert(typeof sw.auth.user.username === 'string', 'user.username');
T.assert(typeof sw.auth.user.role === 'string', 'user.role');
});
await T.test('sdk', 'identity', 'sw.isAdmin reflects role', async function () {
T.assert(typeof sw.isAdmin === 'boolean', 'isAdmin should be boolean');
T.assert(sw.isAdmin === (sw.user.role === 'admin'), 'isAdmin should match role');
T.assert(sw.isAdmin === (sw.auth.user.role === 'admin'), 'isAdmin should match role');
});
// ═══════════════════════════════════════════════════════════
@@ -73,10 +74,9 @@
T.assert(d.status === 'ok', 'health status should be ok');
});
await T.test('sdk', 'api', 'sw.api.get /channels returns envelope', async function () {
await T.test('sdk', 'api', 'sw.api.get /channels returns array', async function () {
var d = await sw.api.get('/api/v1/channels');
T.assertHasKey(d, 'data', '/channels');
T.assert(Array.isArray(d.data), 'data should be array');
T.assert(Array.isArray(d), 'channels should be array (auto-unwrapped)');
});
var _sdkTestChannel = null;
@@ -159,8 +159,8 @@
fired = true;
T.assert(resolved === 'dark' || resolved === 'light', 'resolved should be dark|light');
});
// Trigger a theme change event
Events.emit('theme.changed', {}, { localOnly: true });
// Trigger a theme change event via Preact SDK
sw.emit('theme.changed', {}, { localOnly: true });
T.assert(fired, 'change handler should have fired');
unsub();
});
@@ -425,28 +425,8 @@
T.assert(count >= 2, 'unscoped filter should run on both channel types');
});
// ═══════════════════════════════════════════════════════════
// EXTENSION COMPAT SHIM
// ═══════════════════════════════════════════════════════════
await T.test('sdk', 'compat', 'ctx.renderers.register post → pipe.list() [chat-only]', async function () {
// This tests the compat shim in extensions.js.
// Extensions only loads on the chat surface (scripts-chat template).
if (typeof Extensions === 'undefined') {
T.skip('Extensions only loads on chat surface — run SDK tier from /chat to test compat shim');
}
var shimName = '_sdk-compat-test-' + Date.now();
Extensions._registerRenderer('sdk-test', shimName, {
type: 'post',
priority: 77,
render: function (container) { /* noop */ }
});
var list = sw.pipe.list();
var found = list.render.some(function (f) {
return f.source === 'sdk-test:' + shimName;
});
T.assert(found, 'shimmed post-renderer should appear in pipe.list().render');
});
// v0.37.14: Extension compat shim test removed (Extensions global deleted).
// Extension rendering now goes through Preact SDK pipe directly.
// ═══════════════════════════════════════════════════════════
// INTROSPECTION