Files
orion/app/modules/prospecting/tests/unit/test_prospect_service.py
Samir Boulahtit 6d6eba75bf
Some checks failed
CI / pytest (push) Failing after 48m31s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped
CI / ruff (push) Successful in 11s
CI / validate (push) Successful in 23s
CI / dependency-scanning (push) Successful in 28s
feat(prospecting): add complete prospecting module for lead discovery and scoring
Migrates scanning pipeline from marketing-.lu-domains app into Orion module.
Supports digital (domain scan) and offline (manual capture) lead channels
with enrichment, scoring, campaign management, and interaction tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:59:47 +01:00

150 lines
5.6 KiB
Python

# app/modules/prospecting/tests/unit/test_prospect_service.py
"""
Unit tests for ProspectService.
"""
import pytest
from app.modules.prospecting.exceptions import ProspectNotFoundException
from app.modules.prospecting.services.prospect_service import ProspectService
@pytest.mark.unit
@pytest.mark.prospecting
class TestProspectService:
"""Tests for ProspectService."""
def setup_method(self):
self.service = ProspectService()
def test_create_digital_prospect(self, db):
"""Test creating a digital prospect."""
prospect = self.service.create(
db,
{"channel": "digital", "domain_name": "example.lu", "source": "domain_scan"},
)
assert prospect.id is not None
assert prospect.channel.value == "digital"
assert prospect.domain_name == "example.lu"
assert prospect.status.value == "pending"
def test_create_offline_prospect(self, db):
"""Test creating an offline prospect."""
prospect = self.service.create(
db,
{
"channel": "offline",
"business_name": "Test Café",
"source": "street",
"city": "Luxembourg",
},
)
assert prospect.id is not None
assert prospect.channel.value == "offline"
assert prospect.business_name == "Test Café"
assert prospect.city == "Luxembourg"
def test_create_digital_prospect_with_contacts(self, db):
"""Test creating a digital prospect with inline contacts."""
prospect = self.service.create(
db,
{
"channel": "digital",
"domain_name": "with-contacts.lu",
"contacts": [
{"contact_type": "email", "value": "info@with-contacts.lu"},
],
},
)
assert prospect.id is not None
assert len(prospect.contacts) == 1
assert prospect.contacts[0].value == "info@with-contacts.lu"
def test_get_by_id(self, db, digital_prospect):
"""Test getting a prospect by ID."""
result = self.service.get_by_id(db, digital_prospect.id)
assert result.id == digital_prospect.id
assert result.domain_name == digital_prospect.domain_name
def test_get_by_id_not_found(self, db):
"""Test getting non-existent prospect raises exception."""
with pytest.raises(ProspectNotFoundException):
self.service.get_by_id(db, 99999)
def test_get_by_domain(self, db, digital_prospect):
"""Test getting a prospect by domain name."""
result = self.service.get_by_domain(db, digital_prospect.domain_name)
assert result is not None
assert result.id == digital_prospect.id
def test_get_all_with_pagination(self, db, digital_prospect, offline_prospect):
"""Test listing prospects with pagination."""
prospects, total = self.service.get_all(db, page=1, per_page=10)
assert total >= 2
assert len(prospects) >= 2
def test_get_all_filter_by_channel(self, db, digital_prospect, offline_prospect):
"""Test filtering prospects by channel."""
digital, count = self.service.get_all(db, channel="digital")
assert count >= 1
assert all(p.channel.value == "digital" for p in digital)
def test_get_all_filter_by_status(self, db, digital_prospect):
"""Test filtering prospects by status."""
active, count = self.service.get_all(db, status="active")
assert count >= 1
assert all(p.status.value == "active" for p in active)
def test_get_all_search(self, db, digital_prospect):
"""Test searching prospects by domain or business name."""
domain = digital_prospect.domain_name
results, count = self.service.get_all(db, search=domain[:8])
assert count >= 1
def test_update_prospect(self, db, digital_prospect):
"""Test updating a prospect."""
updated = self.service.update(
db, digital_prospect.id, {"notes": "Updated notes", "status": "contacted"}
)
assert updated.notes == "Updated notes"
assert updated.status.value == "contacted"
def test_delete_prospect(self, db, digital_prospect):
"""Test deleting a prospect."""
pid = digital_prospect.id
self.service.delete(db, pid)
with pytest.raises(ProspectNotFoundException):
self.service.get_by_id(db, pid)
def test_create_bulk(self, db):
"""Test bulk creating prospects from domain list."""
domains = ["bulk1.lu", "bulk2.lu", "bulk3.lu"]
created, skipped = self.service.create_bulk(db, domains, source="csv_import")
assert created == 3
assert skipped == 0
def test_create_bulk_skips_duplicates(self, db, digital_prospect):
"""Test bulk create skips existing domains."""
domains = [digital_prospect.domain_name, "new-domain.lu"]
created, skipped = self.service.create_bulk(db, domains, source="csv_import")
assert created == 1
assert skipped == 1
def test_count_by_status(self, db, digital_prospect, offline_prospect):
"""Test counting prospects by status."""
counts = self.service.count_by_status(db)
assert isinstance(counts, dict)
assert counts.get("active", 0) >= 1
assert counts.get("pending", 0) >= 1
def test_count_by_channel(self, db, digital_prospect, offline_prospect):
"""Test counting prospects by channel."""
counts = self.service.count_by_channel(db)
assert isinstance(counts, dict)
assert counts.get("digital", 0) >= 1
assert counts.get("offline", 0) >= 1