#!/usr/bin/env bun import { spawn } from "node:child_process" import path from "node:path" const args = process.argv.slice(2) const filter = args[0] // e.g., "typescript", "python", "integrations", or specific file const TESTS_DIR = path.join(import.meta.dir, "tests") interface TestFile { name: string path: string type: "ts" | "py" } export function getPythonExecutable( platform = process.platform, baseDir = import.meta.dir, ): string { return platform === "win32" ? path.join(baseDir, ".venv", "Scripts", "python.exe") : path.join(baseDir, ".venv", "bin", "python3") } function getTests(): TestFile[] { const tests: TestFile[] = [] // TypeScript tests const tsTests = ["quickstart", "sdk", "search", "user-profiles"] for (const t of tsTests) { tests.push({ name: `typescript/${t}`, path: path.join(TESTS_DIR, "typescript", `${t}.ts`), type: "ts", }) } // Python tests const pyTests = ["quickstart", "sdk", "search", "user_profiles"] for (const t of pyTests) { tests.push({ name: `python/${t}`, path: path.join(TESTS_DIR, "python", `${t}.py`), type: "py", }) } // Integration tests const intTests = [ { name: "ai-sdk", type: "ts" as const }, { name: "openai-sdk", type: "ts" as const }, { name: "openai-sdk", type: "py" as const }, { name: "claude-memory", type: "ts" as const }, ] for (const t of intTests) { tests.push({ name: `integrations/${t.name}`, path: path.join( TESTS_DIR, "integrations", `${t.name}.${t.type === "ts" ? "ts" : "py"}`, ), type: t.type, }) } return tests } async function runTest(test: TestFile): Promise { return new Promise((resolve) => { console.log(`\n${"=".repeat(60)}`) console.log(`Running: ${test.name}`) console.log("=".repeat(60)) const cmd = test.type === "ts" ? "bun" : getPythonExecutable() const proc = spawn(cmd, [test.path], { stdio: "inherit", env: { ...process.env }, }) proc.once("error", (error) => { console.error(`Failed to start ${test.name}: ${error.message}`) if (test.type === "py" && "code" in error && error.code === "ENOENT") { console.error(`Expected Python executable at: ${cmd}`) console.error( 'Create it with "python -m venv .venv" and install requirements.txt.', ) } resolve(false) }) proc.once("close", (code) => { resolve(code === 0) }) }) } async function main() { console.log("Supermemory Docs Test Runner") console.log("============================\n") let tests = getTests() // Filter tests if specified if (filter) { tests = tests.filter( (t) => t.name.includes(filter) || t.type === filter.replace(".", ""), ) } if (tests.length === 0) { console.log("No tests matched the filter:", filter) console.log("\nAvailable tests:") getTests().forEach((t) => { console.log(` - ${t.name} (${t.type})`) }) process.exit(1) } console.log(`Running ${tests.length} test(s)...\n`) const results: { test: string; passed: boolean }[] = [] for (const test of tests) { const passed = await runTest(test) results.push({ test: test.name, passed }) } // Summary console.log(`\n${"=".repeat(60)}`) console.log("SUMMARY") console.log("=".repeat(60)) const passed = results.filter((r) => r.passed).length const failed = results.filter((r) => !r.passed).length for (const r of results) { console.log(`${r.passed ? "✅" : "❌"} ${r.test}`) } console.log(`\nTotal: ${passed} passed, ${failed} failed`) if (failed > 0) { process.exit(1) } } if (import.meta.main) { main().catch((error) => { console.error(error) process.exitCode = 1 }) }