| defmodule PlausibleWeb.Live.Components.FormTest do |
| use PlausibleWeb.ConnCase, async: true |
| import Phoenix.LiveViewTest, only: [render_component: 2] |
|
|
| alias Plausible.Auth.User |
| alias PlausibleWeb.Live.Components.Form |
|
|
| describe "password_input_with_strength/1" do |
| test "renders for correct, strong password" do |
| doc = render_password_input_with_strength("very-secret-and-very-long-123") |
|
|
| assert element_exists?(doc, ~s/input#user_password[type="password"][name="user[password]"]/) |
| refute element_exists?(doc, "label") |
| assert text_of_element(doc, "p") =~ "Password strength:" |
| assert text_of_element(doc, "p") =~ "Strong" |
| end |
|
|
| test "renders with label when passed" do |
| doc = |
| render_password_input_with_strength( |
| "very-secret-and-very-long-123", |
| label: "New password" |
| ) |
|
|
| assert element_exists?(doc, ~s/input#user_password[type="password"][name="user[password]"]/) |
| assert element_exists?(doc, ~s/label[for="user_password"]/) |
| assert text_of_element(doc, ~s/label[for="user_password"]/) == "New password" |
| end |
|
|
| test "renders weak password warning and hints when password too short" do |
| doc = render_password_input_with_strength("too-short") |
|
|
| assert text_of_element(doc, "p:first-of-type") == "Password is too weak." |
| assert text_of_element(doc, "p:last-of-type") != "" |
| end |
|
|
| test "does not render hints and suggestions paragraph when there's none" do |
| doc = |
| render_password_input_with_strength("very-secret-but-too-short", |
| strength: %{ |
| score: 2, |
| warning: "", |
| suggestions: [] |
| } |
| ) |
|
|
| assert warning_p = find(doc, "p") |
| assert text(warning_p) == "Password is too weak." |
| end |
|
|
| test "renders too long password case gracefully" do |
| too_long_password = String.duplicate("very-long-very-secret-1234567890", 10) |
| doc = render_password_input_with_strength(too_long_password) |
|
|
| assert error_p = find(doc, "p") |
| assert text(error_p) =~ "cannot be longer than" |
| end |
| end |
|
|
| describe "password_length_hint/1" do |
| test "renders for long enough password" do |
| doc = render_password_length_hint("very-secret-and-very-long-123", 12) |
|
|
| assert p_hint = find(doc, "p") |
| assert text_of_attr(p_hint, "class") =~ "text-gray-500" |
| assert text(p_hint) == "At least 12 characters" |
| end |
|
|
| test "renders for too short password" do |
| doc = render_password_length_hint("too-short", 12) |
|
|
| assert p_hint = find(doc, "p") |
| assert text_of_attr(p_hint, "class") =~ "text-red-500" |
| assert text(p_hint) == "At least 12 characters" |
| end |
|
|
| test "renders gracefully for too long password" do |
| too_long_password = String.duplicate("very-long-very-secret-1234567890", 10) |
| doc = render_password_length_hint(too_long_password, 12) |
|
|
| assert p_hint = find(doc, "p") |
| assert text_of_attr(p_hint, "class") =~ "text-gray-500" |
| assert text(p_hint) == "At least 12 characters" |
| end |
| end |
|
|
| describe "strength_meter/1" do |
| test "renders too weak level" do |
| doc = render_component(&Form.strength_meter/1, score: 0, warning: "", suggestions: []) |
|
|
| refute element_exists?(doc, "div.rounded-full") |
| assert text_of_element(doc, "p") == "Password is too weak." |
| end |
|
|
| test "renders very weak level" do |
| doc = render_component(&Form.strength_meter/1, score: 1, warning: "", suggestions: []) |
|
|
| assert text_of_element(doc, "p") == "Password is too weak." |
| end |
|
|
| test "renders somewhat weak level" do |
| doc = render_component(&Form.strength_meter/1, score: 2, warning: "", suggestions: []) |
|
|
| assert text_of_element(doc, "p") == "Password is too weak." |
| end |
|
|
| test "renders strong level" do |
| doc = render_component(&Form.strength_meter/1, score: 3, warning: "", suggestions: []) |
|
|
| assert text_of_element(doc, "p") =~ "Password strength:" |
| assert text_of_element(doc, "p") =~ "Good" |
| end |
|
|
| test "renders very strong level" do |
| doc = render_component(&Form.strength_meter/1, score: 4, warning: "", suggestions: []) |
|
|
| assert text_of_element(doc, "p") =~ "Password strength:" |
| assert text_of_element(doc, "p") =~ "Strong" |
| end |
|
|
| test "renders hints paragraph when warning hint is present" do |
| doc = |
| render_component(&Form.strength_meter/1, |
| score: 2, |
| warning: "Test warning hint", |
| suggestions: [] |
| ) |
|
|
| assert text_of_element(doc, "p:last-of-type") == "Test warning hint." |
| end |
|
|
| test "renders only first suggestion when no warning present" do |
| doc = |
| render_component(&Form.strength_meter/1, |
| score: 2, |
| warning: "", |
| suggestions: ["Test suggestion 1.", "Test suggestion 2."] |
| ) |
|
|
| assert text_of_element(doc, "p:last-of-type") == "Test suggestion 1." |
| end |
|
|
| @tag :slow |
| test "favors hint warning over suggestion when both present" do |
| doc = |
| render_component(&Form.strength_meter/1, |
| score: 2, |
| warning: "Test warning hint", |
| suggestions: ["Test suggestion 1.", "Test suggestion 2."] |
| ) |
|
|
| assert text_of_element(doc, "p:last-of-type") == "Test warning hint." |
| end |
| end |
|
|
| defp render_password_input_with_strength(password, attrs \\ []) do |
| changeset = |
| %{"password" => password} |
| |> User.new() |
| |> Map.put(:action, :validate) |
|
|
| strength = User.password_strength(changeset) |
| form = Phoenix.Component.to_form(changeset) |
|
|
| render_component( |
| &Form.password_input_with_strength/1, |
| Keyword.merge([field: form[:password], strength: strength], attrs) |
| ) |
| end |
|
|
| defp render_password_length_hint(password, minimum) do |
| changeset = |
| %{"password" => password} |
| |> User.new() |
| |> Map.put(:action, :validate) |
|
|
| form = Phoenix.Component.to_form(changeset) |
|
|
| render_component(&Form.password_length_hint/1, field: form[:password], minimum: minimum) |
| end |
| end |
|
|