Skip to content

Commit d0cfaf4

Browse files
bloveclaude
andauthored
test(cockpit-langgraph): aimock e2e for 7 remaining langgraph caps (Task #4) (#482)
* test(cockpit-langgraph): aimock e2e for 7 remaining langgraph caps Brings langgraph product line to FULL aimock coverage (8/8 caps total with streaming pre-existing). Caps shipped: - persistence, interrupts, memory, durable-execution, subgraphs, time-travel, deployment-runtime. All 7 use composed <chat> in the main slot. Fixtures recorded via a new generic recorder at scripts/record-aimock-cap.sh (single shell script taking cap id + prompts; reads registry for ports/paths). Each spec sends "Hello" and asserts the assistant bubble renders — proves backend boots, langgraph routes, aimock replays, UI finalizes. Registry change: added pythonPort to all 8 langgraph cap entries (5300-5307, matching the +1000-from-angular convention used by chat caps). Required by the scaffold generator's all-or-nothing precondition check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cockpit-langgraph): align proxy.conf.json + streaming global-setup with new per-cap pythonPort This PR added pythonPort to all 8 langgraph cap registry entries (5300-5307), but their proxy.conf.json files still pointed at the umbrella port 8123. The cockpit-e2e-wiring spec cross-checks that registry pythonPort matches the global-setup-impl's langgraphPort matches the proxy.conf.json target — mismatch caught by build/test. Fix: update all 8 langgraph proxy.conf.json files to per-cap ports, matching the chat-cap convention (angular port + 1000). Also add the missing langgraphPort to streaming's global-setup-impl (it previously relied on the proxy-fallback in createGlobalSetup; explicit now). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 045283a commit d0cfaf4

54 files changed

Lines changed: 730 additions & 24 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ jobs:
277277
- { angular: cockpit-chat-theming-angular, python: cockpit/chat/theming/python }
278278
- { angular: cockpit-chat-generative-ui-angular, python: cockpit/chat/generative-ui/python }
279279
- { angular: cockpit-chat-a2ui-angular, python: cockpit/chat/a2ui/python }
280+
- { angular: cockpit-langgraph-persistence-angular, python: cockpit/langgraph/persistence/python }
281+
- { angular: cockpit-langgraph-interrupts-angular, python: cockpit/langgraph/interrupts/python }
282+
- { angular: cockpit-langgraph-memory-angular, python: cockpit/langgraph/memory/python }
283+
- { angular: cockpit-langgraph-durable-execution-angular, python: cockpit/langgraph/durable-execution/python }
284+
- { angular: cockpit-langgraph-subgraphs-angular, python: cockpit/langgraph/subgraphs/python }
285+
- { angular: cockpit-langgraph-time-travel-angular, python: cockpit/langgraph/time-travel/python }
286+
- { angular: cockpit-langgraph-deployment-runtime-angular, python: cockpit/langgraph/deployment-runtime/python }
280287
steps:
281288
- uses: actions/checkout@v6.0.2
282289
- uses: actions/setup-node@v6.3.0

apps/cockpit/scripts/capability-registry.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ export interface Capability {
1616
}
1717

1818
export const capabilities: readonly Capability[] = [
19-
{ id: 'streaming', product: 'langgraph', topic: 'streaming', angularProject: 'cockpit-langgraph-streaming-angular', port: 4300, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'streaming' },
20-
{ id: 'persistence', product: 'langgraph', topic: 'persistence', angularProject: 'cockpit-langgraph-persistence-angular', port: 4301, pythonDir: 'cockpit/langgraph/persistence/python', graphName: 'persistence' },
21-
{ id: 'interrupts', product: 'langgraph', topic: 'interrupts', angularProject: 'cockpit-langgraph-interrupts-angular', port: 4302, pythonDir: 'cockpit/langgraph/interrupts/python', graphName: 'interrupts' },
22-
{ id: 'memory', product: 'langgraph', topic: 'memory', angularProject: 'cockpit-langgraph-memory-angular', port: 4303, pythonDir: 'cockpit/langgraph/memory/python', graphName: 'memory' },
23-
{ id: 'durable-execution', product: 'langgraph', topic: 'durable-execution', angularProject: 'cockpit-langgraph-durable-execution-angular', port: 4304, pythonDir: 'cockpit/langgraph/durable-execution/python', graphName: 'durable-execution' },
24-
{ id: 'subgraphs', product: 'langgraph', topic: 'subgraphs', angularProject: 'cockpit-langgraph-subgraphs-angular', port: 4305, pythonDir: 'cockpit/langgraph/subgraphs/python', graphName: 'subgraphs' },
25-
{ id: 'time-travel', product: 'langgraph', topic: 'time-travel', angularProject: 'cockpit-langgraph-time-travel-angular', port: 4306, pythonDir: 'cockpit/langgraph/time-travel/python', graphName: 'time-travel' },
26-
{ id: 'deployment-runtime', product: 'langgraph', topic: 'deployment-runtime', angularProject: 'cockpit-langgraph-deployment-runtime-angular', port: 4307, pythonDir: 'cockpit/langgraph/deployment-runtime/python', graphName: 'deployment-runtime' },
19+
{ id: 'streaming', product: 'langgraph', topic: 'streaming', angularProject: 'cockpit-langgraph-streaming-angular', port: 4300, pythonPort: 5300, pythonDir: 'cockpit/langgraph/streaming/python', graphName: 'streaming' },
20+
{ id: 'persistence', product: 'langgraph', topic: 'persistence', angularProject: 'cockpit-langgraph-persistence-angular', port: 4301, pythonPort: 5301, pythonDir: 'cockpit/langgraph/persistence/python', graphName: 'persistence' },
21+
{ id: 'interrupts', product: 'langgraph', topic: 'interrupts', angularProject: 'cockpit-langgraph-interrupts-angular', port: 4302, pythonPort: 5302, pythonDir: 'cockpit/langgraph/interrupts/python', graphName: 'interrupts' },
22+
{ id: 'memory', product: 'langgraph', topic: 'memory', angularProject: 'cockpit-langgraph-memory-angular', port: 4303, pythonPort: 5303, pythonDir: 'cockpit/langgraph/memory/python', graphName: 'memory' },
23+
{ id: 'durable-execution', product: 'langgraph', topic: 'durable-execution', angularProject: 'cockpit-langgraph-durable-execution-angular', port: 4304, pythonPort: 5304, pythonDir: 'cockpit/langgraph/durable-execution/python', graphName: 'durable-execution' },
24+
{ id: 'subgraphs', product: 'langgraph', topic: 'subgraphs', angularProject: 'cockpit-langgraph-subgraphs-angular', port: 4305, pythonPort: 5305, pythonDir: 'cockpit/langgraph/subgraphs/python', graphName: 'subgraphs' },
25+
{ id: 'time-travel', product: 'langgraph', topic: 'time-travel', angularProject: 'cockpit-langgraph-time-travel-angular', port: 4306, pythonPort: 5306, pythonDir: 'cockpit/langgraph/time-travel/python', graphName: 'time-travel' },
26+
{ id: 'deployment-runtime', product: 'langgraph', topic: 'deployment-runtime', angularProject: 'cockpit-langgraph-deployment-runtime-angular', port: 4307, pythonPort: 5307, pythonDir: 'cockpit/langgraph/deployment-runtime/python', graphName: 'deployment-runtime' },
2727
{ id: 'da-planning', product: 'deep-agents', topic: 'planning', angularProject: 'cockpit-deep-agents-planning-angular', port: 4310, pythonDir: 'cockpit/deep-agents/planning/python', graphName: 'da-planning' },
2828
{ id: 'da-filesystem', product: 'deep-agents', topic: 'filesystem', angularProject: 'cockpit-deep-agents-filesystem-angular', port: 4311, pythonDir: 'cockpit/deep-agents/filesystem/python', graphName: 'da-filesystem' },
2929
{ id: 'da-subagents', product: 'deep-agents', topic: 'subagents', angularProject: 'cockpit-deep-agents-subagents-angular', port: 4312, pythonDir: 'cockpit/deep-agents/subagents/python', graphName: 'subagents' },
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT
2+
import { test, expect } from '@playwright/test';
3+
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';
4+
5+
test('deployment-runtime: hello prompt produces assistant turn', async ({ page }) => {
6+
const bubble = await submitAndWaitForResponse(page, 'Hello');
7+
// Smoke: backend booted, aimock replayed fixture, assistant bubble
8+
// finalized (data-streaming="false") and is present in the DOM.
9+
await expect(bubble).toBeVisible();
10+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"fixtures": [
3+
{
4+
"match": {
5+
"userMessage": "Hello"
6+
},
7+
"response": {
8+
"content": "Hello! How can I help you today?"
9+
}
10+
}
11+
]
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-License-Identifier: MIT
2+
import { resolve } from 'node:path';
3+
import { createGlobalSetup } from '../../../../../libs/e2e-harness/src';
4+
5+
export default createGlobalSetup({
6+
langgraphCwd: 'cockpit/langgraph/deployment-runtime/python',
7+
langgraphPort: 5307,
8+
angularProject: 'cockpit-langgraph-deployment-runtime-angular',
9+
angularPort: 4307,
10+
fixturesDir: resolve(__dirname, 'fixtures'),
11+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: MIT
2+
import { defineConfig, devices } from '@playwright/test';
3+
4+
export default defineConfig({
5+
testDir: '.',
6+
testMatch: '**/*.spec.ts',
7+
fullyParallel: false,
8+
workers: 1,
9+
retries: process.env.CI ? 2 : 0,
10+
reporter: process.env.CI ? [['list'], ['html', { open: 'never' }]] : 'list',
11+
use: {
12+
baseURL: 'http://localhost:4307',
13+
trace: 'retain-on-failure',
14+
},
15+
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
16+
globalSetup: './global-setup-impl.ts',
17+
globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'),
18+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2022",
4+
"module": "ES2022",
5+
"moduleResolution": "Bundler",
6+
"esModuleInterop": true,
7+
"strict": true,
8+
"skipLibCheck": true,
9+
"noEmit": true,
10+
"types": ["node"]
11+
},
12+
"include": ["**/*.ts"],
13+
"exclude": ["node_modules", "test-results", "playwright-report"]
14+
}

cockpit/langgraph/deployment-runtime/angular/project.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@
8787
"cwd": "cockpit/langgraph/deployment-runtime/angular",
8888
"command": "npx tsx -e \"import { langgraphDeploymentRuntimeAngularModule } from './src/index.ts'; const module = langgraphDeploymentRuntimeAngularModule; if (module.id !== 'langgraph-deployment-runtime-angular' || module.title !== 'LangGraph Deployment & Runtime (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
8989
}
90+
},
91+
"e2e": {
92+
"executor": "@nx/playwright:playwright",
93+
"options": {
94+
"config": "cockpit/langgraph/deployment-runtime/angular/e2e/playwright.config.ts"
95+
}
9096
}
9197
}
9298
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"/api": {
3-
"target": "http://localhost:8123",
3+
"target": "http://localhost:5307",
44
"secure": false,
55
"changeOrigin": true,
6-
"pathRewrite": { "^/api": "" },
6+
"pathRewrite": {
7+
"^/api": ""
8+
},
79
"ws": true
810
}
911
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT
2+
import { test, expect } from '@playwright/test';
3+
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';
4+
5+
test('durable-execution: hello prompt produces assistant turn', async ({ page }) => {
6+
const bubble = await submitAndWaitForResponse(page, 'Hello');
7+
// Smoke: backend booted, aimock replayed fixture, assistant bubble
8+
// finalized (data-streaming="false") and is present in the DOM.
9+
await expect(bubble).toBeVisible();
10+
});

0 commit comments

Comments
 (0)