Files

170 lines
6.5 KiB
JavaScript
Raw Permalink Normal View History

2026-10-29 11:57:29 +01:00
// Generated, do not edit. sha256:e3545bf95485dc067f72c9e5c3b65d89fe5d9d0cb4f65e196bb3a28c383f4229
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createDbHarness } from '../helpers/db-node.mjs';
process.env.ASSETAPP_DATA_DIR = mkdtempSync(join(tmpdir(), 'assetapp-control-'));
const { setInstallLocale } = await import('../../server/installation.mjs');
setInstallLocale('nl');
const harness = createDbHarness();
mock.module('../../server/db.js', { namedExports: harness.exports });
const echteConfig = await import('../../shared/config.js');
mock.module('../../shared/config.js', {
namedExports: {
...echteConfig,
CONFIG: Object.freeze({
...echteConfig.CONFIG,
COMMANDS: Object.freeze({ ...echteConfig.CONFIG.COMMANDS, CLAIM_SECONDS: 1 }),
}),
},
});
const { CONTROL_TOOLS } = await import('../../server/mcp/control-tools.mjs');
const { claimNextCommand, resolveCommand } = await import('../../server/data/commands.js');
const { setPref } = await import('../../server/data/preferences.js');
const { TARGETS, targetHash } = await import('../../shared/config.js');
const tool = CONTROL_TOOLS.find(t => t.name === 'navigate_to');
const waar = { scope: tool.scope, run: () => tool.run({}) };
const zetAan = async (control = true) => {
await setPref('ai', 'allow_read', 1);
await setPref('ai', 'allow_control', control ? 1 : 0);
};
let busTijdensWachten = [];
function browserDoet(uitkomst, detail = null, na = 60) {
setTimeout(async () => {
busTijdensWachten = harness.exports.all(`SELECT name FROM BusSignal ORDER BY id`).map(r => r.name);
const c = await claimNextCommand('tab-1');
if (c) await resolveCommand(c.id, 'tab-1', uitkomst, detail);
}, na);
}
beforeEach(async () => { harness.recreate(); busTijdensWachten = []; await zetAan(); });
describe('navigate_to: de poort', () => {
it('declareert scope control, en niet read of write', () => {
assert.equal(tool.scope, 'control');
});
it('weigert als het besturen uit staat, en verandert dan niets', async () => {
await zetAan(false);
await assert.rejects(() => tool.run({ target: 'AI_ACTIVITY' }), /niet besturen/);
assert.equal(await claimNextCommand('tab-1'), null, 'er is geen opdracht klaargezet');
});
});
describe('navigate_to: het doel', () => {
it('zet een opdracht klaar met het adres van de gekozen plek', async () => {
browserDoet('done');
const r = await tool.run({ target: 'AI_ACTIVITY' });
assert.match(r.text, /Gedaan/);
assert.match(r.text, new RegExp(targetHash(TARGETS.AI_ACTIVITY).replace('#', '#')));
});
it('deelt geen enkel administratieveld', async () => {
browserDoet('done');
const r = await tool.run({ target: 'HOME' });
assert.deepEqual(r.fieldsShared, []);
});
it('wijst een onbekende plek af zonder om te vallen, en noemt wat er wél is', async () => {
const r = await tool.run({ target: 'DE_KEUKEN' });
assert.match(r.text, /geen bekende plek/);
assert.match(r.text, /AI_ACTIVITY/);
assert.match(r.text, /TAXES - Belastingen/, r.text);
assert.equal(await claimNextCommand('tab-1'), null, 'en er staat niets klaar');
});
it('wijst een leeg of verkeerd getypt doel net zo af als een verzonnen doel', async () => {
for (const args of [{ target: '' }, { target: 42 }, { target: null }]) {
const r = await tool.run(args);
assert.match(r.text, /geen bekende plek/, `${JSON.stringify(args)} hoort netjes afgewezen te worden`);
}
});
});
describe('navigate_to: het signaal gaat vóóruit', () => {
it('zet het signaal op de bus vóórdat hij gaat wachten', async () => {
browserDoet('done');
await tool.run({ target: 'AI_ACTIVITY' });
assert.ok(busTijdensWachten.includes('commands-changed'),
`de bus was ${JSON.stringify(busTijdensWachten)} toen het tabblad keek`);
});
});
describe('navigate_to: de uitkomst', () => {
it('meldt het als de gebruiker het tegenhoudt, mét de reden', async () => {
browserDoet('rejected', 'Tegengehouden door de gebruiker.');
const r = await tool.run({ target: 'AI_ACTIVITY' });
assert.match(r.text, /Niet uitgevoerd/);
assert.match(r.text, /Tegengehouden door de gebruiker/);
assert.match(r.text, /niet genavigeerd/);
});
it('geeft de schuld niet aan de gebruiker als het tabblad zelf afwees', async () => {
browserDoet('rejected', 'De opdracht wees niet naar een geldige plek in de app.');
const r = await tool.run({ target: 'HOME' });
assert.doesNotMatch(r.text, /de gebruiker/i);
assert.match(r.text, /geldige plek/);
});
it('zegt dat de app niet openstaat als niemand de opdracht oppakt', async () => {
const r = await tool.run({ target: 'HOME' });
assert.match(r.text, /niet open/);
assert.match(r.text, /niet genavigeerd/);
});
});
describe('navigate_to zonder target: waar de gebruiker kijkt', () => {
it('staat achter dezelfde schuif als navigeren', async () => {
assert.equal(waar.scope, 'control');
await zetAan(false);
await assert.rejects(() => waar.run({}), /niet besturen/);
});
it('geeft de NAAM terug die navigate_to kent, niet alleen het adres', async () => {
browserDoet('done', targetHash(TARGETS.CHARTS));
const r = await waar.run({});
assert.match(r.text, /CHARTS/);
assert.match(r.text, new RegExp(targetHash(TARGETS.CHARTS)));
});
it('noemt de belastingpagina bij naam en niet alleen bij adres', async () => {
browserDoet('done', targetHash(TARGETS.TAXES));
const r = await waar.run({});
assert.match(r.text, /Belastingen/, r.text);
assert.match(r.text, /TAXES/);
});
it('geeft bij een plek buiten de registry het adres, en zegt erbij dat het geen naam is', async () => {
browserDoet('done', '#/events/2026/detail');
const r = await waar.run({});
assert.match(r.text, /#\/events\/2026\/detail/);
assert.match(r.text, /geen van de plekken/);
});
it('deelt geen enkel administratieveld', async () => {
browserDoet('done', targetHash(TARGETS.HOME));
const r = await waar.run({});
assert.deepEqual(r.fieldsShared, []);
});
it('zegt dat de app niet openstaat als niemand antwoordt', async () => {
const r = await waar.run({});
assert.match(r.text, /niet open/);
});
it('verzint niets als het tabblad wel antwoordt maar zonder plek', async () => {
browserDoet('done', '');
const r = await waar.run({});
assert.match(r.text, /liet niet weten/);
});
});