the universal sandbox runtime for agents and humans.
pocketenv.io
sandbox
openclaw
agent
claude-code
vercel-sandbox
deno-sandbox
cloudflare-sandbox
atproto
sprites
daytona
1import { vi, describe, it, expect, beforeEach } from "vitest";
2import consola from "consola";
3import { Sandbox } from "@pocketenv/sdk";
4import { exec } from "./exec";
5
6vi.mock("../lib/sdk", () => ({ configureSdk: vi.fn() }));
7vi.mock("consola", () => ({
8 default: { log: vi.fn(), success: vi.fn(), error: vi.fn() },
9}));
10vi.mock("@pocketenv/sdk", () => ({
11 Sandbox: { get: vi.fn(), configure: vi.fn() },
12}));
13
14describe("exec", () => {
15 const mockExit = vi
16 .spyOn(process, "exit")
17 .mockImplementation(() => undefined as never);
18
19 let mockStdoutWrite: ReturnType<typeof vi.spyOn>;
20 let mockStderrWrite: ReturnType<typeof vi.spyOn>;
21
22 beforeEach(() => {
23 vi.clearAllMocks();
24 mockStdoutWrite = vi
25 .spyOn(process.stdout, "write")
26 .mockImplementation(() => true);
27 mockStderrWrite = vi
28 .spyOn(process.stderr, "write")
29 .mockImplementation(() => true);
30 });
31
32 it("writes stdout and exits with 0 on success", async () => {
33 const mockSandbox = {
34 exec: vi.fn().mockResolvedValue({
35 stdout: "hello world\n",
36 stderr: "",
37 exitCode: 0,
38 }),
39 };
40 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any);
41
42 await exec("my-sandbox", ["echo", "hello world"]);
43
44 expect(mockSandbox.exec).toHaveBeenCalledWith("echo hello world");
45 expect(mockStdoutWrite).toHaveBeenCalledWith("hello world\n");
46 expect(mockStderrWrite).not.toHaveBeenCalled();
47 expect(mockExit).toHaveBeenCalledWith(0);
48 });
49
50 it("writes stderr and exits with non-zero code on failure", async () => {
51 const mockSandbox = {
52 exec: vi.fn().mockResolvedValue({
53 stdout: "",
54 stderr: "command not found",
55 exitCode: 127,
56 }),
57 };
58 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any);
59
60 await exec("my-sandbox", ["badcmd"]);
61
62 expect(mockStderrWrite).toHaveBeenCalledWith("command not found\n");
63 expect(consola.error).toHaveBeenCalledWith(
64 "Command exited with code 127",
65 );
66 expect(mockExit).toHaveBeenCalledWith(127);
67 });
68
69 it("appends newline to stdout when missing", async () => {
70 const mockSandbox = {
71 exec: vi.fn().mockResolvedValue({
72 stdout: "output without newline",
73 stderr: "",
74 exitCode: 0,
75 }),
76 };
77 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any);
78
79 await exec("my-sandbox", ["cmd"]);
80
81 expect(mockStdoutWrite).toHaveBeenCalledWith("output without newline\n");
82 });
83
84 it("logs error when execution fails", async () => {
85 vi.mocked(Sandbox.get).mockRejectedValue(new Error("API error"));
86
87 await exec("my-sandbox", ["cmd"]);
88
89 expect(consola.error).toHaveBeenCalledWith(
90 "Failed to execute command:",
91 expect.any(Error),
92 );
93 });
94});