From 892f6110650a76e92aafbbbd4055a943569f09d3 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Mon, 11 May 2026 08:01:11 +0530 Subject: [PATCH] test(mantis): package telegram desktop proof evidence --- .../build-telegram-desktop-proof-evidence.mjs | 251 ++++++++++++++++++ scripts/test-projects.test-support.mjs | 8 + ...ld-telegram-desktop-proof-evidence.test.ts | 101 +++++++ 3 files changed, 360 insertions(+) create mode 100644 scripts/mantis/build-telegram-desktop-proof-evidence.mjs create mode 100644 test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts diff --git a/scripts/mantis/build-telegram-desktop-proof-evidence.mjs b/scripts/mantis/build-telegram-desktop-proof-evidence.mjs new file mode 100644 index 00000000000..215856edea7 --- /dev/null +++ b/scripts/mantis/build-telegram-desktop-proof-evidence.mjs @@ -0,0 +1,251 @@ +#!/usr/bin/env node +import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const LANES = [ + { + altPrefix: "Baseline", + label: "Main", + lane: "baseline", + }, + { + altPrefix: "Candidate", + label: "This PR", + lane: "candidate", + }, +]; + +function parseArgs(argv) { + const args = {}; + for (let index = 0; index < argv.length; index += 1) { + const key = argv[index]; + if (!key.startsWith("--")) { + throw new Error(`Unexpected argument: ${key}`); + } + const name = key.slice(2).replaceAll("-", "_"); + const value = argv[index + 1]; + if (!value || value.startsWith("--")) { + throw new Error(`Missing value for ${key}`); + } + args[name] = value; + index += 1; + } + return args; +} + +function readJson(filePath) { + return JSON.parse(readFileSync(filePath, "utf8")); +} + +function copyArtifact({ outputDir, required = true, source, targetPath }) { + if (!source || !existsSync(source)) { + if (required) { + throw new Error(`Missing required artifact: ${source}`); + } + return false; + } + const target = path.join(outputDir, targetPath); + mkdirSync(path.dirname(target), { recursive: true }); + copyFileSync(source, target); + return true; +} + +function resolveSummaryArtifact(lane, key) { + const value = lane.summary.artifacts?.[key]; + return typeof value === "string" ? path.resolve(lane.repoRoot, value) : undefined; +} + +function loadLane({ outputDir, repoRoot, status }) { + const summaryPath = path.join(outputDir, "telegram-user-crabbox-session-summary.json"); + const summary = readJson(summaryPath); + return { + outputDir, + repoRoot, + status: status || summary.status || "unknown", + summary, + summaryPath, + }; +} + +function copyLaneArtifacts({ lane, laneName, outputDir }) { + const prefix = laneName; + const gif = + resolveSummaryArtifact(lane, "previewGifCropped") ?? resolveSummaryArtifact(lane, "previewGif"); + copyArtifact({ + outputDir, + source: gif, + targetPath: `${prefix}/telegram-desktop-proof.gif`, + }); + copyArtifact({ + outputDir, + required: false, + source: + resolveSummaryArtifact(lane, "trimmedVideoCropped") ?? + resolveSummaryArtifact(lane, "trimmedVideo"), + targetPath: `${prefix}/telegram-desktop-proof.mp4`, + }); + copyArtifact({ + outputDir, + required: false, + source: resolveSummaryArtifact(lane, "screenshot"), + targetPath: `${prefix}/telegram-desktop-proof.png`, + }); + copyArtifact({ + outputDir, + source: lane.summaryPath, + targetPath: `${prefix}/summary.json`, + }); + copyArtifact({ + outputDir, + required: false, + source: + typeof lane.summary.report === "string" + ? path.resolve(lane.repoRoot, lane.summary.report) + : undefined, + targetPath: `${prefix}/report.md`, + }); +} + +function laneStatus(lane) { + return lane.status === "pass" ? "pass" : "fail"; +} + +function laneArtifactEntries() { + return LANES.flatMap(({ altPrefix, label, lane }) => [ + { + alt: `${altPrefix} native Telegram Desktop proof GIF`, + inline: true, + kind: "motionPreview", + label, + lane, + path: `${lane}/telegram-desktop-proof.gif`, + targetPath: `${lane}/telegram-desktop-proof.gif`, + width: 520, + }, + { + kind: "motionClip", + label: `${label} MP4`, + lane, + path: `${lane}/telegram-desktop-proof.mp4`, + required: false, + targetPath: `${lane}/telegram-desktop-proof.mp4`, + }, + { + alt: `${altPrefix} native Telegram Desktop screenshot`, + inline: false, + kind: "desktopScreenshot", + label: `${label} screenshot`, + lane, + path: `${lane}/telegram-desktop-proof.png`, + required: false, + targetPath: `${lane}/telegram-desktop-proof.png`, + }, + { + kind: "metadata", + label: `${label} session summary`, + lane, + path: `${lane}/summary.json`, + targetPath: `${lane}/summary.json`, + }, + { + kind: "report", + label: `${label} session report`, + lane, + path: `${lane}/report.md`, + required: false, + targetPath: `${lane}/report.md`, + }, + ]); +} + +export function buildTelegramDesktopProofManifest({ + baseline, + baselineRef, + baselineSha, + candidate, + candidateRef, + candidateSha, + scenarioLabel, +}) { + const baselineStatus = laneStatus(baseline); + const candidateStatus = laneStatus(candidate); + const pass = baselineStatus === "pass" && candidateStatus === "pass"; + return { + schemaVersion: 1, + id: "telegram-desktop-proof", + title: "Mantis Telegram Desktop Proof", + summary: + "Mantis captured native Telegram Desktop before/after GIF evidence with Convex-leased Telegram credentials.", + scenario: scenarioLabel || "telegram-desktop-proof", + comparison: { + baseline: { + ...(baselineSha ? { sha: baselineSha } : {}), + ...(baselineRef ? { ref: baselineRef } : {}), + expected: "baseline visual proof captured", + status: baselineStatus, + }, + candidate: { + ...(candidateSha ? { sha: candidateSha } : {}), + ...(candidateRef ? { ref: candidateRef } : {}), + expected: "candidate visual proof captured", + status: candidateStatus, + fixed: candidateStatus === "pass", + }, + pass, + }, + artifacts: laneArtifactEntries(), + }; +} + +export function writeTelegramDesktopProofEvidence(rawArgs = process.argv.slice(2)) { + const args = parseArgs(rawArgs); + for (const key of [ + "baseline_output_dir", + "baseline_repo_root", + "candidate_output_dir", + "candidate_repo_root", + "output_dir", + ]) { + if (!args[key]) { + throw new Error(`Missing --${key.replaceAll("_", "-")}.`); + } + } + + const outputDir = path.resolve(args.output_dir); + mkdirSync(outputDir, { recursive: true }); + const baseline = loadLane({ + outputDir: path.resolve(args.baseline_output_dir), + repoRoot: path.resolve(args.baseline_repo_root), + status: args.baseline_status, + }); + const candidate = loadLane({ + outputDir: path.resolve(args.candidate_output_dir), + repoRoot: path.resolve(args.candidate_repo_root), + status: args.candidate_status, + }); + copyLaneArtifacts({ lane: baseline, laneName: "baseline", outputDir }); + copyLaneArtifacts({ lane: candidate, laneName: "candidate", outputDir }); + const manifest = buildTelegramDesktopProofManifest({ + baseline, + baselineRef: args.baseline_ref, + baselineSha: args.baseline_sha, + candidate, + candidateRef: args.candidate_ref, + candidateSha: args.candidate_sha, + scenarioLabel: args.scenario_label, + }); + const manifestPath = path.join(outputDir, "mantis-evidence.json"); + writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8"); + return { manifest, manifestPath }; +} + +const executedPath = process.argv[1] ? path.resolve(process.argv[1]) : ""; +if (executedPath === fileURLToPath(import.meta.url)) { + try { + writeTelegramDesktopProofEvidence(); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } +} diff --git a/scripts/test-projects.test-support.mjs b/scripts/test-projects.test-support.mjs index 0aa84f58b3f..4a0459d32d3 100644 --- a/scripts/test-projects.test-support.mjs +++ b/scripts/test-projects.test-support.mjs @@ -335,6 +335,10 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([ "scripts/mantis/build-telegram-evidence.mjs", ["test/scripts/mantis-build-telegram-evidence.test.ts"], ], + [ + "scripts/mantis/build-telegram-desktop-proof-evidence.mjs", + ["test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts"], + ], ["scripts/mantis/publish-pr-evidence.mjs", ["test/scripts/mantis-publish-pr-evidence.test.ts"]], [ "scripts/run-vitest.mjs", @@ -393,6 +397,10 @@ const TOOLING_TEST_TARGETS = new Map([ "test/scripts/mantis-build-telegram-evidence.test.ts", ["test/scripts/mantis-build-telegram-evidence.test.ts"], ], + [ + "test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts", + ["test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts"], + ], [ "test/scripts/plugin-prerelease-test-plan.test.ts", ["test/scripts/plugin-prerelease-test-plan.test.ts"], diff --git a/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts b/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts new file mode 100644 index 00000000000..86b2546d3c1 --- /dev/null +++ b/test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts @@ -0,0 +1,101 @@ +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; +import { writeTelegramDesktopProofEvidence } from "../../scripts/mantis/build-telegram-desktop-proof-evidence.mjs"; +import { + loadEvidenceManifest, + renderEvidenceComment, +} from "../../scripts/mantis/publish-pr-evidence.mjs"; + +const tempDirs: string[] = []; + +afterEach(() => { + for (const dir of tempDirs.splice(0)) { + rmSync(dir, { recursive: true, force: true }); + } +}); + +function makeLane(name: string) { + const repo = mkdtempSync(path.join(tmpdir(), `mantis-telegram-${name}-repo-`)); + tempDirs.push(repo); + const outputDir = path.join(repo, ".artifacts", "qa-e2e", name); + mkdirSync(outputDir, { recursive: true }); + const gif = path.join(outputDir, "telegram-user-crabbox-session-motion-telegram-window.gif"); + const mp4 = path.join(outputDir, "telegram-user-crabbox-session-motion-telegram-window.mp4"); + const screenshot = path.join(outputDir, "telegram-user-crabbox-session.png"); + const report = path.join(outputDir, "telegram-user-crabbox-session-report.md"); + writeFileSync(gif, `${name} gif`); + writeFileSync(mp4, `${name} mp4`); + writeFileSync(screenshot, `${name} png`); + writeFileSync(report, `${name} report`); + writeFileSync( + path.join(outputDir, "telegram-user-crabbox-session-summary.json"), + JSON.stringify({ + artifacts: { + previewGifCropped: path.relative(repo, gif), + screenshot: path.relative(repo, screenshot), + trimmedVideoCropped: path.relative(repo, mp4), + }, + report: path.relative(repo, report), + status: "pass", + }), + ); + return { outputDir, repo }; +} + +describe("scripts/mantis/build-telegram-desktop-proof-evidence", () => { + it("builds paired native Telegram Desktop GIF evidence for PR comments", () => { + const baseline = makeLane("baseline"); + const candidate = makeLane("candidate"); + const outputDir = mkdtempSync(path.join(tmpdir(), "mantis-telegram-proof-")); + tempDirs.push(outputDir); + + const result = writeTelegramDesktopProofEvidence([ + "--output-dir", + outputDir, + "--baseline-repo-root", + baseline.repo, + "--baseline-output-dir", + baseline.outputDir, + "--baseline-ref", + "main", + "--baseline-sha", + "aaa", + "--candidate-repo-root", + candidate.repo, + "--candidate-output-dir", + candidate.outputDir, + "--candidate-ref", + "refs/pull/1/head", + "--candidate-sha", + "bbb", + "--scenario-label", + "telegram-desktop-proof", + ]); + + expect( + readFileSync(path.join(outputDir, "baseline", "telegram-desktop-proof.gif"), "utf8"), + ).toBe("baseline gif"); + const manifest = loadEvidenceManifest(result.manifestPath); + expect(manifest.comparison.pass).toBe(true); + expect(manifest.artifacts.map((artifact) => artifact.targetPath)).toContain( + "candidate/telegram-desktop-proof.gif", + ); + const body = renderEvidenceComment({ + artifactRoot: "mantis/telegram-desktop/pr-1/run-1", + manifest, + marker: "", + rawBase: + "https://raw.githubusercontent.com/openclaw/openclaw/qa-artifacts/mantis/telegram-desktop/pr-1/run-1", + requestSource: "workflow_dispatch", + runUrl: "https://github.com/openclaw/openclaw/actions/runs/1", + treeUrl: + "https://github.com/openclaw/openclaw/tree/qa-artifacts/mantis/telegram-desktop/pr-1/run-1", + }); + + expect(body).toContain("| Main | This PR |"); + expect(body).toContain("baseline/telegram-desktop-proof.gif"); + expect(body).toContain("candidate/telegram-desktop-proof.gif"); + }); +});