(e2e) add first chat end-to-end test

This is a very simple test, but it paves the way for more of them.
This commit is contained in:
Quentin BEY
2025-11-14 15:09:54 +01:00
parent 8f5419e6ca
commit 22ce90488c
8 changed files with 183 additions and 8 deletions
+2 -2
View File
@@ -126,7 +126,7 @@ build-frontend: ## build the frontend container
build-e2e: cache ?=
build-e2e: ## build the e2e container
@$(MAKE) build-backend cache=$(cache)
@$(COMPOSE_E2E) build frontend $(cache)
@$(COMPOSE_E2E) build frontend openmockllm-mistral $(cache)
.PHONY: build-e2e
down: ## stop and remove containers, networks, images, and volumes
@@ -158,7 +158,7 @@ create-compose-with-models: ## override the docker-compose file with models
run-e2e: ## start the e2e server
run-e2e:
@$(MAKE) run-backend
@$(COMPOSE_E2E) up --force-recreate -d frontend
@$(COMPOSE_E2E) up --force-recreate -d frontend openmockllm-mistral
.PHONY: run-e2e
status: ## an alias for "docker compose ps"
+19
View File
@@ -11,3 +11,22 @@ services:
image: conversations:frontend-production
ports:
- "3000:3000"
openmockllm-mistral:
user: "${DOCKER_USER:-1000}"
build:
context: .
dockerfile: ./src/OpenMockLLM/Dockerfile
image: conversations:openmockllm-mistral
command:
- openmockllm
- --host
- "0.0.0.0"
- --port
- "8000"
- --backend
- mistral
- --model-name
- mistral-mock
ports:
- "8900:8000"
+3
View File
@@ -2,6 +2,9 @@
BURST_THROTTLE_RATES="200/minute"
SUSTAINED_THROTTLE_RATES="200/hour"
# LLM
LLM_CONFIGURATION_FILE_PATH = /app/conversations/configuration/llm/default.e2e.json
# Features
FEATURE_FLAG_WEB_SEARCH=ENABLED
FEATURE_FLAG_DOCUMENT_UPLOAD=ENABLED
+19
View File
@@ -0,0 +1,19 @@
FROM python:3.13.3-alpine
# Upgrade pip to its latest release to speed up dependencies installation
RUN python -m pip install --upgrade pip setuptools lorem-text
# Upgrade system packages to install security updates
RUN apk update && \
apk upgrade
RUN apk add --no-cache git
# Install the package
RUN pip install git+https://github.com/etalab-ia/openmockllm.git
# Expose the default port
EXPOSE 8000
# Set default command
CMD ["openmockllm", "--host", "0.0.0.0", "--port", "8000"]
+19
View File
@@ -0,0 +1,19 @@
[OpenMockLLM](https://github.com/etalab-ia/OpenMockLLM) is a FastAPI-based mock LLM API server that simulates
several Large Language Model API providers.
This is a simple docker image to run the server for testing and development purposes (E2E tests mainly).
It's a bit overkill to have a dedicated image for that, but it allows simple E2E stack with docker-compose since
our code is also run in Docker containers.
## Build and Run manually
```bash
docker build -t openmockllm .
docker run -p 8000:8000 openmockllm
```
## Next steps
- Add more chat completion behaviors (specific text streaming, function calling, etc.)
- Pin a specific OpenMockLLM version in the Dockerfile
@@ -0,0 +1,43 @@
{
"models": [
{
"hrid": "default-model",
"model_name": "mistral-mock",
"human_readable_name": "Default Model",
"provider_name": "default-provider",
"profile": null,
"settings": {},
"is_active": true,
"icon": [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAn1BMVEUALosAKoovTZjw8vb////+9/jlPUniAAz",
"iABUAGIWbpsTwq7HhAAAAI4dle7DrdX4AJohRaaboXWj7+/zn6On5//9NZaT29vfoWmVHYKDoUl/k5OUAIYddc6vpbHYCM47Y3+v53+LiFCUA",
"HIWnsckYPJHi6PL77O7jJjW3wdf1w8jre4QgQ5TZ2txwg7Pr3+I8WZ6OnsTuoamClL7tlZ5xz5y8AAAAzUlEQVR4AZ3RRQKDQBBEUSTu7h5c4",
"vc/W6Yp3KG2Dz4ynDdeEBvOmq12xx2E1u0B+4NOEocj4DgNJ1PgLAvni8WyBq5Yc71ubFJx23C2q4P7dRYejg1xzvCUgvz5guz11k7gXYKF/1",
"8oyiYuvHAYeVkhXCzolVStHcGDjiQzNmMQxsMI5rEJRdQSPZvbpE2E8aY6gC6Z+2Hg4dFA0Yb4YedNL/v4Fk8WJuwiGhrChJNXI210rnib9Fs",
"JlXRUC/HwTscPIXf/iklq/tjb/gHAdxkCUjAg2QAAAABJRU5ErkJggg=="
],
"system_prompt": "You are a helpful AI assistant.",
"tools": []
},
{
"hrid": "default-summarization-model",
"model_name": "mistral-mock",
"human_readable_name": "Default Summarization Model",
"provider_name": "default-provider",
"profile": null,
"settings": {},
"is_active": true,
"icon": null,
"system_prompt": "You are a helpful AI assistant specialized in summarization.",
"tools": []
}
],
"providers": [
{
"hrid": "default-provider",
"base_url": "http://host.docker.internal:8900",
"api_key": "openmockllm-api-key",
"kind": "mistral"
}
]
}
@@ -0,0 +1,76 @@
import { expect, test } from '@playwright/test';
test.beforeEach(async ({ page }) => {
await page.goto('/home/');
});
test.describe('Chat page', () => {
test('it checks the page is displayed properly', async ({ page }) => {
await page.goto('/');
const newChatButton = page.getByRole('button', { name: 'New chat' });
await expect(newChatButton).toBeVisible();
const chatInput = page.getByRole('textbox', {
name: 'Enter your message or a',
});
await expect(chatInput).toBeVisible();
const attachmentButton = page.getByRole('button', {
name: 'Add attach file',
});
await expect(attachmentButton).toBeVisible();
const websearchButton = page.getByRole('button', {
name: 'Research on the web',
});
await expect(websearchButton).toBeVisible();
const sendMessageButton = page.getByRole('button', { name: 'Send' });
await expect(sendMessageButton).toBeVisible();
});
test('the user can chat with LLM (simple)', async ({ page }) => {
await page.goto('/');
const newChatButton = page.getByRole('button', { name: 'New chat' });
await expect(newChatButton).toBeVisible();
const chatInput = page.getByRole('textbox', {
name: 'Enter your message or a',
});
await chatInput.click();
await chatInput.fill('Hello, how are you?');
const sendMessageButton = page.getByRole('button', { name: 'Send' });
await expect(sendMessageButton).toBeEnabled();
await page.keyboard.press('Enter');
// Wait for the response to appear
await page
.getByRole('button', { name: 'See more' })
.waitFor({ timeout: 10000 });
const copyButton = page.getByRole('button', { name: 'Copy' });
await expect(copyButton).toBeVisible();
const messageContent = page.getByText('Lorem ipsum dolor sit amet');
await expect(messageContent).toBeVisible();
// Check history
const chatHistoryLink = page
.getByRole('link', { name: 'Simple chat icon Hello, how' })
.first();
await expect(chatHistoryLink).toBeVisible();
await newChatButton.click();
await page
.getByRole('heading', { name: 'What is on your mind?' })
.isVisible();
await chatHistoryLink.click();
await expect(messageContent).toBeVisible();
});
});
@@ -24,9 +24,7 @@ test.describe('Home page', () => {
// Check the titles
const h2 = page.locator('h2');
await expect(
h2.getByText('Your sovereign AI assistant'),
).toBeVisible();
await expect(h2.getByText('Your sovereign AI assistant')).toBeVisible();
await expect(footer).toBeVisible();
});
@@ -74,9 +72,7 @@ test.describe('Home page', () => {
// Check the titles
const h2 = page.locator('h2');
await expect(
h2.getByText('Your sovereign AI assistant'),
).toBeVisible();
await expect(h2.getByText('Your sovereign AI assistant')).toBeVisible();
await expect(footer).toBeVisible();
});