sandstone-test
v0.0.1
Published
In-game automated test harness for Sandstone datapacks
Maintainers
Readme
sandstone-test
An in-game automated test harness for Sandstone datapacks. Assertions run live in Minecraft with colored PASS/FAIL chat output, a running score-backed tally, not build-time TypeScript checks.

Install
bun add sandstone-testSetup
Set SKIP_TESTS=1 (however your project reads env vars) to skip compiling every test suite entirely (e.g. for a build that shouldn't ship test scaffolding)
This library has no opinion on your test players: asPlayer(name, callback) takes any real, currently-online username, however many you need and however you want to source them (an env var, a hardcoded constant, whatever fits your project).
Usage
import {
asPlayer, assertThat, defineTestSuite, runAllTests,
} from 'sandstone-test'
import { someOperation, SomeState } from './my-library'
const PLAYER_A = Bun.env.MY_TEST_PLAYER_A ?? 'LilSpartan904'
defineTestSuite('my-library', () => {
asPlayer(PLAYER_A, () => someOperation())
assertThat('someOperation sets the expected state', SomeState(PLAYER_A).equalTo(1))
})
// once, anywhere in your entry point
runAllTests('core')This registers /function my-library:test (runs just that suite) and /function core:test (runs every suite registered with defineTestSuite, in registration order, plus a combined grand total).
API
defineTestSuite(namespace, body)- wrapsbodyas<namespace>:testand registers it withrunAllTests.runAllTests(namespace)- creates<namespace>:test, which runs every registered suite and reports a combined grand total. Call once. Pick anamespaceno individualdefineTestSuitecall also uses - both create<namespace>:test, so reusing the same name collides.assertThat(label, condition)- tellraws a colored PASS/FAIL line and tallies it into the current suite's running total (and the grand total).asPlayer(name, callback)-execute.as(name).run(callback), for acting as a real player by username. A username works directly as an entity target, noSelector()wrapping needed.
A note on relative assertions
Prefer relative assertions over hardcoded literals when state persists across runs, e.g. SomeId(A).greaterThan(0) and SomePending(B).equalTo(SomeId(A)) rather than SomeId(A).equalTo(1) - an ever-incrementing id counter (or similar) means exact values drift between runs, but relationships between them usually don't.
Developing this library
bun run setup # install + link the library into test/
bun dev:build # build the library (outputs to lib/)
bun dev:watch # watch mode - rebuilds library and test project on changes
bun dev:test-build # dry-build the test datapack, verbose output
bun test # run snapshot tests