diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..a4231588 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,23 @@ +[run] +source = . +omit = + ./venv/* + ./gallery/* + ./wwwapp/migrations/* + ./wwwapp/management/commands/download_remote_images.py + ./wwwapp/settings*.py + ./wwwapp/wsgi.py + ./manage.py + ./make_plan.py + ./htmlcov/* +plugins = + django_coverage_plugin +relative_files = True + +[report] +show_missing = True +skip_covered = True +exclude_lines = + pragma: no cover + if settings.DEBUG + if not settings.DEBUG diff --git a/.github/workflows/pythontest.yml b/.github/workflows/pythontest.yml index bc153600..c4cffbd1 100644 --- a/.github/workflows/pythontest.yml +++ b/.github/workflows/pythontest.yml @@ -38,4 +38,13 @@ jobs: - name: Django migrations run: ./manage.py makemigrations --check --dry-run - name: Django test - run: ./manage.py test wwwapp -v 2 + run: coverage run ./manage.py test wwwapp -v 2 + - name: Generate coverage report + run: coverage xml + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v1 + with: + file: ./coverage.xml + fail_ci_if_error: true + verbose: true + if: matrix.python-version == 3.8 diff --git a/coverage.sh b/coverage.sh new file mode 100755 index 00000000..a7880a97 --- /dev/null +++ b/coverage.sh @@ -0,0 +1,5 @@ +#!/bin/sh +coverage erase +coverage run manage.py test wwwapp +coverage report +coverage html diff --git a/requirements.txt b/requirements.txt index 8bcdfbb5..dafa1452 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,3 +17,5 @@ social-auth-app-django psycopg2 mock freezegun +coverage +django_coverage_plugin \ No newline at end of file diff --git a/wwwapp/forms.py b/wwwapp/forms.py index 1ade5f02..f5769a03 100644 --- a/wwwapp/forms.py +++ b/wwwapp/forms.py @@ -226,7 +226,7 @@ def __init__(self, *args, has_perm_to_edit=True, **kwargs): if kwargs['instance']: mce_attrs['automatic_uploads'] = True mce_attrs['images_upload_url'] = reverse('upload', kwargs={'type': 'workshop', 'name': kwargs['instance'].name}) - mce_attrs['readonly'] = self.fields['proposition_description'].disabled # does not seem to respect the Django field settings for some reason + mce_attrs['readonly'] = self.fields['page_content'].disabled # does not seem to respect the Django field settings for some reason self.fields['page_content'].widget = TinyMCE(mce_attrs=mce_attrs) # Layout diff --git a/wwwapp/settings_debug.py b/wwwapp/settings_debug.py index 1f82512a..ce1c3139 100644 --- a/wwwapp/settings_debug.py +++ b/wwwapp/settings_debug.py @@ -3,6 +3,7 @@ SECRET_KEY = ')_7av^!cy(wfx=k#3*7x+(=j^fzv+ot^1@sh9s9t=8$bu@r(z$' DEBUG = True +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG ALLOWED_HOSTS = ["*"] EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/wwwapp/tests/test_basic_views.py b/wwwapp/tests/test_basic_views.py new file mode 100644 index 00000000..fcc3b228 --- /dev/null +++ b/wwwapp/tests/test_basic_views.py @@ -0,0 +1,171 @@ +import datetime + +from django.contrib.auth.models import User +from django.test.testcases import TestCase +from django.urls import reverse + +from wwwapp.models import Camp, WorkshopType, WorkshopCategory, Workshop, WorkshopParticipant, Article + + +# Check if all of the important views at least load without crashing +# This is just so that we have something basic until somebody wries better tests +# TODO: write more proper tests for these views + +class CampQualificationViews(TestCase): + def setUp(self): + Camp.objects.all().update(year=2020, start_date=datetime.date(2020, 7, 3), end_date=datetime.date(2020, 7, 15)) + self.year_2020 = Camp.objects.get() + + self.admin_user = User.objects.create_superuser( + username='admin', email='admin@example.com', password='admin123') + self.lecturer_user = User.objects.create_user( + username='lecturer', email='lecturer@example.com', password='user123') + self.participant_user = User.objects.create_user( + username='participant', email='participant@example.com', password='user123') + + self.participant_user.userprofile.profile_page = '

O mnie

' + self.participant_user.userprofile.cover_letter = '

Jestem fajny

' + self.participant_user.userprofile.how_do_you_know_about = 'nie wiem' + self.participant_user.userprofile.save() + + self.workshop_type = WorkshopType.objects.create(year=self.year_2020, name='This type') + self.workshop_category = WorkshopCategory.objects.create(year=self.year_2020, name='This category') + + self.workshop = Workshop.objects.create( + title='Bardzo fajne warsztaty', + name='bardzofajne', + type=self.workshop_type, + proposition_description='

Testowy opis

', + status=Workshop.STATUS_ACCEPTED, + qualification_threshold=5, + max_points=10, + ) + self.workshop.category.add(self.workshop_category) + self.workshop.lecturer.add(self.lecturer_user.userprofile) + self.workshop.save() + + WorkshopParticipant.objects.create(workshop=self.workshop, participant=self.participant_user.userprofile, + qualification_result=7.5, comment='Dobrze') + + self.article = Article.objects.create(name='test_article', title='Testowy', content='Test', + modified_by=self.admin_user, on_menubar=True) + + def test_index_works(self): + response = self.client.get(reverse('index')) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('index')) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Edytuj') + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('index')) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('index')) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + def test_article_view_works(self): + response = self.client.get(reverse('article', args=[self.article.name])) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('article', args=[self.article.name])) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Edytuj') + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('article', args=[self.article.name])) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('article', args=[self.article.name])) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Edytuj') + + def test_participant_view_works(self): + response = self.client.get(reverse('participants', args=[self.year_2020.pk])) + self.assertRedirects(response, reverse('login') + '?next=' + reverse('participants', args=[self.year_2020.pk])) + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('participants', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('participants', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('participants', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 200) + + def test_lecturer_view_works(self): + response = self.client.get(reverse('lecturers', args=[self.year_2020.pk])) + self.assertRedirects(response, reverse('login') + '?next=' + reverse('lecturers', args=[self.year_2020.pk])) + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('lecturers', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('lecturers', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('lecturers', args=[self.year_2020.pk])) + self.assertEqual(response.status_code, 200) + + def test_all_people_view_works(self): + response = self.client.get(reverse('all_people')) + self.assertRedirects(response, reverse('login') + '?next=' + reverse('all_people')) + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('all_people')) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('all_people')) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('all_people')) + self.assertEqual(response.status_code, 200) + + def test_your_workshops_view_works(self): + response = self.client.get(reverse('yourWorkshops')) + self.assertRedirects(response, reverse('login') + '?next=' + reverse('yourWorkshops')) + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('yourWorkshops')) + self.assertEqual(response.status_code, 200) + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('yourWorkshops')) + self.assertEqual(response.status_code, 200) + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('yourWorkshops')) + self.assertEqual(response.status_code, 200) + + def test_all_workshops_view_works(self): + response = self.client.get(reverse('allWorkshops')) + self.assertRedirects(response, reverse('login') + '?next=' + reverse('allWorkshops')) + + self.client.force_login(self.participant_user) + response = self.client.get(reverse('allWorkshops')) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.lecturer_user) + response = self.client.get(reverse('allWorkshops')) + self.assertEqual(response.status_code, 403) + + self.client.force_login(self.admin_user) + response = self.client.get(reverse('allWorkshops')) + self.assertEqual(response.status_code, 200) \ No newline at end of file diff --git a/wwwapp/tests/test_populate_with_test_data.py b/wwwapp/tests/test_populate_with_test_data.py new file mode 100644 index 00000000..412e4238 --- /dev/null +++ b/wwwapp/tests/test_populate_with_test_data.py @@ -0,0 +1,18 @@ +from django.contrib.auth.models import User +from django.core.management import call_command +from django.test import TestCase +from django.test.utils import override_settings + +from wwwapp.models import UserProfile, Workshop + + +@override_settings(DEBUG=True) +class PopulateWithTestData(TestCase): + def test_populate_command(self): + args = [] + opts = {} + call_command('populate_with_test_data', *args, **opts) + + self.assertEquals(User.objects.count(), 51) + self.assertEquals(UserProfile.objects.count(), 51) + self.assertEquals(Workshop.objects.count(), 5) diff --git a/wwwapp/urls.py b/wwwapp/urls.py index c24298e0..339ff3cf 100644 --- a/wwwapp/urls.py +++ b/wwwapp/urls.py @@ -46,7 +46,7 @@ path('/lecturers/', views.lecturers_view, name='lecturers'), path('people/', views.participants_view, name='all_people'), path('filterEmails/', mail_views.filtered_emails_view, name='filter_emails'), - path('filterEmails///', mail_views.filtered_emails_view, name='filter_emails'), + path('filterEmails///', mail_views.filtered_emails_view, name='filter_emails'), path('template_for_workshop_page/', views.template_for_workshop_page_view, name='template_for_workshop_page'), path('program/', views.program_view, name='latest_program'), path('/program/', views.program_view, name='program'),