import { useEffect, useRef, useState, useCallback } from 'react' import { TestTube2, Copy, RefreshCw, CheckCircle2, AlertTriangle, Globe, Terminal as TerminalIcon } from 'lucide-react' export default function Tests({ api }) { const [snippet, setSnippet] = useState(null) const [snippetError, setSnippetError] = useState('') const [sessions, setSessions] = useState([]) const [console_, setConsole_] = useState([]) const [activeSessionId, setActiveSessionId] = useState('') const [copied, setCopied] = useState(false) const pollRef = useRef(null) const refreshSnippet = useCallback(async () => { try { const data = await api.getTestSnippet() setSnippet(data) setSnippetError('') } catch (err) { setSnippetError(err.message || 'Failed to load snippet') } }, [api]) const refreshSessions = useCallback(async () => { try { const data = await api.getTestSessions() const next = data.sessions || [] setSessions(next) if (!activeSessionId && next.length > 0) { setActiveSessionId(next[0].id) } else if (activeSessionId && !next.find(s => s.id === activeSessionId)) { setActiveSessionId(next.length > 0 ? next[0].id : '') } } catch {} }, [api, activeSessionId]) const refreshConsole = useCallback(async () => { if (!activeSessionId) { setConsole_([]) return } try { const data = await api.getTestConsole(activeSessionId) setConsole_(data.console || []) } catch { setConsole_([]) } }, [api, activeSessionId]) useEffect(() => { refreshSnippet() }, [refreshSnippet]) useEffect(() => { refreshSessions() refreshConsole() pollRef.current = setInterval(() => { refreshSessions() refreshConsole() }, 2000) return () => clearInterval(pollRef.current) }, [refreshSessions, refreshConsole]) const copySnippet = useCallback(async () => { if (!snippet) return try { await navigator.clipboard.writeText(snippet.snippet) setCopied(true) setTimeout(() => setCopied(false), 1500) } catch {} }, [snippet]) const activeSession = sessions.find(s => s.id === activeSessionId) || null return (

Tests pilotés par l'IA

Donnez à l'IA Studio le contrôle d'un onglet de votre navigateur pour tester chaque bouton et détecter les erreurs console.

1. Connexion

  1. Ouvrez la page à tester dans n'importe quel navigateur (Chrome, Firefox, Edge…).
  2. Ouvrez la console développeur (F12).
  3. Collez ce snippet et appuyez sur Entrée :
{snippetError && (
{snippetError}
)}
{snippet?.snippet || 'Chargement…'}
            
Le token expire après {snippet?.expires_in ? Math.round(snippet.expires_in / 60) : 5} minutes ou dès la première connexion.

2. Pilotage par l'IA

Une fois la session connectée, allez dans l'onglet Studio et demandez par exemple :

{`Teste tous les boutons de cette page,
clique sur chacun, et dis-moi
lesquels déclenchent une erreur console.`}
          

L'IA dispose de l'outil browser_test avec les actions list_clickables, click, console, eval, type, current_url, wait, summary.

Réflexion avancée auto : tant qu'au moins une session de test est connectée, chaque message dans Studio utilise automatiquement la réflexion avancée — un second modèle (s'il est configuré) produit un rapport d'analyse préalable injecté dans le prompt actif. Le toggle Studio est ignoré pendant la session.

Sessions connectées

{sessions.length > 0 ? : } {sessions.length} session{sessions.length > 1 ? 's' : ''}
{sessions.length === 0 ? (
Aucune session active.
Collez le snippet dans une page pour démarrer.
) : (
{sessions.map(s => ( ))}
)} {activeSession && (

Console (live, dernières {console_.length})

{console_.length === 0 ? (
(aucun message console)
) : ( console_.map((c, i) => (
[{c.time?.slice(11, 19)} {c.level}] {c.message}
)) )}
)}
) } function levelColor(lvl) { switch (lvl) { case 'error': return '#ff6b6b' case 'warn': return '#f5a623' case 'info': return '#4dabf7' case 'debug': return '#888' default: return 'inherit' } }