✅(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:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user