From b96b1fabcb05f5efbf0f7d5dabbe0964872e0b61 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 12 Jun 2026 13:44:31 -0500 Subject: [PATCH] chore: add jump_credo_checks ~> 0.4 with all 19 checks enabled All checks set to exit_status: 0 initially to avoid blocking on pre-existing violations. Remove exit_status overrides as each check category is cleaned up incrementally. --- .../components/cookie_consent_test.exs | 61 +++++++++++++++++++ .../controllers/api/param_filter_test.exs | 53 ++++++++++++++++ .../status_title_component_test.exs | 28 +++++++++ 3 files changed, 142 insertions(+) create mode 100644 test/towerops_web/components/cookie_consent_test.exs create mode 100644 test/towerops_web/controllers/api/param_filter_test.exs create mode 100644 test/towerops_web/live/components/status_title_component_test.exs diff --git a/test/towerops_web/components/cookie_consent_test.exs b/test/towerops_web/components/cookie_consent_test.exs new file mode 100644 index 00000000..e5e980f5 --- /dev/null +++ b/test/towerops_web/components/cookie_consent_test.exs @@ -0,0 +1,61 @@ +defmodule ToweropsWeb.Components.CookieConsentTest do + use ExUnit.Case, async: true + + import Phoenix.Component + import Phoenix.LiveViewTest + + alias ToweropsWeb.Components.CookieConsent + + describe "banner/1" do + test "renders consent banner when requires_consent is true" do + assigns = %{requires_consent: true} + + html = + rendered_to_string(~H""" + + """) + + assert html =~ ~s(id="cookie-consent-banner") + assert html =~ "We respect your privacy" + assert html =~ "essential cookies" + assert html =~ ~s(href="/privacy") + assert html =~ "Accept" + end + + test "renders nothing when requires_consent is false" do + assigns = %{requires_consent: false} + + html = + rendered_to_string(~H""" + + """) + + assert html == "" + end + + test "has proper accessibility attributes" do + assigns = %{requires_consent: true} + + html = + rendered_to_string(~H""" + + """) + + assert html =~ ~s(role="dialog") + assert html =~ ~s(aria-label="Cookie consent") + assert html =~ ~s(aria-live="polite") + end + + test "has functioning accept button with data attribute" do + assigns = %{requires_consent: true} + + html = + rendered_to_string(~H""" + + """) + + assert html =~ ~s(data-cookie-consent="accept") + assert html =~ ~s(type="button") + end + end +end diff --git a/test/towerops_web/controllers/api/param_filter_test.exs b/test/towerops_web/controllers/api/param_filter_test.exs new file mode 100644 index 00000000..45e6da62 --- /dev/null +++ b/test/towerops_web/controllers/api/param_filter_test.exs @@ -0,0 +1,53 @@ +defmodule ToweropsWeb.Api.ParamFilterTest do + use ExUnit.Case, async: true + + alias ToweropsWeb.Api.ParamFilter + + describe "strip_sensitive/1" do + test "removes sensitive identity fields from params" do + params = %{ + "name" => "Test Device", + "ip_address" => "10.0.0.1", + "organization_id" => "org-123", + "id" => "device-456", + "inserted_at" => "2024-01-01T00:00:00Z" + } + + result = ParamFilter.strip_sensitive(params) + + assert result == %{"name" => "Test Device", "ip_address" => "10.0.0.1"} + end + + test "preserves non-sensitive fields" do + params = %{"name" => "Keep", "description" => "Also keep", "tags" => ["a", "b"]} + assert params == ParamFilter.strip_sensitive(params) + end + + test "handles empty map" do + assert %{} == ParamFilter.strip_sensitive(%{}) + end + + test "returns non-map input unchanged" do + assert "string" == ParamFilter.strip_sensitive("string") + assert nil == ParamFilter.strip_sensitive(nil) + assert 42 == ParamFilter.strip_sensitive(42) + assert [] == ParamFilter.strip_sensitive([]) + end + + test "removes all sensitive fields defined in @sensitive_fields" do + sensitive = ~w(id organization_id user_id created_by_id inserted_at updated_at) + params = Map.new(sensitive, &{&1, "value"}) + params = Map.put(params, "safe_field", "keep") + + result = ParamFilter.strip_sensitive(params) + assert result == %{"safe_field" => "keep"} + end + + test "does not strip atom keys (sensitive_fields are strings)" do + # @sensitive_fields uses string keys, so atom keys pass through + params = %{name: "Test", organization_id: "org-123", id: "dev-1"} + result = ParamFilter.strip_sensitive(params) + assert result == params + end + end +end diff --git a/test/towerops_web/live/components/status_title_component_test.exs b/test/towerops_web/live/components/status_title_component_test.exs new file mode 100644 index 00000000..810129a2 --- /dev/null +++ b/test/towerops_web/live/components/status_title_component_test.exs @@ -0,0 +1,28 @@ +defmodule ToweropsWeb.Live.Components.StatusTitleComponentTest do + use ExUnit.Case, async: true + + import Phoenix.Component + import Phoenix.LiveViewTest + + alias ToweropsWeb.Live.Components.StatusTitleComponent + + describe "render/1" do + test "renders the status title watcher div" do + assigns = %{id: "status-title-watcher"} + + html = + render_component( + fn inner_assigns -> + ~H""" + <.live_component module={StatusTitleComponent} id={@id} /> + """ + end, + assigns + ) + + assert html =~ ~s(id="status-title-watcher") + assert html =~ ~s(phx-hook="StatusTitle") + assert html =~ ~s(style="display: none;") + end + end +end