from src.email_utils import format_onboarding_email, parse_contacts_from_array, get_email_addresses class TestFormatOnboardingEmail: """Tests for email formatting function.""" def test_empty_contacts_produces_safe_greeting(self): """Empty contacts should still produce valid email without PII leakage.""" stores = [ { "shop_domain": "store1.myshopify.com", "connect_card_uri": "https://card1", "link_expires_at": "2026-07-09T10:00:00+00:00", } ] contacts = [] body = format_onboarding_email(stores, contacts) assert "Dear ," not in body assert "Dear Team," in body def test_happy_path_produces_valid_email(self): """Valid stores and contacts should produce well-formatted email.""" stores = [ { "shop_domain": "store1.myshopify.com", "connect_card_uri": "https://card1", "link_expires_at": "2026-07-09T10:00:00+00:00", } ] contacts = [{"name": "John", "role": "Admin", "company": "Acme", "email": "john@acme.com"}] body = format_onboarding_email(stores, contacts) assert "John" in body assert "store1.myshopify.com" in body assert "https://card1" in body assert "2026-07-09T10:00:00+00:00" in body class TestParseContactsFromArray: """Tests for contact parsing.""" def test_empty_array_returns_empty_list(self): result = parse_contacts_from_array([]) assert result == [] def test_none_returns_empty_list(self): result = parse_contacts_from_array(None) assert result == [] def test_json_string_parsed_correctly(self): import json contacts_json = json.dumps([{"NAME": "Alice", "EMAIL": "alice@test.com"}]) result = parse_contacts_from_array(contacts_json) assert len(result) == 1 assert result[0]["name"] == "Alice" assert result[0]["email"] == "alice@test.com" class TestGetEmailAddresses: """Tests for email extraction and validation.""" def test_valid_emails_extracted(self): contacts = [ {"name": "John", "email": "john@example.com"}, {"name": "Jane", "email": "jane@example.com"}, ] result = get_email_addresses(contacts) assert len(result) == 2 assert "john@example.com" in result assert "jane@example.com" in result def test_invalid_emails_filtered(self): """Emails without domain should be filtered out.""" contacts = [ {"name": "John", "email": "john@example.com"}, {"name": "Bad", "email": "nodomain"}, {"name": "Invalid", "email": "noatsign.com"}, ] result = get_email_addresses(contacts) assert len(result) == 1 assert result[0] == "john@example.com" def test_empty_contacts_returns_empty_list(self): result = get_email_addresses([]) assert result == [] def test_duplicates_deduplicated(self): contacts = [ {"name": "John1", "email": "john@example.com"}, {"name": "John2", "email": "john@example.com"}, ] result = get_email_addresses(contacts) assert len(result) == 1 assert result[0] == "john@example.com" def test_emails_normalized_to_lowercase(self): contacts = [{"name": "John", "email": "JOHN@EXAMPLE.COM"}] result = get_email_addresses(contacts) assert result[0] == "john@example.com"