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/packages/icd-test-runner/js/crud/dashboard-package.js
Jeffrey Smith 2adaabe5fa
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 6s
CI/CD / test-go-pg (pull_request) Successful in 2m43s
CI/CD / test-sqlite (pull_request) Successful in 2m51s
CI/CD / build-and-deploy (pull_request) Successful in 1m13s
v0.6.5: Renderer pipeline, docs rewrite, architecture diagrams
Lift block rendering to kernel SDK primitives (sw.renderers + sw.markdown)
so all surfaces share one markdown pipeline. Rewrite docs for external
audience — remove all fork history references. Add Mermaid architecture
diagrams, CONTRIBUTING guide, and extension tutorial.

- sw.renderers SDK module: kernel-level renderer registry
- sw.markdown SDK module: unified marked v16 + DOMPurify pipeline
- Browser extension script loader for renderer injection
- Notes + Docs surfaces migrated to sw.markdown.renderSync()
- 4 renderer extensions rewritten to IIFE + sw.renderers.register()
- 6 Mermaid diagrams in ARCHITECTURE.md
- CONTRIBUTING.md + TUTORIAL-FIRST-EXTENSION.md
- DESIGN-WORKFLOWS.md replaces fork-era design doc
- Surface alias routes removed from main.go
- ICD/SDK runners migrated to /admin/packages/ endpoints
- 13 new renderer tests
- Docs, CHANGELOG, ROADMAP cleaned of fork references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:26:44 +00:00

123 lines
5.0 KiB
JavaScript

/**
* ICD Test Runner — CRUD: Dashboard Package (v0.31.1)
* Tests the dashboard .pkg lifecycle: install → surface accessible →
* settings → export/import round-trip.
* 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.dashboardPackage = async function (testTag) {
if (T.user.role !== 'admin') return;
// ── dashpkg: Dashboard package install + lifecycle ──
var dashPkgId = null;
await T.test('crud', 'dashboardPackage', 'dashpkg: POST /admin/packages/install (dashboard .pkg)', async function () {
var manifest = JSON.stringify({
id: 'dashboard',
title: 'Dashboard',
type: 'full',
version: '0.31.1',
tier: 'browser',
author: 'Switchboard Core',
description: 'Project dashboard exercising all SDK primitives',
route: '/s/dashboard',
permissions: [],
settings: [
{ key: 'refresh_interval', label: 'Auto-Refresh (seconds)', type: 'number', 'default': 0 }
]
});
var zipBlob = buildTestZip({
'manifest.json': manifest,
'js/main.js': '// dashboard package entry point\nconsole.log("[DashboardPkg] loaded");',
'css/main.css': '.surface-dashboard { display: flex; }'
});
var d = await T.apiUpload('/admin/packages/install', zipBlob, 'dashboard.pkg');
T.assert(d.id === 'dashboard', 'package id should be "dashboard", got: ' + d.id);
dashPkgId = d.id;
T.registerCleanup(async function () {
if (dashPkgId) {
var token = await T.getAuthToken();
return T.authFetch(token, 'DELETE', '/admin/packages/' + dashPkgId);
}
});
});
if (!dashPkgId) return;
await T.test('crud', 'dashboardPackage', 'dashpkg: GET /admin/packages/:id (verify type full)', async function () {
var d = await T.apiGet('/admin/packages/' + dashPkgId);
T.assertShape(d, T.S.extension, 'dashboard package');
T.assert(d.type === 'full', 'type should be "full", got: ' + d.type);
T.assert(d.tier === 'browser', 'tier should be "browser", got: ' + d.tier);
T.assert(d.source === 'extension', 'source should be "extension", got: ' + d.source);
T.assert(d.enabled === true, 'newly installed package should be enabled');
T.assert(d.version === '0.31.1', 'version mismatch');
});
await T.test('crud', 'dashboardPackage', 'dashpkg: GET /admin/packages (dashboard in list)', async function () {
var d = await T.apiGet('/admin/packages');
T.assertHasKey(d, 'data', '/admin/packages');
var found = d.data.some(function (s) { return s.id === 'dashboard'; });
T.assert(found, 'dashboard package should appear in surfaces list');
});
// ── Settings ──
await T.test('crud', 'dashboardPackage', 'dashpkg: GET /admin/packages/:id/settings', async function () {
var d = await T.apiGet('/admin/packages/' + dashPkgId + '/settings');
T.assert(typeof d === 'object', 'settings should be an object');
});
await T.test('crud', 'dashboardPackage', 'dashpkg: PUT /admin/packages/:id/settings', async function () {
var settings = { refresh_interval: 30 };
var d = await T.apiPut('/admin/packages/' + dashPkgId + '/settings', settings);
T.assert(d._status === 200 || d._status === 204 || !d._status, 'settings PUT should succeed');
// Verify persistence
var check = await T.apiGet('/admin/packages/' + dashPkgId + '/settings');
var vals = check.values || {};
T.assert(vals.refresh_interval === 30, 'refresh_interval should persist as 30');
});
// ── Export/Import Round-Trip ──
var exportBlob = null;
await T.test('crud', 'dashboardPackage', 'dashpkg: GET /admin/packages/:id/export', async function () {
var token = await T.getAuthToken();
var resp = await fetch(T.base + '/api/v1/admin/packages/' + dashPkgId + '/export', {
headers: { 'Authorization': 'Bearer ' + token }
});
T.assert(resp.ok, 'export should return 200, got: ' + resp.status);
exportBlob = await resp.blob();
T.assert(exportBlob.size > 0, 'export blob should not be empty');
});
if (exportBlob) {
await T.test('crud', 'dashboardPackage', 'dashpkg: DELETE + re-import round-trip', async function () {
var token = await T.getAuthToken();
var delResp = await T.authFetch(token, 'DELETE', '/admin/packages/' + dashPkgId);
T.assert(!delResp._status || delResp._status < 300, 'delete should succeed');
var d = await T.apiUpload('/admin/packages/install', exportBlob, 'dashboard.pkg');
T.assert(d.id === 'dashboard', 'reimported package id should be "dashboard"');
var check = await T.apiGet('/admin/packages/' + dashPkgId);
T.assert(check.id === 'dashboard', 'reimported dashboard should be readable');
T.assert(check.type === 'full', 'reimported type should be "full"');
});
}
};
})();