From c2ac75b2bcd088960d67c337fcc2e3542d883b47 Mon Sep 17 00:00:00 2001
From: Todd Dembrey <todd.dembrey@torchbox.com>
Date: Fri, 10 Aug 2018 12:49:20 +0100
Subject: [PATCH] Fixup the tests for the revisions and address

---
 opentech/apply/funds/models/forms.py          |  6 +--
 .../apply/funds/tests/factories/blocks.py     | 46 ++++++++++++++++-
 .../apply/funds/tests/factories/models.py     | 44 ++++++++++++++++-
 opentech/apply/funds/tests/test_models.py     | 43 ++++++++++++----
 opentech/apply/funds/tests/test_views.py      | 39 +++++++++++++++
 .../apply/review/tests/factories/blocks.py    |  2 +-
 .../apply/review/tests/factories/models.py    | 49 +------------------
 opentech/apply/review/tests/test_views.py     | 23 +++++----
 opentech/apply/stream_forms/blocks.py         |  2 +-
 .../apply/stream_forms/testing/factories.py   |  8 +++
 10 files changed, 185 insertions(+), 77 deletions(-)

diff --git a/opentech/apply/funds/models/forms.py b/opentech/apply/funds/models/forms.py
index 0eaba0798..84154539f 100644
--- a/opentech/apply/funds/models/forms.py
+++ b/opentech/apply/funds/models/forms.py
@@ -63,6 +63,9 @@ class LabBaseForm(AbstractRelatedForm):
 
 
 class AbstractRelatedReviewForm(Orderable):
