from django.contrib.auth import get_user_model from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.urls import reverse from .models import Business, BusinessMembership, Customer, Job, JobMedia, ProofCard, ReviewRequest User = get_user_model() class TrustForgeFlowTests(TestCase): def setUp(self): self.user = User.objects.create_user( username='owner@example.com', email='owner@example.com', password='StrongPass123!', ) self.business = Business.objects.create( name='Forge Roofing', slug='forge-roofing', industry='Roofing', primary_city='Austin', primary_state='TX', google_review_url='https://example.com/google-review', ) self.membership = BusinessMembership.objects.create( user=self.user, business=self.business, role=BusinessMembership.Role.OWNER, ) self.customer = Customer.objects.create( business=self.business, full_name='Jordan Lee', email='jordan@example.com', city='Austin', state='TX', ) self.job = Job.objects.create( business=self.business, customer=self.customer, service_type='Roof repair', city='Austin', state='TX', ) JobMedia.objects.create( job=self.job, media_type=JobMedia.MediaType.BEFORE, file=SimpleUploadedFile('before-sample.jpg', b'before-image-bytes', content_type='image/jpeg'), ) JobMedia.objects.create( job=self.job, media_type=JobMedia.MediaType.AFTER, file=SimpleUploadedFile('after-sample.jpg', b'after-image-bytes', content_type='image/jpeg'), ) self.proof_card = ProofCard.objects.create(job=self.job, customer_display_name='Verified homeowner') self.review_request = ReviewRequest.objects.create(job=self.job) def test_home_loads(self): response = self.client.get(reverse('home')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'TrustForge') def test_dashboard_requires_login(self): response = self.client.get(reverse('dashboard')) self.assertEqual(response.status_code, 302) self.assertIn(reverse('login'), response.url) def test_login_with_email_redirects_to_dashboard(self): response = self.client.post( reverse('login'), {'username': 'owner@example.com', 'password': 'StrongPass123!'}, ) self.assertRedirects(response, reverse('dashboard')) def test_logged_in_user_without_membership_redirects_to_onboarding(self): user = User.objects.create_user( username='solo@example.com', email='solo@example.com', password='StrongPass123!', ) self.client.force_login(user) response = self.client.get(reverse('dashboard')) self.assertRedirects(response, reverse('business_onboarding')) def test_dashboard_only_shows_active_business_data(self): other_business = Business.objects.create( name='Hidden Plumbing', slug='hidden-plumbing', industry='Plumbing', primary_city='Dallas', primary_state='TX', ) other_customer = Customer.objects.create( business=other_business, full_name='Taylor Shade', city='Dallas', state='TX', ) Job.objects.create( business=other_business, customer=other_customer, service_type='Leak repair', city='Dallas', state='TX', ) self.client.force_login(self.user) response = self.client.get(reverse('dashboard')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Forge Roofing proof momentum') self.assertNotContains(response, 'Leak repair') def test_technician_cannot_edit_proof_card(self): technician = User.objects.create_user( username='tech@example.com', email='tech@example.com', password='StrongPass123!', ) BusinessMembership.objects.create( user=technician, business=self.business, role=BusinessMembership.Role.TECHNICIAN, ) self.client.force_login(technician) response = self.client.get(reverse('proof_card_edit', args=[self.proof_card.id])) self.assertEqual(response.status_code, 403) def test_public_review_positive_feedback_publishes_proof(self): response = self.client.post( reverse('review_request', args=[self.review_request.token]), {'experience': 'great', 'testimonial': 'They showed up on time and the roof looks incredible.'}, ) self.assertEqual(response.status_code, 200) self.proof_card.refresh_from_db() self.assertEqual(self.proof_card.status, 'published') self.assertEqual(self.proof_card.rating, 5) def test_public_gallery_only_shows_published_cards_for_requested_business(self): self.proof_card.status = ProofCard.Status.PUBLISHED self.proof_card.is_featured = True self.proof_card.testimonial_quote = 'Published proof for Forge Roofing.' self.proof_card.save(update_fields=['status', 'is_featured', 'testimonial_quote']) other_business = Business.objects.create( name='Quiet Electric', slug='quiet-electric', industry='Electrical', primary_city='Denver', primary_state='CO', ) other_customer = Customer.objects.create( business=other_business, full_name='Morgan Bright', city='Denver', state='CO', ) other_job = Job.objects.create( business=other_business, customer=other_customer, service_type='Panel upgrade', city='Denver', state='CO', ) ProofCard.objects.create( job=other_job, customer_display_name='Verified homeowner', status=ProofCard.Status.PUBLISHED, testimonial_quote='This should not appear in Forge Roofing gallery.', ) draft_customer = Customer.objects.create( business=self.business, full_name='Casey Draft', city='Austin', state='TX', ) draft_job = Job.objects.create( business=self.business, customer=draft_customer, service_type='Draft-only repair', city='Austin', state='TX', ) ProofCard.objects.create( job=draft_job, customer_display_name='Hidden draft', status=ProofCard.Status.DRAFT, testimonial_quote='Draft cards should stay private.', ) response = self.client.get(reverse('public_proof_gallery', args=[self.business.slug])) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Forge Roofing completed work') self.assertContains(response, 'Published proof for Forge Roofing.') self.assertContains(response, self.job.before_media.file.url) self.assertContains(response, self.job.after_media.file.url) self.assertNotContains(response, 'This should not appear in Forge Roofing gallery.') self.assertNotContains(response, 'Draft cards should stay private.') def test_workspace_proof_detail_renders_uploaded_media(self): self.client.force_login(self.user) response = self.client.get(reverse('proof_card_detail', args=[self.proof_card.id])) self.assertEqual(response.status_code, 200) self.assertContains(response, self.job.before_media.file.url) self.assertContains(response, self.job.after_media.file.url) def test_public_proof_detail_requires_published_status(self): response = self.client.get(reverse('public_proof_detail', args=[self.business.slug, self.proof_card.id])) self.assertEqual(response.status_code, 404) self.proof_card.status = ProofCard.Status.PUBLISHED self.proof_card.testimonial_quote = 'Proof card is now public.' self.proof_card.save(update_fields=['status', 'testimonial_quote']) response = self.client.get(reverse('public_proof_detail', args=[self.business.slug, self.proof_card.id])) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Proof card is now public.') self.assertContains(response, self.job.before_media.file.url) self.assertContains(response, self.job.after_media.file.url)