All checks were successful
deploy / deploy (push) Successful in 3m28s
- Create dedicated /admin/account page for user account management - Move email, password, and 2FA settings from /admin/settings - Add Account link to top of admin sidebar navigation - Add TOTP-based two-factor authentication with NimbleTOTP - Add TOTP verification LiveView for login flow - Add AccountController for TOTP session management - Remove Advanced section from settings (duplicated in dev tools) - Remove user email from sidebar footer (replaced by Account link) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
193 lines
5.5 KiB
Elixir
193 lines
5.5 KiB
Elixir
defmodule BerrypodWeb.Admin.SettingsTest do
|
|
use BerrypodWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
import Berrypod.AccountsFixtures
|
|
import Berrypod.ProductsFixtures
|
|
|
|
alias Berrypod.Settings
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
%{user: user}
|
|
end
|
|
|
|
describe "shop status toggle" do
|
|
setup %{conn: conn, user: user} do
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "shows offline status by default", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "Offline"
|
|
assert html =~ "coming soon"
|
|
assert html =~ "Go live"
|
|
end
|
|
|
|
test "can go live", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html = render_click(view, "toggle_site_live")
|
|
|
|
assert html =~ "Shop is now live"
|
|
assert html =~ "Live"
|
|
assert html =~ "Take offline"
|
|
assert Settings.site_live?()
|
|
end
|
|
|
|
test "can take offline after going live", %{conn: conn} do
|
|
{:ok, _} = Settings.set_site_live(true)
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html = render_click(view, "toggle_site_live")
|
|
|
|
assert html =~ "Shop taken offline"
|
|
assert html =~ "Offline"
|
|
assert html =~ "Go live"
|
|
refute Settings.site_live?()
|
|
end
|
|
end
|
|
|
|
describe "unauthenticated" do
|
|
test "redirects to login", %{conn: conn} do
|
|
{:error, redirect} = live(conn, ~p"/admin/settings")
|
|
assert {:redirect, %{to: path}} = redirect
|
|
assert path == ~p"/users/log-in"
|
|
end
|
|
end
|
|
|
|
describe "authenticated - not configured" do
|
|
setup %{conn: conn, user: user} do
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "renders setup form when Stripe is not configured", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "Settings"
|
|
assert html =~ "Not connected"
|
|
assert html =~ "Connect Stripe"
|
|
assert html =~ "Stripe dashboard"
|
|
end
|
|
|
|
test "shows error for empty API key", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html =
|
|
view
|
|
|> form(~s(form[phx-submit="connect_stripe"]), %{stripe: %{api_key: ""}})
|
|
|> render_submit()
|
|
|
|
assert html =~ "Please enter your Stripe secret key"
|
|
end
|
|
end
|
|
|
|
describe "authenticated - connected (localhost)" do
|
|
setup %{conn: conn, user: user} do
|
|
# Pre-configure a Stripe API key
|
|
Settings.put_secret("stripe_api_key", "sk_test_simulated_key_12345")
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "renders dev mode view with CLI instructions", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "Dev mode"
|
|
assert html =~ "sk_test_•••345"
|
|
assert html =~ "stripe listen"
|
|
assert html =~ "Webhook signing secret"
|
|
end
|
|
|
|
test "saves manual signing secret", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html =
|
|
view
|
|
|> form(~s(form[phx-submit="save_signing_secret"]), %{
|
|
webhook: %{signing_secret: "whsec_test_manual_456"}
|
|
})
|
|
|> render_submit()
|
|
|
|
assert has_element?(view, ".admin-inline-feedback-saved")
|
|
assert html =~ "whsec_te•••456"
|
|
end
|
|
|
|
test "shows error for empty signing secret", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html =
|
|
view
|
|
|> form(~s(form[phx-submit="save_signing_secret"]), %{webhook: %{signing_secret: ""}})
|
|
|> render_submit()
|
|
|
|
assert html =~ "Please enter a signing secret"
|
|
end
|
|
|
|
test "disconnect clears configuration", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
html = render_click(view, "disconnect_stripe")
|
|
|
|
assert html =~ "Stripe disconnected"
|
|
assert html =~ "Not connected"
|
|
assert html =~ "Connect Stripe"
|
|
refute Settings.has_secret?("stripe_api_key")
|
|
end
|
|
end
|
|
|
|
describe "products section" do
|
|
setup %{conn: conn, user: user} do
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "shows connect button when no provider connected", %{conn: conn} do
|
|
{:ok, view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "Products"
|
|
assert html =~ "Not connected"
|
|
assert has_element?(view, ~s(a[href="/admin/providers"]), "Connect a provider")
|
|
end
|
|
|
|
test "shows connection info when provider connected", %{conn: conn} do
|
|
conn_record = provider_connection_fixture(%{name: "Test Shop"})
|
|
product_fixture(%{provider_connection: conn_record})
|
|
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "Connected"
|
|
assert html =~ "Test Shop"
|
|
assert html =~ "Sync products"
|
|
end
|
|
end
|
|
|
|
describe "from address" do
|
|
setup %{conn: conn, user: user} do
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "shows from address section", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings")
|
|
|
|
assert html =~ "From address"
|
|
assert html =~ "sender address"
|
|
end
|
|
|
|
test "saves from address", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings")
|
|
|
|
view
|
|
|> form("form[phx-submit=\"save_from_address\"]", %{from_address: "shop@example.com"})
|
|
|> render_submit()
|
|
|
|
assert has_element?(view, ".admin-inline-feedback-saved")
|
|
assert Settings.get_setting("email_from_address") == "shop@example.com"
|
|
end
|
|
end
|
|
end
|