Co-authored-by: Carlo <carloantonio.patti@mistral.ai>
Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai>
Co-authored-by: Clement Sirieix <clem.sirieix@gmail.com>
Co-authored-by: Michel Thomazo <michel.thomazo@mistral.ai>
Co-authored-by: Clément Drouin <clement.drouin@mistral.ai>
Co-authored-by: Vincent Guilloux <vincent.guilloux@mistral.ai>
Co-authored-by: Thomas Kenbeek <thomas.kenbeek@mistral.ai>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Quentin 2026-02-27 17:31:58 +01:00 committed by GitHub
parent a560a47ce8
commit 5d2e01a6d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
139 changed files with 7152 additions and 1457 deletions

86
tests/e2e/common.py Normal file
View file

@ -0,0 +1,86 @@
from __future__ import annotations
from collections.abc import Callable
from contextlib import AbstractContextManager
import io
from pathlib import Path
import re
import time
from typing import Protocol
import pexpect
class SpawnedVibeProcessFixture(Protocol):
def __call__(
self, workdir: Path
) -> AbstractContextManager[tuple[pexpect.spawn, io.StringIO]]: ...
def ansi_tolerant_pattern(text: str) -> re.Pattern[str]:
ansi = r"(?:\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07]*\x07|\r|\n)*"
return re.compile(ansi.join(re.escape(char) for char in text))
def write_e2e_config(vibe_home: Path, api_base: str) -> None:
vibe_home.mkdir(parents=True, exist_ok=True)
(vibe_home / "config.toml").write_text(
"\n".join([
'active_model = "mock-model"',
"enable_update_checks = false",
"enable_auto_update = false",
"",
"[[providers]]",
'name = "mock-provider"',
f'api_base = "{api_base}"',
'api_key_env_var = "MISTRAL_API_KEY"',
'backend = "generic"',
"",
"[[models]]",
'name = "mock-model"',
'provider = "mock-provider"',
'alias = "mock-model"',
]),
encoding="utf-8",
)
def strip_ansi(text: str) -> str:
return re.sub(r"\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07]*\x07", "", text)
def wait_for_request_count(
request_count_getter: Callable[[], int], expected_count: int, timeout: float
) -> None:
start = time.monotonic()
while time.monotonic() - start < timeout:
if request_count_getter() >= expected_count:
return
time.sleep(0.05)
raise AssertionError(f"Timed out waiting for {expected_count} backend request(s).")
def wait_for_main_screen(child: pexpect.spawn, timeout: float = 20.0) -> None:
child.expect(ansi_tolerant_pattern("Mistral Vibe v"), timeout=timeout)
def wait_for_rendered_text(
child: pexpect.spawn, captured: io.StringIO, needle: str, timeout: float
) -> None:
start = time.monotonic()
while time.monotonic() - start < timeout:
if needle in strip_ansi(captured.getvalue()):
return
try:
child.expect(r"\S", timeout=0.1)
except pexpect.TIMEOUT:
pass
except pexpect.EOF as exc:
rendered_tail = strip_ansi(captured.getvalue())[-1200:]
raise AssertionError(
f"Child exited while waiting for rendered text: {needle!r}\n\nRendered tail:\n{rendered_tail}"
) from exc
rendered_tail = strip_ansi(captured.getvalue())[-1200:]
raise AssertionError(
f"Timed out waiting for rendered text: {needle!r}\n\nRendered tail:\n{rendered_tail}"
)