diff --git a/e2e/tests/create-bot-pipeline.spec.ts b/e2e/tests/create-bot-pipeline.spec.ts new file mode 100644 index 0000000..04ca47b --- /dev/null +++ b/e2e/tests/create-bot-pipeline.spec.ts @@ -0,0 +1,62 @@ +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-bot"); +const LAUNCHER = path.join(REPO_ROOT, "cmd/launcher/main.go"); + +test.describe("create-bot pipeline (validacion estructural)", () => { + test("agents/test-bot/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-bot"'); + expect(content).toContain("return nil"); + }); + + test("agents/test-bot/config.yaml tiene type: robot", () => { + const configYaml = path.join(AGENT_DIR, "config.yaml"); + expect(fs.existsSync(configYaml)).toBe(true); + + const content = fs.readFileSync(configYaml, "utf-8"); + expect(content).toMatch(/type:\s*robot/); + expect(content).toMatch(/id:\s*test-bot/); + expect(content).toMatch(/enabled:\s*true/); + }); + + test("agents/test-bot NO tiene prompts/system.md", () => { + const systemPrompt = path.join(AGENT_DIR, "prompts/system.md"); + expect(fs.existsSync(systemPrompt)).toBe(false); + }); + + test("agents/test-bot/commands.go existe con Commands()", () => { + const commandsGo = path.join(AGENT_DIR, "commands.go"); + expect(fs.existsSync(commandsGo)).toBe(true); + + const content = fs.readFileSync(commandsGo, "utf-8"); + expect(content).toContain("func Commands()"); + expect(content).toContain('"echo"'); + expect(content).toContain('"dice"'); + }); + + test("cmd/launcher/main.go tiene import de test-bot", () => { + const content = fs.readFileSync(LAUNCHER, "utf-8"); + expect(content).toContain("agents/test-bot"); + }); + + test("config.yaml tiene command_prefix vacio (sin prefijo !)", () => { + const configYaml = path.join(AGENT_DIR, "config.yaml"); + const content = fs.readFileSync(configYaml, "utf-8"); + expect(content).toMatch(/command_prefix:\s*""/); + }); + + test("config.yaml tiene encryption habilitada", () => { + const configYaml = path.join(AGENT_DIR, "config.yaml"); + const content = fs.readFileSync(configYaml, "utf-8"); + // encryption.enabled should be true + expect(content).toMatch(/encryption:[\s\S]*?enabled:\s*true/); + }); +}); diff --git a/e2e/tests/test-bot.spec.ts b/e2e/tests/test-bot.spec.ts new file mode 100644 index 0000000..3b84bf3 --- /dev/null +++ b/e2e/tests/test-bot.spec.ts @@ -0,0 +1,87 @@ +import { test, expect, handleElementDialogs } from "../fixtures/persistent-context"; +import { + goToRoom, + sendMessage, + waitForBotReply, + assertNoDecryptionErrors, +} from "../fixtures/matrix-room"; + +test.describe("test-bot (robot)", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/"); + await handleElementDialogs(page); + await goToRoom(page, "Test Bot"); + }); + + test("help lista comandos built-in y custom", async ({ page }) => { + await sendMessage(page, "help"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBeTruthy(); + expect(reply.toLowerCase()).toContain("help"); + expect(reply.toLowerCase()).toContain("ping"); + expect(reply.toLowerCase()).toContain("echo"); + expect(reply.toLowerCase()).toContain("dice"); + }); + + test("ping responde sin prefijo !", async ({ page }) => { + await sendMessage(page, "ping"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBeTruthy(); + }); + + test("!ping tambien funciona (retrocompatible)", async ({ page }) => { + await sendMessage(page, "!ping"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBeTruthy(); + }); + + test("echo repite el texto exacto", async ({ page }) => { + await sendMessage(page, "echo hello world"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBe("hello world"); + }); + + test("dice devuelve un numero entre 1 y 6", async ({ page }) => { + await sendMessage(page, "dice"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBeTruthy(); + const num = parseInt(reply.trim(), 10); + expect(num).toBeGreaterThanOrEqual(1); + expect(num).toBeLessThanOrEqual(6); + }); + + test("comando desconocido muestra error", async ({ page }) => { + await sendMessage(page, "unknowncommand"); + + const reply = await waitForBotReply(page, { + timeout: 10_000, + sender: "Test Bot", + }); + expect(reply).toBeTruthy(); + expect(reply.toLowerCase()).toMatch(/desconocido|unknown|no reconozco/); + }); + + test("no hay errores de E2EE en el timeline", async ({ page }) => { + await assertNoDecryptionErrors(page); + }); +});