+    class Meta(Orderable.Meta):
+        abstract = True
+
     form = models.ForeignKey('review.ReviewForm', on_delete=models.PROTECT)
 
     panels = [
@@ -73,9 +76,6 @@ class AbstractRelatedReviewForm(Orderable):
     def fields(self):
         return self.form.form_fields
 
-    class Meta(Orderable.Meta):
-        abstract = True
-
     def __eq__(self, other):
         try:
             return self.fields == other.fields
diff --git a/opentech/apply/funds/tests/factories/blocks.py b/opentech/apply/funds/tests/factories/blocks.py
index 77cc38d4c..f562cf496 100644
--- a/opentech/apply/funds/tests/factories/blocks.py
+++ b/opentech/apply/funds/tests/factories/blocks.py
@@ -1,3 +1,4 @@
+import json
 import random
 import factory
 
@@ -54,15 +55,58 @@ class ValueFieldBlockFactory(FormFieldBlockFactory):
         model = blocks.ValueBlock
 
     @classmethod
-    def make_answer(cls, params=dict()):
+    def make_answer(cls, params=dict(), form=False):
         return random.randint(0, 1_000_000)
 
 
+class AddressFieldBlockFactory(FormFieldBlockFactory):
+    class Meta:
+        model = blocks.AddressFieldBlock
+
+    @classmethod
+    def an_adress(cls):
+        return {
+            'country': 'GB',
+            'thoroughfare': 'bah',
+            'premise': 'baz',
+            'locality': {
+                'locality_name': 'bish',
+                'administrative_area': 'bosh',
+                'postal_code': 'SW1 4AQ',
+            }
+        }
+
+    @classmethod
+    def make_answer(cls, params=dict()):
+        return json.dumps({
+            'country': 'GB',
+            'thoroughfare': 'bah',
+            'premise': 'baz',
+            'localityname': 'bish',
+            'administrativearea': 'bosh',
+            'postalcode': 'SW1 4AQ',
+        })
+
+    @classmethod
+    def make_form_answer(cls, params=dict()):
+        return {
+            'country': 'GB',
+            'thoroughfare': 'bah',
+            'premise': 'baz',
+            'locality': {
+                'locality_name': 'bish',
+                'administrative_area': 'bosh',
+                'postal_code': 'SW1 4AQ',
+            }
+        }
+
+
 CustomFormFieldsFactory = StreamFieldUUIDFactory({
     'duration': DurationBlockFactory,
     'title': TitleBlockFactory,
     'value': ValueFieldBlockFactory,
     'email': EmailBlockFactory,
+    'address': AddressFieldBlockFactory,
     'full_name': FullNameBlockFactory,
     'char': CharFieldBlockFactory,
     'number': NumberFieldBlockFactory,
diff --git a/opentech/apply/funds/tests/factories/models.py b/opentech/apply/funds/tests/factories/models.py
index cffdc36f1..591854e89 100644
--- a/opentech/apply/funds/tests/factories/models.py
+++ b/opentech/apply/funds/tests/factories/models.py
@@ -15,8 +15,11 @@ from opentech.apply.funds.models import (
 from opentech.apply.funds.models.forms import (
     ApplicationForm,
     ApplicationBaseForm,
+    ApplicationBaseReviewForm,
     LabBaseForm,
+    LabBaseReviewForm,
     RoundBaseForm,
+    RoundBaseReviewForm,
 )
 from opentech.apply.users.tests.factories import StaffFactory, UserFactory
 from opentech.apply.stream_forms.testing.factories import FormDataFactory
@@ -69,14 +72,16 @@ class FundTypeFactory(wagtail_factories.PageFactory):
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
         if create:
-            from opentech.apply.review.tests.factories.models import ReviewFormFactory
             for _ in self.workflow.stages:
                 # Generate a form based on all defined fields on the model
                 ApplicationBaseFormFactory(
                     application=self,
                     **kwargs,
                 )
-                ReviewFormFactory(**kwargs)
+                ApplicationBaseReviewForm(
+                    application=self,
+                    **kwargs,
+                )
 
 
 class RequestForPartnersFactory(FundTypeFactory):
@@ -128,6 +133,10 @@ class RoundFactory(wagtail_factories.PageFactory):
                     round=self,
                     **kwargs,
                 )
+                RoundBaseReviewFormFactory(
+                    round=self,
+                    **kwargs,
+                )
 
 
 class SealedRoundFactory(RoundFactory):
@@ -167,6 +176,10 @@ class LabFactory(wagtail_factories.PageFactory):
                     lab=self,
                     **kwargs,
                 )
+                LabBaseReviewFormFactory(
+                    lab=self,
+                    **kwargs,
+                )
 
 
 class LabBaseFormFactory(AbstractRelatedFormFactory):
@@ -239,3 +252,30 @@ class ApplicationRevisionFactory(factory.DjangoModelFactory):
         for_factory=ApplicationSubmissionFactory,
         clean=True,
     )
+
+
+class AbstractReviewFormFactory(factory.DjangoModelFactory):
+    class Meta:
+        abstract = True
+    form = factory.SubFactory('opentech.apply.review.tests.factories.ReviewFormFactory')
+
+
+class ApplicationBaseReviewFormFactory(AbstractReviewFormFactory):
+    class Meta:
+        model = ApplicationBaseReviewForm
+
+    application = factory.SubFactory(FundTypeFactory)
+
+
+class RoundBaseReviewFormFactory(AbstractReviewFormFactory):
+    class Meta:
+        model = RoundBaseReviewForm
+
+    round = factory.SubFactory(RoundFactory)
+
+
+class LabBaseReviewFormFactory(AbstractReviewFormFactory):
+    class Meta:
+        model = LabBaseReviewForm
+
+    lab = factory.SubFactory(LabFactory)
diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py
index 9b21854c4..b3b79b32f 100644
--- a/opentech/apply/funds/tests/test_models.py
+++ b/opentech/apply/funds/tests/test_models.py
@@ -12,6 +12,7 @@ from django.test import TestCase, override_settings
 from wagtail.core.models import Site
 
 from opentech.apply.funds.models import ApplicationSubmission
+from opentech.apply.funds.blocks import EmailBlock, FullNameBlock
 from opentech.apply.funds.workflow import Request
 from opentech.apply.utils.testing import make_request
 
@@ -28,6 +29,18 @@ def days_from_today(days):
     return date.today() + timedelta(days=days)
 
 
+def flatten_for_form(data, field_name='', number=False):
+    result = {}
+    for i, (field, value) in enumerate(data.items()):
+        if number:
+            field = f'{field_name}_{i}'
+        if isinstance(value, dict):
+            result.update(**flatten_for_form(value, field_name=field, number=True))
+        else:
+            result[field] = value
+    return result
+
+
 class TestFundModel(TestCase):
     def setUp(self):
         self.fund = FundTypeFactory(parent=None)
@@ -196,16 +209,24 @@ class TestFormSubmission(TestCase):
         self.round_page = RoundFactory(parent=fund, now=True)
         self.lab_page = LabFactory(lead=self.round_page.lead)
 
-    def submit_form(self, page=None, email=None, name=None, user=AnonymousUser()):
-        if email is None:
-            email = self.email
-        if name is None:
-            name = self.name
-
+    def submit_form(self, page=None, email=None, name=None, user=AnonymousUser(), ignore_errors=False):
         page = page or self.round_page
         fields = page.get_form_fields()
-        # This needs to match the order of the fields defined on the form factory
-        data = {k: v for k, v in zip(fields, [1, 'project', 0, email, name])}
+
+        data = {
+            field: factory.make_form_answer()
+            for field, factory in zip(fields, CustomFormFieldsFactory.factories.values())
+            if hasattr(factory, 'make_form_answer')
+        }
+
+        data = flatten_for_form(data)
+
+        for field in page.forms.first().fields:
+            if isinstance(field.block, EmailBlock):
+                data[field.id] = self.email if email is None else email
+            if isinstance(field.block, FullNameBlock):
+                data[field.id] = self.name if name is None else name
+
         request = make_request(user, data, method='post', site=self.site)
 
         try:
@@ -213,7 +234,9 @@ class TestFormSubmission(TestCase):
         except AttributeError:
             response = page.serve(request)
 
-        self.assertNotContains(response, 'There where some errors with your form')
+        if not ignore_errors:
+            # Check the data we submit is correct
+            self.assertNotContains(response, 'errors')
         return response
 
     def test_workflow_and_status_assigned(self):
@@ -287,7 +310,7 @@ class TestFormSubmission(TestCase):
         # Lead + applicant
         self.assertEqual(self.User.objects.count(), 2)
 
-        response = self.submit_form(email='', name='', user=user)
+        response = self.submit_form(email='', name='', user=user, ignore_errors=True)
         self.assertContains(response, 'This field is required')
 
         # Lead + applicant
diff --git a/opentech/apply/funds/tests/test_views.py b/opentech/apply/funds/tests/test_views.py
index ebacea7f3..19d73c2e0 100644
--- a/opentech/apply/funds/tests/test_views.py
+++ b/opentech/apply/funds/tests/test_views.py
@@ -1,5 +1,7 @@
 from datetime import datetime, timedelta
+import json
 
+from addressfield.widgets import AddressWidget
 from opentech.apply.activity.models import Activity
 from opentech.apply.funds.tests.factories import (
     ApplicationSubmissionFactory,
@@ -12,6 +14,7 @@ from opentech.apply.users.tests.factories import UserFactory, StaffFactory, Supe
 from opentech.apply.utils.testing.tests import BaseViewTestCase
 
 from ..models import ApplicationRevision
+from .test_models import flatten_for_form
 
 
 class BaseSubmissionViewTestCase(BaseViewTestCase):
@@ -130,6 +133,17 @@ class TestApplicantSubmissionView(BaseSubmissionViewTestCase):
 class TestRevisionsView(BaseSubmissionViewTestCase):
     user_factory = UserFactory
 
+    def prepare_address(self, address, field):
+        address = json.loads(address)
+        address['locality'] = {
+            'localityname': address.pop('localityname'),
+            'administrativearea': address.pop('administrativearea'),
+            'postalcode': address.pop('postalcode'),
+        }
+        address = flatten_for_form(address, field, number=True)
+        return address
+
+
     def test_create_revisions_on_submit(self):
         submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
         old_data = submission.form_data.copy()
@@ -137,6 +151,13 @@ class TestRevisionsView(BaseSubmissionViewTestCase):
         new_title = 'New title'
         new_data[submission.must_include['title']] = new_title
 
+        address_id = submission.must_include['address']
+
+        new_data.update(**self.prepare_address(
+            new_data[submission.must_include['address']],
+            address_id,
+        ))
+
         self.post_page(submission, {'submit': True, **new_data}, 'edit')
 
         submission = self.refresh(submission)
@@ -151,7 +172,16 @@ class TestRevisionsView(BaseSubmissionViewTestCase):
     def test_dont_update_live_revision_on_save(self):
         submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
         old_data = submission.form_data.copy()
+
         new_data = submission.raw_data
+
+        address_id = submission.must_include['address']
+
+        new_data.update(**self.prepare_address(
+            new_data[submission.must_include['address']],
+            address_id,
+        ))
+
         new_data[submission.must_include['title']] = 'New title'
         self.post_page(submission, {'save': True, **new_data}, 'edit')
 
@@ -166,7 +196,16 @@ class TestRevisionsView(BaseSubmissionViewTestCase):
     def test_existing_draft_edit_and_submit(self):
         submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2, user=self.user)
         draft_data = submission.raw_data.copy()
+
+        address_id = submission.must_include['address']
+
+        draft_data.update(**self.prepare_address(
+            draft_data[submission.must_include['address']],
+            address_id,
+        ))
+
         draft_data[submission.must_include['title']] = 'New title'
+
         self.post_page(submission, {'save': True, **draft_data}, 'edit')
 
         submission = self.refresh(submission)
diff --git a/opentech/apply/review/tests/factories/blocks.py b/opentech/apply/review/tests/factories/blocks.py
index 77c8a1612..600291d33 100644
--- a/opentech/apply/review/tests/factories/blocks.py
+++ b/opentech/apply/review/tests/factories/blocks.py
@@ -37,7 +37,7 @@ class ScoreFieldBlockFactory(FormFieldBlockFactory):
 ReviewFormFieldsFactory = StreamFieldUUIDFactory({
     'char': CharFieldBlockFactory,
     'rich_text': RichTextFieldBlockFactory,
-    'scored_answer': ScoreFieldBlockFactory,
+    'score': ScoreFieldBlockFactory,
     'recommendation': RecommendationBlockFactory,
     'recommendation_comments': RecommendationCommentsBlockFactory,
 })
diff --git a/opentech/apply/review/tests/factories/models.py b/opentech/apply/review/tests/factories/models.py
index 79a82eb4b..6e7e57229 100644
--- a/opentech/apply/review/tests/factories/models.py
+++ b/opentech/apply/review/tests/factories/models.py
@@ -1,7 +1,6 @@
 import factory
 
-from opentech.apply.funds.models.forms import ApplicationBaseReviewForm
-from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory, FundTypeFactory
+from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory
 from opentech.apply.stream_forms.testing.factories import AddFormFieldsMetaclass
 from opentech.apply.users.tests.factories import StaffFactory
 
@@ -11,26 +10,12 @@ from ...views import get_fields_for_stage
 
 from . import blocks
 
-__all__ = ['ReviewFactory', 'ReviewFormFactory',
-           'ApplicationBaseReviewFormFactory', 'ReviewFundTypeFactory',
-           'ReviewApplicationSubmissionFactory']
+__all__ = ['ReviewFactory', 'ReviewFormFactory']
 
 
 class ReviewFormDataFactory(factory.DictFactory, metaclass=AddFormFieldsMetaclass):
     field_factory = blocks.ReviewFormFieldsFactory
 
-    @classmethod
-    def _build(cls, model_class, *args, **kwargs):
-        submission = kwargs.pop('submission')
-
-        form_fields = {
-            field.id: 0
-            for field in get_fields_for_stage(submission)
-        }
-
-        form_fields.update(**kwargs)
-        return super()._build(model_class, *args, **form_fields)
-
 
 class ReviewFactory(factory.DjangoModelFactory):
     class Meta:
@@ -47,7 +32,6 @@ class ReviewFactory(factory.DjangoModelFactory):
     form_data = factory.SubFactory(
         ReviewFormDataFactory,
         form_fields=factory.SelfAttribute('..form_fields'),
-        submission=factory.SelfAttribute('..submission'),
     )
     is_draft = False
     recommendation = NO
@@ -60,32 +44,3 @@ class ReviewFormFactory(factory.DjangoModelFactory):
 
     name = factory.Faker('word')
     form_fields = blocks.ReviewFormFieldsFactory
-
-
-class AbstractRelatedReviewFormFactory(factory.DjangoModelFactory):
-    class Meta:
-        abstract = True
-    form = factory.SubFactory(ReviewFormFactory)
-
-
-class ReviewFundTypeFactory(FundTypeFactory):
-
-    @factory.post_generation
-    def review_forms(self, create, extracted, **kwargs):
-        if create:
-            for _ in self.workflow.stages:
-                # Generate a form based on all defined fields on the model
-                ApplicationBaseReviewFormFactory(
-                    application=self,
-                    **kwargs
-                )
-
-
-class ApplicationBaseReviewFormFactory(AbstractRelatedReviewFormFactory):
-    class Meta:
-        model = ApplicationBaseReviewForm
-    application = factory.SubFactory(ReviewFundTypeFactory, parent=None)
-
-
-class ReviewApplicationSubmissionFactory(ApplicationSubmissionFactory):
-    page = factory.SubFactory(ReviewFundTypeFactory)
diff --git a/opentech/apply/review/tests/test_views.py b/opentech/apply/review/tests/test_views.py
index d1b1da318..3ac1e6ab2 100644
--- a/opentech/apply/review/tests/test_views.py
+++ b/opentech/apply/review/tests/test_views.py
@@ -1,6 +1,6 @@
 from django.urls import reverse
 
-from opentech.apply.review.tests.factories.models import ReviewApplicationSubmissionFactory
+from opentech.apply.funds.tests.factories.models import ApplicationSubmissionFactory
 from opentech.apply.users.tests.factories import StaffFactory, UserFactory
 from opentech.apply.utils.testing.tests import BaseViewTestCase
 from .factories import ReviewFactory
@@ -15,15 +15,14 @@ class StaffReviewsTestCase(BaseViewTestCase):
         return {'pk': instance.id, 'submission_pk': instance.submission.id}
 
     def test_can_access_review(self):
-        submission = ReviewApplicationSubmissionFactory()
-        review = ReviewFactory(submission=submission, author=self.user)
+        review = ReviewFactory(author=self.user)
         response = self.get_page(review)
         self.assertContains(response, review.submission.title)
         self.assertContains(response, self.user.full_name)
-        self.assertContains(response, reverse('funds:submissions:detail', kwargs={'pk': submission.id}))
+        self.assertContains(response, reverse('funds:submissions:detail', kwargs={'pk': review.submission.id}))
 
     def test_cant_access_other_review(self):
-        submission = ReviewApplicationSubmissionFactory()
+        submission = ApplicationSubmissionFactory()
         review = ReviewFactory(submission=submission)
         response = self.get_page(review)
         self.assertEqual(response.status_code, 403)
@@ -38,7 +37,7 @@ class StaffReviewListingTestCase(BaseViewTestCase):
         return {'submission_pk': instance.id}
 
     def test_can_access_review_listing(self):
-        submission = ReviewApplicationSubmissionFactory()
+        submission = ApplicationSubmissionFactory()
         reviews = ReviewFactory.create_batch(3, submission=submission)
         response = self.get_page(submission, 'list')
         self.assertContains(response, submission.title)
@@ -56,18 +55,18 @@ class StaffReviewFormTestCase(BaseViewTestCase):
         return {'submission_pk': instance.id}
 
     def test_can_access_form(self):
-        submission = ReviewApplicationSubmissionFactory(status='internal_review')
+        submission = ApplicationSubmissionFactory(status='internal_review')
         response = self.get_page(submission, 'form')
         self.assertContains(response, submission.title)
         self.assertContains(response, reverse('funds:submissions:detail', kwargs={'pk': submission.id}))
 
     def test_cant_access_wrong_status(self):
-        submission = ReviewApplicationSubmissionFactory()
+        submission = ApplicationSubmissionFactory()
         response = self.get_page(submission, 'form')
         self.assertEqual(response.status_code, 403)
 
     def test_cant_resubmit_review(self):
-        submission = ReviewApplicationSubmissionFactory(status='internal_review')
+        submission = ApplicationSubmissionFactory(status='internal_review')
         ReviewFactory(submission=submission, author=self.user)
         response = self.post_page(submission, {'data': 'value'}, 'form')
         self.assertEqual(response.context['has_submitted_review'], True)
@@ -76,7 +75,7 @@ class StaffReviewFormTestCase(BaseViewTestCase):
     def test_can_edit_draft_review(self):
         # FIXME fix form generation issue in ReviewFundTypeFactory review_forms()
         return
-        submission = ReviewApplicationSubmissionFactory(status='internal_review')
+        submission = ApplicationSubmissionFactory(status='internal_review')
         ReviewFactory(submission=submission, author=self.user, is_draft=True)
         response = self.post_page(submission, {'data': 'value'}, 'form')
         self.assertEqual(response.context['has_submitted_review'], False)
@@ -92,7 +91,7 @@ class UserReviewFormTestCase(BaseViewTestCase):
         return {'submission_pk': instance.id}
 
     def test_cant_access_form(self):
-        submission = ReviewApplicationSubmissionFactory(status='internal_review')
+        submission = ApplicationSubmissionFactory(status='internal_review')
         response = self.get_page(submission, 'form')
         self.assertEqual(response.status_code, 403)
 
@@ -106,7 +105,7 @@ class ReviewDetailTestCase(BaseViewTestCase):
         return {'pk': instance.id, 'submission_pk': instance.submission.id}
 
     def test_review_detail_recommendation(self):
-        submission = ReviewApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2)
+        submission = ApplicationSubmissionFactory(status='draft_proposal', workflow_stages=2)
         review = ReviewFactory(submission=submission, author=self.user, recommendation_yes=True)
         response = self.get_page(review)
         self.assertContains(response, submission.title)
