Skip to content
Sandbox SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Testing with memory()

Test code that uses sandboxes without Docker or cloud keys. memory() is an in-process fake with files, scripted commands, processes, and fake preview URLs.

Your tests shouldn’t start real machines. memory() is a provider that runs entirely inside your test process. It keeps files in a map, answers commands from a table of handlers you write, and returns fake preview URLs. It never touches the network.

Write your code against createSandbox(provider) and pass memory() in tests and a real provider in production.

Code under test

import type { Sandbox } from "@opencoredev/sandbox-sdk";

export async function scaffold(box: Sandbox, name: string) {
  await box.files.write(`${name}/package.json`, JSON.stringify({ name, private: true }));
  const install = await box.run("npm install", { cwd: name });
  if (!install.ok) throw new Error(`install failed: ${install.output}`);
  return box.files.list(name);
}

scaffold takes any sandbox, so the test decides where it runs.

Write the test

import { expect, test } from "vitest";
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { memory } from "@opencoredev/sandbox-sdk/memory";
import { scaffold } from "./scaffold";

test("scaffold writes package.json and installs", async () => {
  const provider = memory({
    handlers: {
      npm: async ({ args, stdout }) => {
        stdout(`npm ${args.join(" ")}: ok\n`);
        return 0;
      },
    },
  });

  await using box = await createSandbox(provider);
  const files = await scaffold(box, "app");

  expect(files.map((f) => f.path)).toContain("/workspace/app/package.json");
});

The test runs in milliseconds and needs no Docker or API keys.

Script commands

memory() understands a small shell subset, such as cd, export, and &&, plus the handlers you register. A handler is keyed by program name, receives the parsed command, and returns an exit code.

import { createSandbox } from "@opencoredev/sandbox-sdk";
import { memory } from "@opencoredev/sandbox-sdk/memory";

const provider = memory({
  handlers: {
    node: async ({ args, files, stdout, stderr }) => {
      if (args[0] !== "build.mjs") {
        stderr("unexpected script\n");
        return 1;
      }
      await files.write("/workspace/dist/index.html", "<h1>built</h1>");
      stdout("built\n");
      return 0;
    },
  },
});

await using box = await createSandbox(provider);
const result = await box.run("node build.mjs");
console.log(result.ok, await box.files.read("dist/index.html"));

Each handler gets args, cwd, env, stdin, a signal, stdout and stderr writers, and files to read and write the fake file system. You can also add handlers after creation with provider.register(name, handler).

Processes and previews

box.start works with handlers too. A handler that keeps running until its signal aborts behaves like a long-running server, and stop() aborts that signal. box.preview(port) returns a URL on the memory.invalid host. It is there so you can assert on it. Don’t fetch it: the host never resolves, so a test that tries fails instead of reaching the internet.

What memory() does not do

  • No real shell. Pipes, globs, variable assignments, and programs without a handler are not available.
  • No git. box.git needs a real provider. files.mark() and files.changes() do work, from in-memory copies of the files.
  • No terminals, no real sockets, and no pause or snapshots.

For those, run the same test against local() in CI. It needs Docker but no cloud keys.

Check a custom provider

If you write your own provider adapter, runConformance from @opencoredev/sandbox-sdk/testing runs the same suite every built-in provider passes. It covers create and find by key, commands, $ escaping, processes, files, git, previews, and cleanup.

import { runConformance } from "@opencoredev/sandbox-sdk/testing";
import { myProvider } from "./my-provider";

runConformance(() => myProvider(), { live: true });

live: true is required for every provider except memory() and local(); without it the suite refuses to run. Custom providers covers timeouts and how to skip checks your runtime can’t pass.

Was this page helpful?