meta { name: POST ability cast happy (NEO-30 cast accept path) type: http seq: 22 } script:pre-request { const { resetPrototypeCombatTargets } = require("./scripts/combat-targets-reset-helper"); await resetPrototypeCombatTargets(bru); const axios = require("axios"); const baseUrl = bru.getEnvVar("baseUrl") || bru.getVar("baseUrl"); const playerId = bru.getEnvVar("playerId") || bru.getVar("playerId"); const jsonHeaders = { headers: { "Content-Type": "application/json" } }; await axios.post( `${baseUrl}/game/players/${playerId}/move`, { schemaVersion: 1, target: { x: 5, y: 0.9, z: 5 } }, jsonHeaders, ); await axios.post( `${baseUrl}/game/players/${playerId}/hotbar-loadout`, { schemaVersion: 1, slots: [{ slotIndex: 0, abilityId: "prototype_pulse" }], }, jsonHeaders, ); await axios.post( `${baseUrl}/game/players/${playerId}/target/select`, { schemaVersion: 1, targetId: "prototype_npc_ranged" }, jsonHeaders, ); } post { url: {{baseUrl}}/game/players/dev-local-1/ability-cast body: json auth: none } body:json { { "schemaVersion": 1, "slotIndex": 0, "abilityId": "prototype_pulse", "targetId": "prototype_npc_ranged" } } tests { test("status 200", function () { // NEO-30 review follow-up: cast JSON contract unchanged (server comments only). // Optional: NEON_SPRAWL_API_LOG=1 on server prints ability_cast_requested for accepted JSON. expect(res.getStatus()).to.equal(200); }); test("accepted true with combat resolution", function () { const body = res.getBody(); expect(body.schemaVersion).to.equal(1); expect(body.accepted).to.equal(true); expect(body.combatResolution).to.be.an("object"); expect(body.combatResolution.abilityId).to.equal("prototype_pulse"); expect(body.combatResolution.targetId).to.equal("prototype_npc_ranged"); expect(body.combatResolution.damageDealt).to.equal(25); expect(body.combatResolution.targetRemainingHp).to.equal(55); expect(body.combatResolution.targetDefeated).to.equal(false); }); }