the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 120 lines 3.6 kB view raw
1import { vi, describe, it, expect, beforeEach } from "vitest"; 2import consola from "consola"; 3import { Sandbox } from "@pocketenv/sdk"; 4import copy from "./copy"; 5 6vi.mock("../lib/sdk", () => ({ configureSdk: vi.fn() })); 7vi.mock("../theme", () => ({ 8 c: { 9 primary: (s: string | number) => String(s), 10 }, 11})); 12vi.mock("consola", () => ({ 13 default: { log: vi.fn(), success: vi.fn(), error: vi.fn() }, 14})); 15vi.mock("@pocketenv/sdk", () => ({ 16 Sandbox: { get: vi.fn(), configure: vi.fn() }, 17})); 18vi.mock("ora", () => ({ 19 default: vi.fn(() => ({ 20 start: vi.fn().mockReturnThis(), 21 stop: vi.fn(), 22 stopAndPersist: vi.fn(), 23 })), 24})); 25 26describe("copy", () => { 27 const mockExit = vi 28 .spyOn(process, "exit") 29 .mockImplementation(() => undefined as never); 30 31 beforeEach(() => { 32 vi.clearAllMocks(); 33 }); 34 35 it("copies from local to sandbox", async () => { 36 const mockSandbox = { 37 data: { status: "RUNNING" }, 38 copy: { upload: vi.fn().mockResolvedValue(undefined) }, 39 }; 40 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any); 41 42 await copy("./local/file.txt", "my-sandbox:/remote/file.txt"); 43 44 expect(Sandbox.get).toHaveBeenCalledWith("my-sandbox"); 45 expect(mockSandbox.copy.upload).toHaveBeenCalledWith( 46 "./local/file.txt", 47 "/remote/file.txt", 48 expect.objectContaining({ signal: expect.any(AbortSignal) }), 49 ); 50 }); 51 52 it("copies from sandbox to local", async () => { 53 const mockSandbox = { 54 data: { status: "RUNNING" }, 55 copy: { download: vi.fn().mockResolvedValue(undefined) }, 56 }; 57 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any); 58 59 await copy("my-sandbox:/remote/file.txt", "./local/file.txt"); 60 61 expect(mockSandbox.copy.download).toHaveBeenCalledWith( 62 "/remote/file.txt", 63 "./local/file.txt", 64 expect.objectContaining({ signal: expect.any(AbortSignal) }), 65 ); 66 }); 67 68 it("copies between two sandboxes", async () => { 69 const mockSourceSandbox = { 70 data: { status: "RUNNING" }, 71 copy: { to: vi.fn().mockResolvedValue(undefined) }, 72 }; 73 const mockDestSandbox = { data: { status: "RUNNING" } }; 74 vi.mocked(Sandbox.get) 75 .mockResolvedValueOnce(mockSourceSandbox as any) 76 .mockResolvedValueOnce(mockDestSandbox as any); 77 78 await copy("src-sandbox:/src/file.txt", "dst-sandbox:/dst/file.txt"); 79 80 expect(mockSourceSandbox.copy.to).toHaveBeenCalledWith( 81 "dst-sandbox", 82 "/src/file.txt", 83 "/dst/file.txt", 84 expect.objectContaining({ signal: expect.any(AbortSignal) }), 85 ); 86 }); 87 88 it("exits with error when source and destination are both local", async () => { 89 await copy("./local/src.txt", "./local/dst.txt"); 90 91 expect(consola.error).toHaveBeenCalledWith( 92 "Both source and destination cannot be local paths.", 93 ); 94 expect(mockExit).toHaveBeenCalledWith(1); 95 }); 96 97 it("exits with error when source equals destination", async () => { 98 await copy("same-path", "same-path"); 99 100 expect(consola.error).toHaveBeenCalledWith( 101 "Source and destination cannot be the same.", 102 ); 103 expect(mockExit).toHaveBeenCalledWith(1); 104 }); 105 106 it("exits with error when sandbox is not running", async () => { 107 const mockSandbox = { 108 data: { status: "STOPPED" }, 109 copy: { upload: vi.fn() }, 110 }; 111 vi.mocked(Sandbox.get).mockResolvedValue(mockSandbox as any); 112 113 await copy("./local/file.txt", "my-sandbox:/remote/file.txt"); 114 115 expect(consola.error).toHaveBeenCalledWith( 116 expect.stringContaining("not running"), 117 ); 118 expect(mockExit).toHaveBeenCalledWith(1); 119 }); 120});