def test_approve_docs(browser, base_test_data, logged_in_staff): """ Test the financial aid review page """ program = base_test_data.program tier_program = program.tier_programs.get(discount_amount=0) FinancialAidFactory.create( user=base_test_data.student_user, tier_program=tier_program, status=FinancialAidStatus.DOCS_SENT, ) browser.get("/financial_aid/review/{}/{}".format( program.id, FinancialAidStatus.DOCS_SENT)) browser.click_when_loaded(By.CLASS_NAME, "mark-docs-as-received") alert = browser.driver.switch_to_alert() alert.accept() browser.wait_until_loaded(By.CLASS_NAME, "alert-success") browser.assert_no_console_errors() def is_now_pending(driver): # pylint: disable=unused-argument """Wait until the change to the financial aid takes effect""" assert FinancialAid.objects.count() == 1 financial_aid = FinancialAid.objects.first() return financial_aid.status == FinancialAidStatus.PENDING_MANUAL_APPROVAL browser.wait().until(is_now_pending)
def test_approve_docs(browser, base_test_data, logged_in_staff): """ Test the financial aid review page """ program = base_test_data.program tier_program = program.tier_programs.get(discount_amount=0) FinancialAidFactory.create( user=base_test_data.student_user, tier_program=tier_program, status=FinancialAidStatus.DOCS_SENT, ) browser.get("/financial_aid/review/{}/{}".format(program.id, FinancialAidStatus.DOCS_SENT)) browser.click_when_loaded(By.CLASS_NAME, "mark-docs-as-received") alert = browser.driver.switch_to_alert() alert.accept() browser.wait_until_loaded(By.CLASS_NAME, "alert-success") browser.assert_no_console_errors() def is_now_pending(driver): # pylint: disable=unused-argument """Wait until the change to the financial aid takes effect""" assert FinancialAid.objects.count() == 1 financial_aid = FinancialAid.objects.first() return financial_aid.status == FinancialAidStatus.PENDING_MANUAL_APPROVAL browser.wait().until(is_now_pending)
def setUpTestData(cls): # replace imported thresholds with fake ones created here CountryIncomeThreshold.objects.all().delete() cls.program, cls.tier_programs = create_program() cls.profile = create_enrolled_profile(cls.program, country="50") cls.staff_user_profile = create_enrolled_profile(cls.program, role=Staff.ROLE_ID) cls.instructor_user_profile = create_enrolled_profile( cls.program, role=Instructor.ROLE_ID) cls.country_income_threshold_0 = CountryIncomeThreshold.objects.create( country_code="0", income_threshold=0, ) CountryIncomeThreshold.objects.create( country_code=cls.profile.country, income_threshold=50000, ) # Create a FinancialAid with a reset status to verify that it is ignored FinancialAidFactory.create( user=cls.profile.user, tier_program=cls.tier_programs['75k'], status=FinancialAidStatus.RESET, )
def setUpTestData(cls): cls.user = SocialUserFactory.create() cls.run_fa = CourseRunFactory.create( freeze_grade_date=now_in_utc() - timedelta(days=1), course__program__financial_aid_availability=True, ) cls.run_fa_with_cert = CourseRunFactory.create( freeze_grade_date=None, course__program=cls.run_fa.course.program, ) cls.run_no_fa = CourseRunFactory.create( freeze_grade_date=now_in_utc() + timedelta(days=1), course__program__financial_aid_availability=False, ) cls.run_no_fa_with_cert = CourseRunFactory.create( course__program=cls.run_no_fa.course.program, ) all_course_runs = ( cls.run_fa, cls.run_fa_with_cert, cls.run_no_fa, cls.run_no_fa_with_cert, ) for run in all_course_runs: if run.course.program.financial_aid_availability: FinancialAidFactory.create( user=cls.user, tier_program=TierProgramFactory.create( program=run.course.program, income_threshold=0, current=True), status=FinancialAidStatus.RESET, ) cls.enrollments = { course_run.edx_course_key: CachedEnrollmentFactory.create(user=cls.user, course_run=course_run) for course_run in all_course_runs } cls.current_grades = { course_run.edx_course_key: CachedCurrentGradeFactory.create(user=cls.user, course_run=course_run) for course_run in all_course_runs } cls.certificates = { course_run.edx_course_key: CachedCertificateFactory.create(user=cls.user, course_run=course_run) for course_run in (cls.run_fa_with_cert, cls.run_no_fa_with_cert) } cls.user_edx_data = CachedEdxUserData(cls.user)
def test_invalid_sorting_and_filter(self, staff_client, program_data, fin_aid_status, sort_param): """ Shouldn't break with invalid sorting or filter parameters """ FinancialAidFactory.create(tier_program=program_data.tier_programs["0k"]) url = self.review_url(program_data.program.id, status=fin_aid_status, sort_param=sort_param) resp = staff_client.get(url) assert resp.status_code == status.HTTP_200_OK
def test_financialaid_object_cannot_be_skipped_if_already_terminal_status(self, financial_aid_status): """ Tests that an existing FinancialAid object that has already reached a terminal status cannot be skipped. """ FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs["25k"], status=financial_aid_status, ) self.make_http_request(self.client.patch, self.skip_url, status.HTTP_400_BAD_REQUEST)
def test_financial_aid_factory_create(self): """ Tests that FinancialAidFactory.create() will create a profile for the user field if a user is not specified """ assert FinancialAid.objects.count() == 0 assert User.objects.count() == 0 assert Profile.objects.count() == 0 FinancialAidFactory.create() assert FinancialAid.objects.count() == 1 assert User.objects.count() == 1 assert Profile.objects.count() == 1
def make_fa_program_enrollment(self, status): """Enroll user in financial aid program""" Program.objects.get(title='Analog Learning').delete() # We need to use Digital Learning here since it has financial aid enabled. Deleting Analog Learning # because it's simpler than adjusting the UI to show the right one program = Program.objects.get(title='Digital Learning') ProgramEnrollment.objects.create(user=self.user, program=program) FinancialAidFactory.create( user=self.user, status=status, tier_program__program=program, tier_program__discount_amount=50, )
def test_financial_aid_factory_create_with_user(self): """ Tests that FinancialAidFactory.create() will still work normally if provided a User object """ with mute_signals(post_save): user = UserFactory.create() assert FinancialAid.objects.count() == 0 assert User.objects.count() == 1 assert Profile.objects.count() == 0 FinancialAidFactory.create(user=user) assert FinancialAid.objects.count() == 1 assert User.objects.count() == 1 assert Profile.objects.count() == 0
def setUpTestData(cls): cls.user = SocialUserFactory.create() cls.run_fa = CourseRunFactory.create( freeze_grade_date=now_in_utc()-timedelta(days=1), course__program__financial_aid_availability=True, ) cls.run_fa_with_cert = CourseRunFactory.create( freeze_grade_date=None, course__program=cls.run_fa.course.program, ) cls.run_no_fa = CourseRunFactory.create( freeze_grade_date=now_in_utc()+timedelta(days=1), course__program__financial_aid_availability=False, ) cls.run_no_fa_with_cert = CourseRunFactory.create( course__program=cls.run_no_fa.course.program, ) all_course_runs = (cls.run_fa, cls.run_fa_with_cert, cls.run_no_fa, cls.run_no_fa_with_cert, ) for run in all_course_runs: if run.course.program.financial_aid_availability: FinancialAidFactory.create( user=cls.user, tier_program=TierProgramFactory.create( program=run.course.program, income_threshold=0, current=True ), status=FinancialAidStatus.RESET, ) cls.enrollments = { course_run.edx_course_key: CachedEnrollmentFactory.create( user=cls.user, course_run=course_run) for course_run in all_course_runs } cls.current_grades = { course_run.edx_course_key: CachedCurrentGradeFactory.create( user=cls.user, course_run=course_run) for course_run in all_course_runs } cls.certificates = { course_run.edx_course_key: CachedCertificateFactory.create( user=cls.user, course_run=course_run) for course_run in (cls.run_fa_with_cert, cls.run_no_fa_with_cert) } cls.user_edx_data = CachedEdxUserData(cls.user)
def test_props(self, program_data): """ Fixture that provides test properties for FinancialAidDetailView test cases """ user = create_enrolled_profile(program_data.program).user pending_fa = FinancialAidFactory.create( user=user, tier_program=program_data.tier_programs["25k"], status=FinancialAidStatus.PENDING_DOCS ) docs_sent_url = reverse( "financial_aid", kwargs={"financial_aid_id": pending_fa.id} ) docs_sent_date = now_in_utc().date() docs_sent_request_params = dict( content_type="application/json", data=json.dumps({ "date_documents_sent": docs_sent_date.strftime("%Y-%m-%d") }) ) return SimpleNamespace( user=user, pending_fa=pending_fa, docs_sent_url=docs_sent_url, docs_sent_request_params=docs_sent_request_params, docs_sent_date=docs_sent_date, )
def test_datetime(self): """ Test that a model with a datetime and date field is handled correctly """ financial_aid = FinancialAidFactory.create(justification=None) assert serialize_model_object(financial_aid) == { 'country_of_income': financial_aid.country_of_income, 'country_of_residence': financial_aid.country_of_residence, 'created_on': format_as_iso8601(financial_aid.created_on), 'date_documents_sent': financial_aid.date_documents_sent.isoformat(), 'date_exchange_rate': format_as_iso8601(financial_aid.date_exchange_rate), 'id': financial_aid.id, 'income_usd': financial_aid.income_usd, 'justification': None, 'original_currency': financial_aid.original_currency, 'original_income': financial_aid.original_income, 'status': financial_aid.status, 'tier_program': financial_aid.tier_program.id, 'updated_on': format_as_iso8601(financial_aid.updated_on), 'user': financial_aid.user.id, }
def test_save_and_log(self): """ Tests that FinancialAid.save_and_log() creates an audit record with the correct information. """ with mute_signals(post_save): profile = ProfileFactory.create() acting_user = profile.user financial_aid = FinancialAidFactory.create() original_before_json = serialize_model_object(financial_aid) # Make sure audit object is created assert FinancialAidAudit.objects.count() == 0 financial_aid.status = FinancialAidStatus.AUTO_APPROVED financial_aid.save_and_log(acting_user) assert FinancialAidAudit.objects.count() == 1 # Make sure the before and after data are correct financial_aid.refresh_from_db() original_after_json = serialize_model_object(financial_aid) financial_aid_audit = FinancialAidAudit.objects.first() before_json = financial_aid_audit.data_before after_json = financial_aid_audit.data_after for field, value in before_json.items(): # Data before if isinstance(value, float): # JSON serialization of FloatField is precise, so we need to do almost equal self.assertAlmostEqual(value, original_before_json[field]) else: assert value == original_before_json[field] for field, value in after_json.items(): # Data after if isinstance(value, float): # JSON serialization of FloatField is precise, so we need to do almost equal self.assertAlmostEqual(value, original_after_json[field]) else: assert value == original_after_json[field]
def setUpTestData(cls): super().setUpTestData() cls.financialaid = FinancialAidFactory.create( user=cls.profile.user, tier_program=cls.tier_programs["25k"], status=FinancialAidStatus.PENDING_MANUAL_APPROVAL ) cls.action_url = reverse("financial_aid_action", kwargs={"financial_aid_id": cls.financialaid.id})
def setUpTestData(cls): with mute_signals(post_save): cls.staff_user_profile = ProfileFactory.create() course_run = CourseRunFactory.create() cls.financial_aid = FinancialAidFactory.create() cls.tier_program = cls.financial_aid.tier_program cls.tier_program.program = course_run.course.program cls.tier_program.save() cls.program_enrollment = ProgramEnrollment.objects.create( user=cls.financial_aid.user, program=cls.tier_program.program)
def create_purchasable_course_run(): """ Creates a purchasable course run and an associated user """ course_run = CourseRunFactory.create( course__program__live=True, course__program__financial_aid_availability=True, ) price = course_run.course.program.price user = UserFactory.create() FinancialAidFactory.create( tier_program__current=True, tier_program__program=course_run.course.program, tier_program__discount_amount=price/2, user=user, status=FinancialAidStatus.APPROVED, ) ProgramEnrollment.objects.create(user=user, program=course_run.course.program) return course_run, user
def test_financial_aid_with_application_in_reset(self): """ Test that a user that has a FinancialAid record with the reset status will have serialized financial aid information that indicates that they have not applied """ FinancialAidFactory.create(user=self.user, tier_program=self.min_tier_program, date_documents_sent=None, status=FinancialAidStatus.RESET) serialized = FinancialAidDashboardSerializer.serialize( self.user, self.program) assert serialized == { "id": None, "has_user_applied": False, "application_status": None, "min_possible_cost": 250, "max_possible_cost": 1000, "date_documents_sent": None, }
def test_determine_auto_approval(self, income_usd, country_code, expected): """ Tests determine_auto_approval() assigning the correct auto-approval status. This should return True if income is strictly greater than the threshold (or if the threshold is 0, which is inclusive of 0). """ financial_aid = FinancialAidFactory.create( income_usd=income_usd, country_of_income=country_code, ) tier_program = determine_tier_program(self.program, income_usd) assert determine_auto_approval(financial_aid, tier_program) is expected
def test_financial_aid_with_application_in_reset(self): """ Test that a user that has a FinancialAid record with the reset status will have serialized financial aid information that indicates that they have not applied """ FinancialAidFactory.create( user=self.user, tier_program=self.min_tier_program, date_documents_sent=None, status=FinancialAidStatus.RESET ) serialized = FinancialAidDashboardSerializer.serialize(self.user, self.program) assert serialized == { "id": None, "has_user_applied": False, "application_status": None, "min_possible_cost": 250, "max_possible_cost": 1000, "date_documents_sent": None, }
def setUpTestData(cls): super().setUpTestData() cls.financial_aid = FinancialAidFactory.create( tier_program=TierProgramFactory.create(program=cls.program)) cls.url = reverse('financial_aid_mail_api', kwargs={'financial_aid_id': cls.financial_aid.id}) cls.request_data = { 'email_subject': 'email subject', 'email_body': 'email body' }
def test_get_course_price_for_learner_with_financial_aid_in_reset(self): """ Tests get_course_price_for_learner() who has financial aid request in status `reset` """ enrollment = ProgramEnrollment.objects.get(program=self.program, user=self.profile.user) FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs['25k'], status=FinancialAidStatus.RESET, ) # Enrolled and has no financial aid course_price = self.program.price expected_response = { "program_id": enrollment.program.id, "price": course_price, "financial_aid_availability": True, "has_financial_aid_request": False } self.assertDictEqual(get_formatted_course_price(enrollment), expected_response)
def setUpTestData(cls): with mute_signals(post_save): cls.staff_user_profile = ProfileFactory.create() course_run = CourseRunFactory.create() cls.financial_aid = FinancialAidFactory.create() cls.tier_program = cls.financial_aid.tier_program cls.tier_program.program = course_run.course.program cls.tier_program.save() cls.program_enrollment = ProgramEnrollment.objects.create( user=cls.financial_aid.user, program=cls.tier_program.program )
def test_financial_aid_model_duplicate_if_reset(self): """ Tests that FinancialAid objects can not be unique per User and Program if the other are in reset status """ financial_aid = FinancialAidFactory.create() # change the first one to any state that is not `reset` will fail to create a new financial aid for status in FinancialAidStatus.ALL_STATUSES: if status == FinancialAidStatus.RESET: continue financial_aid.status = status financial_aid.save() with self.assertRaises(ValidationError): FinancialAidFactory.create( user=financial_aid.user, tier_program=financial_aid.tier_program) # reset status will allow a new financial aid financial_aid.status = FinancialAidStatus.RESET financial_aid.save() FinancialAidFactory.create(user=financial_aid.user, tier_program=financial_aid.tier_program)
def test_get_course_price_for_learner_with_financial_aid_in_reset(self): """ Tests get_course_price_for_learner() who has financial aid request in status `reset` """ enrollment = ProgramEnrollment.objects.get(program=self.program, user=self.profile.user) FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs['25k'], status=FinancialAidStatus.RESET, ) # Enrolled and has no financial aid course_price = self.program.price expected_response = { "program_id": enrollment.program.id, "price": course_price, "financial_aid_availability": True, "has_financial_aid_request": False } self.assertDictEqual( get_formatted_course_price(enrollment), expected_response )
def setUpTestData(cls): super().setUpTestData() cls.financial_aid = FinancialAidFactory.create( tier_program=TierProgramFactory.create(program=cls.program) ) cls.url = reverse( 'financial_aid_mail_api', kwargs={'financial_aid_id': cls.financial_aid.id} ) cls.request_data = { 'email_subject': 'email subject', 'email_body': 'email body' }
def setUpTestData(cls): # replace imported thresholds with fake ones created here CountryIncomeThreshold.objects.all().delete() cls.program, cls.tier_programs = create_program() cls.profile = create_enrolled_profile(cls.program, country="50") cls.staff_user_profile = create_enrolled_profile(cls.program, role=Staff.ROLE_ID) cls.instructor_user_profile = create_enrolled_profile(cls.program, role=Instructor.ROLE_ID) cls.country_income_threshold_0 = CountryIncomeThreshold.objects.create( country_code="0", income_threshold=0, ) CountryIncomeThreshold.objects.create( country_code=cls.profile.country, income_threshold=50000, ) # Create a FinancialAid with a reset status to verify that it is ignored FinancialAidFactory.create( user=cls.profile.user, tier_program=cls.tier_programs['75k'], status=FinancialAidStatus.RESET, )
def test_determine_auto_approval(self): # pylint: disable=no-self-use """ Tests determine_auto_approval() """ # Assumes US threshold is 100000 assert COUNTRY_INCOME_THRESHOLDS["US"] == 100000 financial_aid = FinancialAidFactory.create(income_usd=150000, country_of_income="US") assert determine_auto_approval(financial_aid) is True financial_aid = FinancialAidFactory.create(income_usd=1000, country_of_income="US") assert not determine_auto_approval(financial_aid) financial_aid = FinancialAidFactory.create(income_usd=0, country_of_income="US") assert not determine_auto_approval(financial_aid) # Assumes MX threshold is 50000 assert COUNTRY_INCOME_THRESHOLDS["MX"] == 50000 financial_aid = FinancialAidFactory.create(income_usd=55000, country_of_income="MX") assert determine_auto_approval(financial_aid) is True financial_aid = FinancialAidFactory.create(income_usd=45000, country_of_income="MX") assert not determine_auto_approval(financial_aid) # Assumes IN threshold is 15000 assert COUNTRY_INCOME_THRESHOLDS["IN"] == 15000 financial_aid = FinancialAidFactory.create(income_usd=20000, country_of_income="IN") assert determine_auto_approval(financial_aid) is True financial_aid = FinancialAidFactory.create(income_usd=1000, country_of_income="IN") assert not determine_auto_approval(financial_aid) # Assumes KP threshold is 0 assert COUNTRY_INCOME_THRESHOLDS["KP"] == 0 financial_aid = FinancialAidFactory.create(income_usd=3000, country_of_income="KP") assert determine_auto_approval(financial_aid) is True financial_aid = FinancialAidFactory.create(income_usd=0, country_of_income="KP") assert determine_auto_approval(financial_aid) is True
def test_save_and_log_model(self): """ Tests that the save_model() function on FinancialAidAdmin model creates FinancialAidAudit object """ financial_aid = FinancialAidFactory.create() assert FinancialAidAudit.objects.count() == 0 financial_aid_admin = FinancialAidAdmin(model=financial_aid, admin_site=Mock()) mock_request = Mock(user=self.staff_user_profile.user) financial_aid_admin.save_model(request=mock_request, obj=financial_aid_admin.model, form=Mock(), change=Mock()) assert FinancialAidAudit.objects.count() == 1
def test_save_and_log_model(self): """ Tests that the save_model() function on FinancialAidAdmin model creates FinancialAidAudit object """ financial_aid = FinancialAidFactory.create() assert FinancialAidAudit.objects.count() == 0 financial_aid_admin = FinancialAidAdmin(model=financial_aid, admin_site=Mock()) mock_request = Mock(user=self.staff_user_profile.user) financial_aid_admin.save_model( request=mock_request, obj=financial_aid_admin.model, form=Mock(), change=Mock() ) assert FinancialAidAudit.objects.count() == 1
def test_skipped_financialaid_object_updated(self, financial_aid_status): """ Tests that an existing FinancialAid object is updated to have the status "skipped" """ financial_aid = FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs["75k"], status=financial_aid_status, ) assert FinancialAidAudit.objects.count() == 0 self.make_http_request(self.client.patch, self.skip_url, status.HTTP_200_OK) assert FinancialAid.objects.exclude(status=FinancialAidStatus.RESET).count() == 1 financial_aid.refresh_from_db() assert financial_aid.tier_program == self.tier_programs["75k"] assert financial_aid.status == FinancialAidStatus.SKIPPED # Check logging assert FinancialAidAudit.objects.count() == 1
def test_financial_aid_model_unique(self): """ Tests that FinancialAid objects are unique per User and Program """ financial_aid = FinancialAidFactory.create() # Test creation of FinancialAid that isn't unique_together with "user" and "tier_program__program" # financial aid with same user and different program (new program created by the factory) FinancialAidFactory.create(user=financial_aid.user) # financial aid with same program and different user (new user created by the factory) FinancialAidFactory.create(tier_program=financial_aid.tier_program) # Test updating the original FinancialAid doesn't raise ValidationError financial_aid.income_usd = 100 financial_aid.save() # Test creation should fail for FinancialAid already existing with the same "user" and "tier_program__program" with self.assertRaises(ValidationError): FinancialAidFactory.create(user=financial_aid.user, tier_program=financial_aid.tier_program)
def test_financial_aid_with_documents_sent(self): """ Test that a user that has a FinancialAid record and has sent documents will have serialized financial aid information that indicates the date that documents were sent """ now = now_in_utc() fin_aid = FinancialAidFactory.create( user=self.user, tier_program=self.min_tier_program, date_documents_sent=now, ) serialized = FinancialAidDashboardSerializer.serialize(self.user, self.program) assert serialized == { "id": fin_aid.id, "has_user_applied": True, "application_status": fin_aid.status, "min_possible_cost": 250, "max_possible_cost": 1000, "date_documents_sent": now.date(), }
def test_get_course_price_for_learner_with_financial_aid(self, status): """ Tests get_course_price_for_learner() who has approved financial aid """ enrollment = ProgramEnrollment.objects.get(program=self.program, user=self.profile.user) financial_aid = FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs['25k'], status=status, ) course_price = self.program.price expected_response = { "program_id": enrollment.program.id, "price": course_price - financial_aid.tier_program.discount_amount, "financial_aid_availability": True, "has_financial_aid_request": True } self.assertDictEqual(get_formatted_course_price(enrollment), expected_response)
def test_financial_aid_with_documents_sent(self): """ Test that a user that has a FinancialAid record and has sent documents will have serialized financial aid information that indicates the date that documents were sent """ now = now_in_utc() fin_aid = FinancialAidFactory.create( user=self.user, tier_program=self.min_tier_program, date_documents_sent=now, ) serialized = FinancialAidDashboardSerializer.serialize( self.user, self.program) assert serialized == { "id": fin_aid.id, "has_user_applied": True, "application_status": fin_aid.status, "min_possible_cost": 250, "max_possible_cost": 1000, "date_documents_sent": now.date(), }
def test_get_course_price_for_learner_with_financial_aid(self, status): """ Tests get_course_price_for_learner() who has approved financial aid """ enrollment = ProgramEnrollment.objects.get(program=self.program, user=self.profile.user) financial_aid = FinancialAidFactory.create( user=self.profile.user, tier_program=self.tier_programs['25k'], status=status, ) course_price = self.program.price expected_response = { "program_id": enrollment.program.id, "price": course_price - financial_aid.tier_program.discount_amount, "financial_aid_availability": True, "has_financial_aid_request": True } self.assertDictEqual( get_formatted_course_price(enrollment), expected_response )
def setUpTestData(cls): course_run = CourseRunFactory.create() cls.financial_aid = FinancialAidFactory.create() cls.tier_program = cls.financial_aid.tier_program cls.tier_program.program = course_run.course.program cls.tier_program.save()
def test_to_dict(self): """ assert output of to_dict """ financial_aid = FinancialAidFactory.create() assert financial_aid.to_dict() == serialize_model_object(financial_aid)