Raiju/tests/dashboard-ai-visibility-smoke.js
2026-10-25 06:05:42 +03:00

87 lines
5.1 KiB
JavaScript

const { apiSource, dashboardSource } = require('./source-helpers');
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { resolve } = require('node:path');
const { execFileSync } = require('node:child_process');
const { runInNewContext } = require('node:vm');
const source = dashboardSource();
const assignment = source.match(/^\$aiDashboardVisible = .+;$/m);
assert.ok(assignment, 'Dashboard visibility gate must exist');
const phpResults = JSON.parse(execFileSync('php', ['-r',
'$results = []; foreach ([false, true] as $aiFeaturesEnabled) {' +
'foreach ([false, true] as $isAdminUser) {' + assignment[0] +
'$results[] = $aiDashboardVisible; }} echo json_encode($results);'
], { encoding: 'utf8' }));
assert.deepEqual(phpResults, [false, false, true, true],
'Disabled module must hide the server-rendered panel, including for admins');
assert.match(source, /<\?php if \(\$aiDashboardVisible\): \?>\s*<section[^>]+id="dashboardAiSection"/,
'Visibility gate must wrap the AI section');
const start = source.indexOf(' function updateDashboardAiPanel(settings) {');
const end = source.indexOf("\n document.getElementById('aiUnavailableDismiss')", start);
assert.ok(start >= 0 && end > start, 'AI panel updater must exist');
const updater = source.slice(start, end);
let cases = 0;
for (const moduleEnabled of [false, true]) {
for (const configured of [false, true]) {
for (const enabled of [false, true]) {
for (const dismissed of [false, true]) {
const ids = ['dashboardAiSection', 'aiUnavailableBanner', 'aiUnavailableText',
'dashboardAiTools', 'aiUsageSummary', 'aiImageJobsPanel',
'aiAssistantCard', 'aiToolsCard'];
const elements = Object.fromEntries(ids.map(id => [id, { hidden: false }]));
const settings = { enabled };
const context = {
AI_FEATURES_ENABLED: moduleEnabled,
currentAiSettings: settings,
dashboardAiImageUsable: false,
document: {
getElementById: id => elements[id] || null,
querySelectorAll: () => [],
querySelector: () => null
},
window: {},
aiProviderIsConfigured: () => configured,
aiUnavailableNoticeDismissed: () => dismissed,
aiFeatureEnabled: () => true,
aiImageServiceUsable: () => true,
syncAssistantEmbed: () => {},
updateDashboardAiStatus: () => {},
switchAiToolTab: () => {},
t: key => key
};
runInNewContext(updater + '\nupdateDashboardAiPanel(currentAiSettings);', context);
const usable = moduleEnabled && configured && enabled;
const label = JSON.stringify({ moduleEnabled, configured, enabled, dismissed });
assert.equal(elements.dashboardAiSection.hidden,
!moduleEnabled || (!usable && dismissed), label + ': panel visibility');
assert.equal(elements.aiUnavailableBanner.hidden, usable, label + ': notice');
assert.equal(elements.dashboardAiTools.hidden, !usable, label + ': tools');
assert.equal(context.dashboardAiImageUsable, usable, label + ': image capability');
cases++;
}
}
}
}
// An image service that cannot work (no key yet) keeps the tools visible but switches the image tool off.
{
const ids = ['dashboardAiSection', 'aiUnavailableBanner', 'aiUnavailableText', 'dashboardAiTools', 'aiUsageSummary', 'aiImageJobsPanel', 'aiAssistantCard', 'aiToolsCard'];
const elements = Object.fromEntries(ids.map(id => [id, { hidden: false }]));
const tabs = [{ dataset: { aiFeature: 'imageGeneration', aiToolTab: 'image' }, hidden: true, classList: { remove() {}, contains: () => true }, setAttribute() {} }];
const context = {
AI_FEATURES_ENABLED: true, currentAiSettings: { enabled: true }, dashboardAiImageUsable: true,
document: { getElementById: id => elements[id] || null, querySelectorAll: () => tabs, querySelector: () => null },
window: {}, aiProviderIsConfigured: () => true, aiUnavailableNoticeDismissed: () => false, aiFeatureEnabled: () => true,
aiImageServiceUsable: () => false, syncAssistantEmbed: () => {}, updateDashboardAiStatus: () => {}, switchAiToolTab: () => {}, t: key => key
};
runInNewContext(updater + '\nupdateDashboardAiPanel(currentAiSettings);', context);
assert.equal(tabs[0].hidden, false, 'the image tab stays while the service cannot work (it explains why)');
assert.equal(context.dashboardAiImageUsable, false, 'but the image tool is off');
assert.equal(elements.aiImageJobsPanel.hidden, true, 'and so is the jobs panel');
}
runInNewContext(updater + '\nupdateDashboardAiPanel({});', {
document: { getElementById: () => null }
});
console.log('Dashboard AI visibility smoke passed (PHP role/module gate, ' + cases + ' UI states, absent panel).');