test: add settings session/TOTP manager unit tests

This commit is contained in:
Graham McIntire 2026-05-07 09:25:30 -05:00
parent 0e2cc6b7ce
commit 1b7312a8df
2 changed files with 185 additions and 0 deletions

View file

@ -0,0 +1,88 @@
defmodule ToweropsWeb.UserSettingsLive.SessionManagerTest do
use Towerops.DataCase, async: false
import Towerops.AccountsFixtures
alias Phoenix.LiveView.Socket
alias Towerops.Accounts.Scope
alias ToweropsWeb.UserSettingsLive.SessionManager
describe "show_revoke_all_modal/1 and cancel_revoke_all/1" do
test "show flips the modal flag, cancel resets it" do
socket = base_socket(user_fixture())
assert socket.assigns[:show_revoke_all_modal] in [nil, false]
shown = SessionManager.show_revoke_all_modal(socket)
assert shown.assigns.show_revoke_all_modal == true
cancelled = SessionManager.cancel_revoke_all(shown)
assert cancelled.assigns.show_revoke_all_modal == false
end
end
describe "assign_mobile_sessions/1" do
test "assigns the user's mobile sessions list (empty when none exist)" do
socket = base_socket(user_fixture())
result = SessionManager.assign_mobile_sessions(socket)
assert is_list(result.assigns.mobile_sessions)
assert result.assigns.mobile_sessions == []
end
end
describe "assign_browser_sessions/1" do
test "assigns the user's active browser sessions" do
socket = base_socket(user_fixture())
result = SessionManager.assign_browser_sessions(socket)
assert is_list(result.assigns.browser_sessions)
end
end
describe "get_current_token_id/1" do
test "returns nil when no token is present in assigns" do
socket = base_socket(user_fixture())
assert SessionManager.get_current_token_id(socket) == nil
end
test "returns nil for a token value that no UserToken row matches" do
socket = %Socket{assigns: %{current_token: "no-such-token"}}
assert SessionManager.get_current_token_id(socket) == nil
end
test "ignores non-binary current_token values" do
socket = %Socket{assigns: %{current_token: nil}}
assert SessionManager.get_current_token_id(socket) == nil
end
end
describe "revoke_mobile_device/2 + toggle_device_alerts/3" do
test "revoke returns an error flash for a mobile session that doesn't exist" do
socket = base_socket(user_fixture())
result = SessionManager.revoke_mobile_device(socket, Ecto.UUID.generate())
assert result.assigns.flash["error"]
end
test "toggle returns an error flash for a mobile session that doesn't exist" do
socket = base_socket(user_fixture())
result = SessionManager.toggle_device_alerts(socket, Ecto.UUID.generate(), "true")
assert result.assigns.flash["error"]
end
end
# -- helpers --
defp base_socket(user) do
scope = Scope.for_user(user)
%Socket{
assigns: %{
current_scope: scope,
flash: %{},
__changed__: %{}
}
}
end
end

View file

@ -0,0 +1,97 @@
defmodule ToweropsWeb.UserSettingsLive.TotpManagerTest do
use Towerops.DataCase, async: false
import Towerops.AccountsFixtures
alias Phoenix.LiveView.Socket
alias Towerops.Accounts.Scope
alias ToweropsWeb.UserSettingsLive.TotpManager
describe "modal state helpers" do
test "show_add_device_modal flips the flag, cancel resets it" do
socket = base_socket(user_fixture())
assert socket.assigns[:show_add_device_modal] in [nil, false]
shown = TotpManager.show_add_device_modal(socket)
assert shown.assigns.show_add_device_modal == true
cancelled = TotpManager.cancel_add_device(shown)
assert cancelled.assigns.show_add_device_modal == false
end
test "close_recovery_codes_modal hides modal and clears generated codes" do
socket =
user_fixture()
|> base_socket()
|> Phoenix.Component.assign(:show_recovery_codes_modal, true)
|> Phoenix.Component.assign(:generated_recovery_codes, ["a", "b"])
result = TotpManager.close_recovery_codes_modal(socket)
assert result.assigns.show_recovery_codes_modal == false
assert result.assigns.generated_recovery_codes == nil
end
end
describe "assign_totp_devices/1" do
test "assigns the user's totp device list (empty when none)" do
socket = base_socket(user_fixture())
result = TotpManager.assign_totp_devices(socket)
assert is_list(result.assigns.totp_devices)
end
end
describe "assign_recovery_codes_count/1" do
test "assigns an integer count of unused recovery codes" do
socket = base_socket(user_fixture())
result = TotpManager.assign_recovery_codes_count(socket)
assert is_integer(result.assigns.unused_recovery_codes_count)
end
end
describe "verify_new_device/2" do
test "rejects a wrong code with an error flash" do
user = user_fixture()
# Stage the QR-modal assigns the way create_device would have done.
socket =
user
|> base_socket()
|> Phoenix.Component.assign(:new_device_secret, "JBSWY3DPEHPK3PXP")
|> Phoenix.Component.assign(:new_device_id, Ecto.UUID.generate())
result = TotpManager.verify_new_device(socket, "000000")
assert result.assigns.flash["error"] =~ "Invalid code"
end
end
describe "delete_device/2" do
test "returns an error flash for a device id that doesn't belong to the user" do
socket = base_socket(user_fixture())
result = TotpManager.delete_device(socket, Ecto.UUID.generate())
assert result.assigns.flash["error"]
end
end
describe "regenerate_recovery_codes/1" do
test "stages the modal and generated codes on success" do
socket = base_socket(user_fixture())
result = TotpManager.regenerate_recovery_codes(socket)
# Either succeeded (modal flag true) or failed with an error flash.
assert result.assigns[:show_recovery_codes_modal] == true or
result.assigns.flash["error"]
end
end
defp base_socket(user) do
%Socket{
assigns: %{
current_scope: Scope.for_user(user),
flash: %{},
__changed__: %{}
}
}
end
end