Add integration and model tests for BreakEscape game mechanics

- Implement RoomLazyLoadTest to verify room data retrieval and error handling for non-existent rooms.
- Create FilteredScenarioTest to ensure scenario data is filtered correctly for game initialization, preserving navigation structure while removing unnecessary details like objects and NPCs.
- Add tests for lock requirements and ensure original scenario data remains unmodified after filtering.
This commit is contained in:
Z. Cliffe Schreuders
2025-11-21 15:27:54 +00:00
parent 6e65b9030d
commit c2fadcd169
8 changed files with 863 additions and 2 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,76 @@
require 'test_helper'
module BreakEscape
class RoomLazyLoadTest < ActionDispatch::IntegrationTest
include Engine.routes.url_helpers
setup do
@mission = break_escape_missions(:ceo_exfil)
@player = break_escape_demo_users(:test_user)
@game = Game.create!(
mission: @mission,
player: @player,
scenario_data: {
"startRoom" => "test_room",
"rooms" => {
"test_room" => {
"type" => "office",
"objects" => [],
"connections" => {}
},
"test_room_2" => {
"type" => "office",
"objects" => [],
"connections" => {}
}
}
}
)
end
test 'should return room data for valid room_id' do
# Get a room_id from the scenario data
room_id = @game.scenario_data['rooms']&.keys&.first
skip 'No rooms in scenario data' unless room_id.present?
get "/break_escape/games/#{@game.id}/room/#{room_id}"
assert_response :success
data = JSON.parse(response.body)
assert_equal room_id, data['room_id']
assert data['room'].present?
assert data['room']['type'].present?
end
test 'should return 404 for non-existent room' do
get "/break_escape/games/#{@game.id}/room/non_existent_room"
assert_response :not_found
data = JSON.parse(response.body)
assert_match /Room not found/, data['error']
end
test 'should return 400 when room_id is missing' do
# This would require a malformed URL, which is hard to test with helpers
# The route constraint should prevent this in practice
skip 'Route requires room_id parameter'
end
test 'room response includes all room data' do
room_id = @game.scenario_data['rooms']&.keys&.first
skip 'No rooms in scenario data' unless room_id.present?
get "/break_escape/games/#{@game.id}/room/#{room_id}"
assert_response :success
data = JSON.parse(response.body)
room = data['room']
# Verify room contains expected structure
assert room['type'].present?, 'Room should have type'
# Room may have connections, objects, npcs, etc. - all optional
end
end
end

View File

@@ -0,0 +1,137 @@
require 'test_helper'
module BreakEscape
class FilteredScenarioTest < ActiveSupport::TestCase
setup do
@scenario_data = {
"scenario_brief" => "Test mission",
"startRoom" => "start",
"startItemsInInventory" => [
{ "type" => "phone", "name" => "Test Phone" }
],
"rooms" => {
"start" => {
"type" => "room_office",
"connections" => { "north" => "next_room" },
"locked" => false,
"objects" => [
{ "type" => "desk", "name" => "Desk", "takeable" => false }
],
"npcs" => [
{ "id" => "npc1", "displayName" => "NPC One" }
]
},
"next_room" => {
"type" => "room_server",
"connections" => { "south" => "start" },
"locked" => true,
"lockType" => "key",
"requires" => "key123",
"objects" => [
{ "type" => "server", "name" => "Server", "takeable" => false }
]
}
}
}
end
test 'filtered_scenario_for_bootstrap removes room contents' do
# Create a game with custom scenario data, bypassing the generate callback
mission = break_escape_missions(:ceo_exfil)
player = break_escape_demo_users(:test_user)
game = Game.new(
mission: mission,
player: player,
scenario_data: @scenario_data
)
# Manually skip callback and save
game.save(validate: false)
filtered = game.filtered_scenario_for_bootstrap
# Check top-level fields are preserved
assert_equal "Test mission", filtered["scenario_brief"]
assert_equal "start", filtered["startRoom"]
assert filtered["startItemsInInventory"].present?
# Check rooms structure exists
assert filtered["rooms"].present?
assert filtered["rooms"]["start"].present?
assert filtered["rooms"]["next_room"].present?
end
test 'filtered_scenario_for_bootstrap preserves navigation structure' do
mission = break_escape_missions(:ceo_exfil)
player = break_escape_demo_users(:test_user)
game = Game.new(mission: mission, player: player, scenario_data: @scenario_data)
game.save(validate: false)
filtered = game.filtered_scenario_for_bootstrap
start_room = filtered["rooms"]["start"]
# Keep connections for navigation
assert_equal({ "north" => "next_room" }, start_room["connections"])
# Keep type for room rendering
assert_equal "room_office", start_room["type"]
# Keep lock info for validation
assert_equal false, start_room["locked"]
end
test 'filtered_scenario_for_bootstrap removes objects and npcs' do
mission = break_escape_missions(:ceo_exfil)
player = break_escape_demo_users(:test_user)
game = Game.new(mission: mission, player: player, scenario_data: @scenario_data)
game.save(validate: false)
filtered = game.filtered_scenario_for_bootstrap
start_room = filtered["rooms"]["start"]
# Objects and NPCs should be removed
assert_nil start_room["objects"]
assert_nil start_room["npcs"]
end
test 'filtered_scenario_for_bootstrap preserves lock requirements' do
mission = break_escape_missions(:ceo_exfil)
player = break_escape_demo_users(:test_user)
game = Game.new(mission: mission, player: player, scenario_data: @scenario_data)
game.save(validate: false)
filtered = game.filtered_scenario_for_bootstrap
locked_room = filtered["rooms"]["next_room"]
# Keep lock data for server-side validation
assert_equal true, locked_room["locked"]
assert_equal "key", locked_room["lockType"]
assert_equal "key123", locked_room["requires"]
end
test 'filtered_scenario_for_bootstrap does not modify original' do
mission = break_escape_missions(:ceo_exfil)
player = break_escape_demo_users(:test_user)
game = Game.new(mission: mission, player: player, scenario_data: @scenario_data)
game.save(validate: false)
original_rooms = game.scenario_data["rooms"].keys
filtered = game.filtered_scenario_for_bootstrap
# Original should still have all data
assert game.scenario_data["rooms"]["start"]["objects"].present?
assert game.scenario_data["rooms"]["start"]["npcs"].present?
# Filtered should not
assert_nil filtered["rooms"]["start"]["objects"]
assert_nil filtered["rooms"]["start"]["npcs"]
end
end
end