- New `sync_worker_perform_test.exs` drives every cron sync worker's
`perform/1` body via `Req.Test` stubs, exercising the {:error, _}
branch of `sync_integration/1` for Sonar, Splynx, Visp, and NetBox,
plus the should_sync?-skip path.
- OnboardingLive: covers `finish` event, `skip` from :agent (both
trigger complete_onboarding), and `go_to_step :agent` (which calls
the previously-untested `load_agent_token/1`).
- GaiiaInsightWorker: adds a test that drives `generate_mismatch_insights/2`
by inserting an inventory item whose ip_address disagrees with its
mapped device.
Coverage: 86.52% → 86.61%.
334 lines
11 KiB
Elixir
334 lines
11 KiB
Elixir
defmodule ToweropsWeb.OnboardingLiveTest do
|
|
@moduledoc """
|
|
Tests for ToweropsWeb.OnboardingLive.
|
|
|
|
Note: OnboardingLive is not currently routed, so we test the module's
|
|
behavior through direct socket/event simulation rather than HTTP mounting.
|
|
"""
|
|
use ToweropsWeb.ConnCase, async: true
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Phoenix.LiveView.Socket
|
|
alias ToweropsWeb.OnboardingLive
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
organization = organization_fixture(user.id)
|
|
|
|
%{user: user, organization: organization}
|
|
end
|
|
|
|
describe "module structure" do
|
|
test "module exists and is a LiveView" do
|
|
Code.ensure_loaded!(OnboardingLive)
|
|
assert function_exported?(OnboardingLive, :mount, 3)
|
|
assert function_exported?(OnboardingLive, :handle_event, 3)
|
|
assert function_exported?(OnboardingLive, :handle_params, 3)
|
|
end
|
|
end
|
|
|
|
describe "mount/3" do
|
|
test "initializes with correct default state", %{user: user, organization: organization} do
|
|
socket =
|
|
%Socket{
|
|
assigns: %{
|
|
__changed__: %{},
|
|
current_scope: %{user: user, organization: organization},
|
|
flash: %{}
|
|
},
|
|
endpoint: ToweropsWeb.Endpoint
|
|
}
|
|
|
|
assert {:ok, socket} = OnboardingLive.mount(%{}, %{}, socket)
|
|
|
|
assert socket.assigns.step == :snmp
|
|
assert socket.assigns.organization == organization
|
|
assert socket.assigns.steps == [:snmp, :site, :billing, :agent]
|
|
assert socket.assigns.selected_provider == nil
|
|
assert socket.assigns.agent_token == nil
|
|
assert socket.assigns.agent_token_value == nil
|
|
assert socket.assigns.page_title
|
|
end
|
|
end
|
|
|
|
describe "handle_event skip" do
|
|
test "skip advances from snmp to site", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> Map.put(:assigns, Map.put(build_socket(user, organization).assigns, :step, :snmp))
|
|
|
|
assert {:noreply, socket} = OnboardingLive.handle_event("skip", %{}, socket)
|
|
assert socket.assigns.step == :site
|
|
end
|
|
|
|
test "skip advances from site to billing", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
socket = put_in(socket.assigns.step, :site)
|
|
|
|
assert {:noreply, socket} = OnboardingLive.handle_event("skip", %{}, socket)
|
|
assert socket.assigns.step == :billing
|
|
end
|
|
end
|
|
|
|
describe "handle_event go_to_step" do
|
|
test "navigates to specified step", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} = OnboardingLive.handle_event("go_to_step", %{"step" => "site"}, socket)
|
|
assert socket.assigns.step == :site
|
|
end
|
|
|
|
test "navigates to billing step", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} = OnboardingLive.handle_event("go_to_step", %{"step" => "billing"}, socket)
|
|
assert socket.assigns.step == :billing
|
|
end
|
|
end
|
|
|
|
describe "handle_event select_provider" do
|
|
test "sets selected provider and creates integration form", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
socket = put_in(socket.assigns.step, :billing)
|
|
|
|
assert {:noreply, socket} = OnboardingLive.handle_event("select_provider", %{"provider" => "sonar"}, socket)
|
|
assert socket.assigns.selected_provider == "sonar"
|
|
assert socket.assigns.integration_form
|
|
end
|
|
end
|
|
|
|
describe "handle_event validate_snmp / save_snmp" do
|
|
test "validate updates the form changeset", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"validate_snmp",
|
|
%{"organization" => %{"snmp_community" => "secret"}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.form
|
|
end
|
|
|
|
test "save_snmp advances to :site on success", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"save_snmp",
|
|
%{"organization" => %{"snmp_community" => "ok"}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.step == :site
|
|
end
|
|
|
|
test "save_snmp returns same step on validation failure", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"save_snmp",
|
|
%{"organization" => %{"name" => ""}},
|
|
socket
|
|
)
|
|
|
|
# remains in onboarding (no flash on failure path)
|
|
assert socket.assigns.step in [:snmp, :site]
|
|
end
|
|
end
|
|
|
|
describe "handle_event validate_site / save_site" do
|
|
test "validate updates the site form", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"validate_site",
|
|
%{"site" => %{"name" => "S"}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.site_form
|
|
end
|
|
|
|
test "save_site advances to :billing on success", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"save_site",
|
|
%{"site" => %{"name" => "Main Site"}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.step == :billing
|
|
end
|
|
|
|
test "save_site stays on :site when validation fails", %{user: user, organization: organization} do
|
|
socket = build_socket(user, organization)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"save_site",
|
|
%{"site" => %{"name" => ""}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.site_form
|
|
end
|
|
end
|
|
|
|
describe "handle_event validate_integration / save_integration" do
|
|
test "validate updates the integration form", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> put_in([Access.key(:assigns), :selected_provider], "sonar")
|
|
|> put_in([Access.key(:assigns), :step], :billing)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"validate_integration",
|
|
%{"integration" => %{"instance_url" => "https://x", "api_token" => "k"}},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.integration_form
|
|
end
|
|
|
|
test "save_integration advances to :agent and loads token", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> put_in([Access.key(:assigns), :selected_provider], "splynx")
|
|
|> put_in([Access.key(:assigns), :step], :billing)
|
|
|
|
assert {:noreply, socket} =
|
|
OnboardingLive.handle_event(
|
|
"save_integration",
|
|
%{
|
|
"integration" => %{
|
|
"instance_url" => "https://splynx.example.com",
|
|
"api_key" => "k",
|
|
"api_secret" => "s"
|
|
}
|
|
},
|
|
socket
|
|
)
|
|
|
|
assert socket.assigns.step == :agent
|
|
assert socket.assigns.agent_token
|
|
end
|
|
end
|
|
|
|
describe "handle_event finish + skip-to-done + go_to_step :agent" do
|
|
test "finish/3 marks onboarding completed and pushes to dashboard", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> put_in([Access.key(:assigns), :step], :agent)
|
|
|
|
assert {:noreply, socket_after} = OnboardingLive.handle_event("finish", %{}, socket)
|
|
# complete_onboarding pushes navigate; the redirect is captured in flash/redirected.
|
|
assert socket_after.redirected
|
|
end
|
|
|
|
test "skip from :agent triggers complete_onboarding", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> put_in([Access.key(:assigns), :step], :agent)
|
|
|
|
assert {:noreply, socket_after} = OnboardingLive.handle_event("skip", %{}, socket)
|
|
assert socket_after.redirected
|
|
end
|
|
|
|
test "go_to_step :agent loads the agent token", %{user: user, organization: organization} do
|
|
socket =
|
|
user
|
|
|> build_socket(organization)
|
|
|> put_in([Access.key(:assigns), :step], :site)
|
|
|
|
assert {:noreply, socket_after} =
|
|
OnboardingLive.handle_event("go_to_step", %{"step" => "agent"}, socket)
|
|
|
|
assert socket_after.assigns.step == :agent
|
|
# load_agent_token assigns either an existing or newly-created token.
|
|
assert Map.has_key?(socket_after.assigns, :agent_token)
|
|
end
|
|
end
|
|
|
|
describe "next_step / step_index" do
|
|
test "step ordering" do
|
|
assert OnboardingLive.next_step(:snmp) == :site
|
|
assert OnboardingLive.next_step(:site) == :billing
|
|
assert OnboardingLive.next_step(:billing) == :agent
|
|
assert OnboardingLive.next_step(:agent) == :done
|
|
|
|
assert OnboardingLive.step_index(:snmp) == 0
|
|
assert OnboardingLive.step_index(:agent) == 3
|
|
end
|
|
end
|
|
|
|
describe "normalize_integration_params/2" do
|
|
test "sonar shape" do
|
|
params = %{"instance_url" => " https://x.com ", "api_token" => "tok"}
|
|
assert %{credentials: creds} = OnboardingLive.normalize_integration_params(params, "sonar")
|
|
assert creds["instance_url"] == "https://x.com"
|
|
assert creds["api_token"] == "tok"
|
|
end
|
|
|
|
test "splynx shape" do
|
|
params = %{"instance_url" => "u", "api_key" => "k", "api_secret" => "s"}
|
|
assert %{credentials: creds} = OnboardingLive.normalize_integration_params(params, "splynx")
|
|
assert creds["api_secret"] == "s"
|
|
end
|
|
|
|
test "fallback shape" do
|
|
params = %{"api_key" => "k"}
|
|
assert %{credentials: creds} = OnboardingLive.normalize_integration_params(params, "anything")
|
|
assert creds["api_key"] == "k"
|
|
end
|
|
|
|
test "fallback handles missing api_key gracefully" do
|
|
assert %{credentials: %{"api_key" => ""}} =
|
|
OnboardingLive.normalize_integration_params(%{}, "fallback")
|
|
end
|
|
end
|
|
|
|
# Helper to build a socket with required assigns for OnboardingLive
|
|
defp build_socket(user, organization) do
|
|
changeset = Towerops.Organizations.change_organization(organization)
|
|
site_changeset = Towerops.Sites.change_site(%Towerops.Sites.Site{}, %{})
|
|
|
|
%Socket{
|
|
assigns: %{
|
|
__changed__: %{},
|
|
current_scope: %{user: user, organization: organization},
|
|
flash: %{},
|
|
step: :snmp,
|
|
steps: [:snmp, :site, :billing, :agent],
|
|
organization: organization,
|
|
form: Phoenix.Component.to_form(changeset),
|
|
site_form: Phoenix.Component.to_form(site_changeset, as: "site"),
|
|
billing_providers: [
|
|
%{id: "gaiia", name: "Gaiia", icon: "hero-user-group"},
|
|
%{id: "sonar", name: "Sonar", icon: "hero-currency-dollar"},
|
|
%{id: "splynx", name: "Splynx", icon: "hero-banknotes"},
|
|
%{id: "visp", name: "VISP", icon: "hero-cloud"}
|
|
],
|
|
selected_provider: nil,
|
|
integration_form: nil,
|
|
agent_token: nil,
|
|
agent_token_value: nil,
|
|
page_title: "Setup"
|
|
},
|
|
endpoint: ToweropsWeb.Endpoint
|
|
}
|
|
end
|
|
end
|