feat(scenario): export scenarios as standalone playwright e2e test projects

- Added E2eExportService to package scenarios as plug-and-play zip archives
  containing package.json, playwright.config.ts, test.spec.ts, .env, credentials.json,
  snippets, and referenced scenario files
- Only bundles credentials, snippets, and files actually referenced (directly or
  transitively) by the scenario's steps, reducing archive size
- Exported test runs entirely offline using a context shim that mirrors liqa's API
  (page, getCredential, runSnippet, getScenarioFiles, downloadFile, assert, etc.)
- Added GET /scenarios/:id/export-e2e HTTP endpoint and export_e2e_test MCP tool
- Added getUsedSnippets() endpoint to list snippets referenced by a scenario
- Added "Used Snippets" section on scenario detail page
- Added archiver@^7.0.1 dependency for zip archive creation
- Bumped version to 1.11.0
This commit is contained in:
Andrii Arsenin
2026-09-16 12:33:16 +03:00
parent 85a87b5fb2
commit 69d16c9a94
14 changed files with 1348 additions and 11 deletions
+36
View File
@@ -11,6 +11,7 @@ import { CredentialService } from "../credential/credential.service";
import { BrowserService } from "../browser/browser.service";
import { CodeExecutorService } from "../code-executor/code-executor.service";
import { ScenarioService } from "../scenario/scenario.service";
import { E2eExportService } from "../scenario/e2e-export.service";
import { SnippetService } from "../snippet/snippet.service";
import pkg from "../../package.json";
@@ -25,6 +26,7 @@ export class McpService {
private readonly browserService: BrowserService,
private readonly codeExecutor: CodeExecutorService,
private readonly scenarioService: ScenarioService,
private readonly e2eExportService: E2eExportService,
private readonly snippetService: SnippetService,
) {}
@@ -1062,6 +1064,40 @@ export class McpService {
},
);
server.registerTool(
"export_e2e_test",
{
description:
"Export a scenario as a standalone, plug-and-play Playwright e2e test project (package.json, playwright.config.ts, test.spec.ts, .env), zipped and returned as base64",
inputSchema: {
id: z.uuid().describe("Scenario ID to export"),
},
},
async ({ id }) => {
try {
const { filename, buffer } =
await this.e2eExportService.buildE2eTestPackage(id);
return {
content: [
{
type: "text" as const,
text: JSON.stringify({
filename,
contentBase64: buffer.toString("base64"),
encoding: "base64",
}),
},
],
};
} catch (err) {
return {
isError: true,
content: [{ type: "text" as const, text: (err as Error).message }],
};
}
},
);
// ── Scenario Files ────────────────────────────────────────────────────────
server.registerTool(