diff --git a/opentech/apply/stream_forms/blocks.py b/opentech/apply/stream_forms/blocks.py
index 77692d430..b0c450dc5 100644
--- a/opentech/apply/stream_forms/blocks.py
+++ b/opentech/apply/stream_forms/blocks.py
@@ -61,7 +61,7 @@ class FormFieldBlock(StructBlock):
     def format_data(self, data):
         return data
 
-    def no_responose(self):
+    def no_response(self):
         return "No response"
 
 
diff --git a/opentech/apply/stream_forms/testing/factories.py b/opentech/apply/stream_forms/testing/factories.py
index dfccb6bf9..a7a12f3fe 100644
--- a/opentech/apply/stream_forms/testing/factories.py
+++ b/opentech/apply/stream_forms/testing/factories.py
@@ -88,6 +88,10 @@ class FormFieldBlockFactory(wagtail_factories.StructBlockFactory):
     def make_answer(cls, params=dict()):
         return cls.default_value.generate(params)
 
+    @classmethod
+    def make_form_answer(cls, params=dict()):
+        return cls.make_answer(params)
+
 
 class CharFieldBlockFactory(FormFieldBlockFactory):
     default_value = factory.Faker('sentence')
@@ -123,11 +127,15 @@ class UploadableMediaFactory(FormFieldBlockFactory):
 
     @classmethod
     def make_answer(cls, params=dict()):
+        params = params.copy()
+        params.setdefault('data', b'this is some content')
         file_name, file = cls.default_value()._make_content(params)
         return InMemoryUploadedFile(file, 'file', file_name, None, file.tell(), None)
 
 
 class ImageFieldBlockFactory(UploadableMediaFactory):
+    default_value = factory.django.ImageField
+
     class Meta:
         model = stream_blocks.ImageFieldBlock
 
-- 
GitLab