mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-26 12:17:14 +00:00
feat(web): unify processor detail workbench
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { installLangBotApiMocks } from './fixtures/langbot-api';
|
||||
|
||||
test.describe('processor detail workbench', () => {
|
||||
test.use({ viewport: { width: 1440, height: 900 } });
|
||||
|
||||
test('agent keeps debugging left of its orchestration settings', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, {
|
||||
authenticated: true,
|
||||
withRunnerToolSelector: true,
|
||||
});
|
||||
|
||||
await page.goto('/home/agents?id=agent-workbench');
|
||||
|
||||
const debugPanel = page.getByRole('region', { name: 'Debug' });
|
||||
const configPanel = page.getByRole('region', { name: 'Configuration' });
|
||||
await expect(debugPanel).toBeVisible();
|
||||
await expect(configPanel).toBeVisible();
|
||||
|
||||
const debugBox = await debugPanel.boundingBox();
|
||||
const configBox = await configPanel.boundingBox();
|
||||
expect(debugBox).not.toBeNull();
|
||||
expect(configBox).not.toBeNull();
|
||||
expect(debugBox!.x).toBeLessThan(configBox!.x);
|
||||
expect(configBox!.width).toBeGreaterThan(debugBox!.width);
|
||||
|
||||
const flow = configPanel.locator('ol');
|
||||
await expect(flow.getByRole('button').nth(0)).toContainText(
|
||||
'Bindable Event Range',
|
||||
);
|
||||
await expect(flow.getByRole('button').nth(1)).toContainText('Runner');
|
||||
await expect(flow.getByRole('button').nth(2)).toContainText('Local Agent');
|
||||
|
||||
await flow.getByRole('button').nth(0).click();
|
||||
await expect(
|
||||
configPanel.getByText('Bindable Event Range', { exact: true }).last(),
|
||||
).toBeVisible();
|
||||
await flow.getByRole('button').nth(2).click();
|
||||
await expect(
|
||||
configPanel.getByText('Local Agent', { exact: true }).last(),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('pipeline keeps debug chat left and exposes its main flow first', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: true });
|
||||
|
||||
await page.goto('/home/pipelines?id=pipeline-workbench');
|
||||
|
||||
const debugPanel = page.getByRole('region', { name: 'Debug Chat' });
|
||||
const configPanel = page.getByRole('region', { name: 'Configuration' });
|
||||
await expect(debugPanel).toBeVisible();
|
||||
await expect(configPanel).toBeVisible();
|
||||
|
||||
const debugBox = await debugPanel.boundingBox();
|
||||
const configBox = await configPanel.boundingBox();
|
||||
expect(debugBox).not.toBeNull();
|
||||
expect(configBox).not.toBeNull();
|
||||
expect(debugBox!.x).toBeLessThan(configBox!.x);
|
||||
expect(configBox!.width).toBeGreaterThan(debugBox!.width);
|
||||
|
||||
const flow = configPanel.locator('ol');
|
||||
await expect(flow.getByRole('button').nth(0)).toContainText(
|
||||
'Trigger Conditions',
|
||||
);
|
||||
await expect(flow.getByRole('button').nth(1)).toContainText(
|
||||
'AI Capabilities',
|
||||
);
|
||||
await expect(flow.getByRole('button').nth(2)).toContainText(
|
||||
'Output Processing',
|
||||
);
|
||||
|
||||
await flow.getByRole('button').nth(1).click();
|
||||
await expect(
|
||||
configPanel.getByText('Runtime', { exact: true }).last(),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const testDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const webRoot = path.resolve(testDir, '../..');
|
||||
|
||||
function readSource(relativePath) {
|
||||
return fs.readFileSync(path.join(webRoot, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
test('agent and pipeline details share the split processor workbench', () => {
|
||||
const workbench = readSource(
|
||||
'src/app/home/components/processor-detail/ProcessorDetailWorkbench.tsx',
|
||||
);
|
||||
const agentDetail = readSource('src/app/home/agents/AgentDetailContent.tsx');
|
||||
const pipelineDetail = readSource(
|
||||
'src/app/home/pipelines/PipelineDetailContent.tsx',
|
||||
);
|
||||
const websocketClient = readSource(
|
||||
'src/app/infra/websocket/WebSocketClient.ts',
|
||||
);
|
||||
|
||||
assert.match(
|
||||
workbench,
|
||||
/lg:grid-cols-\[minmax\(20rem,0\.72fr\)_minmax\(0,1\.28fr\)\]/,
|
||||
);
|
||||
assert.ok(
|
||||
workbench.indexOf('{debugContent}') < workbench.indexOf('{configContent}'),
|
||||
);
|
||||
assert.match(agentDetail, /<ProcessorDetailWorkbench/);
|
||||
assert.match(agentDetail, /debugContent=/);
|
||||
assert.match(pipelineDetail, /<ProcessorDetailWorkbench/);
|
||||
assert.match(pipelineDetail, /compact=\{true\}/);
|
||||
assert.doesNotMatch(
|
||||
websocketClient,
|
||||
/this\.ws\.onopen = \(\) => \{\s*this\.reconnectAttempts = 0/,
|
||||
);
|
||||
assert.match(
|
||||
websocketClient,
|
||||
/data\.type === 'connected'[\s\S]*this\.reconnectAttempts = 0/,
|
||||
);
|
||||
});
|
||||
|
||||
test('processor forms expose their primary orchestration flow horizontally', () => {
|
||||
const agentForm = readSource(
|
||||
'src/app/home/agents/components/AgentFormComponent.tsx',
|
||||
);
|
||||
const pipelineForm = readSource(
|
||||
'src/app/home/pipelines/components/pipeline-form/PipelineFormComponent.tsx',
|
||||
);
|
||||
|
||||
assert.match(
|
||||
agentForm,
|
||||
/name: 'events'[\s\S]*name: 'runner'[\s\S]*name: 'runner_config'/,
|
||||
);
|
||||
assert.match(
|
||||
pipelineForm,
|
||||
/const primarySectionNames = \['trigger', 'ai', 'output'\]/,
|
||||
);
|
||||
assert.match(agentForm, /grid min-w-\[34rem\] grid-cols-3/);
|
||||
assert.match(pipelineForm, /grid min-w-\[34rem\] grid-cols-3/);
|
||||
});
|
||||
Reference in New Issue
Block a user