class TestLocationAutocompleteView(BaseTenantTestCase): def setUp(self): super(TestLocationAutocompleteView, self).setUp() self.unicef_staff = UserFactory(is_staff=True) self.client = TenantClient(self.tenant) def test_non_auth(self): LocationFactory() response = self.client.get(reverse("locations-autocomplete-light")) self.assertEqual(response.status_code, status.HTTP_302_FOUND) def test_get(self): LocationFactory() self.client.force_login(self.unicef_staff) response = self.client.get(reverse("locations-autocomplete-light")) self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json() self.assertEqual(len(data["results"]), 1) def test_get_filter(self): LocationFactory(name="Test") LocationFactory(name="Other") self.client.force_login(self.unicef_staff) response = self.client.get("{}?q=te".format( reverse("locations-autocomplete-light"))) self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json() self.assertEqual(len(data["results"]), 1)
class QuestionDetailViewTests(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) def test_future_question(self): """ The detail view of a question with a pub_date in the future returns a 404 not found. """ future_question = create_question(question_text='Future question.', days=5) url = reverse('detail', args=(future_question.id, )) response = self.client.get(url) self.assertEqual(response.status_code, 404) def test_past_question(self): """ The detail view of a question with a pub_date in the past displays the question's text. """ past_question = create_question(question_text='Past Question.', days=-5) url = reverse('detail', args=(past_question.id, )) print(url) response = self.client.get(url) self.assertContains(response, past_question.question_text)
class ViewsTest(ViewTestUtilsMixin, TenantTestCase): def setUp(self): # Every test needs access to the request factory. # https://docs.djangoproject.com/en/3.0/topics/testing/advanced/#the-request-factory # self.factory = RequestFactory() self.client = TenantClient(self.tenant) def test_home_view_staff(self): staff_user = User.objects.create_user(username="******", password="******", is_staff=True) self.client.force_login(staff_user) response = self.client.get(reverse('home')) self.assertRedirects(response, reverse('quests:approvals')) def test_home_view_authenticated(self): user = User.objects.create_user(username="******", password="******") self.client.force_login(user) self.assertRedirectsQuests('home') def test_home_view_anonymous(self): response = self.client.get(reverse('home')) self.assertRedirects(response, reverse('account_login')) def test_secret_view(self): self.assert200('simple')
class IndexTestCase(TenantTestCase): """ tests the index page of the recruitment tab """ def setUp(self): self.client = TenantClient(self.tenant) self.u = User.objects.create(username="******") self.client.force_login(self.u) self.event1 = RushEvent.objects.create(name='test_event1', date='2001-01-01', time='00:00:00', round=1, new_rushees_allowed=True) self.event2 = RushEvent.objects.create(name='test_event2', date='2001-01-01', time='00:00:00', round=3, new_rushees_allowed=True) def test_index_health(self): path = reverse('rush:index') response = self.client.get(path) self.assertEqual(response.status_code, 200) def test_index_round_groups(self): path = reverse('rush:index') response = self.client.get(path) self.assertContains(response, "<h4>Round 1</h4>") self.assertContains(response, "<h4>Round 3</h4>")
class SearchTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.admin = User.objects.create(username="******", is_staff=True, is_superuser=True) self.client.force_login(self.admin) file = SimpleUploadedFile("file.txt", b"file_content", content_type="text/plain") for i in range(0, 10): SocialEvent.objects.create(name="test_event_" + str(i)) ResourceLink.objects.create(name="test_link_" + str(i), description="test", url="https://www.google.com") Announcement.objects.create(title="announcement_" + str(i)) ResourceFile.objects.create(name="test_file_" + str(i), file=file, description="test") # deletes any files created in this test case from the server def tearDown(self): for i in range(0, 10): ResourceFile.objects.get(name="test_file_" + str(i)).file.delete() # tests basic search def test_search_basic(self): path = reverse('search') get_data = {'query': 'test'} response = self.client.get(path, get_data, follow=True) self.assertContains(response, "40 results") # test paginate feature for more than 10 results def test_search_paginate_more_than_10(self): path = reverse('search') get_data = {'query': 'test'} response = self.client.get(path, get_data, follow=True) # should be 40 results over 4 pages self.assertContains(response, 'nav aria-label="Page navigation"') self.assertContains(response, 'href="search?query=test&page=4') self.assertNotContains(response, 'href="search?query=test&page=5') # test paginate doesn't appear with fewer than 10 def test_search_paginate_fewer_than_10(self): path = reverse('search') get_data = {'query': 'test1'} response = self.client.get(path, get_data, follow=True) self.assertNotContains(response, 'nav aria-label="Page navigation"') # test search with empty string query def test_search_empty_string(self): path = reverse('search') get_data = {'query': ''} response = self.client.get(path, get_data, follow=True) self.assertContains(response, '0 results for <b>None</b>')
class QuestionIndexViewTests(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) def test_no_questions(self): """ If no questions exist, an appropriate message is displayed. """ response = self.client.get(reverse('index')) self.assertEqual(response.status_code, 200) self.assertContains(response, "No polls are available.") self.assertQuerysetEqual(response.context['latest_question_list'], []) def test_past_question(self): """ Questions with a pub_date in the past are displayed on the index page. """ create_question(question_text="Past question.", days=-30) response = self.client.get(reverse('index')) self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: Past question.>']) def test_future_question(self): """ Questions with a pub_date in the future aren't displayed on the index page. """ create_question(question_text="Future question.", days=30) response = self.client.get(reverse('index')) self.assertContains(response, "No polls are available.") self.assertQuerysetEqual(response.context['latest_question_list'], []) def test_future_question_and_past_question(self): """ Even if both past and future questions exist, only past questions are displayed. """ create_question(question_text="Past question.", days=-30) create_question(question_text="Future question.", days=30) response = self.client.get(reverse('index')) self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: Past question.>']) def test_two_past_questions(self): """ The questions index page may display multiple questions. """ create_question(question_text="Past question 1.", days=-30) create_question(question_text="Past question 2.", days=-5) response = self.client.get(reverse('index')) self.assertQuerysetEqual( response.context['latest_question_list'], ['<Question: Past question 2.>', '<Question: Past question 1.>'])
def test_contact_by_campaign_filtering(self) -> None: self.set_tenant(0) user = self.users[0] first_contact = Contact.objects.create(email='*****@*****.**', first_name='First', last_name='Smith') second_contact = Contact.objects.create(email='*****@*****.**', first_name='Second', last_name='Smith') Contact.objects.create(email='*****@*****.**', first_name='Third', last_name='Smith') fourth_contact = Contact.objects.create(email='*****@*****.**', first_name='Fourth', last_name='Smith') first_campaign = Campaign.objects.create(name='first campaign for filtering test', owner=user) second_campaign = Campaign.objects.create(name='second campaign for filtering test', owner=user) Participation.objects.bulk_create([ Participation(campaign=first_campaign, contact=first_contact), Participation(campaign=second_campaign, contact=second_contact), Participation(campaign=first_campaign, contact=fourth_contact), Participation(campaign=second_campaign, contact=fourth_contact), ]) t_client = TenantClient(self.get_current_tenant()) t_client.handler = ForceAuthClientHandler(enforce_csrf_checks=False) t_client.handler._force_user = user self.assertTrue(t_client.login(username=user.username, password='******'), 'Test user was not logged in') url = reverse.reverse('api:contacts-list') with modify_settings(ALLOWED_HOSTS={'append': self.get_current_tenant().domain_url}): query = '?campaigns__in=%s' % ','.join(map(str, [first_campaign.id, second_campaign.id])) response = t_client.get(urljoin(url, query)) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.content)) contacts_data = response.data self.assertEqual(3, len(contacts_data)) self.assertSetEqual({first_contact.id, second_contact.id, fourth_contact.id}, {c['id'] for c in contacts_data}) with modify_settings(ALLOWED_HOSTS={'append': self.get_current_tenant().domain_url}): query = '?campaigns=' + ','.join(map(str, [first_campaign.id, second_campaign.id])) response = t_client.get(urljoin(url, query)) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.content)) contacts_data = response.data self.assertEqual(1, len(contacts_data)) self.assertEqual(fourth_contact.id, contacts_data[0]['id']) with modify_settings(ALLOWED_HOSTS={'append': self.get_current_tenant().domain_url}): query = '?campaigns=%s' % second_campaign.id response = t_client.get(urljoin(url, query)) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.content)) contacts_data = response.data self.assertEqual(1, len(contacts_data)) self.assertEqual(second_contact.id, contacts_data[0]['id'])
class TestMultiTenantSocialAuth(TenantTestCase): @classmethod def setUpClass(cls): settings.AUTHENTICATION_BACKENDS = ('social_core.backends.twitter.TwitterOAuth', 'django.contrib.auth.backends.ModelBackend',) cls.sync_shared() tenant_domain = 'tenant.test.com' invalid_tenant_domain = 'invalid_tenant.test.com' cls.social_auth_settings = { 'twitter': { 'SOCIAL_AUTH_TWITTER_KEY': 'TtfLziJDLaNc0bRwCCYCxpMIc', 'SOCIAL_AUTH_TWITTER_SECRET': 'AXgPEFhJNHtbhBycoKn9KfMtsINOAOHsQ4o2wSJmzG0XCMeVbr' } } cls.tenant = get_tenant_model()(domain_url=tenant_domain, schema_name='test', social_auth_settings=cls.social_auth_settings) cls.tenant.save(verbosity=0) cls.invalid_tenant = get_tenant_model()(domain_url=invalid_tenant_domain, schema_name='invalid_test', social_auth_settings={}) cls.invalid_tenant.save(verbosity=0) connection.set_tenant(cls.tenant) def setUp(self): self.c = TenantClient(self.tenant) self.invalid_c = TenantClient(self.invalid_tenant) def test_tenant_social_auth_settings(self): self.assertEqual(self.tenant.social_auth_settings, self.social_auth_settings) def test_user_login(self): response = self.c.get( reverse('social:begin', args=['twitter'])) self.assertIn('auth_token=', response['Location']) def test_invalid_user_login(self): connection.set_tenant(self.invalid_tenant) response = self.invalid_c.get( reverse('social:begin', args=['twitter'])) self.assertEqual(400, response.status_code)
class ErrorsTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) # tests custom 404 page appears on 404 error def test_404_custom_page(self): path = '/path/that/does/not/exist' response = self.client.get(path) self.assertEqual(response.status_code, 404) self.assertIn("The requested URL, " + path + " could not be found.", str(response.content))
class SubmissionTestModel(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() self.semester = baker.make(Semester) self.teacher = Recipe(User, is_staff=True).make( ) # need a teacher or student creation will fail. self.student = baker.make(User) self.submission = baker.make(QuestSubmission, quest__name="Test") # self.badge = Recipe(Badge, xp=20).make() # self.badge_assertion_recipe = Recipe(QuestSubmission, user=self.student, badge=self.badge) def test_submission_creation(self): self.assertIsInstance(self.submission, QuestSubmission) self.assertEqual(str("Test"), self.submission.quest.name) def test_submission_url(self): self.assertEqual( self.client.get(self.submission.get_absolute_url(), follow=True).status_code, 200) def test_submission_without_quest(self): # creating a submission without a quest, null=True so no Quest created. sub = baker.make(QuestSubmission) self.assertIsNone(sub.quest) self.assertIsNotNone(str(sub)) def test_submission_mark_completed(self): draft_text = "Draft words" sub = baker.make(QuestSubmission, draft_text=draft_text) self.assertFalse(sub.is_completed) self.assertEqual(sub.draft_text, draft_text) sub.mark_completed() self.assertTrue(sub.is_completed) self.assertIsNotNone(sub.first_time_completed) self.assertIsNone(sub.draft_text) def test_submission_get_previous(self): """ If this is a repeatable quest and has been completed already, return that previous submission """ repeat_quest = baker.make(Quest, name="repeatable-quest", max_repeats=-1) first_sub = baker.make(QuestSubmission, user=self.student, quest=repeat_quest, semester=self.semester) self.assertIsNone(first_sub.get_previous()) # need to complete so can make another first_sub.mark_completed() SiteConfig.get().set_active_semester(first_sub.semester.id) second_sub = QuestSubmission.objects.create_submission( user=self.student, quest=repeat_quest) self.assertEqual(first_sub, second_sub.get_previous())
class StudentProfileTestView(StudentProfileViewsTest): def setUp(self): self.c = TenantClient(self.tenant) self.factory = RequestFactory() def test_student_list_view(self): request = self.factory.get('/account/student/') response = self.c.get('/account/student/') self.assertEqual(response.status_code, 403) # forbidden for user in group student def test_student_detail_view(self): request = self.factory.get('/account/student/1/detail/') respnonse = self.c.login('/account/student/1/detail/') self.assertEqual(response.status_code, 403) def test_student_register_view(self): # data = { # 'user':cls.user, # 'photo':'img.jpg', # } response = self.c.get('/account/student/register/') self.assertEqual(response.status_code, 403) self.assertEqual(response.template, 'account/students/list.html') # with self.assertTemplateUsed('solos/solo_detail.html'): # response.render() # response = StudentListView.as_view()( # request, # self.user # # ) # self.assertEqual(response, 200) def test_student_register_view(self): pass def test_student_detail_view(self): pass def test_student_update_view(self): pass
class AuthenticationTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.u = User.objects.create(username="******", is_superuser=True) self.client.force_login(self.u) # tests that logged in user can logout def test_logout_redirects_to_login(self): path = reverse('logout') response = self.client.post(path, follow=True) self.assertContains(response, 'Login') # gets template with signup form def test_signup_get_template(self): path = reverse('signup') response = self.client.get(path) self.assertContains(response, "Register") # tests that inactive users can activate with activate view def test_activate_view(self): user = User.objects.create(username="******", is_active="False") token = account_activation_token.make_token(user) path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) response = self.client.post(path) self.assertContains(response, "Your account has been verified!") # tests user that does not exist def test_activate_user_does_not_exist(self): user = User.objects.create(username="******", is_active="False") token = account_activation_token.make_token(user) path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) user.delete() response = self.client.post(path) self.assertContains(response, "Activation link is invalid") # tests invalid activation token def test_activate_user_invalid_token(self): user = User.objects.create(username="******", is_active="False") token = "999-99999999999999999999" path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) response = self.client.post(path) self.assertContains(response, "Activation link is invalid") # tests logout def test_logout(self): user = User.objects.create(username="******") self.client.force_login(user) path = reverse('logout') response = self.client.post(path, follow=True) self.assertContains(response, "Login")
def test_unread_only_filtering(self): self.set_tenant(0) now = timezone.now() action = NoticeType.objects.first() Notification.objects.bulk_create([ Notification(user=self.user, created=now, action=action), Notification(user=self.user, created=now, action=action, read_datetime=now, extra_context=dict(mark=True)), Notification(user=self.user, created=now, action=action), ]) t_client = TenantClient(self.get_current_tenant()) t_client.handler = ForceAuthClientHandler(enforce_csrf_checks=False) t_client.handler._force_user = self.user self.assertTrue( t_client.login(username=self.user.username, password='******'), 'Test user was not logged in') url = reverse.reverse('api:notifications-list') with modify_settings( ALLOWED_HOSTS={'append': self.get_current_tenant().domain_url }): query = '?unread_only=true' response = t_client.get(urljoin(url, query)) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.content)) notifications_data = response.data self.assertEqual(2, len(notifications_data)) notifications = Notification.objects.filter( extra_context__isnull=True).all() self.assertSetEqual({n.id for n in notifications}, {n['id'] for n in notifications_data})
class BadgeTestModel(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.badge = baker.make(Badge) def test_badge_creation(self): self.assertIsInstance(self.badge, Badge) self.assertEqual(str(self.badge), self.badge.name) def test_badge_icon(self): pass def test_badge_url(self): self.assertEqual( self.client.get(self.badge.get_absolute_url(), follow=True).status_code, 200) def test_default_badge_data(self): """ Data migration should create 4 badges """ self.assertTrue(Badge.objects.filter(name="Penny").exists()) self.assertTrue(Badge.objects.filter(name="Nickel").exists()) self.assertTrue(Badge.objects.filter(name="Dime").exists()) self.assertTrue( Badge.objects.filter(name="ByteDeck Proficiency").exists())
class SubmissionViewTests(TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user('test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user('test_student', password=self.test_password) self.test_student2 = mommy.make(User) self.quest1 = mommy.make(Quest) self.quest2 = mommy.make(Quest) self.sub1 = mommy.make(QuestSubmission, user=self.test_student1, quest=self.quest1) self.sub2 = mommy.make(QuestSubmission, quest=self.quest1) self.sub3 = mommy.make(QuestSubmission, quest=self.quest2) def test_all_submission_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) s1_pk = self.sub1.pk s2_pk = self.sub2.pk # Student's own submission self.assertEqual(self.client.get(reverse('quests:submission', args=[s1_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:drop', args=[s1_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[s1_pk])).status_code, 200) # Students shouldn't have access to these self.assertEqual(self.client.get(reverse('quests:flagged')).status_code, 302) # Student's own submission self.assertEqual(self.client.get(reverse('quests:skip', args=[s1_pk])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:approve', args=[s1_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[s1_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:flag', args=[s1_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:unflag', args=[s1_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:complete', args=[s1_pk])).status_code, 404) # Not this student's submission self.assertEqual(self.client.get(reverse('quests:submission', args=[s2_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:drop', args=[s2_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:skip', args=[s2_pk])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[s2_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:complete', args=[s2_pk])).status_code, 404) # Non existent submissions self.assertEqual(self.client.get(reverse('quests:submission', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:drop', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:skip', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:complete', args=[0])).status_code, 404) # These Needs to be completed via POST self.assertEqual(self.client.get(reverse('quests:complete', args=[s1_pk])).status_code, 404) def test_all_submission_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) s1_pk = self.sub1.pk # s2_pk = self.sub2.pk self.assertEqual(self.client.get(reverse('quests:flagged')).status_code, 200) # View it self.assertEqual(self.client.get(reverse('quests:submission', args=[s1_pk])).status_code, 200) # Flag it # self.assertEqual(self.client.get(reverse('quests:flag', args=[s1_pk])).status_code, 200) self.assertRedirects( response=self.client.get(reverse('quests:flag', args=[s1_pk])), expected_url=reverse('quests:approvals'), ) # TODO Why does this fail? Why is self.sub1.flagged_by == None # self.assertEqual(self.sub1.flagged_by, self.test_teacher) # Unflag it self.assertRedirects( response=self.client.get(reverse('quests:unflag', args=[s1_pk])), expected_url=reverse('quests:approvals'), ) self.assertIsNone(self.sub1.flagged_by) # self.assertEqual(self.client.get(reverse('quests:drop', args=[s1_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[s1_pk])).status_code, 200) # Non existent submissions self.assertEqual(self.client.get(reverse('quests:submission', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:drop', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:skip', args=[0])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:submission_past', args=[0])).status_code, 404) # These Needs to be completed via POST # self.assertEqual(self.client.get(reverse('quests:complete', args=[s1_pk])).status_code, 404) self.assertEqual(self.client.get(reverse('quests:skip', args=[s1_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:approve', args=[s1_pk])).status_code, 404) def test_student_quest_completion(self): # self.sub1 = mommy.make(QuestSubmission, user=self.test_student1, quest=self.quest1) # self.assertRedirects( # response=self.client.post(reverse('quests:complete', args=[self.sub1.id])), # expected_url=reverse('quests:quests'), # ) # TODO self.assertEqual(self.client.get(reverse('quests:complete', args=[s1_pk])).status_code, 404) pass def test_submission_when_quest_not_visible(self): """When a quest is hidden from students, they should still be able to to see their submission in a static way""" # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # Make quest invisible to students self.quest1.visible_to_students = False self.quest1.save() self.assertFalse(self.quest1.visible_to_students) # TODO: should redirect, not 404? self.assertEqual(self.client.get(reverse('quests:submission', args=[self.sub1.pk])).status_code, 404) def test_ajax_save_draft(self): # loging required for this view self.client.force_login(self.test_student1) quest = mommy.make(Quest, name="TestSaveDrafts") sub = mommy.make(QuestSubmission, quest=quest) draft_comment = "Test draft comment" # Send some draft data via the ajax view, which should save it. ajax_data = { 'comment': draft_comment, 'submission_id': sub.id, } response = self.client.post( reverse('quests:ajax_save_draft'), data=ajax_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['result'], "Draft saved") sub.refresh_from_db() self.assertEqual(draft_comment, sub.draft_text) # fAILS CUS MODEL DIDN'T SAVE! aRGH..
class QuestTestModel(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.quest = baker.make(Quest) def test_badge_creation(self): self.assertIsInstance(self.quest, Quest) self.assertEqual(str(self.quest), self.quest.name) def test_quest_icon(self): pass def test_quest_url(self): self.assertEqual( self.client.get(self.quest.get_absolute_url(), follow=True).status_code, 200) def test_quest_html_formatting(self): test_markup = "<p>this <span>span</span> tag should not break</p>" self.quest.instructions = test_markup # Auto formatting on save self.quest.save() formatted_markup = self.quest.instructions # search for line breaks before or after span tags matches_found = re.search( '(([ ]+)?\n([ ]+)?</?span>)|(</?span>([ ]+)?\n([ ]+)?)', formatted_markup) self.assertIsNone(matches_found) def test_quest_html_formatting_math(self): test_markup = r"""<span class="note-math"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mrow><mi>x</mi></mrow></mrow><annotation encoding="application/x-tex">{x}</annotation></semantics></math></span>""" # noqa self.quest.instructions = test_markup # Auto formatting on save self.quest.save() formatted_markup = self.quest.instructions self.assertIn(test_markup, formatted_markup) matches_found = re.search('({{)|(}})', formatted_markup) self.assertIsNone(matches_found) def test_quest_html_formatting_tabs(self): markup = [ # test, expected out come ("<p>some text</p>", "<p>\n some text\n</p>"), ("<p>some text\n\n</p>", "<p>\n some text\n</p>"), ("<p>some \ntext</p>", "<p>\n some \ntext\n</p>"), ("<p>some \n text</p>", "<p>\n some \n text\n</p>"), ("<ol><li>test</li></ol>", "<ol>\n <li>\n test\n </li>\n</ol>"), (" <p>", "<p>\n</p>") ] for pair in markup: self.quest.instructions = pair[0] # Auto formatting on save self.quest.save() formatted_markup = self.quest.instructions self.assertEqual(formatted_markup, pair[1]) @freeze_time('2018-10-12 00:54:00', tz_offset=0) def test_is_repeat_available(self): """ QuestManager.is_repeat_available should return True if: 1. it is repeatable (is_repeatable != 0) 2. the cooldown time has passed for the quest since the last completion 3. the max repeats have not been completed already (by semester or overall) Assumes there has already been at least one submission (change that?) def test_is_repeat_available(self, user):""" User = get_user_model() baker.make( User, is_staff=True) # need a teacher or student creation will fail. student = baker.make(User) quest_not_repeatable = baker.make(Quest, name="quest-not-repeatable") quest_infinite_repeat = baker.make(Quest, name="quest-infinite-repeatable", max_repeats=-1) quest_repeat_1hr = baker.make(Quest, name="quest-repeatable-1hr", max_repeats=1, hours_between_repeats=1) quest_semester_repeat = baker.make(Quest, name="quest-semester-repeatable", max_repeats=1, repeat_per_semester=True) quest_semester = baker.make(Quest, name="quest-semester", max_repeats=0, repeat_per_semester=True) # TESTS WITH NOT REPEATABLE QUEST sub_not_repeatable = QuestSubmission.objects.create_submission( student, quest_not_repeatable) # non-repeatable quest is not available again. self.assertFalse(quest_not_repeatable.is_repeat_available(student)) # even when completed sub_not_repeatable.mark_completed() self.assertFalse(quest_not_repeatable.is_repeat_available(student)) # and when approved sub_not_repeatable.mark_approved() self.assertFalse(quest_not_repeatable.is_repeat_available(student)) # TESTS WITH INFINITE REPEATABLE QUEST, 0HRS COOLDOWN # in progress, shouldn't be available. sub_infinite_repeatable = QuestSubmission.objects.create_submission( student, quest_infinite_repeat) self.assertFalse(quest_infinite_repeat.is_repeat_available(student)) # available after completion sub_infinite_repeatable.mark_completed() self.assertTrue(quest_infinite_repeat.is_repeat_available(student)) # and when approved sub_infinite_repeatable.mark_approved() self.assertTrue(quest_infinite_repeat.is_repeat_available(student)) # TESTS WITH REPEATABLE QUEST, 1HRS COOLDOWN # started sub_repeat_1hr = QuestSubmission.objects.create_submission( student, quest_repeat_1hr) self.assertFalse(quest_repeat_1hr.is_repeat_available(student)) sub_repeat_1hr.mark_completed() # jump ahead an hour so repeat cooldown is over with freeze_time(localtime() + timedelta(hours=1, minutes=1)): self.assertTrue(quest_repeat_1hr.is_repeat_available(student)) # start another one QuestSubmission.objects.create_submission(student, quest_repeat_1hr) self.assertFalse(quest_repeat_1hr.is_repeat_available(student)) # TESTS WITH REPEATABLE QUEST, BY SEMESTER # started sub_repeat_semester = QuestSubmission.objects.create_submission( student, quest_semester_repeat) self.assertFalse(quest_semester_repeat.is_repeat_available(student)) sub_repeat_semester.mark_completed() # one repeat avail per semester self.assertTrue(quest_semester_repeat.is_repeat_available(student)) sub_repeat_semester2 = QuestSubmission.objects.create_submission( student, quest_semester_repeat) sub_repeat_semester2.mark_completed() # Ran out this semester self.assertFalse(quest_semester_repeat.is_repeat_available(student)) # TEST NO REPEAT, BUT YES SEMESTER # started sub_semester = QuestSubmission.objects.create_submission( student, quest_semester) self.assertFalse(quest_semester.is_repeat_available(student)) sub_semester.mark_completed() # No repeat left this semester self.assertFalse(quest_semester.is_repeat_available(student)) # change semesters and the quest should appear new_active_sem = baker.make(Semester, active=True) SiteConfig.get().set_active_semester(new_active_sem.id) self.assertTrue(quest_semester_repeat.is_repeat_available(student)) # Repeat this semester, another two should be available sub_repeat_semester = QuestSubmission.objects.create_submission( student, quest_semester_repeat) self.assertFalse(quest_semester_repeat.is_repeat_available(student)) sub_repeat_semester.mark_completed() # one repeat avail per semester self.assertTrue(quest_semester_repeat.is_repeat_available(student)) sub_repeat_semester2 = QuestSubmission.objects.create_submission( student, quest_semester_repeat) sub_repeat_semester2.mark_completed() # Ran out this semester self.assertFalse(quest_semester_repeat.is_repeat_available(student)) # TEST NO REPEAT, BUT YES SEMESTER, in this new semester self.assertTrue(quest_semester.is_repeat_available(student)) # started sub_semester = QuestSubmission.objects.create_submission( student, quest_semester) self.assertFalse(quest_semester.is_repeat_available(student)) sub_semester.mark_completed() # No repeat left this semester self.assertFalse(quest_semester.is_repeat_available(student))
class QuestViewTests(TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() self.sem = SiteConfig.get().active_semester # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user('test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user('test_student', password=self.test_password) self.test_student2 = mommy.make(User) self.quest1 = mommy.make(Quest) self.quest2 = mommy.make(Quest) # self.sub1 = mommy.make(QuestSubmission, user=self.test_student1, quest=self.quest1) # self.sub2 = mommy.make(QuestSubmission, quest=self.quest1) def test_all_quest_page_status_codes_for_anonymous(self): """ If not logged in then all views should redirect to home page """ self.assertRedirects( response=self.client.get(reverse('quests:quests')), expected_url='%s?next=%s' % (reverse('home'), reverse('quests:quests')), ) def test_all_quest_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) q_pk = self.quest1.pk q2_pk = self.quest2.pk self.assertEqual(self.client.get(reverse('quests:quests')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:available')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:available2')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:inprogress')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:completed')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:past')).status_code, 200) # anyone can view drafts if they figure out the url, but it will be blank for them self.assertEqual(self.client.get(reverse('quests:drafts')).status_code, 200) self.assertEqual(self.client.get(reverse('quests:quest_detail', args=[q_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:quest_detail', args=[q_pk])).status_code, 200) # students shouldn't have access to these and should be redirected to login self.assertEqual(self.client.get(reverse('quests:submitted')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:submitted_all')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:returned')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:approved')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:skipped')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:submitted_for_quest', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:returned_for_quest', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:approved_for_quest', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:approved_for_quest_all', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:skipped_for_quest', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:quest_create')).status_code, 403) self.assertEqual(self.client.get(reverse('quests:quest_update', args=[q_pk])).status_code, 403) self.assertEqual(self.client.get(reverse('quests:quest_copy', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:quest_delete', args=[q_pk])).status_code, 403) self.assertEqual(self.client.get(reverse('quests:start', args=[q2_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:hide', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:unhide', args=[q_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('quests:skip_for_quest', args=[q_pk])).status_code, 404) def test_all_quest_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) s_pk = self.test_student1.profile.pk # s2_pk = self.test_student2.pk q_pk = self.quest1.pk q2_pk = self.quest2.pk self.assertEqual(self.client.get(reverse('profiles:profile_detail', args=[s_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('profiles:profile_update', args=[s_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('profiles:profile_list')).status_code, 200) self.assertEqual(self.client.get(reverse('profiles:profile_list_current')).status_code, 200) self.assertEqual(self.client.get(reverse('profiles:comment_ban', args=[s_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('profiles:comment_ban_toggle', args=[s_pk])).status_code, 302) self.assertEqual(self.client.get(reverse('profiles:GameLab_toggle', args=[s_pk])).status_code, 302) # self.assertEqual(self.client.get(reverse('profiles:recalculate_xp_current')).status_code, 302) self.assertEqual(self.client.get(reverse('quests:quest_delete', args=[q2_pk])).status_code, 200) self.assertEqual(self.client.get(reverse('quests:quest_copy', args=[q_pk])).status_code, 200)
class AnnouncementViewTests(TenantTestCase): def setUp(self): # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.client = TenantClient(self.tenant) self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user( 'test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user( 'test_student', password=self.test_password) self.test_student2 = mommy.make(User) self.test_announcement = mommy.make(Announcement, draft=False) self.ann_pk = self.test_announcement.pk def assertRedirectsHome(self, url_name, args=None): self.assertRedirects( response=self.client.get(reverse(url_name, args=args)), expected_url='%s?next=%s' % (reverse('home'), reverse(url_name, args=args)), ) def assertRedirectsAdmin(self, url_name, args=None): self.assertRedirects( response=self.client.get(reverse(url_name, args=args)), expected_url='{}?next={}'.format('/admin/login/', reverse(url_name, args=args)), ) def assert200(self, url_name, args=None): self.assertEqual( self.client.get(reverse(url_name, args=args)).status_code, 200) def test_all_announcement_page_status_codes_for_anonymous(self): ''' If not logged in then all views should redirect to home page or admin ''' # go home self.assertRedirectsHome('announcements:list') self.assertRedirectsHome('announcements:list2') self.assertRedirectsHome('announcements:comment', args=[1]) self.assertRedirectsHome('announcements:list', args=[1]) # go admin self.assertRedirectsAdmin('announcements:create') self.assertRedirectsAdmin('announcements:delete', args=[1]) self.assertRedirectsAdmin('announcements:update', args=[1]) self.assertRedirectsAdmin('announcements:copy', args=[1]) self.assertRedirectsAdmin('announcements:publish', args=[1]) def test_all_announcement_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # all_fields = self.test_announcement._meta.get_fields() # for field in all_fields: # print(field, getattr(self.test_announcement, field.name)) # students should have access to these: self.assertEqual( self.client.get(reverse('announcements:list')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list2')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list', args=[self.ann_pk])).status_code, 200) # Announcement from setup() should appear in the list self.assertContains(self.client.get(reverse('announcements:list')), self.test_announcement.title) comment_response_get = self.client.get( reverse('announcements:comment', args=[self.ann_pk])) self.assertEqual(comment_response_get.status_code, 404) # Comments via POST only # Posting a comment redirects to the announcement commented on self.assertRedirects( response=self.client.post( reverse('announcements:comment', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) # These views should redirect to admin login self.assertRedirectsAdmin('announcements:create') self.assertRedirectsAdmin('announcements:delete', args=[1]) self.assertRedirectsAdmin('announcements:update', args=[1]) self.assertRedirectsAdmin('announcements:copy', args=[1]) self.assertRedirectsAdmin('announcements:publish', args=[1]) def test_all_announcement_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) self.assertEqual( self.client.get(reverse('announcements:list')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list2')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list', args=[self.ann_pk])).status_code, 200) # Announcement from setup() should appear in the list self.assertContains(self.client.get(reverse('announcements:list')), self.test_announcement.title) comment_response_get = self.client.get( reverse('announcements:comment', args=[self.ann_pk])) self.assertEqual(comment_response_get.status_code, 404) # Comments via POST only # Posting a comment redirects to the announcement commented on self.assertRedirects( response=self.client.post( reverse('announcements:comment', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) # These staff views should work self.assert200('announcements:create') self.assert200('announcements:update', args=[self.ann_pk]) self.assert200('announcements:copy', args=[self.ann_pk]) self.assert200('announcements:delete', args=[self.ann_pk]) self.assertRedirects( response=self.client.post( reverse('announcements:publish', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) def test_draft_announcement(self): draft_announcement = mommy.make(Announcement) # default is draft self.assertTrue(draft_announcement.draft) # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # Students shoudn't see draft announcements in the list self.assertNotContains(self.client.get(reverse('announcements:list')), draft_announcement.title) # set draft to false draft_announcement.draft = False draft_announcement.save() # Student can now see it self.assertContains(self.client.get(reverse('announcements:list')), draft_announcement.title) # @patch('announcements.views.publish_announcement.apply_async') def test_publish_announcement(self): draft_announcement = mommy.make(Announcement) # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) # draft announcement should appear with a link to publish it. TODO This is crude, should be checking HTML? publish_link = reverse('announcements:publish', args=[draft_announcement.pk]) self.assertContains(self.client.get(reverse('announcements:list')), publish_link) # publish the announcement self.assertRedirects( response=self.client.post( reverse('announcements:publish', args=[draft_announcement.pk])), expected_url=reverse('announcements:list', args=[draft_announcement.pk]), ) # Should probably mock the task in above code, but don't know how... # Fake mock...? draft_announcement.draft = False draft_announcement.save() # publish link for this announcement should no longer appear in the list: self.assertNotContains(self.client.get(reverse('announcements:list')), publish_link) def test_create_announcement_form_past_date_auto_publish(self): draft_announcement = mommy.make( Announcement, datetime_released=timezone.now() - timedelta(days=3), auto_publish=True, ) form = AnnouncementForm(data=model_to_dict(draft_announcement)) self.assertFalse(form.is_valid())
class AnnouncementViewTests(ViewTestUtilsMixin, TenantTestCase): def setUp(self): # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.client = TenantClient(self.tenant) self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user( 'test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user( 'test_student', password=self.test_password) self.test_student2 = baker.make(User) self.test_announcement = baker.make(Announcement, draft=False) self.ann_pk = self.test_announcement.pk def test_all_announcement_page_status_codes_for_anonymous(self): ''' If not logged in then all views should redirect to home page or admin ''' # go home self.assertRedirectsLogin('announcements:list') self.assertRedirectsLogin('announcements:list2') self.assertRedirectsLogin('announcements:comment', args=[1]) self.assertRedirectsLogin('announcements:list', args=[1]) # go admin self.assertRedirectsAdmin('announcements:create') self.assertRedirectsAdmin('announcements:delete', args=[1]) self.assertRedirectsAdmin('announcements:update', args=[1]) self.assertRedirectsAdmin('announcements:copy', args=[1]) self.assertRedirectsAdmin('announcements:publish', args=[1]) def test_all_announcement_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # all_fields = self.test_announcement._meta.get_fields() # for field in all_fields: # print(field, getattr(self.test_announcement, field.name)) # students should have access to these: self.assertEqual( self.client.get(reverse('announcements:list')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list2')).status_code, 200) self.assertEqual( self.client.get(reverse('announcements:list', args=[self.ann_pk])).status_code, 200) # Announcement from setup() should appear in the list self.assertContains(self.client.get(reverse('announcements:list')), self.test_announcement.title) comment_response_get = self.client.get( reverse('announcements:comment', args=[self.ann_pk])) self.assertEqual(comment_response_get.status_code, 404) # Comments via POST only # Posting a comment redirects to the announcement commented on self.assertRedirects( response=self.client.post( reverse('announcements:comment', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) # These views should redirect to admin login self.assertRedirectsAdmin('announcements:create') self.assertRedirectsAdmin('announcements:delete', args=[1]) self.assertRedirectsAdmin('announcements:update', args=[1]) self.assertRedirectsAdmin('announcements:copy', args=[1]) self.assertRedirectsAdmin('announcements:publish', args=[1]) def test_all_announcement_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) self.assert200('announcements:list') self.assert200('announcements:list2') self.assert200('announcements:list', args=[self.ann_pk]) # Announcement from setup() should appear in the list self.assertContains(self.client.get(reverse('announcements:list')), self.test_announcement.title) comment_response_get = self.client.get( reverse('announcements:comment', args=[self.ann_pk])) self.assertEqual(comment_response_get.status_code, 404) # Comments via POST only # Posting a comment redirects to the announcement commented on self.assertRedirects( response=self.client.post( reverse('announcements:comment', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) # These staff views should work self.assert200('announcements:create') self.assert200('announcements:update', args=[self.ann_pk]) self.assert200('announcements:copy', args=[self.ann_pk]) self.assert200('announcements:delete', args=[self.ann_pk]) self.assertRedirects( response=self.client.post( reverse('announcements:publish', args=[self.ann_pk])), expected_url=reverse('announcements:list', args=[self.ann_pk]), ) def test_draft_announcement(self): draft_announcement = baker.make(Announcement) # default is draft self.assertTrue(draft_announcement.draft) # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # Students shoudn't see draft announcements in the list self.assertNotContains(self.client.get(reverse('announcements:list')), draft_announcement.title) # set draft to false draft_announcement.draft = False draft_announcement.save() # Student can now see it self.assertContains(self.client.get(reverse('announcements:list')), draft_announcement.title) # @patch('announcements.views.publish_announcement.apply_async') def test_publish_announcement(self): draft_announcement = baker.make(Announcement) # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) # draft announcement should appear with a link to publish it. TODO This is crude, should be checking HTML? publish_link = reverse('announcements:publish', args=[draft_announcement.pk]) self.assertContains(self.client.get(reverse('announcements:list')), publish_link) # publish the announcement self.assertRedirects( response=self.client.post( reverse('announcements:publish', args=[draft_announcement.pk])), expected_url=reverse('announcements:list', args=[draft_announcement.pk]), ) # Should probably mock the task in above code, but don't know how... # Fake mock...? draft_announcement.draft = False draft_announcement.save() # publish link for this announcement should no longer appear in the list: self.assertNotContains(self.client.get(reverse('announcements:list')), publish_link) def test_create_announcement_from_past_date_auto_publish(self): draft_announcement = baker.make( Announcement, datetime_released=timezone.now() - timedelta(days=3), auto_publish=True, ) form = AnnouncementForm(data=model_to_dict(draft_announcement)) self.assertFalse(form.is_valid()) def test_comment_on_announcement_by_student(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) form_data = { 'comment_text': "test comment", } response = self.client.post( reverse('announcements:comment', args=[self.test_announcement.id]), form_data) self.assertEqual(response.status_code, 404) # invalid submit button # make sure it was submitted with the 'comment_button' form_data['comment_button'] = True response = self.client.post(reverse('announcements:comment', args=[self.test_announcement.id]), data=form_data) # Empty comment strings should be replaced with blank string or we get an error # WHY? THIS SEEMS SILLY! THE FORM SHOULDN'T VALIDATE IF THERE IS NO COMMENT! # Old code not relevant any more? # form_data['comment_text'] = None # response = self.client.post( # reverse('announcements:comment', args=[self.test_announcement.id]), # data=form_data # ) # self.assertRedirects(response, self.test_announcement.get_absolute_url()) def test_copy_announcement(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) # hit the view as a get request first, to load a copy of the announcement in the form response = self.client.get( reverse('announcements:copy', args=[self.test_announcement.id]), ) self.assertEqual(response.status_code, 200) # Don't know how to get the form data from the get request... # https://stackoverflow.com/questions/61532873/how-to-plug-the-reponse-of-a-django-view-get-request-into-the-same-view-as-a-pos # So, instead we'll manually create valid form data for post request: form_data = { 'title': "Copy test", 'content': "test content", 'datetime_released': "2006-10-25 14:30:59" # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DATETIME_INPUT_FORMATS } response = self.client.post(reverse('announcements:copy', args=[self.test_announcement.id]), data=form_data) # Get the newest announcement new_ann = Announcement.objects.latest('datetime_created') self.assertEqual(new_ann.title, "Copy test") # if successful, should redirect to the new announcement self.assertRedirects(response, new_ann.get_absolute_url())
class ViewTests(TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user( 'test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user( 'test_student', password=self.test_password) self.test_student2 = mommy.make(User) # needed because BadgeAssertions use a default that might not exist yet self.sem = SiteConfig.get().active_semester self.test_badge = mommy.make(Badge) self.test_assertion = mommy.make(BadgeAssertion) def test_all_badge_page_status_codes_for_anonymous(self): ''' If not logged in then all views should redirect to home page ''' self.assertRedirects( response=self.client.get(reverse('badges:list')), expected_url='%s?next=%s' % (reverse('home'), reverse('badges:list')), ) # for path in urlpatterns: # name = 'badges:%s' % path.name # # path.name # # print(url) # self.assertRedirects( # response=self.client.get(reverse(name)), # expected_url='%s?next=%s' % (reverse('home'), reverse(name)), # msg_prefix=name, # ) def test_all_badge_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) b_pk = self.test_badge.pk # a_pk = self.test_assertion.pk s_pk = self.test_student1.pk self.assertEqual( self.client.get(reverse('badges:list')).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_detail', args=[b_pk])).status_code, 200) # students shouldn't have access to these and should be redirected self.assertEqual( self.client.get(reverse('badges:badge_create')).status_code, 302) self.assertEqual( self.client.get(reverse('badges:badge_update', args=[b_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('badges:badge_copy', args=[b_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('badges:badge_delete', args=[b_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('badges:grant', args=[b_pk, s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('badges:bulk_grant_badge', args=[b_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('badges:bulk_grant')).status_code, 302) self.assertEqual( self.client.get(reverse('badges:revoke', args=[s_pk])).status_code, 302) def test_all_badge_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) b_pk = self.test_badge.pk a_pk = self.test_assertion.pk s_pk = self.test_student1.pk self.assertEqual( self.client.get(reverse('badges:list')).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_detail', args=[b_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_create')).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_update', args=[b_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_copy', args=[b_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:badge_delete', args=[b_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:grant', args=[b_pk, s_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:bulk_grant_badge', args=[b_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('badges:bulk_grant')).status_code, 200) self.assertEqual( self.client.get(reverse('badges:revoke', args=[a_pk])).status_code, 200)
class RosterTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.admin = User.objects.create(username="******", is_superuser=True, is_staff=True) self.client.force_login(self.admin) self.roster = Roster.objects.create(title="test_roster") # tests roster view function def test_roster_view(self): path = reverse('roster', kwargs=dict(roster_id=self.roster.pk)) response = self.client.get(path) self.assertContains(response, "test_roster</h1>") # tests roster appears in social view def test_roster_appears_in_social(self): path = reverse('social') response = self.client.get(path) self.assertContains(response, "test_roster</a>") # tests that rosters are paginated if more than 10 def test_roster_paginates_over_ten(self): for i in range(15): Roster.objects.create(title=str(i)) path = reverse('social') response = self.client.get(path) self.assertContains(response, "<a class=\"page-link\" href=\"?rosterspage") # tests edit_roster view function def test_edit_roster_view(self): path = reverse('edit_roster', kwargs=dict(roster_id=self.roster.pk)) referer = reverse('roster', kwargs=dict(roster_id=self.roster.pk)) post_data = {'updated_members': 'test1\ntest2\ntest3'} response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, "test1</td>") self.assertContains(response, "test2</td>") self.assertContains(response, "test3</td>") self.assertEqual(self.roster.members.count(), 3) # tests editing roster with duplicates def test_edit_roster_duplicates(self): path = reverse('edit_roster', kwargs=dict(roster_id=self.roster.pk)) referer = reverse('roster', kwargs=dict(roster_id=self.roster.pk)) # contains duplicate of test1 post_data = {'updated_members': 'test1\ntest2\ntest1'} response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains( response, "The following name was not added to the roster, because it is a duplicate:</b> test1" ) self.assertEqual(self.roster.members.count(), 2) # tests edit roster with get request, should return 404 def test_edit_roster_get(self): path = reverse('edit_roster', kwargs=dict(roster_id=1)) response = self.client.get(path) self.assertEqual(response.status_code, 404) # tests remove_from_roster function def test_remove_from_roster(self): member = RosterMember.objects.create(name="test", roster=self.roster) path = reverse('remove_from_roster', kwargs=dict(roster_id=self.roster.pk, member_id=member.pk)) referer = reverse('roster', kwargs=dict(roster_id=self.roster.pk)) response = self.client.get(path, HTTP_REFERER=referer, follow=True) self.assertEqual(self.roster.members.count(), 0) self.assertNotContains(response, "test</td>") # test add_roster_to_events function def test_add_roster_to_events(self): path = reverse('add_roster_to_events', kwargs=dict(roster_id=1)) s = SocialEvent.objects.create() RosterMember.objects.create(name="test", roster=self.roster) referer = reverse('roster', kwargs=dict(roster_id=1)) # contains the name of all checked events, default name for an event is test post_data = {'event_checkboxes': 'test'} response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) s.refresh_from_db() self.assertContains( response, "The members of this roster were successfully added to the following event:</b> test" ) self.assertEqual(s.list.count(), 1) # shouldn't behave differently, but shouldn't add duplicates to the event def test_add_roster_to_events(self): path = reverse('add_roster_to_events', kwargs=dict(roster_id=1)) s = SocialEvent.objects.create() Attendee.objects.create(name="test", user="******", event=s) RosterMember.objects.create(name="test", roster=self.roster) referer = reverse('roster', kwargs=dict(roster_id=1)) # contains the name of all checked events, default name for an event is test post_data = {'event_checkboxes': 'test'} response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) s.refresh_from_db() self.assertContains( response, "The members of this roster were successfully added to the following event:</b> test" ) self.assertEqual(s.list.count(), 1) # test add_roster_to_events with get request, should return 404 def test_add_roster_to_events_get(self): path = reverse('add_roster_to_events', kwargs=dict(roster_id=1)) response = self.client.get(path) self.assertEqual(response.status_code, 404) # test save_as_roster view def test_save_as_roster(self): s = SocialEvent.objects.create() path = reverse('save_as_roster', kwargs=dict(event_id=s.pk)) Attendee.objects.create(name="test", user="******", event=s) post_data = {'roster_name': 'saved_roster'} referer = reverse('social_event', kwargs=dict(event_id=s.pk)) response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, "List successfully saved as roster: saved_roster") self.assertTrue(Roster.objects.get(title="saved_roster")) self.assertEqual( Roster.objects.get(title="saved_roster").members.count(), 1) self.assertTrue( Roster.objects.get(title="saved_roster").members.get(name="test")) # test save_as_roster view with get method, which should return 404 def test_save_as_roster_get(self): s = SocialEvent.objects.create() path = reverse('save_as_roster', kwargs=dict(event_id=s.pk)) response = self.client.get(path) self.assertEqual(response.status_code, 404) # tests create_roster function def test_create_roster(self): path = reverse('create_roster') post_data = { 'title': 'created_roster', 'members': 'test1\ntest2\ntest3' } referer = reverse('social') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, "created_roster</a>") self.assertTrue(Roster.objects.get(title="created_roster")) self.assertEqual( Roster.objects.get(title="created_roster").members.count(), 3) # tests create_roster with duplicates def test_create_roster_duplicates(self): path = reverse('create_roster') post_data = { 'title': 'created_roster', 'members': 'test1\ntest2\ntest1' } referer = reverse('social') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, "created_roster</a>") self.assertTrue(Roster.objects.get(title="created_roster")) self.assertEqual( Roster.objects.get(title="created_roster").members.count(), 2) # tests create_roster function under get request, should be 404 def test_create_roster_get(self): path = reverse('create_roster') response = self.client.get(path) self.assertEqual(response.status_code, 404) # tests remove_roster function def test_remove_roster(self): path = reverse('remove_roster', kwargs=dict(roster_id=self.roster.pk)) referer = reverse('social') response = self.client.post(path, HTTP_REFERER=referer, follow=True) self.assertNotContains(response, "test_roster</a>") self.assertFalse(Roster.objects.filter(id=1))
class ProfileViewTests(ViewTestUtilsMixin, TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user( 'test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user( 'test_student', password=self.test_password) self.test_student2 = baker.make(User) # create semester with pk of default semester # this seems backward, but no semesters should exist yet in the test, so their shouldn't be any conflicts. self.active_sem = SiteConfig.get().active_semester def test_all_profile_page_status_codes_for_anonymous(self): """ If not logged in then all views should redirect to home page """ self.assertRedirectsLogin('profiles:profile_list') def test_all_profile_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) s_pk = self.test_student1.profile.pk s2_pk = self.test_student2.profile.pk self.assert200('profiles:profile_detail', args=[s_pk]) self.assert200('profiles:profile_update', args=[s_pk]) self.assert200('profiles:profile_list_current') # students shouldn't have access to these and should be redirected to login or permission denied self.assert403('profiles:profile_list') # viewing the profile of another student self.assertRedirectsQuests('profiles:profile_detail', args=[s2_pk]) self.assertEqual( self.client.get(reverse('profiles:comment_ban', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:comment_ban_toggle', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:GameLab_toggle', args=[s_pk])).status_code, 302) # self.assertEqual(self.client.get(reverse('profiles:recalculate_xp_current')).status_code, 302) self.assert404('profiles:profile_update', args=[s2_pk]) def test_all_profile_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) s_pk = self.test_student1.profile.pk # s2_pk = self.test_student2.pk self.assert200('profiles:profile_detail', args=[s_pk]) self.assert200('profiles:profile_update', args=[s_pk]) self.assert200('profiles:profile_list') self.assert200('profiles:profile_list_current') self.assertEqual( self.client.get(reverse('profiles:comment_ban', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:comment_ban_toggle', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:GameLab_toggle', args=[s_pk])).status_code, 302) # self.assertEqual(self.client.get(reverse('profiles:recalculate_xp_current')).status_code, 302) def test_profile_recalculate_xp_status_codes(self): """Need to test this view with students in an active course""" # why testing this here? self.assertEqual(self.active_sem.pk, SiteConfig.get().active_semester.pk) self.assertEqual( self.client.get( reverse('profiles:recalculate_xp_current')).status_code, 302) def test_student_marks_button(self): """ Student should be able to see marks button when `display_marks_calculation` is True. Otherwise, they should not be able to see it. """ # Login a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # View profile page s_pk = self.test_student1.profile.pk # `display_marks_calculation` is disabled by default. Student should not be able to view it response = self.client.get( reverse('profiles:profile_detail', args=[s_pk])) self.assertNotContains(response, 'View your Mark Calculations') config = SiteConfig.get() config.display_marks_calculation = True config.save() # Student should be able to view marks calculation response = self.client.get( reverse('profiles:profile_detail', args=[s_pk])) self.assertContains(response, 'View your Mark Calculations') def test_student_view_marks_404_if_disabled(self): """ Student marks should return 404 if disabled by admin. """ # Login a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) self.assert404('courses:my_marks')
class CalendarTestCase(TenantTestCase): """ tests basic appearance and functionality of calendar """ def setUp(self): self.client = TenantClient(self.tenant) self.user = User.objects.create(username='******', is_superuser=True, is_staff=True) self.client.force_login(self.user) self.rush_event = RushEvent.objects.create(name="rush_test", date=datetime.strptime( "2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), location="test") self.social_event = SocialEvent.objects.create(name="social_test", date=datetime.strptime( "2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), location="test") self.chapter_event = ChapterEvent.objects.create_chapter_event( name="chapter_test", date=datetime.strptime("2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), is_public=False, location="test") def test_calendar_template(self): """ tests that the current month appears by default """ today = datetime.today() path = reverse('cal:index') response = self.client.post(path) self.assertContains(response, today.month) def test_rush_event_appears(self): """ tests that rush events are appearing on calendar """ path = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path) self.assertContains(response, '<a href="/rush/events/' + str(self.rush_event.pk)) def test_social_event_appears(self): """ tests that social events are appearing on calendar """ path = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path) self.assertContains( response, '<a href="/social_event' + str(self.social_event.pk)) def test_chapter_event_appears(self): """ tests that chapter events are appearing on calendar """ path = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path) self.assertContains(response, 'chapter_test') def test_chapter_event_recurrence(self): """ tests that chapter events are recurring properly """ event = ChapterEvent.objects.create_chapter_event( name="recurrence_test", date=datetime.strptime("2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), is_public=False, location="test", recurring='Daily', end_date=datetime.strptime("2020-07-21", "%Y-%m-%d").date()) path = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path) self.assertContains( response, 'recurrence_test', count=6 ) # 2 events on calendar, 2 modal titles, 2 in modal details def test_month_overlap(self): """ tests that going to next month from december will run back to january """ get_data = {'month': '13', 'year': '2020'} path = reverse('cal:index') response = self.client.get(path, get_data) self.assertContains(response, 'January 2021') def test_month_underlap(self): """ tests that going to previous month from january will run back to december """ get_data = {'month': '0', 'year': '2020'} path = reverse('cal:index') response = self.client.get(path, get_data) self.assertContains(response, 'December 2019') def test_create_chapter_event_valid(self): """ tests creating chapter event from form data """ post_data = { 'name': 'test_chapter_event_create', 'location': 'test', 'date': datetime.strptime("2020-07-20", "%Y-%m-%d").date(), 'time': '12:00', 'recurring': 'None', 'end_date': '' } path = reverse('cal:create_chapter_event') referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, 'test_chapter_event_create') def test_create_chapter_event_invalid(self): """ tests creating chapter event with invalid data """ post_data = { 'name': 'test_chapter_event_create_invalid', 'location': 'test', 'date': '', 'time': '12:00', 'recurring': 'None', 'end_date': '' } # date is a required field form = ChapterEventForm(post_data) self.assertFalse(form.is_valid()) path = reverse('cal:create_chapter_event') referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, b'date') def test_create_chapter_event_recurring_no_end(self): """ tests creating a chapter event with a recurrence set but no end date """ post_data = { 'name': 'test_chapter_event_create_invalid', 'location': 'test', 'date': datetime.strptime("2020-07-20", "%Y-%m-%d").date(), 'time': '12:00', 'recurring': 'Daily', 'end_date': '' } # end date is required if event is recurrent form = ChapterEventForm(post_data) self.assertFalse(form.is_valid()) path = reverse('cal:create_chapter_event') referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, b'end_date') def test_create_chapter_event_get(self): """ test using get method on create_chapter_event """ path = reverse('cal:create_chapter_event') referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.get(path, HTTP_REFERER=referer, follow=True) self.assertEqual(response.status_code, 404)
class SignupTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.form_data = { 'username': '******', 'email': '*****@*****.**', 'first_name': 'Test_first', 'last_name': 'Test_last', 'verification_key': '9999', 'password1': 'c0mpl#x_p@$$w0rd', 'password2': 'c0mpl#x_p@$$w0rd' } # tests that signup form accepts valid input def test_signup_form(self): form = SignupForm(self.form_data) self.assertTrue(form.is_valid()) # tests that form rejects passwords that are too simple def test_simple_password(self): self.form_data.update({ 'password1': 'password', 'password2': 'password' }) form = SignupForm(self.form_data) self.assertFalse(form.is_valid()) self.assertIn('This password is too common', form.errors['password2'][0]) # tests that form rejects passwords that don't match def test_passwords_not_match(self): self.form_data.update({ 'password1': 'password1', 'password2': 'password2' }) form = SignupForm(self.form_data) self.assertFalse(form.is_valid()) self.assertEqual("The two password fields didn't match.", form.errors['password2'][0]) # tests that form rejects usernames that are already in use def test_username_already_taken(self): User.objects.create(username="******") form = SignupForm(self.form_data) self.assertFalse(form.is_valid()) self.assertEqual("A user with that username already exists.", form.errors['username'][0]) # tests that the user is redirected to successful verification page def test_valid_input_template(self): post_data = self.form_data path = reverse('signup') response = self.client.post(path, post_data) self.assertContains(response, "Thank you for signing up for GreekRho") # tests that inactive users can activate with activate view def test_activate_view(self): user = User.objects.create(username="******", is_active="False") token = account_activation_token.make_token(user) path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) response = self.client.post(path) self.assertContains(response, "Your account has been verified!") # tests user that does not exist def test_activate_user_does_not_exist(self): user = User.objects.create(username="******", is_active="False") token = account_activation_token.make_token(user) path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) user.delete() response = self.client.post(path) self.assertContains(response, "Activation link is invalid") # tests invalid activation token def test_activate_user_invalid_token(self): user = User.objects.create(username="******", is_active="False") token = "999-99999999999999999999" path = reverse('activate', kwargs=dict(user_id=user.pk, token=token)) response = self.client.post(path) self.assertContains(response, "Activation link is invalid") # tests logout def test_logout(self): user = User.objects.create(username="******") self.client.force_login(user) path = reverse('logout') response = self.client.post(path, follow=True) self.assertContains(response, "Login") # tests forgot_credentials view under a get method def test_forgot_credentials_get(self): path = reverse('forgot_credentials') response = self.client.get(path) self.assertContains(response, "Forgot Credentials?") # tests forgot_credentials view under a post method def test_forgot_credentials_post(self): user = User.objects.create(username="******", email="*****@*****.**") post_data = {'email': '*****@*****.**'} path = reverse('forgot_credentials') response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) self.assertContains(response, "Email with password reset link has been sent.") # tests forgot_credentials view when email is not unique def test_forgot_credentials_common_email(self): user1 = User.objects.create(username="******", email="*****@*****.**") user2 = User.objects.create(username="******", email="*****@*****.**") post_data = {'email': '*****@*****.**'} path = reverse('forgot_credentials') response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) self.assertContains( response, "Multiple accounts exist with the same email address.") # tests forgot_credentials view when email does not exist def test_forgot_credentials_email_dne(self): post_data = {'email': '*****@*****.**'} path = reverse('forgot_credentials') response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) self.assertContains(response, "User with this email does not exist") # tests reset_password view under a get method def test_reset_password_view_get(self): user = User.objects.create(username="******", email="*****@*****.**") token = account_activation_token.make_token(user) path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) response = self.client.get(path) self.assertContains(response, "Reset Password") # tests reset_password view under a post method def test_reset_password_view_post(self): user = User.objects.create(username="******", email="*****@*****.**") user.set_password("originalpassword") user.save() token = account_activation_token.make_token(user) path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) post_data = { 'new_password1': 'testpassword', 'new_password2': 'testpassword' } response = self.client.post(path, post_data) user.refresh_from_db() self.assertContains(response, "Your password has been changed.") self.assertFalse(user.check_password("originalpassword")) self.assertTrue(user.check_password("testpassword")) # tests reset password with invalid token def test_reset_password_invalid_token(self): user = User.objects.create(username="******", email="*****@*****.**") token = '999-99999999999999999999' path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) response = self.client.get(path) self.assertContains(response, "Invalid token!") # tests reset password with passwords that don't match def test_reset_password_no_match(self): user = User.objects.create(username="******", email="*****@*****.**") user.set_password("originalpassword") user.save() token = account_activation_token.make_token(user) path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) post_data = { 'new_password1': 'testpassword1', 'new_password2': 'testpassword2' } response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) user.refresh_from_db() self.assertContains(response, "The two password fields") self.assertFalse(user.check_password('testpassword1')) self.assertFalse(user.check_password('testpassword2')) self.assertTrue(user.check_password("originalpassword")) def test_reset_password_common(self): user = User.objects.create(username="******", email="*****@*****.**") user.set_password("originalpassword") user.save() token = account_activation_token.make_token(user) path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) post_data = {'new_password1': 'password', 'new_password2': 'password'} response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) user.refresh_from_db() self.assertContains(response, "This password is too common") self.assertFalse(user.check_password('password')) self.assertTrue(user.check_password('originalpassword')) def test_reset_password_short(self): user = User.objects.create(username="******", email="*****@*****.**") user.set_password("originalpassword") user.save() token = account_activation_token.make_token(user) path = reverse('reset_password', kwargs=dict(user_id=user.pk, token=token)) post_data = {'new_password1': 'xyzabc', 'new_password2': 'xyzabc'} response = self.client.post(path, post_data, HTTP_REFERER=path, follow=True) user.refresh_from_db() self.assertContains(response, "This password is too short.") self.assertFalse(user.check_password('xyzabc')) self.assertTrue(user.check_password('originalpassword'))
class SocialEventTestCase(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.admin = User.objects.create(username="******", is_staff=True, is_superuser=True) self.client.force_login(self.admin) self.event = SocialEvent.objects.create() self.attendees = [] for i in range(1, 4): a = Attendee.objects.create(name="attendee" + str(i), user=self.admin, event=self.event) self.attendees.append(a) self.event.save() # tests remove_from_list feature to make sure attendees are removed from database and UI def test_remove_from_list(self): path = reverse('remove_from_list', kwargs=dict(event_id=self.event.pk, attendee_id=self.attendees[0].pk)) referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, HTTP_REFERER=referer, follow=True) self.assertFalse(Attendee.objects.filter(name="attendee1")) self.assertFalse( re.findall("<td.*>attendee1</td>", str(response.content))) self.assertTrue( re.findall("<td.*>attendee2</td>", str(response.content))) path = reverse('remove_from_list', kwargs=dict(event_id=self.event.pk, attendee_id=self.attendees[1].pk)) response = self.client.post(path, HTTP_REFERER=referer, follow=True) self.assertFalse(Attendee.objects.filter(name="attendee2")) self.assertFalse( re.findall("<td.*>attendee2</td>", str(response.content))) self.assertTrue( re.findall("<td.*>attendee3</td>", str(response.content))) # tests clear list feature def test_clear_list(self): path = reverse('clear_list', kwargs=dict(event_id=self.event.pk)) referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, HTTP_REFERER=referer, follow=True) content = str(response.content) self.assertFalse(re.findall("<td>attendee[1-3]</td>", content)) self.assertFalse(self.event.list.all()) # tests exporting a spreadsheet of attendees def test_export_xls(self): path = reverse('export_xls', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path) self.assertEqual(response.get('Content-Type'), 'application/ms-excel') self.assertEqual( response.get('Content-Disposition'), 'attachment; filename=' + str(self.event.pk) + '_attendance.xls') # tests adding single duplicate name to the list def test_add_individual_duplicate(self): path = reverse('add_to_list', kwargs=dict(event_id=self.event.pk)) # should fail, because name is a duplicate post_data = {'multiple_names': '', 'name': 'attendee1'} referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains( response, " <b>The following name was not added to the list, because it is a duplicate:</b> attendee1" ) self.assertEqual(len(Attendee.objects.filter(name="attendee1")), 1) # tests adding multiple duplicate names to the list def test_add_multiple_duplicate(self): path = reverse('add_to_list', kwargs=dict(event_id=self.event.pk)) # should fail, because both names are duplicates post_data = {'multiple_names': 'attendee1\nattendee2', 'name': ''} referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains( response, " <b>The following name was not added to the list, because it is a duplicate:</b> attendee1" ) self.assertContains( response, " <b>The following name was not added to the list, because it is a duplicate:</b> attendee2" ) self.assertEqual(len(Attendee.objects.filter(name="attendee1")), 1) self.assertEqual(len(Attendee.objects.filter(name="attendee2")), 1) # tests adding multiple names where some are duplicates and some aren't def test_add_duplicates_and_new(self): path = reverse('add_to_list', kwargs=dict(event_id=self.event.pk)) # one should fail, one should work post_data = {'multiple_names': 'attendee1\nattendee5', 'name': ''} referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains( response, "<b>The following name was not added to the list, because it is a duplicate:</b> attendee1" ) self.assertNotContains( response, "<b>The following name was not added to the list, because it is a duplicate:</b> attendee2" ) self.assertEqual(len(Attendee.objects.filter(name="attendee1")), 1) self.assertEqual(len(Attendee.objects.filter(name="attendee2")), 1) # tests checking attendance feature def test_check_attendance(self): path = reverse('check_attendee') a = self.event.list.first() get_data = {'attendee_id': a.id} response = self.client.get(path, get_data) self.assertEqual(response.status_code, 200) self.assertJSONEqual(str(response.content, encoding='utf8'), {'attended': True}) a.refresh_from_db() self.assertTrue(a.attended) def test_uncheck_attendance(self): a = self.event.list.first() a.attended = True a.save() path = reverse('check_attendee') get_data = {'attendee_id': a.id} response = self.client.get(path, get_data) self.assertEqual(response.status_code, 200) self.assertJSONEqual(str(response.content, encoding='utf8'), {'attended': False}) a.refresh_from_db() self.assertFalse(a.attended) # tests refresh_attendees view for three attendees with attended=False def test_refresh_attendees_static(self): path = reverse('refresh_attendees') get_data = {'event_id': self.event.id} response = self.client.get(path, get_data) self.assertEqual(response.status_code, 200) # response should be false for all three attendees self.assertJSONEqual( str(response.content, encoding='utf8'), { str(self.attendees[0].pk): False, str(self.attendees[1].pk): False, str(self.attendees[2].pk): False }) # tests refresh_attendees view when status of attendee changes, to ensure change is propagated def test_refresh_attendees_dynamic(self): path = reverse('refresh_attendees') get_data = {'event_id': self.event.id} response = self.client.get(path, get_data) self.assertJSONEqual( str(response.content, encoding='utf8'), { str(self.attendees[0].pk): False, str(self.attendees[1].pk): False, str(self.attendees[2].pk): False }) # change one of the attendees, to see if the refresh changes the JSON response a = Attendee.objects.get(id=self.attendees[1].pk) a.attended = True a.save() response = self.client.get(path, get_data) self.assertJSONEqual( str(response.content, encoding='utf8'), { str(self.attendees[0].pk): False, str(self.attendees[1].pk): True, str(self.attendees[2].pk): False }) # test toggle_party_mode view def test_toggle_party_mode_view(self): # event.party_mode is initially false, request should make it true path = reverse('toggle_party_mode', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path) self.event.refresh_from_db() self.assertTrue(self.event.party_mode) # sending request again should make event.party_mode false again response = self.client.post(path) self.event.refresh_from_db() self.assertFalse(self.event.party_mode) # test toggle_party_mode template def test_toggle_party_mode_template(self): # party mode should initially be false referer = reverse('social_event', kwargs=dict(event_id=self.event.pk)) response = self.client.post(referer) # when party mode is off, the label by the button should say off self.assertContains(response, "Party mode off") # the add to list form should be availiable self.assertContains(response, "Type Full Name Here") # the ajax script refreshing the list should not be linked self.assertFalse( re.findall('<script src=".*cross_off_list.js', str(response.content))) # the "attended" column of the list table should not be present self.assertNotContains(response, "Attended") # set party mode to true path = reverse('toggle_party_mode', kwargs=dict(event_id=self.event.pk)) response = self.client.post(path, HTTP_REFERER=referer, follow=True) # when party mode is on, the label by the button should say on self.assertContains(response, "Party mode on") # The attended column should be present self.assertContains(response, "Attended") # the ajax script refreshing the list should be linked self.assertTrue( re.findall('<script src=".*cross_off_list.js', str(response.content))) # the add to list form should not be available self.assertNotContains(response, "Type Full Name Here")
class EditChapterEventTestCase(TenantTestCase): """ tests editing chapter events """ def setUp(self): self.client = TenantClient(self.tenant) self.user = User.objects.create(username="******", is_superuser=True, is_staff=True) self.client.force_login(self.user) self.singular = ChapterEvent.objects.create_chapter_event( name="singular event", date=datetime.strptime("2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), is_public=False, location="test") self.recurring = ChapterEvent.objects.create_chapter_event( name="recurring event", date=datetime.strptime("2020-07-20", "%Y-%m-%d").date(), time=datetime.now(), is_public=False, location="test", recurring='Daily', end_date=datetime.strptime("2020-07-26", "%Y-%m-%d").date()) def test_edit_singular(self): """ tests editing singular event """ post_data = { 'name': 'new_singular_name', 'date': "2020-07-21", 'time': '12:00:00', 'location': 'new_location', 'recurring': 'None', 'end_date': '2020-07-21', 'action': 'singular', } path = reverse('cal:edit_chapter_event', kwargs=dict(event_id=self.singular.pk)) referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertNotContains(response, "singular event") try: ChapterEvent.objects.get(name="singular event") self.fail('event should have been deleted') except ChapterEvent.DoesNotExist: pass def test_edit_recursive(self): """ tests editing multiple events at once """ post_data = { 'name': 'new_recursive_name', 'date': '2020-07-21', 'time': '12:00:00', 'location': 'new_location', 'recurring': 'Daily', 'end_date': '2020-07-23', 'action': 'recursive', } path = reverse('cal:edit_chapter_event', kwargs=dict(event_id=self.recurring.pk)) referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertNotContains(response, "recurring event") self.assertContains(response, "new_recursive_name", count=9) try: ChapterEvent.objects.get(name="recurring event") self.fail('event should have been deleted') except ChapterEvent.DoesNotExist: pass def test_edit_single_of_recursive(self): """ tests editing a single event that is recursive """ post_data = { 'name': 'new_recursive_name', 'date': '2020-07-21', 'time': '12:00:00', 'location': 'new_location', 'recurring': 'Daily', 'end_date': '2020-07-26', 'action': 'singular', } event = ChapterEvent.objects.get( date=datetime.strptime("2020-07-21", "%Y-%m-%d").date()) path = reverse('cal:edit_chapter_event', kwargs=dict(event_id=event.pk)) referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, 'new_recursive_name', count=3) self.assertContains(response, 'recurring event', count=18) def test_edit_first_of_recursive(self): """ tests editing single event that is recursive, where other events use this as a base """ post_data = { 'name': 'new_recursive_name', 'date': '2020-07-21', 'time': '12:00:00', 'location': 'new_location', 'recurring': 'Daily', 'end_date': '2020-07-26', 'action': 'singular', } path = reverse('cal:edit_chapter_event', kwargs=dict(event_id=self.recurring.pk)) referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.post(path, post_data, HTTP_REFERER=referer, follow=True) self.assertContains(response, "new_recursive_name", count=3) self.assertContains(response, "recurring event", count=18) def test_edit_chapter_event_get_request(self): """ test using get request on edit_chapter_event, should return 404 """ path = reverse('cal:edit_chapter_event', kwargs=dict(event_id=self.singular.pk)) referer = "%s?month=7&year=2020" % reverse('cal:index') response = self.client.get(path, HTTP_REFERER=referer, follow=True) self.assertEqual(response.status_code, 404)
class NotificationViewTests(ViewTestUtilsMixin, TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user('test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user('test_student', password=self.test_password) self.test_student2 = baker.make(User) def test_all_notification_page_status_codes_for_anonymous(self): ''' If not logged in then all views should redirect to home page ''' self.assertRedirectsLogin('notifications:list') self.assertRedirectsLogin('notifications:list_unread') self.assertRedirectsLogin('notifications:read', kwargs={'id': 1}) self.assertRedirectsLogin('notifications:read_all') self.assertRedirectsLogin('notifications:ajax') # this doesn't make sense. Should 404 self.assertRedirectsLogin('notifications:ajax_mark_read') # this doesn't make sense. Should 404 def test_all_notification_page_status_codes_for_students(self): # log in student1 success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) # Accessible views: self.assertEqual(self.client.get(reverse('notifications:list')).status_code, 200) self.assertEqual(self.client.get(reverse('notifications:list_unread')).status_code, 200) self.assertRedirects( response=self.client.get(reverse('notifications:read_all')), expected_url=reverse('notifications:list'), ) # Inaccessible views: self.assertEqual(self.client.get(reverse('notifications:ajax_mark_read')).status_code, 404) # requires AJAX self.assertEqual(self.client.get(reverse('notifications:ajax')).status_code, 404) # requires POST def test_all_notification_page_status_codes_for_teachers(self): # log in student1 success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) # Accessible views: self.assertEqual(self.client.get(reverse('notifications:list')).status_code, 200) self.assertEqual(self.client.get(reverse('notifications:list_unread')).status_code, 200) self.assertRedirects( response=self.client.get(reverse('notifications:read_all')), expected_url=reverse('notifications:list'), ) # Inaccessible views: self.assertEqual(self.client.get(reverse('notifications:ajax_mark_read')).status_code, 404) # requires POST self.assertEqual(self.client.get(reverse('notifications:ajax')).status_code, 404) # requires POST def test_ajax_mark_read(self): """ Marks a Notification as read via Ajax (by setting unread = FALSE) """ # log in student1 success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) notification = baker.make('notifications.Notification', recipient=self.test_student1) # make sure it is unread self.assertTrue(notification.unread) # mark it as read via the view being tested ajax_data = { 'id': notification.id, } response = self.client.post( reverse('notifications:ajax_mark_read'), data=ajax_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) self.assertEqual(response.status_code, 200) def test_ajax(self): # log in student1 success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) response = self.client.post( reverse('notifications:ajax'), HTTP_X_REQUESTED_WITH='XMLHttpRequest', ) self.assertEqual(response.status_code, 200)
class ProfileViewTests(TenantTestCase): # includes some basic model data # fixtures = ['initial_data.json'] def setUp(self): self.client = TenantClient(self.tenant) User = get_user_model() # need a teacher and a student with known password so tests can log in as each, or could use force_login()? self.test_password = "******" # need a teacher before students can be created or the profile creation will fail when trying to notify self.test_teacher = User.objects.create_user( 'test_teacher', password=self.test_password, is_staff=True) self.test_student1 = User.objects.create_user( 'test_student', password=self.test_password) self.test_student2 = mommy.make(User) # create semester with pk of default semester # this seems backward, but no semesters should exist yet in the test, so their shouldn't be any conflicts. self.active_sem = SiteConfig.get().active_semester def test_all_profile_page_status_codes_for_anonymous(self): """ If not logged in then all views should redirect to home page """ self.assertRedirects( response=self.client.get(reverse('profiles:profile_list')), expected_url='%s?next=%s' % (reverse('home'), reverse('profiles:profile_list')), ) def test_all_profile_page_status_codes_for_students(self): # log in a student success = self.client.login(username=self.test_student1.username, password=self.test_password) self.assertTrue(success) s_pk = self.test_student1.profile.pk s2_pk = self.test_student2.profile.pk # self.assertEqual(self.client.get(reverse('profiles:profile_detail')).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:profile_detail', args=[s_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:profile_update', args=[s_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:profile_list')).status_code, 200) self.assertEqual( self.client.get( reverse('profiles:profile_list_current')).status_code, 200) # students shouldn't have access to these and should be redirected to login self.assertEqual( self.client.get(reverse('profiles:profile_detail', args=[s2_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:comment_ban', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:comment_ban_toggle', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:GameLab_toggle', args=[s_pk])).status_code, 302) # self.assertEqual(self.client.get(reverse('profiles:recalculate_xp_current')).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:profile_update', args=[s2_pk])).status_code, 404) def test_all_profile_page_status_codes_for_teachers(self): # log in a teacher success = self.client.login(username=self.test_teacher.username, password=self.test_password) self.assertTrue(success) s_pk = self.test_student1.profile.pk # s2_pk = self.test_student2.pk self.assertEqual( self.client.get(reverse('profiles:profile_detail', args=[s_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:profile_update', args=[s_pk])).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:profile_list')).status_code, 200) self.assertEqual( self.client.get( reverse('profiles:profile_list_current')).status_code, 200) self.assertEqual( self.client.get(reverse('profiles:comment_ban', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:comment_ban_toggle', args=[s_pk])).status_code, 302) self.assertEqual( self.client.get(reverse('profiles:GameLab_toggle', args=[s_pk])).status_code, 302) # self.assertEqual(self.client.get(reverse('profiles:recalculate_xp_current')).status_code, 302) def test_profile_recalculate_xp_status_codes(self): """Need to test this view with students in an active course""" # why testing this here? self.assertEqual(self.active_sem.pk, SiteConfig.get().active_semester.pk) self.assertEqual( self.client.get( reverse('profiles:recalculate_xp_current')).status_code, 302)
class BadgeAssertionTestModel(TenantTestCase): def setUp(self): self.client = TenantClient(self.tenant) self.sem = SiteConfig.get().active_semester self.teacher = Recipe(User, is_staff=True).make( ) # need a teacher or student creation will fail. self.student = baker.make(User) self.assertion = baker.make(BadgeAssertion, semester=self.sem) self.badge = Recipe(Badge, xp=20).make() self.badge_assertion_recipe = Recipe(BadgeAssertion, user=self.student, badge=self.badge, semester=self.sem) def test_badge_assertion_creation(self): self.assertIsInstance(self.assertion, BadgeAssertion) self.assertEqual(str(self.assertion), self.assertion.badge.name) def test_badge_assertion_url(self): self.assertEqual( self.client.get(self.assertion.get_absolute_url(), follow=True).status_code, 200) def test_badge_assertion_count(self): num = 5 for _ in range(num): badge_assertion = BadgeAssertion.objects.create_assertion( self.student, self.badge, issued_by=self.teacher) # Why doesn't below work? # badge_assertion = self.badge_assertion_recipe.make() count = badge_assertion.count() # print(num, count) self.assertEqual(num, count) def test_badge_assertion_count_bootstrap_badge(self): """Returns empty string if count < 2, else returns proper count""" badge_assertion = baker.make(BadgeAssertion, semester=self.sem) self.assertEqual(badge_assertion.count_bootstrap_badge(), "") num = 4 for _ in range(num): badge_assertion = BadgeAssertion.objects.create_assertion( self.student, self.badge, issued_by=self.teacher) # Why doesn't below work? # badge_assertion = self.badge_assertion_recipe.make() count = badge_assertion.count_bootstrap_badge() # print(num, count) self.assertEqual(num, count) def test_badge_assertion_get_duplicate_assertions(self): num = 5 values = [] for _ in range(num): badge_assertion = self.badge_assertion_recipe.make() values.append(repr(badge_assertion)) qs = badge_assertion.get_duplicate_assertions() self.assertQuerysetEqual( list(qs), values, ) def test_badge_assertion_manager_create_assertion(self): # no semester new_assertion = BadgeAssertion.objects.create_assertion( self.student, baker.make(Badge), self.teacher) self.assertIsInstance(new_assertion, BadgeAssertion) # no teacher new_assertion = BadgeAssertion.objects.create_assertion( self.student, baker.make(Badge), ) self.assertIsInstance(new_assertion, BadgeAssertion) def test_badge_assertion_manager_xp_to_date(self): xp = BadgeAssertion.objects.calculate_xp_to_date( self.student, timezone.now()) self.assertEqual(xp, 0) # give them a badge assertion and make sure the XP works BadgeAssertion.objects.create_assertion(self.student, self.badge, self.teacher) xp = BadgeAssertion.objects.calculate_xp_to_date( self.student, timezone.now()) self.assertEqual(xp, self.badge.xp) def test_badge_assertion_manager_get_by_type_for_user(self): badge_list_by_type = BadgeAssertion.objects.get_by_type_for_user( self.student) self.assertIsInstance(badge_list_by_type, list) # TODO need to test this properly def test_badge_assertion_manager_check_for_new_assertions(self): BadgeAssertion.objects.check_for_new_assertions(self.student) # TODO need to tefrom django.contrib.auth import get_user_model def test_fraction_of_active_users_granted_this(self): num_students_with_badge = 3 students_with_badge = baker.make(User, _quantity=num_students_with_badge) self.assertEqual(len(students_with_badge), num_students_with_badge) total_students = User.objects.filter(is_active=True).count() badge = baker.make(Badge) for student in students_with_badge: baker.make(BadgeAssertion, user=student, badge=badge) fraction = badge.fraction_of_active_users_granted_this() self.assertEqual(fraction, num_students_with_badge / total_students) percentile = badge.percent_of_active_users_granted_this() self.assertEqual(percentile, num_students_with_badge / total_students * 100)
class TestPortalDashView(BaseTenantTestCase): def test_get(self): self.client = TenantClient(self.tenant) response = self.client.get(reverse("management:dashboard")) self.assertEqual(response.status_code, status.HTTP_200_OK)