Skip to content
Merged
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: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ jobs:
- { angular: cockpit-chat-subagents-angular, python: cockpit/chat/subagents/python }
- { angular: cockpit-chat-interrupts-angular, python: cockpit/chat/interrupts/python }
- { angular: cockpit-chat-messages-angular, python: cockpit/chat/messages/python }
- { angular: cockpit-chat-input-angular, python: cockpit/chat/input/python }
- { angular: cockpit-chat-threads-angular, python: cockpit/chat/threads/python }
- { angular: cockpit-chat-timeline-angular, python: cockpit/chat/timeline/python }
- { angular: cockpit-chat-theming-angular, python: cockpit/chat/theming/python }
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/setup-node@v6.3.0
Expand Down
23 changes: 23 additions & 0 deletions cockpit/chat/input/angular/e2e/c-input.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
import { test, expect } from '@playwright/test';
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';

const PROMPT = 'Hello';

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

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

await expect(bubble).toContainText('chat-input demo');
});

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

// c-input uses raw ChatMessageListComponent primitives with projected
// templates (per PR #466's fix). Regression coverage for that fix.
await expect(page.locator('chat-message-list chat-message')).toHaveCount(2);
});
10 changes: 10 additions & 0 deletions cockpit/chat/input/angular/e2e/fixtures/c-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"fixtures": [
{
"match": { "userMessage": "Hello" },
"response": {
"content": "Hi! I'm the chat-input demo. Try Enter to send, Shift+Enter for newline, and watch the sidebar reflect the streaming status."
}
}
]
}
11 changes: 11 additions & 0 deletions cockpit/chat/input/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/input/python',
langgraphPort: 5502,
angularProject: 'cockpit-chat-input-angular',
angularPort: 4502,
fixturesDir: resolve(__dirname, 'fixtures'),
});
18 changes: 18 additions & 0 deletions cockpit/chat/input/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:4502',
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/input/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/input/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
"cwd": "cockpit/chat/input/angular",
"command": "npx tsx -e \"import { chatInputAngularModule } from './src/index.ts'; const module = chatInputAngularModule; if (module.id !== 'chat-input-angular' || module.title !== 'Chat Input (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
}
},
"e2e": {
"executor": "@nx/playwright:playwright",
"options": {
"config": "cockpit/chat/input/angular/e2e/playwright.config.ts"
}
}
}
}
19 changes: 19 additions & 0 deletions cockpit/chat/theming/angular/e2e/c-theming.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
import { test, expect } from '@playwright/test';
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';

const PROMPT = 'Hello';

test('c-theming: AI response renders in composed chat surface', async ({ page }) => {
const bubble = await submitAndWaitForResponse(page, PROMPT);
await expect(bubble).toContainText('chat-theming demo');
});

test('c-theming: theme picker buttons are present in sidebar', async ({ page }) => {
await page.goto('/');
// Distinctive surface — four theme-picker buttons that set CSS custom
// properties on document.documentElement.
for (const label of ['Dark', 'Light', 'Ocean', 'Forest']) {
await expect(page.getByRole('button', { name: label })).toBeVisible();
}
});
10 changes: 10 additions & 0 deletions cockpit/chat/theming/angular/e2e/fixtures/c-theming.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"fixtures": [
{
"match": { "userMessage": "Hello" },
"response": {
"content": "Hi! I'm the chat-theming demo. Try the theme picker buttons in the sidebar to switch between dark, light, ocean, and forest schemes."
}
}
]
}
11 changes: 11 additions & 0 deletions cockpit/chat/theming/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/theming/python',
langgraphPort: 5510,
angularProject: 'cockpit-chat-theming-angular',
angularPort: 4510,
fixturesDir: resolve(__dirname, 'fixtures'),
});
18 changes: 18 additions & 0 deletions cockpit/chat/theming/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:4510',
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/theming/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/theming/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
"cwd": "cockpit/chat/theming/angular",
"command": "npx tsx -e \"import { chatThemingAngularModule } from './src/index.ts'; const module = chatThemingAngularModule; if (module.id !== 'chat-theming-angular' || module.title !== 'Chat Theming (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
}
},
"e2e": {
"executor": "@nx/playwright:playwright",
"options": {
"config": "cockpit/chat/theming/angular/e2e/playwright.config.ts"
}
}
}
}
17 changes: 17 additions & 0 deletions cockpit/chat/threads/angular/e2e/c-threads.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
import { test, expect } from '@playwright/test';
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';

