feat: adds row validation

This commit is contained in:
carla 2026-01-19 11:22:11 +01:00
parent 9be5dc8751
commit 8b3cc6a6b2
2 changed files with 300 additions and 27 deletions

View file

@ -124,7 +124,52 @@ defmodule Mv.Membership.Import.MemberCSVTest do
error = List.first(chunk_result.errors)
assert error.csv_line_number == 2
assert error.field == :email
assert error.message =~ "email"
# Error message should come from validate_row (Gettext-backed)
assert is_binary(error.message)
assert error.message != ""
end
test "returns error for missing email" do
chunk_rows_with_lines = [
{2, %{member: %{}, custom: %{}}}
]
column_map = %{}
custom_field_map = %{}
opts = []
assert {:ok, chunk_result} =
MemberCSV.process_chunk(chunk_rows_with_lines, column_map, custom_field_map, opts)
assert chunk_result.inserted == 0
assert chunk_result.failed == 1
assert length(chunk_result.errors) == 1
error = List.first(chunk_result.errors)
assert error.csv_line_number == 2
assert error.field == :email
assert is_binary(error.message)
end
test "returns error for whitespace-only email" do
chunk_rows_with_lines = [
{3, %{member: %{email: " "}, custom: %{}}}
]
column_map = %{email: 0}
custom_field_map = %{}
opts = []
assert {:ok, chunk_result} =
MemberCSV.process_chunk(chunk_rows_with_lines, column_map, custom_field_map, opts)
assert chunk_result.inserted == 0
assert chunk_result.failed == 1
assert length(chunk_result.errors) == 1
error = List.first(chunk_result.errors)
assert error.csv_line_number == 3
assert error.field == :email
end
test "returns error for duplicate email" do
@ -218,6 +263,9 @@ defmodule Mv.Membership.Import.MemberCSVTest do
error = List.first(chunk_result.errors)
assert error.csv_line_number == 3
assert error.field == :email
# Error should come from validate_row, not from DB insert
assert is_binary(error.message)
end
test "preserves CSV line numbers in errors" do
@ -279,6 +327,145 @@ defmodule Mv.Membership.Import.MemberCSVTest do
end
end
describe "validate_row/3" do
test "returns error when email is missing" do
row_map = %{member: %{}, custom: %{}}
csv_line_number = 5
opts = []
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert %MemberCSV.Error{} = error
assert error.csv_line_number == 5
assert error.field == :email
assert error.message != nil
assert error.message != ""
end
test "returns error when email is only whitespace" do
row_map = %{member: %{email: " "}, custom: %{}}
csv_line_number = 3
opts = []
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert %MemberCSV.Error{} = error
assert error.csv_line_number == 3
assert error.field == :email
assert error.message != nil
end
test "returns error when email is nil" do
row_map = %{member: %{email: nil}, custom: %{}}
csv_line_number = 7
opts = []
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert %MemberCSV.Error{} = error
assert error.csv_line_number == 7
assert error.field == :email
end
test "returns error when email format is invalid" do
row_map = %{member: %{email: "invalid-email"}, custom: %{}}
csv_line_number = 4
opts = []
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert %MemberCSV.Error{} = error
assert error.csv_line_number == 4
assert error.field == :email
assert error.message != nil
end
test "returns {:ok, trimmed_row_map} when email is valid with whitespace" do
row_map = %{member: %{email: " john@example.com "}, custom: %{}}
csv_line_number = 2
opts = []
assert {:ok, trimmed_row_map} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert trimmed_row_map.member.email == "john@example.com"
end
test "returns {:ok, trimmed_row_map} when email is valid without whitespace" do
row_map = %{member: %{email: "john@example.com"}, custom: %{}}
csv_line_number = 2
opts = []
assert {:ok, trimmed_row_map} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert trimmed_row_map.member.email == "john@example.com"
end
test "trims all string values in member map" do
row_map = %{
member: %{
email: " john@example.com ",
first_name: " John ",
last_name: " Doe "
},
custom: %{}
}
csv_line_number = 2
opts = []
assert {:ok, trimmed_row_map} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert trimmed_row_map.member.email == "john@example.com"
assert trimmed_row_map.member.first_name == "John"
assert trimmed_row_map.member.last_name == "Doe"
end
test "preserves custom map unchanged" do
row_map = %{
member: %{email: "john@example.com"},
custom: %{"field1" => "value1"}
}
csv_line_number = 2
opts = []
assert {:ok, trimmed_row_map} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert trimmed_row_map.custom == %{"field1" => "value1"}
end
test "uses Gettext for error messages" do
row_map = %{member: %{}, custom: %{}}
csv_line_number = 5
opts = []
# Test with default locale (should work)
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert is_binary(error.message)
# Test with German locale
Gettext.put_locale(MvWeb.Gettext, "de")
assert {:error, error_de} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert is_binary(error_de.message)
# Test with English locale
Gettext.put_locale(MvWeb.Gettext, "en")
assert {:error, error_en} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert is_binary(error_en.message)
# Reset to default
Gettext.put_locale(MvWeb.Gettext, "en")
end
test "handles empty opts gracefully" do
row_map = %{member: %{email: "john@example.com"}, custom: %{}}
csv_line_number = 2
opts = []
assert {:ok, _} = MemberCSV.validate_row(row_map, csv_line_number, opts)
end
test "handles missing member key gracefully" do
row_map = %{custom: %{}}
csv_line_number = 3
opts = []
assert {:error, error} = MemberCSV.validate_row(row_map, csv_line_number, opts)
assert %MemberCSV.Error{} = error
assert error.csv_line_number == 3
end
end
describe "module documentation" do
test "module has @moduledoc" do
# Check that the module exists and has documentation