require "test_helper" class DevicesControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:david) sign_in_as @user end test "index shows user devices" do @user.devices.create!(token: "test_token_123", platform: "apple", name: "iPhone 15 Pro") get devices_path assert_response :success assert_select "strong", "iPhone 15 Pro" assert_select "li", /iOS/ end test "index shows empty state when no devices" do @user.devices.delete_all get devices_path assert_response :success assert_select "p", /No devices registered/ end test "index requires authentication" do sign_out get devices_path assert_response :redirect end test "creates a new device via api" do token = SecureRandom.hex(32) assert_difference "ActionPushNative::Device.count", 1 do post devices_path, params: { token: token, platform: "apple", name: "iPhone 15 Pro" }, as: :json end assert_response :created device = ActionPushNative::Device.last assert_equal token, device.token assert_equal "apple", device.platform assert_equal "iPhone 15 Pro", device.name assert_equal @user, device.owner end test "creates android device" do post devices_path, params: { token: SecureRandom.hex(32), platform: "google", name: "Pixel 8" }, as: :json assert_response :created device = ActionPushNative::Device.last assert_equal "google", device.platform end test "same token can be registered by multiple users" do shared_token = "shared_push_token_123" other_user = users(:kevin) # Other user registers the token first other_device = other_user.devices.create!( token: shared_token, platform: "apple", name: "Kevin's iPhone" ) # Current user registers the same token with their own device assert_difference "ActionPushNative::Device.count", 1 do post devices_path, params: { token: shared_token, platform: "apple", name: "David's iPhone" }, as: :json end assert_response :created # Both users have their own device records assert_equal shared_token, other_device.reload.token assert_equal other_user, other_device.owner davids_device = @user.devices.last assert_equal shared_token, davids_device.token assert_equal @user, davids_device.owner end test "rejects invalid platform" do post devices_path, params: { token: SecureRandom.hex(32), platform: "windows", name: "Surface" }, as: :json assert_response :unprocessable_entity end test "rejects missing token" do post devices_path, params: { platform: "apple", name: "iPhone" }, as: :json assert_response :bad_request end test "create requires authentication" do sign_out post devices_path, params: { token: SecureRandom.hex(32), platform: "apple" }, as: :json assert_response :redirect end test "destroys device by id" do device = @user.devices.create!( token: "token_to_delete", platform: "apple", name: "iPhone" ) assert_difference "ActionPushNative::Device.count", -1 do delete device_path(device) end assert_redirected_to devices_path assert_not ActionPushNative::Device.exists?(device.id) end test "returns not found when device not found by id" do assert_no_difference "ActionPushNative::Device.count" do delete device_path(id: "nonexistent") end assert_response :not_found end test "returns not found for another user's device by id" do other_user = users(:kevin) device = other_user.devices.create!( token: "other_users_token", platform: "apple", name: "Other iPhone" ) assert_no_difference "ActionPushNative::Device.count" do delete device_path(device) end assert_response :not_found assert ActionPushNative::Device.exists?(device.id) end test "destroy by id requires authentication" do device = @user.devices.create!( token: "my_token", platform: "apple", name: "iPhone" ) sign_out delete device_path(device) assert_response :redirect assert ActionPushNative::Device.exists?(device.id) end test "destroys device by token" do device = @user.devices.create!( token: "token_to_unregister", platform: "apple", name: "iPhone" ) assert_difference "ActionPushNative::Device.count", -1 do delete device_path("token_to_unregister"), as: :json end assert_response :no_content assert_not ActionPushNative::Device.exists?(device.id) end test "returns not found when device not found by token" do assert_no_difference "ActionPushNative::Device.count" do delete device_path("nonexistent_token"), as: :json end assert_response :not_found end test "returns not found for another user's device by token" do other_user = users(:kevin) device = other_user.devices.create!( token: "other_users_token", platform: "apple", name: "Other iPhone" ) assert_no_difference "ActionPushNative::Device.count" do delete device_path("other_users_token"), as: :json end assert_response :not_found assert ActionPushNative::Device.exists?(device.id) end test "destroy by token requires authentication" do device = @user.devices.create!( token: "my_token", platform: "apple", name: "iPhone" ) sign_out delete device_path("my_token"), as: :json assert_response :redirect assert ActionPushNative::Device.exists?(device.id) end end