const PROMPT = 'Hello';

test('c-threads: AI response renders in composed chat surface', async ({ page }) => {
const bubble = await submitAndWaitForResponse(page, PROMPT);
await expect(bubble).toContainText('chat-threads demo');
});

test('c-threads: chat-thread-list sidebar is mounted', async ({ page }) => {
await page.goto('/');
// Sidebar's distinctive surface — thread switcher seeded with 3 hardcoded
// threads (thread-1/2/3). Existence + non-zero entry count proves wiring.
await expect(page.locator('chat-thread-list')).toBeVisible();
});
10 changes: 10 additions & 0 deletions cockpit/chat/threads/angular/e2e/fixtures/c-threads.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"fixtures": [
{
"match": { "userMessage": "Hello" },
"response": {
"content": "Hi! I'm the chat-threads demo. Switch between threads using the sidebar list to see independent conversation contexts."
}
}
]
}
11 changes: 11 additions & 0 deletions cockpit/chat/threads/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/threads/python',
langgraphPort: 5506,
angularProject: 'cockpit-chat-threads-angular',
angularPort: 4506,
fixturesDir: resolve(__dirname, 'fixtures'),
});
18 changes: 18 additions & 0 deletions cockpit/chat/threads/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:4506',
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/threads/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/threads/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
"cwd": "cockpit/chat/threads/angular",
"command": "npx tsx -e \"import { chatThreadsAngularModule } from './src/index.ts'; const module = chatThreadsAngularModule; if (module.id !== 'chat-threads-angular' || module.title !== 'Chat Threads (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
}
},
"e2e": {
"executor": "@nx/playwright:playwright",
"options": {
"config": "cockpit/chat/threads/angular/e2e/playwright.config.ts"
}
}
}
}
16 changes: 16 additions & 0 deletions cockpit/chat/timeline/angular/e2e/c-timeline.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
import { test, expect } from '@playwright/test';
import { submitAndWaitForResponse } from '../../../../../libs/e2e-harness/src';

const PROMPT = 'Hello';

test('c-timeline: AI response renders in composed chat surface', async ({ page }) => {
const bubble = await submitAndWaitForResponse(page, PROMPT);
await expect(bubble).toContainText('chat-timeline demo');
});

test('c-timeline: chat-timeline-slider sidebar is mounted', async ({ page }) => {
await page.goto('/');
// Distinctive surface — slider reflects checkpoint state.
await expect(page.locator('chat-timeline-slider')).toBeVisible();
});
10 changes: 10 additions & 0 deletions cockpit/chat/timeline/angular/e2e/fixtures/c-timeline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"fixtures": [
{
"match": { "userMessage": "Hello" },
"response": {
"content": "Hi! I'm the chat-timeline demo. Each message creates a checkpoint you can scrub with the timeline slider in the sidebar."
}
}
]
}
11 changes: 11 additions & 0 deletions cockpit/chat/timeline/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/timeline/python',
langgraphPort: 5507,
angularProject: 'cockpit-chat-timeline-angular',
angularPort: 4507,
fixturesDir: resolve(__dirname, 'fixtures'),
});
18 changes: 18 additions & 0 deletions cockpit/chat/timeline/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:4507',
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/timeline/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/timeline/angular/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@
"cwd": "cockpit/chat/timeline/angular",
"command": "npx tsx -e \"import { chatTimelineAngularModule } from './src/index.ts'; const module = chatTimelineAngularModule; if (module.id !== 'chat-timeline-angular' || module.title !== 'Chat Timeline (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\""
}
},
"e2e": {
"executor": "@nx/playwright:playwright",
"options": {
"config": "cockpit/chat/timeline/angular/e2e/playwright.config.ts"
}
}
}
}
Loading