meta { name: GET contracts after encounter clear type: http seq: 3 } docs { NEO-151 AC: issue prototype contract, clear prototype_combat_pocket via three-NPC defeat spine, GET contracts shows completed row with completionRewardSummary. } script:pre-request { const axios = require("axios"); const { resetAllContractInstances } = require("./scripts/reset-contract-instances-helper.js"); const { resetPrototypeCombatTargets } = require("./scripts/combat-targets-reset-helper.js"); const { moveNearPrototypeNpc, PULSE_COOLDOWN_MS, MAX_PULSE_DEFEAT_ATTEMPTS, sleep, } = require("./scripts/prototype-npc-bruno-helper.js"); const baseUrl = bru.getEnvVar("baseUrl") || bru.getVar("baseUrl"); const playerId = bru.getEnvVar("playerId") || bru.getVar("playerId"); const jsonHeaders = { headers: { "Content-Type": "application/json" } }; const slotIndex = 3; async function defeatNpc(targetId) { await moveNearPrototypeNpc(baseUrl, playerId, targetId, jsonHeaders); await axios.post( `${baseUrl}/game/players/${playerId}/target/select`, { schemaVersion: 1, targetId }, jsonHeaders, ); await sleep(bru, PULSE_COOLDOWN_MS); const castBody = { schemaVersion: 1, slotIndex, abilityId: "prototype_pulse", targetId, }; for (let i = 0; i < MAX_PULSE_DEFEAT_ATTEMPTS; i++) { const response = await axios.post( `${baseUrl}/game/players/${playerId}/ability-cast`, castBody, jsonHeaders, ); const body = response.data; if (!body?.accepted || !body?.combatResolution) { throw new Error( `cast ${i + 1} vs ${targetId} failed (${body?.reasonCode ?? "no_reason"}): ${JSON.stringify(body)}`, ); } if (body.combatResolution.targetDefeated) { return; } if (i < MAX_PULSE_DEFEAT_ATTEMPTS - 1) { await sleep(bru, PULSE_COOLDOWN_MS); } } throw new Error( `did not defeat ${targetId} within ${MAX_PULSE_DEFEAT_ATTEMPTS} pulses`, ); } await resetAllContractInstances(bru); await resetPrototypeCombatTargets(bru); const issueResponse = await axios.post( `${baseUrl}/game/players/${playerId}/contracts/issue`, { schemaVersion: 1, playerId, templateId: "prototype_contract_clear_combat_pocket", seedBucket: "2026-06-28-neo151-bruno-clear", }, jsonHeaders, ); if (issueResponse.status !== 200 || !issueResponse.data?.issued) { throw new Error(`contract issue failed: ${JSON.stringify(issueResponse.data)}`); } bru.setVar("neo151ContractInstanceId", issueResponse.data.contract.contractInstanceId); await axios.post( `${baseUrl}/game/players/${playerId}/hotbar-loadout`, { schemaVersion: 1, slots: [{ slotIndex, abilityId: "prototype_pulse" }], }, jsonHeaders, ); await defeatNpc("prototype_npc_melee"); await defeatNpc("prototype_npc_ranged"); await defeatNpc("prototype_npc_elite"); } get { url: {{baseUrl}}/game/players/{{playerId}}/contracts body: none auth: none } script:post-response { const axios = require("axios"); const baseUrl = bru.getEnvVar("baseUrl") || bru.getVar("baseUrl"); const playerId = bru.getEnvVar("playerId") || bru.getVar("playerId"); const second = await axios.get(`${baseUrl}/game/players/${playerId}/contracts`); bru.setVar("neo151SecondContractsGetJson", JSON.stringify(second.data)); } tests { test("completed contract row includes delivery summary", function () { expect(res.getStatus()).to.equal(200); const body = res.getBody(); expect(body.schemaVersion).to.equal(1); const instanceId = bru.getVar("neo151ContractInstanceId"); const row = body.contracts.find((x) => x.contractInstanceId === instanceId); expect(row).to.be.an("object"); expect(row.status).to.equal("completed"); expect(row.encounterTemplateId).to.equal("prototype_combat_pocket"); expect(row.completedAt).to.be.a("string"); expect(row.completionRewardSummary).to.eql({ itemGrants: [{ itemId: "scrap_metal_bulk", quantity: 5 }], skillXpGrants: [{ skillId: "salvage", amount: 15 }], reputationGrants: [], }); }); test("second GET completionRewardSummary matches first GET", function () { const first = res.getBody(); const second = JSON.parse(bru.getVar("neo151SecondContractsGetJson")); const instanceId = bru.getVar("neo151ContractInstanceId"); const firstRow = first.contracts.find((x) => x.contractInstanceId === instanceId); const secondRow = second.contracts.find((x) => x.contractInstanceId === instanceId); expect(secondRow.completionRewardSummary).to.eql(firstRow.completionRewardSummary); }); }