fix(web): make processor debugging reliable

This commit is contained in:
RockChinQ
2026-08-25 15:52:59 +08:00
parent 781d8a9ac8
commit 6a6a2b865b
24 changed files with 788 additions and 160 deletions
@@ -19,7 +19,6 @@ test.describe('processor detail workbench', () => {
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();
@@ -28,9 +27,21 @@ test.describe('processor detail workbench', () => {
expect(configBox!.width).toBeGreaterThan(debugBox!.width);
const appShell = page.locator('[class*="group/sidebar-wrapper"]');
const sidebarInset = page.locator('[data-slot="sidebar-inset"]');
await expect(appShell).toHaveCSS('overflow', 'clip');
await expect(sidebarInset).toHaveCSS('overflow', 'clip');
await appShell.evaluate((element) => {
element.scrollTop = 300;
});
await sidebarInset.evaluate((element) => {
element.scrollTop = 300;
});
await expect
.poll(() => appShell.evaluate((element) => element.scrollTop))
.toBe(0);
await expect
.poll(() => sidebarInset.evaluate((element) => element.scrollTop))
.toBe(0);
expect(debugBox!.y).toBeGreaterThanOrEqual(0);
const flow = configPanel.getByRole('tablist');
@@ -66,10 +77,95 @@ test.describe('processor detail workbench', () => {
).toBeVisible();
});
test('agent saves edits before debugging and shows the real output', async ({
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
const requests: string[] = [];
page.on('request', (request) => {
const path = new URL(request.url()).pathname;
if (
request.method() === 'PUT' &&
path === '/api/v1/agents/agent-workbench'
) {
requests.push('save');
}
if (
request.method() === 'POST' &&
path === '/api/v1/agents/agent-workbench/debug'
) {
requests.push('debug');
}
});
await page.goto('/home/agents?id=agent-workbench');
await page.getByLabel('Description').fill('Updated before debugging');
await page
.getByRole('textbox', { name: 'Conversation input' })
.fill('Hello');
await page.getByRole('button', { name: 'Save and run' }).click();
await expect(page.getByText('Mock Agent response')).toBeVisible();
expect(requests).toEqual(['save', 'debug']);
});
test('agent turns runner failures into an actionable message', async ({
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
await page.route(
'**/api/v1/agents/agent-workbench/debug',
async (route) => {
await route.fulfill({
status: 422,
contentType: 'application/json',
body: JSON.stringify({
code: 'dify.config_invalid',
msg: 'api-key is required',
}),
});
},
);
await page.goto('/home/agents?id=agent-workbench');
await page
.getByRole('textbox', { name: 'Conversation input' })
.fill('Hello');
await page.getByRole('button', { name: 'Run test' }).click();
await expect(
page.getByText(
'The runner configuration is incomplete: API Key is missing',
),
).toBeVisible();
await expect(page.getByText('Internal server error')).toHaveCount(0);
await page
.getByRole('button', { name: 'Review runner configuration' })
.click();
await expect(
page.getByRole('tab', { name: 'Local Agent', exact: true }),
).toHaveAttribute('data-state', 'active');
});
test('pipeline keeps debug chat left and exposes its main flow first', async ({
page,
}) => {
await installLangBotApiMocks(page, { authenticated: true });
await page.routeWebSocket('**/api/v1/pipelines/**/ws/connect**', (ws) => {
ws.onMessage((raw) => {
const message = JSON.parse(String(raw));
if (message.type === 'authenticate') {
ws.send(
JSON.stringify({
type: 'connected',
connection_id: 'playwright-connection',
pipeline_uuid: 'pipeline-workbench',
session_type: 'person',
}),
);
}
});
});
await page.goto('/home/pipelines?id=pipeline-workbench');
@@ -77,6 +173,18 @@ test.describe('processor detail workbench', () => {
const configPanel = page.getByRole('region', { name: 'Configuration' });
await expect(debugPanel).toBeVisible();
await expect(configPanel).toBeVisible();
await expect(
debugPanel.getByRole('button', { name: 'Private Chat' }),
).toBeVisible();
await expect(
debugPanel.getByRole('button', { name: 'Group Chat' }),
).toBeVisible();
await debugPanel
.getByRole('button', { name: 'Reset Conversation' })
.click();
await expect(
page.getByText('Conversation reset successfully'),
).toBeVisible();
const debugBox = await debugPanel.boundingBox();
const configBox = await configPanel.boundingBox();
@@ -86,19 +194,18 @@ test.describe('processor detail workbench', () => {
expect(configBox!.width).toBeGreaterThan(debugBox!.width);
const appShell = page.locator('[class*="group/sidebar-wrapper"]');
const sidebarInset = page.locator('[data-slot="sidebar-inset"]');
await expect(appShell).toHaveCSS('overflow', 'clip');
await expect(sidebarInset).toHaveCSS('overflow', 'clip');
await expect
.poll(() => appShell.evaluate((element) => element.scrollTop))
.toBe(0);
expect(debugBox!.y).toBeGreaterThanOrEqual(0);
const flow = configPanel.getByRole('tablist');
await expect(flow.getByRole('tab').nth(0)).toContainText(
'Trigger Conditions',
);
await expect(flow.getByRole('tab').nth(1)).toContainText('AI Capabilities');
await expect(flow.getByRole('tab').nth(2)).toContainText(
'Output Processing',
);
await expect(flow.getByRole('tab').nth(0)).toContainText('Trigger');
await expect(flow.getByRole('tab').nth(1)).toContainText('AI');
await expect(flow.getByRole('tab').nth(2)).toContainText('Output');
await flow.getByRole('tab').nth(1).click();
await expect(