Files
sure/test/controllers/api/v1/users_controller_test.rb
Juan José Mata ad3087f1dd Improvements to Flutter client (#1042)
* Chat improvements

* Delete/reset account via API for Flutter app

* Fix tests.

* Add "contact us" to settings

* Update mobile/lib/screens/chat_conversation_screen.dart

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Juan José Mata <jjmata@jjmata.com>

* Improve LLM special token detection

* Deactivated user shouldn't have API working

* Fix tests

* API-Key usage

* Flutter app launch failure on no network

* Handle deletion/reset delays

* Local cached data may become stale

* Use X-Api-Key correctly!

---------

Signed-off-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-22 21:22:32 -05:00

117 lines
3.3 KiB
Ruby

# frozen_string_literal: true
require "test_helper"
class Api::V1::UsersControllerTest < ActionDispatch::IntegrationTest
setup do
@user = users(:family_admin)
@user.api_keys.active.destroy_all
@api_key = ApiKey.create!(
user: @user,
name: "Test Read-Write Key",
scopes: [ "read_write" ],
display_key: "test_rw_#{SecureRandom.hex(8)}"
)
@read_only_api_key = ApiKey.create!(
user: @user,
name: "Test Read-Only Key",
scopes: [ "read" ],
display_key: "test_ro_#{SecureRandom.hex(8)}",
source: "mobile"
)
end
# -- Authentication --------------------------------------------------------
test "reset requires authentication" do
delete "/api/v1/users/reset"
assert_response :unauthorized
end
test "destroy requires authentication" do
delete "/api/v1/users/me"
assert_response :unauthorized
end
# -- Scope enforcement -----------------------------------------------------
test "reset requires write scope" do
delete "/api/v1/users/reset", headers: api_headers(@read_only_api_key)
assert_response :forbidden
end
test "destroy requires write scope" do
delete "/api/v1/users/me", headers: api_headers(@read_only_api_key)
assert_response :forbidden
end
# -- Reset -----------------------------------------------------------------
test "reset enqueues FamilyResetJob and returns 200" do
assert_enqueued_with(job: FamilyResetJob) do
delete "/api/v1/users/reset", headers: api_headers(@api_key)
end
assert_response :ok
body = JSON.parse(response.body)
assert_equal "Account reset has been initiated", body["message"]
end
# -- Delete account --------------------------------------------------------
test "destroy deactivates user and returns 200" do
solo_family = Family.create!(name: "Solo Family", currency: "USD", locale: "en", date_format: "%m-%d-%Y")
solo_user = solo_family.users.create!(
email: "solo@example.com",
password: "password123",
password_confirmation: "password123",
role: :admin
)
solo_api_key = ApiKey.create!(
user: solo_user,
name: "Solo Key",
scopes: [ "read_write" ],
display_key: "test_solo_#{SecureRandom.hex(8)}"
)
delete "/api/v1/users/me", headers: api_headers(solo_api_key)
assert_response :ok
body = JSON.parse(response.body)
assert_equal "Account has been deleted", body["message"]
solo_user.reload
assert_not solo_user.active?
assert_not_equal "solo@example.com", solo_user.email
end
test "destroy returns 422 when admin has other family members" do
delete "/api/v1/users/me", headers: api_headers(@api_key)
assert_response :unprocessable_entity
body = JSON.parse(response.body)
assert_equal "Failed to delete account", body["error"]
end
# -- Deactivated user ------------------------------------------------------
test "rejects deactivated user with 401" do
@user.update_column(:active, false)
delete "/api/v1/users/reset", headers: api_headers(@api_key)
assert_response :unauthorized
body = JSON.parse(response.body)
assert_equal "Account has been deactivated", body["message"]
end
private
def api_headers(api_key)
{ "X-Api-Key" => api_key.display_key }
end
end