test: E2E tests para agente test-personality y pipeline de creacion
Tests funcionales (test-personality.spec.ts): - Saludo con personalidad pirata espacial (keywords flexibles) - Personalidad consistente en respuestas serias (fotosintesis + pirata) - !help y !ping funcionan (assertions estrictas) - Sin errores E2EE Tests de pipeline (create-agent-pipeline.spec.ts): - Valida agent.go con Rules() y ActionKindLLM - Config sin type: robot (es agent por defecto) - System prompt con personalidad + seccion de seguridad - LLM configurado (openai/gpt-4o) - Encryption habilitada, import en launcher Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const REPO_ROOT = path.resolve(__dirname, "../..");
|
||||
const AGENT_DIR = path.join(REPO_ROOT, "agents/test-personality");
|
||||
const LAUNCHER = path.join(REPO_ROOT, "cmd/launcher/main.go");
|
||||
|
||||
test.describe("create-agent pipeline (validacion estructural)", () => {
|
||||
test("agents/test-personality/agent.go existe y exporta Rules()", () => {
|
||||
const agentGo = path.join(AGENT_DIR, "agent.go");
|
||||
expect(fs.existsSync(agentGo)).toBe(true);
|
||||
|
||||
const content = fs.readFileSync(agentGo, "utf-8");
|
||||
expect(content).toContain("func Rules()");
|
||||
expect(content).toContain('agents.Register("test-personality"');
|
||||
// Agent (not robot) should have actual rules, not nil
|
||||
expect(content).toContain("ActionKindLLM");
|
||||
});
|
||||
|
||||
test("agents/test-personality/config.yaml tiene type: agent (default)", () => {
|
||||
const configYaml = path.join(AGENT_DIR, "config.yaml");
|
||||
expect(fs.existsSync(configYaml)).toBe(true);
|
||||
|
||||
const content = fs.readFileSync(configYaml, "utf-8");
|
||||
expect(content).toMatch(/id:\s*test-personality/);
|
||||
expect(content).toMatch(/enabled:\s*true/);
|
||||
// Should NOT have type: robot
|
||||
expect(content).not.toMatch(/type:\s*robot/);
|
||||
});
|
||||
|
||||
test("agents/test-personality/prompts/system.md existe con personalidad", () => {
|
||||
const systemPrompt = path.join(AGENT_DIR, "prompts/system.md");
|
||||
expect(fs.existsSync(systemPrompt)).toBe(true);
|
||||
|
||||
const content = fs.readFileSync(systemPrompt, "utf-8");
|
||||
// Pirate space personality keywords
|
||||
expect(content.toLowerCase()).toContain("pirata");
|
||||
expect(content.toLowerCase()).toContain("cosmonauta");
|
||||
expect(content.toLowerCase()).toContain("estelar");
|
||||
// Security section
|
||||
expect(content.toLowerCase()).toContain("seguridad");
|
||||
expect(content).toContain("instrucciones obligatorias");
|
||||
});
|
||||
|
||||
test("config.yaml tiene LLM configurado (openai/gpt-4o)", () => {
|
||||
const configYaml = path.join(AGENT_DIR, "config.yaml");
|
||||
const content = fs.readFileSync(configYaml, "utf-8");
|
||||
expect(content).toMatch(/provider:\s*openai/);
|
||||
expect(content).toMatch(/model:\s*"?gpt-4o"?/);
|
||||
});
|
||||
|
||||
test("config.yaml tiene encryption habilitada", () => {
|
||||
const configYaml = path.join(AGENT_DIR, "config.yaml");
|
||||
const content = fs.readFileSync(configYaml, "utf-8");
|
||||
expect(content).toMatch(/encryption:[\s\S]*?enabled:\s*true/);
|
||||
});
|
||||
|
||||
test("cmd/launcher/main.go tiene import de test-personality", () => {
|
||||
const content = fs.readFileSync(LAUNCHER, "utf-8");
|
||||
expect(content).toContain("agents/test-personality");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
import { test, expect, handleElementDialogs } from "../fixtures/persistent-context";
|
||||
import {
|
||||
goToRoom,
|
||||
sendMessage,
|
||||
waitForBotReply,
|
||||
assertNoDecryptionErrors,
|
||||
} from "../fixtures/matrix-room";
|
||||
|
||||
// Keywords that indicate pirate-space personality.
|
||||
// The LLM is non-deterministic, so we check for presence of ANY keyword from the set.
|
||||
const PIRATE_SPACE_KEYWORDS = [
|
||||
"arrr",
|
||||
"cosmonauta",
|
||||
"estelar",
|
||||
"marea",
|
||||
"nave",
|
||||
"galaxia",
|
||||
"estrella",
|
||||
"pirata",
|
||||
"capitan",
|
||||
"nebulosa",
|
||||
"intergal",
|
||||
"asteroide",
|
||||
"meteorito",
|
||||
"agujero negro",
|
||||
"tripulacion",
|
||||
"🏴☠️",
|
||||
"🚀",
|
||||
"⭐",
|
||||
"🌌",
|
||||
"☄️",
|
||||
"💀",
|
||||
];
|
||||
|
||||
function containsPirateKeyword(text: string): boolean {
|
||||
const lower = text.toLowerCase();
|
||||
return PIRATE_SPACE_KEYWORDS.some((kw) => lower.includes(kw.toLowerCase()));
|
||||
}
|
||||
|
||||
test.describe("test-personality (pirata espacial)", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
await goToRoom(page, "Test Personality");
|
||||
});
|
||||
|
||||
test("responde a saludo con personalidad pirata espacial", async ({ page }) => {
|
||||
await sendMessage(page, "Hola, como estas?");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Test Personality",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.length).toBeGreaterThan(20);
|
||||
expect(containsPirateKeyword(reply)).toBe(true);
|
||||
});
|
||||
|
||||
test("personalidad consistente en respuestas serias", async ({ page }) => {
|
||||
await sendMessage(page, "Que es la fotosintesis? Responde en una frase.");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Test Personality",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.length).toBeGreaterThan(20);
|
||||
// Should contain real content about photosynthesis
|
||||
expect(reply.toLowerCase()).toMatch(/luz|sol|planta|energia|clorofila|carbon/i);
|
||||
// And still maintain pirate personality
|
||||
expect(containsPirateKeyword(reply)).toBe(true);
|
||||
});
|
||||
|
||||
test("!help muestra lista de comandos", async ({ page }) => {
|
||||
await sendMessage(page, "!help");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Test Personality",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
expect(reply.toLowerCase()).toContain("help");
|
||||
expect(reply.toLowerCase()).toContain("ping");
|
||||
});
|
||||
|
||||
test("!ping responde", async ({ page }) => {
|
||||
await sendMessage(page, "!ping");
|
||||
|
||||
const reply = await waitForBotReply(page, {
|
||||
timeout: 10_000,
|
||||
sender: "Test Personality",
|
||||
});
|
||||
expect(reply).toBeTruthy();
|
||||
});
|
||||
|
||||
test("no hay errores de E2EE en el timeline", async ({ page }) => {
|
||||
await assertNoDecryptionErrors(page);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user