add tests for reviews liveviews and worker
All checks were successful
deploy / deploy (push) Successful in 39s
All checks were successful
deploy / deploy (push) Successful in 39s
- admin reviews test: list, filter, search, moderation (approve/reject/delete) - review form test: rendering, validation, submission, edit flow - review request worker test: email sending, edge cases, scheduling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
149
test/berrypod/reviews/review_request_worker_test.exs
Normal file
149
test/berrypod/reviews/review_request_worker_test.exs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
defmodule Berrypod.Reviews.ReviewRequestWorkerTest do
|
||||||
|
use Berrypod.DataCase, async: false
|
||||||
|
|
||||||
|
import Swoosh.TestAssertions
|
||||||
|
|
||||||
|
alias Berrypod.Orders
|
||||||
|
alias Berrypod.Reviews
|
||||||
|
alias Berrypod.Reviews.ReviewRequestWorker
|
||||||
|
|
||||||
|
import Berrypod.ProductsFixtures
|
||||||
|
|
||||||
|
defp delivered_order_fixture(attrs \\ %{}) do
|
||||||
|
conn = provider_connection_fixture(%{provider_type: "printify"})
|
||||||
|
product = product_fixture(%{provider_connection: conn})
|
||||||
|
variant = product_variant_fixture(%{product: product})
|
||||||
|
|
||||||
|
# Create order with product_id set on the item so review request can find unreviewable products
|
||||||
|
items = [
|
||||||
|
%{
|
||||||
|
variant_id: variant.id,
|
||||||
|
product_id: product.id,
|
||||||
|
name: product.title,
|
||||||
|
variant: variant.title,
|
||||||
|
price: 1999,
|
||||||
|
quantity: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
order_attrs =
|
||||||
|
%{
|
||||||
|
customer_email: Map.get(attrs, :customer_email, "buyer@example.com"),
|
||||||
|
currency: "gbp",
|
||||||
|
items: items
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, order} = Orders.create_order(order_attrs)
|
||||||
|
|
||||||
|
# Mark as paid
|
||||||
|
{:ok, order} = Orders.mark_paid(order, "pi_test_#{System.unique_integer([:positive])}")
|
||||||
|
|
||||||
|
# Mark as delivered
|
||||||
|
{:ok, order} = Orders.update_fulfilment(order, %{fulfilment_status: "delivered"})
|
||||||
|
|
||||||
|
{order, product}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "perform/1 — sends review request" do
|
||||||
|
test "sends review request email for delivered order" do
|
||||||
|
{order, _product} = delivered_order_fixture()
|
||||||
|
|
||||||
|
assert :ok =
|
||||||
|
ReviewRequestWorker.new(%{order_id: order.id})
|
||||||
|
|> Oban.insert!()
|
||||||
|
|> then(fn job -> ReviewRequestWorker.perform(job) end)
|
||||||
|
|
||||||
|
# Subject includes shop name so use function to check partial match
|
||||||
|
assert_email_sent(fn email ->
|
||||||
|
# to field format varies - just check email address is present
|
||||||
|
to_string = inspect(email.to)
|
||||||
|
assert to_string =~ order.customer_email
|
||||||
|
assert email.subject =~ "How was your order"
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not send if customer has already reviewed all products" do
|
||||||
|
{order, product} = delivered_order_fixture()
|
||||||
|
|
||||||
|
# Create review for the product
|
||||||
|
{:ok, _review} =
|
||||||
|
Reviews.create_review(%{
|
||||||
|
product_id: product.id,
|
||||||
|
email: order.customer_email,
|
||||||
|
author_name: "Buyer",
|
||||||
|
rating: 5
|
||||||
|
})
|
||||||
|
|
||||||
|
ReviewRequestWorker.perform(%Oban.Job{args: %{"order_id" => order.id}})
|
||||||
|
|
||||||
|
assert_no_email_sent()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not send if email is suppressed" do
|
||||||
|
{order, _product} = delivered_order_fixture(%{customer_email: "suppressed@example.com"})
|
||||||
|
Orders.add_suppression("suppressed@example.com", "unsubscribed")
|
||||||
|
|
||||||
|
ReviewRequestWorker.perform(%Oban.Job{args: %{"order_id" => order.id}})
|
||||||
|
|
||||||
|
assert_no_email_sent()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "cancels if order not found" do
|
||||||
|
result =
|
||||||
|
ReviewRequestWorker.perform(%Oban.Job{
|
||||||
|
args: %{"order_id" => Ecto.UUID.generate()}
|
||||||
|
})
|
||||||
|
|
||||||
|
assert {:cancel, :not_found} = result
|
||||||
|
assert_no_email_sent()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "skips if order has no customer email" do
|
||||||
|
{order, _product} = delivered_order_fixture()
|
||||||
|
|
||||||
|
# Clear email
|
||||||
|
{:ok, order} = Orders.update_order(order, %{customer_email: nil})
|
||||||
|
|
||||||
|
result = ReviewRequestWorker.perform(%Oban.Job{args: %{"order_id" => order.id}})
|
||||||
|
|
||||||
|
assert :ok = result
|
||||||
|
assert_no_email_sent()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "skips if order has empty customer email" do
|
||||||
|
{order, _product} = delivered_order_fixture()
|
||||||
|
|
||||||
|
# Set empty email
|
||||||
|
{:ok, order} = Orders.update_order(order, %{customer_email: ""})
|
||||||
|
|
||||||
|
result = ReviewRequestWorker.perform(%Oban.Job{args: %{"order_id" => order.id}})
|
||||||
|
|
||||||
|
assert :ok = result
|
||||||
|
assert_no_email_sent()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "enqueue/1" do
|
||||||
|
test "creates job with order_id" do
|
||||||
|
{order, _product} = delivered_order_fixture()
|
||||||
|
|
||||||
|
{:ok, job} = ReviewRequestWorker.enqueue(order.id)
|
||||||
|
|
||||||
|
assert job.args["order_id"] == order.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "new/2 with schedule_in" do
|
||||||
|
test "creates scheduled changeset with delay" do
|
||||||
|
# Test the changeset creation directly to verify schedule_in is applied
|
||||||
|
# (Oban inline mode doesn't preserve scheduled_at on insert)
|
||||||
|
changeset = ReviewRequestWorker.new(%{order_id: "test-id"}, schedule_in: 7 * 24 * 60 * 60)
|
||||||
|
|
||||||
|
assert changeset.changes.args == %{order_id: "test-id"}
|
||||||
|
assert changeset.changes.scheduled_at != nil
|
||||||
|
# Should be roughly 7 days in the future
|
||||||
|
diff = DateTime.diff(changeset.changes.scheduled_at, DateTime.utc_now(), :second)
|
||||||
|
assert diff > 6 * 24 * 60 * 60
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
234
test/berrypod_web/live/admin/reviews_test.exs
Normal file
234
test/berrypod_web/live/admin/reviews_test.exs
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
defmodule BerrypodWeb.Admin.ReviewsTest do
|
||||||
|
use BerrypodWeb.ConnCase, async: false
|
||||||
|
|
||||||
|
import Phoenix.LiveViewTest
|
||||||
|
import Berrypod.AccountsFixtures
|
||||||
|
import Berrypod.ProductsFixtures
|
||||||
|
|
||||||
|
alias Berrypod.Reviews
|
||||||
|
|
||||||
|
setup do
|
||||||
|
user = user_fixture()
|
||||||
|
%{user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_review(product, attrs \\ %{}) do
|
||||||
|
defaults = %{
|
||||||
|
product_id: product.id,
|
||||||
|
email: "reviewer-#{System.unique_integer([:positive])}@example.com",
|
||||||
|
author_name: "Test Reviewer",
|
||||||
|
rating: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, review} = Reviews.create_review(Map.merge(defaults, attrs))
|
||||||
|
review
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "unauthenticated" do
|
||||||
|
test "redirects to login", %{conn: conn} do
|
||||||
|
{:error, redirect} = live(conn, ~p"/admin/reviews")
|
||||||
|
assert {:redirect, %{to: path}} = redirect
|
||||||
|
assert path == ~p"/users/log-in"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "review list" do
|
||||||
|
setup %{conn: conn, user: user} do
|
||||||
|
conn = log_in_user(conn, user)
|
||||||
|
%{conn: conn}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders empty state when no reviews", %{conn: conn} do
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
assert html =~ "No reviews to show"
|
||||||
|
assert html =~ "Reviews"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders reviews list", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
create_review(product, %{author_name: "Jane Doe", rating: 5})
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
assert html =~ product.title
|
||||||
|
assert html =~ "Jane Doe"
|
||||||
|
assert html =~ "pending"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows status counts in tabs", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
_pending = create_review(product, %{email: "p@test.com"})
|
||||||
|
approved = create_review(product, %{email: "a@test.com"})
|
||||||
|
Reviews.approve_review(approved)
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
# Should show counts - pending has badge
|
||||||
|
assert html =~ "Pending"
|
||||||
|
assert html =~ "Approved"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filters by pending status", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
_pending = create_review(product, %{email: "pending@test.com", author_name: "Pending User"})
|
||||||
|
|
||||||
|
approved =
|
||||||
|
create_review(product, %{email: "approved@test.com", author_name: "Approved User"})
|
||||||
|
|
||||||
|
Reviews.approve_review(approved)
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
html = render_click(view, "filter", %{"status" => "pending"})
|
||||||
|
|
||||||
|
assert html =~ "Pending User"
|
||||||
|
refute html =~ "Approved User"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filters by approved status", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
_pending = create_review(product, %{email: "pending@test.com", author_name: "Pending User"})
|
||||||
|
|
||||||
|
approved =
|
||||||
|
create_review(product, %{email: "approved@test.com", author_name: "Approved User"})
|
||||||
|
|
||||||
|
Reviews.approve_review(approved)
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
html = render_click(view, "filter", %{"status" => "approved"})
|
||||||
|
|
||||||
|
assert html =~ "Approved User"
|
||||||
|
refute html =~ "Pending User"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "filters by rejected status", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
_pending = create_review(product, %{email: "pending@test.com", author_name: "Pending User"})
|
||||||
|
|
||||||
|
rejected =
|
||||||
|
create_review(product, %{email: "rejected@test.com", author_name: "Rejected User"})
|
||||||
|
|
||||||
|
Reviews.reject_review(rejected)
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
html = render_click(view, "filter", %{"status" => "rejected"})
|
||||||
|
|
||||||
|
assert html =~ "Rejected User"
|
||||||
|
refute html =~ "Pending User"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "search filters by author name", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
create_review(product, %{email: "a@test.com", author_name: "Alice"})
|
||||||
|
create_review(product, %{email: "b@test.com", author_name: "Bob"})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
html = render_submit(view, "search", %{"search" => %{"query" => "Alice"}})
|
||||||
|
|
||||||
|
assert html =~ "Alice"
|
||||||
|
refute html =~ "Bob"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "review moderation" do
|
||||||
|
setup %{conn: conn, user: user} do
|
||||||
|
conn = log_in_user(conn, user)
|
||||||
|
%{conn: conn}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expands review to show details", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product, %{title: "Great product!", body: "Would buy again."})
|
||||||
|
|
||||||
|
{:ok, view, html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
# Initially collapsed - body not visible
|
||||||
|
refute html =~ "Would buy again."
|
||||||
|
|
||||||
|
# Expand the review
|
||||||
|
html = render_click(view, "expand", %{"id" => review.id})
|
||||||
|
|
||||||
|
assert html =~ "Great product!"
|
||||||
|
assert html =~ "Would buy again."
|
||||||
|
end
|
||||||
|
|
||||||
|
test "approves a pending review", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product, %{author_name: "Jane"})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
# Expand first to see approve button
|
||||||
|
render_click(view, "expand", %{"id" => review.id})
|
||||||
|
html = render_click(view, "approve", %{"id" => review.id})
|
||||||
|
|
||||||
|
assert html =~ "Review approved"
|
||||||
|
|
||||||
|
# Verify in database
|
||||||
|
updated = Reviews.get_review(review.id)
|
||||||
|
assert updated.status == "approved"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rejects a pending review", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product, %{author_name: "Jane"})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
# Expand first to see reject button
|
||||||
|
render_click(view, "expand", %{"id" => review.id})
|
||||||
|
html = render_click(view, "reject", %{"id" => review.id})
|
||||||
|
|
||||||
|
assert html =~ "Review rejected"
|
||||||
|
|
||||||
|
# Verify in database
|
||||||
|
updated = Reviews.get_review(review.id)
|
||||||
|
assert updated.status == "rejected"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deletes a review", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product, %{author_name: "Jane"})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
# Expand first to see delete button
|
||||||
|
render_click(view, "expand", %{"id" => review.id})
|
||||||
|
html = render_click(view, "delete", %{"id" => review.id})
|
||||||
|
|
||||||
|
assert html =~ "Review deleted"
|
||||||
|
|
||||||
|
# Verify removed from database
|
||||||
|
assert Reviews.get_review(review.id) == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows rating only message when no title/body", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product, %{title: nil, body: nil})
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews")
|
||||||
|
|
||||||
|
html = render_click(view, "expand", %{"id" => review.id})
|
||||||
|
|
||||||
|
assert html =~ "No written review — rating only"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "approve button hidden for already approved reviews", %{conn: conn} do
|
||||||
|
product = product_fixture()
|
||||||
|
review = create_review(product)
|
||||||
|
{:ok, review} = Reviews.approve_review(review)
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/admin/reviews?status=approved")
|
||||||
|
|
||||||
|
html = render_click(view, "expand", %{"id" => review.id})
|
||||||
|
|
||||||
|
# Should show reject but not approve
|
||||||
|
assert html =~ "Reject"
|
||||||
|
refute html =~ ">Approve</button>" or html =~ "phx-click=\"approve\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
244
test/berrypod_web/live/shop/review_form_test.exs
Normal file
244
test/berrypod_web/live/shop/review_form_test.exs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
defmodule BerrypodWeb.Shop.ReviewFormTest do
|
||||||
|
use BerrypodWeb.ConnCase, async: false
|
||||||
|
|
||||||
|
import Phoenix.LiveViewTest
|
||||||
|
import Berrypod.AccountsFixtures
|
||||||
|
import Berrypod.ProductsFixtures
|
||||||
|
import Berrypod.OrdersFixtures
|
||||||
|
|
||||||
|
alias Berrypod.Reviews
|
||||||
|
|
||||||
|
setup do
|
||||||
|
user_fixture()
|
||||||
|
{:ok, _} = Berrypod.Settings.set_site_live(true)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp with_email_session(conn, email) do
|
||||||
|
conn
|
||||||
|
|> Phoenix.ConnTest.init_test_session(%{})
|
||||||
|
|> Plug.Conn.put_session("email_session", email)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "review form with valid token" do
|
||||||
|
setup do
|
||||||
|
prov_conn = provider_connection_fixture(%{provider_type: "printify"})
|
||||||
|
product = product_fixture(%{provider_connection: prov_conn})
|
||||||
|
variant = product_variant_fixture(%{product: product})
|
||||||
|
|
||||||
|
order =
|
||||||
|
order_fixture(%{
|
||||||
|
customer_email: "buyer@example.com",
|
||||||
|
payment_status: "paid",
|
||||||
|
variant_id: variant.id
|
||||||
|
})
|
||||||
|
|
||||||
|
token = Reviews.generate_review_token("buyer@example.com", product.id)
|
||||||
|
|
||||||
|
%{product: product, order: order, token: token}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders review form", %{conn: conn, product: product, token: token} do
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
assert html =~ "Write a review"
|
||||||
|
assert html =~ product.title
|
||||||
|
assert html =~ "Rating"
|
||||||
|
assert html =~ "Your name"
|
||||||
|
assert html =~ "Submit review"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "pre-fills author name from order shipping address", %{
|
||||||
|
conn: conn,
|
||||||
|
order: order,
|
||||||
|
token: token
|
||||||
|
} do
|
||||||
|
# Update order with shipping address
|
||||||
|
Berrypod.Orders.update_order(order, %{
|
||||||
|
shipping_address: %{"name" => "Jane Doe", "line1" => "123 Test St"}
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
assert html =~ "Jane Doe"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "validates rating is required", %{conn: conn, token: token} do
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
html =
|
||||||
|
view
|
||||||
|
|> form("form", %{"review" => %{"author_name" => "Jane", "rating" => ""}})
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert html =~ "can't be blank" or html =~ "is invalid"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "validates author name is required", %{conn: conn, token: token} do
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
# Set rating via event instead of form data (the hidden field only accepts "")
|
||||||
|
render_click(view, "set_rating", %{"rating" => "5"})
|
||||||
|
|
||||||
|
html =
|
||||||
|
view
|
||||||
|
|> form("form", %{"review" => %{"author_name" => ""}})
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert html =~ "can't be blank"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sets rating via star buttons", %{conn: conn, token: token} do
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
# Click on star 4
|
||||||
|
render_click(view, "set_rating", %{"rating" => "4"})
|
||||||
|
|
||||||
|
# The hidden input should have value 4
|
||||||
|
html = render(view)
|
||||||
|
assert html =~ ~r/name="review\[rating\]".*value="4"/s or html =~ "star-filled"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "submits review successfully", %{conn: conn, product: product, token: token} do
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
# Set rating first
|
||||||
|
render_click(view, "set_rating", %{"rating" => "5"})
|
||||||
|
|
||||||
|
html =
|
||||||
|
view
|
||||||
|
|> form("form", %{
|
||||||
|
"review" => %{
|
||||||
|
"author_name" => "Jane Doe",
|
||||||
|
"title" => "Great product!",
|
||||||
|
"body" => "Would recommend to everyone."
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert html =~ "Thanks for your review"
|
||||||
|
assert html =~ "Your review will appear on the product page once it's been approved"
|
||||||
|
|
||||||
|
# Verify review was created
|
||||||
|
review = Reviews.get_review_by_email_and_product("buyer@example.com", product.id)
|
||||||
|
assert review
|
||||||
|
assert review.rating == 5
|
||||||
|
assert review.author_name == "Jane Doe"
|
||||||
|
assert review.title == "Great product!"
|
||||||
|
assert review.status == "pending"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows error for already reviewed product", %{conn: conn, product: product, token: token} do
|
||||||
|
# Create existing review first
|
||||||
|
{:ok, _} =
|
||||||
|
Reviews.create_review(%{
|
||||||
|
product_id: product.id,
|
||||||
|
email: "buyer@example.com",
|
||||||
|
author_name: "Jane",
|
||||||
|
rating: 5
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/new?token=#{token}")
|
||||||
|
|
||||||
|
assert html =~ "already reviewed"
|
||||||
|
assert html =~ "Edit your existing review"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "review form with invalid token" do
|
||||||
|
test "shows error for invalid token", %{conn: conn} do
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/new?token=invalid_token")
|
||||||
|
|
||||||
|
assert html =~ "expired or is invalid"
|
||||||
|
assert html =~ "Please request a new one"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows error when no token provided", %{conn: conn} do
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/new")
|
||||||
|
|
||||||
|
assert html =~ "Invalid review link"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "edit review" do
|
||||||
|
setup do
|
||||||
|
prov_conn = provider_connection_fixture(%{provider_type: "printify"})
|
||||||
|
product = product_fixture(%{provider_connection: prov_conn})
|
||||||
|
variant = product_variant_fixture(%{product: product})
|
||||||
|
|
||||||
|
_order =
|
||||||
|
order_fixture(%{
|
||||||
|
customer_email: "editor@example.com",
|
||||||
|
payment_status: "paid",
|
||||||
|
variant_id: variant.id
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, review} =
|
||||||
|
Reviews.create_review(%{
|
||||||
|
product_id: product.id,
|
||||||
|
email: "editor@example.com",
|
||||||
|
author_name: "Editor",
|
||||||
|
rating: 4,
|
||||||
|
title: "Good product",
|
||||||
|
body: "It works well."
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, review} = Reviews.approve_review(review)
|
||||||
|
|
||||||
|
%{product: product, review: review}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows edit form with existing values when email session matches", %{
|
||||||
|
conn: conn,
|
||||||
|
product: product,
|
||||||
|
review: review
|
||||||
|
} do
|
||||||
|
conn = with_email_session(conn, "editor@example.com")
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/#{review.id}/edit?product=#{product.slug}")
|
||||||
|
|
||||||
|
assert html =~ "Edit your review"
|
||||||
|
assert html =~ "Editor"
|
||||||
|
assert html =~ "Good product"
|
||||||
|
assert html =~ "It works well"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows error when email session doesn't match", %{conn: conn, review: review} do
|
||||||
|
conn = with_email_session(conn, "other@example.com")
|
||||||
|
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/#{review.id}/edit")
|
||||||
|
|
||||||
|
assert html =~ "don't have permission"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows error when no email session", %{conn: conn, review: review} do
|
||||||
|
{:ok, _view, html} = live(conn, ~p"/reviews/#{review.id}/edit")
|
||||||
|
|
||||||
|
assert html =~ "don't have permission"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates review and resets to pending", %{conn: conn, product: product, review: review} do
|
||||||
|
conn = with_email_session(conn, "editor@example.com")
|
||||||
|
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/reviews/#{review.id}/edit?product=#{product.slug}")
|
||||||
|
|
||||||
|
html =
|
||||||
|
view
|
||||||
|
|> form("form", %{
|
||||||
|
"review" => %{
|
||||||
|
"title" => "Updated title",
|
||||||
|
"body" => "Updated body"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert html =~ "Your updated review will appear once approved"
|
||||||
|
|
||||||
|
# Verify review was updated and status reset
|
||||||
|
updated = Reviews.get_review(review.id)
|
||||||
|
assert updated.title == "Updated title"
|
||||||
|
assert updated.body == "Updated body"
|
||||||
|
assert updated.status == "pending"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user