3c54cd84fc
- Add action_push_native gem and SaaS configuration - Add device registration API and UI - Add User::Devices concern - Add NotificationPusher::Native for push delivery - Add tests and fixtures for native push
235 lines
5.6 KiB
Ruby
235 lines
5.6 KiB
Ruby
require "test_helper"
|
|
|
|
class Users::DevicesControllerTest < ActionDispatch::IntegrationTest
|
|
setup do
|
|
@user = users(:david)
|
|
sign_in_as @user
|
|
end
|
|
|
|
# === Index (Web) ===
|
|
|
|
test "index shows user devices" do
|
|
@user.devices.create!(uuid: "test-uuid", token: "test_token_123", platform: "apple", name: "iPhone 15 Pro")
|
|
|
|
get users_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 users_devices_path
|
|
|
|
assert_response :success
|
|
assert_select "p", /No devices registered/
|
|
end
|
|
|
|
test "index requires authentication" do
|
|
sign_out
|
|
|
|
get users_devices_path
|
|
|
|
assert_response :redirect
|
|
end
|
|
|
|
# === Create (API) ===
|
|
|
|
test "creates a new device via api" do
|
|
uuid = SecureRandom.uuid
|
|
token = SecureRandom.hex(32)
|
|
|
|
assert_difference "ActionPushNative::Device.count", 1 do
|
|
post users_devices_path, params: {
|
|
uuid: uuid,
|
|
token: token,
|
|
platform: "apple",
|
|
name: "iPhone 15 Pro"
|
|
}, as: :json
|
|
end
|
|
|
|
assert_response :created
|
|
|
|
device = ActionPushNative::Device.last
|
|
assert_equal uuid, device.uuid
|
|
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 users_devices_path, params: {
|
|
uuid: SecureRandom.uuid,
|
|
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 "updates existing device with same uuid" do
|
|
existing_device = @user.devices.create!(
|
|
uuid: "my-device-uuid",
|
|
token: "old_token",
|
|
platform: "apple",
|
|
name: "Old iPhone"
|
|
)
|
|
|
|
assert_no_difference "ActionPushNative::Device.count" do
|
|
post users_devices_path, params: {
|
|
uuid: "my-device-uuid",
|
|
token: "new_token",
|
|
platform: "apple",
|
|
name: "New iPhone"
|
|
}, as: :json
|
|
end
|
|
|
|
assert_response :created
|
|
existing_device.reload
|
|
assert_equal "new_token", existing_device.token
|
|
assert_equal "New iPhone", existing_device.name
|
|
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!(
|
|
uuid: "kevins-device-uuid",
|
|
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 users_devices_path, params: {
|
|
uuid: "davids-device-uuid",
|
|
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.find_by(uuid: "davids-device-uuid")
|
|
assert_equal shared_token, davids_device.token
|
|
assert_equal @user, davids_device.owner
|
|
end
|
|
|
|
test "rejects invalid platform" do
|
|
post users_devices_path, params: {
|
|
uuid: SecureRandom.uuid,
|
|
token: SecureRandom.hex(32),
|
|
platform: "windows",
|
|
name: "Surface"
|
|
}, as: :json
|
|
|
|
assert_response :bad_request
|
|
end
|
|
|
|
test "rejects missing uuid" do
|
|
post users_devices_path, params: {
|
|
token: SecureRandom.hex(32),
|
|
platform: "apple",
|
|
name: "iPhone"
|
|
}, as: :json
|
|
|
|
assert_response :bad_request
|
|
end
|
|
|
|
test "rejects missing token" do
|
|
post users_devices_path, params: {
|
|
uuid: SecureRandom.uuid,
|
|
platform: "apple",
|
|
name: "iPhone"
|
|
}, as: :json
|
|
|
|
assert_response :bad_request
|
|
end
|
|
|
|
test "create requires authentication" do
|
|
sign_out
|
|
|
|
post users_devices_path, params: {
|
|
uuid: SecureRandom.uuid,
|
|
token: SecureRandom.hex(32),
|
|
platform: "apple"
|
|
}, as: :json
|
|
|
|
assert_response :redirect
|
|
end
|
|
|
|
# === Destroy (Web) ===
|
|
|
|
test "destroys device" do
|
|
device = @user.devices.create!(
|
|
uuid: "device-to-delete",
|
|
token: "token_to_delete",
|
|
platform: "apple",
|
|
name: "iPhone"
|
|
)
|
|
|
|
assert_difference "ActionPushNative::Device.count", -1 do
|
|
delete users_device_path(device)
|
|
end
|
|
|
|
assert_redirected_to users_devices_path
|
|
assert_not ActionPushNative::Device.exists?(device.id)
|
|
end
|
|
|
|
test "does nothing when device not found" do
|
|
assert_no_difference "ActionPushNative::Device.count" do
|
|
delete users_device_path(id: "nonexistent")
|
|
end
|
|
|
|
assert_redirected_to users_devices_path
|
|
end
|
|
|
|
test "cannot destroy another user's device" do
|
|
other_user = users(:kevin)
|
|
device = other_user.devices.create!(
|
|
uuid: "other-users-device",
|
|
token: "other_users_token",
|
|
platform: "apple",
|
|
name: "Other iPhone"
|
|
)
|
|
|
|
assert_no_difference "ActionPushNative::Device.count" do
|
|
delete users_device_path(device)
|
|
end
|
|
|
|
assert_redirected_to users_devices_path
|
|
assert ActionPushNative::Device.exists?(device.id)
|
|
end
|
|
|
|
test "destroy requires authentication" do
|
|
device = @user.devices.create!(
|
|
uuid: "my-device",
|
|
token: "my_token",
|
|
platform: "apple",
|
|
name: "iPhone"
|
|
)
|
|
|
|
sign_out
|
|
|
|
delete users_device_path(device)
|
|
|
|
assert_response :redirect
|
|
assert ActionPushNative::Device.exists?(device.id)
|
|
end
|
|
end
|