Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Testing

Running tests locally

osy test [path] [--filter <text>] [--test <id>] [--pixels] [--headed] [--json]

Runs your app's tests against a Platform on your own machine — no account, no network, no setup beyond a running local platform. `osyrin dev` starts that platform; `osy test` runs your tests against it.

stable2 examples compiled by CItestingauthoringclilocal

Summary#

Runs your app's tests against a Platform running on your own machine — no account, no network, no cloud. It is the local counterpart of Running tests: the same tests, the same throwaway-copy isolation, the same streamed report. The only difference is where it runs.

Signature#

osy test [path] [--filter <text>] [--test <id>] [--pixels] [--headed] [--json]

Description#

Start a local platform, then test against it#

A local platform is a full Platform that runs on your machine, with a database it manages itself. Start one from your project directory:

osyrin dev

The first start downloads a small database bundle once; after that it is up in seconds. It binds to your machine only — nothing outside can reach it — and it needs no account and no cloud project. Leave it running in a terminal.

In another terminal, run your tests against it:

osy test

That is the whole loop: edit your source, osy test, watch it turn green. There is nothing to log into and nothing to deploy — osy test finds the running local platform for your project on its own, ensures your app exists there, compiles the source on your disk into it, and runs your tests.

--pixels — the same tests, in a real browser#

osy test renders your pages in a headless DOM with no font engine and no compositor. That is what makes it fast enough to run on every change, and it means the run is blind to layout: a control is "visible" whether it is on its card, off it, or underneath something else.

osy test --pixels runs the same tests in a real browser instead. Nothing about your test file changes — the same locators, the same refusals — but the geometric claims in Layout assertions — is it actually usable on screen? are actually judged, and Ui.Shot("label") writes a PNG you can open.

osy test                     # behaviour, in seconds
osy test --pixels            # the same tests, with layout checked and screenshots written
osy test --pixels --headed   # …and show the browser, slowed down, so you can watch it drive

It is opt-in because it costs a browser: the tier needs Playwright and a Chromium, or the Chrome already on your machine, which it prefers. The check runs before anything is compiled or booted, so a machine that cannot run it is told in a second — with the command that fixes it — rather than a minute into a run.

The tests run exactly as they would anywhere#

Local is not a weaker mode. Your app's own security is enforced just as it is in production: a [Test] runs as an anonymous, secured caller, so a test that creates or reads data needs your model to grant it — a plain new app is secure by default. This is the same behavior described in Running tests; the point of running locally is speed and privacy, never a relaxed rulebook. The starter model a new project ships with grants exactly what its first test needs and nothing more.

Everything else is identical to a remote run: each [TestFixture] seeds its own private branch, each [Test] forks its own throwaway clone, results stream back one at a time, and nothing a test writes survives it. See Running tests for the full model.

Choosing what to run#

The same two ways as a remote run:

  • --filter <text> runs the tests whose names contain text.
  • --test <id> runs exactly one test, named by its id (file::fixture::name). Repeat the flag for several.

A fixture is never filtered away, and a [Skip("reason")] test is always reported and never runs.

Scripting a run#

--json writes one JSON object per line, in the order events happen, so a script can react to each test as it lands. The command exits non-zero when any test fails or errors, and diagnostics go to standard error — standard output stays a clean stream of events. The event shape is the same as a remote run.

When there is no local platform#

If no local platform is running for your project, osy test says so and stops, rather than silently reaching elsewhere:

No local platform is running for this project. Start one with `osyrin dev`.

Run osyrin dev and try again.

Examples#

The two-terminal loop — one platform, many test runs:

# terminal 1
osyrin dev

# terminal 2
osy test
osy test --filter Totals
osy test --test "tests/orders.test.osy::Seeded::Totals_Add_Up"

A first test in a freshly scaffolded project, which passes because the starter model grants it:

// model/note.osy
entity Note {
  [Required] string Title;
  security { allow read, create when IsAuthenticated || IsAnonymous; }
}
// tests/note.test.osy
[Test]
void a_new_note_keeps_its_title() {
  var note = new Note { Title = "First note" };
  Assert.Equal("First note", note.Title);
}

See also#

Running tests — the same run against a remote platform, and the full description of fixtures, isolation, and the streamed report.

Debugging tests locally — debug a single test locally with breakpoints and stepping in your editor.

Running a local platform — the local platform these tests run against, and how to start it.

Related

Layout assertions — is it actually usable on screen?

Every other assertion is about TEXT or STATE, and all of them pass on a screen that is visually broken: a control can…

Running tests

Runs your app's tests against a throwaway copy of its database, reporting each test as it finishes. Your local source…

Debugging tests locally

Debugs one of your app's tests against a Platform on your own machine — breakpoints, stepping, and variable inspection…

Running a local platform

Runs a full platform on your own machine — its own database, no account, no cloud, reachable only from your computer…