feat(KAN-52): add server selection and isolated native sessions

This commit is contained in:
2026-09-16 18:58:49 +02:00
parent 0f62445c3e
commit 1be2d06ff4
13 changed files with 988 additions and 183 deletions
+37 -8
View File
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
import { en } from '../ui/locales/en.js';
import { normalizeServer, needsConfirmation } from '../ui/server.js';
const html = readFileSync(new URL('../ui/index.html', import.meta.url), 'utf8');
@@ -12,13 +13,41 @@ test('every launcher text resolves to a nonempty English translation', () => {
}
});
test('the launcher opens only the configured HTTPS workspace without an IPC bridge', () => {
const links = [...html.matchAll(/<a\s[^>]*href="([^"]+)"/g)];
assert.equal(links.length, 1);
assert.equal(links[0][1], 'https://kanbangit.de/');
const main = readFileSync(
new URL('../ui/main.js', import.meta.url),
'utf8',
test('installation addresses support custom domains, ports and base paths', () => {
assert.equal(
normalizeServer(' HTTPS://Example.com:443/kanban '),
'https://example.com/kanban/',
);
assert.equal(normalizeServer('https://[::1]:8443/'), 'https://[::1]:8443/');
for (const input of [
'http://example.com',
'https:example.com',
'https://user:secret@example.com',
'https://user@example.com',
'https://example.com/?token=secret',
'https://example.com/#secret',
'https://exa\nmple.com',
'https://example.com\\other',
'file:///tmp/test',
'javascript:alert(1)',
'',
]) {
assert.throws(() => normalizeServer(input), undefined, input);
}
});
test('changing the installation requires confirmation, retrying does not', () => {
assert.equal(needsConfirmation(null, 'https://example.com/'), false);
assert.equal(
needsConfirmation('https://example.com/', 'https://example.com/'),
false,
);
assert.equal(
needsConfirmation('https://example.com/', 'https://example.com:8443/'),
true,
);
assert.equal(
needsConfirmation('https://example.com/a/', 'https://example.com/b/'),
true,
);
assert.doesNotMatch(main, /__TAURI__|invoke\(/);
});