What flow tests are, why they matter, and how tick-waiting enables multi-step integration testing.
Flow tests are multi-step integration tests that exercise a complete gameplay sequence across multiple server ticks. They are the closest thing to “playing through a scenario” that you can automate in HRTK.
A flow test simulates a sequence of game events and verifies the outcome at each stage. For example:
Spawn an entity in the world
Wait for ECS processors to initialize it
Apply damage to trigger combat logic
Wait for the entity to die
Verify loot drops
Each step may require one or more server ticks to take effect. Flow tests use waitTicks() and awaitCondition() to synchronize with the server’s tick loop.
Hytale’s game loop processes everything in discrete ticks. When you call ctx.spawnEntity(), the entity is created in the command buffer but ECS processors have not run yet. Components like health, stats, transform, and effects are initialized by processors that run on subsequent ticks.Without tick waiting:
@FlowTest(timeoutTicks = 200)void myFlowTest(WorldTestContext ctx) { // 1. SETUP -- spawn entities, place blocks Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0); ctx.waitTicks(1); // 2. ACTION -- trigger the behavior you're testing triggerAction(ctx, entity); // 3. WAIT -- let the server process the action ctx.waitTicks(5); // 4. ASSERT -- verify the expected outcome HytaleAssert.assertTrue(expectedResult(ctx, entity)); // 5. (Optional) SECONDARY ACTION + ASSERT triggerSecondAction(ctx, entity); ctx.waitTicks(3); HytaleAssert.assertTrue(secondExpectedResult(ctx, entity));}
Use awaitCondition() instead of fixed waitTicks() when you do not know exactly how many ticks an action will take. It polls every tick and returns as soon as the condition is met, making your tests both faster and more reliable.
Flow tests almost always mutate world state. Use IsolationStrategy.DEDICATED_WORLD:
@HytaleSuite(value = "Combat Flows", isolation = IsolationStrategy.DEDICATED_WORLD)@Tag("flow")public class CombatFlows { // All flow tests run in a temporary void world}