77 lines
4.3 KiB
JavaScript
77 lines
4.3 KiB
JavaScript
// @ts-check
|
|
// Conversation Playground LLM endpoint picker (all /api routes mocked).
|
|
const { test, expect } = require('./_guard');
|
|
|
|
const CONTAINERS = { containers: [
|
|
{ name: 'ollama', label: 'Ollama', role: 'llm', port: 11434, status: 'running' },
|
|
{ name: 'vllm', label: 'vLLM', role: 'llm', port: 8000, status: 'exited' },
|
|
{ name: 'ghost', label: 'Ghost', role: 'llm', port: 1, status: 'not_found' },
|
|
{ name: 'kokoro-tts', label: 'Kokoro', role: 'tts', port: 8880, status: 'running' },
|
|
] };
|
|
|
|
async function boot(page, settings, containers = CONTAINERS) {
|
|
/** @type {any[]} */ const patches = [];
|
|
/** @type {string[]} */ const modelReqs = [];
|
|
await page.route('**/api/**', route => route.request().method() === 'GET' ? route.fulfill({ json: {} }) : route.fulfill({ json: { ok: true } }));
|
|
await page.route('**/api/local-containers*', route => route.fulfill({ json: containers }));
|
|
await page.route('**/api/conversation/llm-models*', route => { modelReqs.push(route.request().url()); return route.fulfill({ json: { models: ['m1'] } }); });
|
|
await page.route('**/api/settings', route => {
|
|
if (route.request().method() === 'GET') return route.fulfill({ json: settings });
|
|
patches.push(route.request().postDataJSON());
|
|
return route.fulfill({ json: { ok: true } });
|
|
});
|
|
await page.route('**/static/dist/main.min.js*', r => r.abort());
|
|
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
|
await page.waitForFunction(() => typeof window.navTo === 'function', null, { timeout: 15_000 });
|
|
await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 });
|
|
await page.evaluate(() => window.navTo('s-conversation'));
|
|
return { patches, modelReqs };
|
|
}
|
|
|
|
test('lists configured endpoints, picking one saves it and fetches models', async ({ page }) => {
|
|
const { patches, modelReqs } = await boot(page, {});
|
|
const pick = page.locator('#conv-llm-endpoint');
|
|
await expect(pick.locator('option')).toHaveCount(3);
|
|
await expect(pick.locator('option').nth(0)).toContainText('Ollama');
|
|
await expect(pick.locator('option').nth(0)).toContainText('http://host.docker.internal:11434/v1');
|
|
await expect(pick.locator('option').nth(1)).toContainText('✗');
|
|
const box = await pick.boundingBox();
|
|
expect(box && box.height).toBeGreaterThanOrEqual(44);
|
|
await pick.selectOption({ index: 1 });
|
|
await expect(page.locator('#conv-llm-url')).toBeHidden();
|
|
await expect.poll(() => patches.some(p => p && p.conv_llm_url === 'http://host.docker.internal:8000/v1')).toBe(true);
|
|
await expect.poll(() => modelReqs.some(u => u.includes(encodeURIComponent('http://host.docker.internal:8000/v1')))).toBe(true);
|
|
await expect(page.locator('#conv-llm-model-select')).toContainText('m1');
|
|
});
|
|
|
|
test('saved matching URL preselects its entry and hides the input', async ({ page }) => {
|
|
await boot(page, { conv_llm_url: 'http://host.docker.internal:11434/v1' });
|
|
await expect(page.locator('#conv-llm-endpoint')).toHaveValue('http://host.docker.internal:11434/v1');
|
|
await expect(page.locator('#conv-llm-url')).toBeHidden();
|
|
});
|
|
|
|
test('saved custom URL preselects Custom', async ({ page }) => {
|
|
await boot(page, { conv_llm_url: 'http://192.168.178.8:17861/v1' });
|
|
await expect(page.locator('#conv-llm-endpoint')).toHaveValue('__custom__');
|
|
await expect(page.locator('#conv-llm-url')).toBeVisible();
|
|
await expect(page.locator('#conv-llm-url')).toHaveValue('http://192.168.178.8:17861/v1');
|
|
});
|
|
|
|
test('Custom… reveals the input right after the select and focuses it', async ({ page }) => {
|
|
await boot(page, { conv_llm_url: 'http://host.docker.internal:11434/v1' });
|
|
await page.locator('#conv-llm-endpoint').selectOption('__custom__');
|
|
const inp = page.getByRole('textbox', { name: 'Custom LLM base URL' });
|
|
await expect(inp).toBeFocused();
|
|
expect(await page.evaluate(() => document.getElementById('conv-llm-endpoint').nextElementSibling.id)).toBe('conv-llm-url');
|
|
});
|
|
|
|
test('empty list shows only Custom… and the hint linking to Engines', async ({ page }) => {
|
|
await boot(page, {}, { containers: [] });
|
|
await expect(page.locator('#conv-llm-endpoint option')).toHaveCount(1);
|
|
await expect(page.locator('#conv-llm-url')).toBeVisible();
|
|
const hint = page.locator('#conv-llm-empty-hint a');
|
|
await expect(hint).toBeVisible();
|
|
await hint.click();
|
|
await expect(page.locator('#s-llms')).toBeVisible();
|
|
});
|