Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ jobs:
run: uv sync
- working-directory: cockpit/chat/interrupts/python
run: uv sync
- working-directory: cockpit/chat/messages/python
run: uv sync
- run: npx playwright install --with-deps chromium
# Explicit sequential loop (not `nx run-many --parallel=1`) so each
# per-example e2e gets a fresh Playwright process and a clean port
Expand All @@ -297,7 +299,7 @@ jobs:
- name: Run cockpit example aimock e2e suites
run: |
set -e
for proj in cockpit-langgraph-streaming-angular cockpit-chat-tool-calls-angular cockpit-chat-subagents-angular cockpit-chat-interrupts-angular; do
for proj in cockpit-langgraph-streaming-angular cockpit-chat-tool-calls-angular cockpit-chat-subagents-angular cockpit-chat-interrupts-angular cockpit-chat-messages-angular; do
echo "::group::nx e2e $proj"
npx nx e2e "$proj" --skip-nx-cache
echo "::endgroup::"
Expand Down
41 changes: 41 additions & 0 deletions cockpit/chat/messages/angular/e2e/c-messages.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
import { test, expect } from '@playwright/test';

// Note: c-messages uses raw ChatInputComponent/ChatMessageListComponent
// primitives rather than the composed <chat> component. With aimock's
// near-instant chunked response (~30ms), the `isLoading()` signal flips
// false before Playwright can observe the conditional "Stop generating"
// button — so the shared `sendPromptAndWait` helper times out here.
// Wait directly on the durable end-state signal instead:
// `chat-message[data-role="assistant"][data-streaming="false"]`.

const PROMPT = 'Hello';
const RESPONSE_SUBSTRING = 'chat-messages capability demo';

async function submitAndWaitForResponse(page: import('@playwright/test').Page) {
await page.goto('/');
const input = page.getByRole('textbox', { name: /message|prompt/i });
await input.fill(PROMPT);
await page.getByRole('button', { name: /send message/i }).click();
const finalAssistant = page
.locator('chat-message[data-role="assistant"][data-streaming="false"]')
.last();
await expect(finalAssistant).toBeAttached({ timeout: 30_000 });
return finalAssistant;
}

test('c-messages: user message and AI response both render', async ({ page }) => {
const finalBubble = await submitAndWaitForResponse(page);

await expect(
page.locator('chat-message[data-role="user"]').last(),
).toContainText(PROMPT);

await expect(finalBubble).toContainText(RESPONSE_SUBSTRING);
});

test('c-messages: chat-message-list renders both turns', async ({ page }) => {
await submitAndWaitForResponse(page);

await expect(page.locator('chat-message-list chat-message')).toHaveCount(2);
});
15 changes: 15 additions & 0 deletions cockpit/chat/messages/angular/e2e/fixtures/c-messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"fixtures": [
{
"match": {
"userMessage": "Hello",
"model": "gpt-5-mini",
"turnIndex": 0,
"hasToolResult": false
},
"response": {
"content": "Hi! I'm the chat-messages capability demo. I show how ChatMessageListComponent, ChatInputComponent, and ChatTypingIndicatorComponent render together. Try sending a few messages to see the bubbles and typing indicator in action."
}
}
]
}
11 changes: 11 additions & 0 deletions cockpit/chat/messages/angular/e2e/global-setup-impl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
import { resolve } from 'node:path';
import { createGlobalSetup } from '../../../../../libs/e2e-harness/src';

export default createGlobalSetup({
langgraphCwd: 'cockpit/chat/messages/python',
langgraphPort: 5501,
angularProject: 'cockpit-chat-messages-angular',
angularPort: 4501,
fixturesDir: resolve(__dirname, 'fixtures'),
});
18 changes: 18 additions & 0 deletions cockpit/chat/messages/angular/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: '.',
testMatch: '**/*.spec.ts',
fullyParallel: false,
workers: 1,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? [['list'], ['html', { open: 'never' }]] : 'list',
use: {
baseURL: 'http://localhost:4501',
trace: 'retain-on-failure',
},
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
globalSetup: './global-setup-impl.ts',
globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'),
});
14 changes: 14 additions & 0 deletions cockpit/chat/messages/angular/e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Bundler",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"types": ["node"]
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "test-results", "playwright-report"]
}
6 changes: 6 additions & 0 deletions cockpit/chat/messages/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
"cwd": "cockpit/chat/messages/angular",
"command": "npx tsx -e \"import { chatMessagesAngularModule } from './src/index.ts'; const module = chatMessagesAngularModule; if (module.id !== 'chat-messages-angular' || module.title !== 'Chat Messages (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
}
},
"e2e": {
"executor": "@nx/playwright:playwright",
"options": {
"config": "cockpit/chat/messages/angular/e2e/playwright.config.ts"
}
}
}
}
Loading
Loading