-
Notifications
You must be signed in to change notification settings - Fork 0
Integration Testing
yuzhe edited this page Mar 12, 2026
·
1 revision
RedScript ships with an integration test suite that compiles scripts and runs them against a real Paper 1.21.4 Minecraft server, then asserts behavior via HTTP API.
RedScript Test Suite (Jest + TypeScript)
↕ HTTP (port 25561)
redscript-testharness (Paper plugin)
↕ Bukkit API
Paper 1.21.4 Server
(void superflat world)
# macOS
brew install openjdk@21
export JAVA_HOME=/opt/homebrew/opt/openjdk@21mkdir ~/mc-test-server && cd ~/mc-test-server
curl -L "https://api.papermc.io/v2/projects/paper/versions/1.21.4/builds/232/downloads/paper-1.21.4-232.jar" -o paper.jar
echo "eula=true" > eula.txtserver.properties:
online-mode=false
gamemode=creative
spawn-protection=0
difficulty=peaceful
spawn-monsters=false
level-type=flat
generator-settings={"biome":"minecraft:the_void","layers":[{"block":"minecraft:air","height":1}],"structures":{"structures":{}}}git clone https://github.com/bkmashiro/redscript-testharness
cd redscript-testharness
JAVA_HOME=/opt/homebrew/opt/openjdk@21 gradle jar
cp build/libs/redscript-testharness-1.0.0.jar ~/mc-test-server/plugins/cd ~/mc-test-server
java -Xmx1G -jar paper.jar --nogui
# Wait for: [RedScriptTestHarness] TestHarness HTTP API started on port 25561MC_SERVER_DIR=~/mc-test-server npx jest mc-integration --testTimeout=120000 MC Integration Tests
✓ server is online and healthy
✓ counter.rs: tick function increments scoreboard over time
✓ world_manager.rs: setblock places correct block
✓ world_manager.rs: fill creates smooth_stone floor
✓ scoreboard arithmetic works via commands
✓ scoreboard proxy test
✓ inline rs: if/else logic executes correctly
✓ entity query: armor_stands survive peaceful mode
✓ @tick: tick_test increments counter every tick
✓ fullReset clears previously placed blocks
E2E Scenario Tests
✓ A: game_loop timer countdown sets ended=1 after N ticks
✓ B: calc_sum + calc_product — no temp var collision
✓ C: 3-deep call chain preserves intermediate state (10→15→30)
✓ D: fill optimizer — 4 adjacent setblocks all placed correctly
Tests: 14 passed, 14 total
import { MCTestClient } from './src/mc-test/client'
const mc = new MCTestClient('localhost', 25561)
await mc.isOnline() // → boolean
await mc.status() // → { tps, players, version }
await mc.command('/function ns:load') // run MC command
await mc.ticks(20) // wait N real server ticks
await mc.reload() // safe Bukkit.reloadData()
// Assertions (throw on failure)
await mc.assertScore('player', 'obj', 42)
await mc.assertBlock(4, 65, 4, 'minecraft:gold_block')
await mc.assertChatContains('Game started!')
// Queries
await mc.scoreboard('player', 'obj') // → number
await mc.block(x, y, z) // → { type, blockData }
await mc.entities('@e[type=armor_stand]') // → Entity[]
await mc.chat(since?) // → ChatEntry[]
// Reset
await mc.fullReset() // clear area + kill entities + reset scoreboards
await mc.fullReset({ x1: 0, y1: 60, z1: 0, x2: 20, y2: 80, z2: 20 })- No terrain →
setblock/fillresults fully predictable - No random mob spawns → entity queries deterministic
- Fast world generation
-
fullReset()can restore pristine state between tests
-
Bukkit.reloadData()is used instead of/reload confirm— the latter can crash Paper with plugins loaded - All chunks in the test area are force-loaded on each reset (void worlds don't load chunks without players)
- Multiple namespaces share one datapack directory;
tick.json/load.jsonare merged, not overwritten