Files
fizzy/test/controllers/users_controller_test.rb
Donal McBreen b4c4a32205 Return 401 for bearer tokens on non-JSON requests
Rather than silently ignoring bearer tokens on HTML requests
(which breaks the audit console's error handling), explicitly
reject them with 401. Bearer tokens on JSON requests continue
to authenticate normally.
2026-04-01 09:09:00 +01:00

180 lines
4.8 KiB
Ruby

require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest
test "show" do
sign_in_as :kevin
get user_path(users(:david))
assert_in_body users(:david).name
end
test "update oneself" do
sign_in_as :kevin
get edit_user_path(users(:kevin))
assert_response :ok
put user_path(users(:kevin)), params: { user: { name: "New Kevin" } }
assert_redirected_to user_path(users(:kevin))
assert_equal "New Kevin", users(:kevin).reload.name
end
test "update other as admin" do
sign_in_as :kevin
get edit_user_path(users(:david))
assert_response :ok
put user_path(users(:david)), params: { user: { name: "New David" } }
assert_redirected_to user_path(users(:david))
assert_equal "New David", users(:david).reload.name
end
test "destroy" do
sign_in_as :kevin
assert_difference -> { User.active.count }, -1 do
delete user_path(users(:david))
end
assert_redirected_to account_settings_path
assert_nil User.active.find_by(id: users(:david).id)
end
test "admin cannot deactivate the owner" do
sign_in_as :kevin
assert users(:jason).owner?
assert users(:jason).active
assert_no_difference -> { User.active.count } do
delete user_path(users(:jason))
end
assert_response :forbidden
assert users(:jason).reload.active
end
test "non-admins cannot perform actions" do
sign_in_as :jz
put user_path(users(:david)), params: { user: { role: "admin" } }
assert_response :forbidden
delete user_path(users(:david))
assert_response :forbidden
end
test "update with invalid avatar content type shows validation error" do
sign_in_as :kevin
svg_file = fixture_file_upload("avatar.svg", "image/svg+xml")
put user_path(users(:kevin)), params: { user: { avatar: svg_file } }
assert_response :unprocessable_entity
assert_select "form[action='#{user_path(users(:kevin))}']"
assert_select ".txt-negative", text: /must be a JPEG, PNG, GIF, or WebP image/
end
test "update with oversized avatar shows validation error" do
sign_in_as :kevin
png_file = fixture_file_upload("avatar.png", "image/png")
ActiveStorage::Analyzer::ImageAnalyzer::Vips.any_instance.stubs(:metadata).returns({ width: 5000, height: 100 })
put user_path(users(:kevin)), params: { user: { avatar: png_file } }
assert_response :unprocessable_entity
assert_select ".txt-negative", text: /width must be less than 4096px/
end
test "update with valid avatar" do
sign_in_as :kevin
png_file = fixture_file_upload("avatar.png", "image/png")
put user_path(users(:kevin)), params: { user: { avatar: png_file } }
assert_redirected_to user_path(users(:kevin))
assert users(:kevin).reload.avatar.attached?
assert_equal "image/png", users(:kevin).avatar.content_type
end
test "index as JSON" do
sign_in_as :kevin
get users_path, as: :json
assert_response :success
assert_equal users(:kevin).account.users.active.count, @response.parsed_body.count
end
test "show as JSON" do
sign_in_as :kevin
get user_path(users(:david)), as: :json
assert_response :success
assert_equal users(:david).name, @response.parsed_body["name"]
end
test "update as JSON" do
sign_in_as :kevin
put user_path(users(:david)), params: { user: { name: "New David" } }, as: :json
assert_response :no_content
assert_equal "New David", users(:david).reload.name
end
test "update as JSON with invalid avatar returns errors" do
sign_in_as :kevin
svg_file = fixture_file_upload("avatar.svg", "image/svg+xml")
put user_path(users(:kevin), format: :json), params: { user: { avatar: svg_file } }
assert_response :unprocessable_entity
assert @response.parsed_body["avatar"].present?
end
test "destroy as JSON" do
sign_in_as :kevin
assert_difference -> { User.active.count }, -1 do
delete user_path(users(:david)), as: :json
end
assert_response :no_content
end
test "bearer token does not authenticate HTML requests" do
sign_in_as :jason
sign_out
bearer = { "HTTP_AUTHORIZATION" => "Bearer #{identity_access_tokens(:jasons_api_token).token}" }
get user_path(users(:jason)), env: bearer
assert_response :unauthorized
end
test "bearer token authenticates JSON requests" do
sign_in_as :jason
sign_out
bearer = { "HTTP_AUTHORIZATION" => "Bearer #{identity_access_tokens(:jasons_api_token).token}" }
get user_path(users(:jason)), env: bearer, as: :json
assert_response :success
end
test "index avoids N+1 queries on identity" do
sign_in_as :kevin
assert_queries_match(/FROM [`"]identities[`"].* IN \(/, count: 1) do
get users_path, as: :json
assert_response :success
end
json = @response.parsed_body
assert json.first["email_address"].present?
end
end