From 8ab4722b81915ae585739cd04dd67c0f0137a1c2 Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Thu, 24 Dec 2020 01:13:28 +0100 Subject: [PATCH 1/7] Ignore .vscode/ and .idea/ From Repository --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 652363d27..6d3828530 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,8 @@ static/stylesheets/no-mq.css static/stylesheets/style.css __pycache__ *.db + + +# Ignore Microsoft Visual Studio Code's and Jetbrain's Pycharm Files +.vscode/ +.idea/ From 242faa48b3e13154fe3b918ec3a2b50a6d9486ce Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 02:27:09 +0100 Subject: [PATCH 2/7] Add Methods To Check If Event Starts And Ends This Year --- events/models.py | 18 ++++++++++++++++++ events/tests/test_models.py | 23 ++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/events/models.py b/events/models.py index 1f315654d..75d0e548c 100644 --- a/events/models.py +++ b/events/models.py @@ -181,6 +181,24 @@ def next_time(self): except IndexError: return None + def is_scheduled_to_start_this_year(self) -> bool: + current_year: int = datetime.datetime.now().year + try: + if self.next_time.dt_start.year == current_year: + return True + except Exception: + pass + return False + + def is_scheduled_to_end_this_year(self) -> bool: + current_year: int = datetime.datetime.now().year + try: + if self.next_time.dt_end.year == current_year: + return True + except Exception: + pass + return False + @property def previous_time(self): now = timezone.now() diff --git a/events/tests/test_models.py b/events/tests/test_models.py index 0f3bafe76..b6d2e7ef3 100644 --- a/events/tests/test_models.py +++ b/events/tests/test_models.py @@ -62,7 +62,6 @@ def test_recurring_event(self): self.assertEqual(self.event.next_time.dt_start, recurring_time_dtstart) self.assertTrue(rt.valid_dt_end()) - rt.begin = now - datetime.timedelta(days=5) rt.finish = now - datetime.timedelta(days=3) rt.save() @@ -186,3 +185,25 @@ def test_event_previous_event(self): # 'Event.previous_event' can return None if there is no # OccurringRule or RecurringRule found. self.assertIsNone(self.event.previous_event) + + def test_scheduled_to_start_this_year_method(self): + now = seconds_resolution(timezone.now()) + + occurring_time_dtstart = now + datetime.timedelta(days=3) + OccurringRule.objects.create( + event=self.event, + dt_start=occurring_time_dtstart, + dt_end=occurring_time_dtstart + ) + self.assertTrue(self.event.is_scheduled_to_start_this_year()) + + def test_scheduled_to_end_this_year_method(self): + now = seconds_resolution(timezone.now()) + + occurring_time_dtstart = now + datetime.timedelta(days=3) + OccurringRule.objects.create( + event=self.event, + dt_start=occurring_time_dtstart, + dt_end=occurring_time_dtstart + ) + self.assertTrue(self.event.is_scheduled_to_end_this_year()) From f63f5a52bc1bb40ed80af59e0b328daa260fd548 Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 03:31:06 +0100 Subject: [PATCH 3/7] Set Up Templates For Querying Start And End Years Passed variables to the time_tag template [time_tag.html] that checks if an event was scheduled to start or end with the current year. --- templates/events/event_list.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/templates/events/event_list.html b/templates/events/event_list.html index bbfb764d2..285fa0c7d 100644 --- a/templates/events/event_list.html +++ b/templates/events/event_list.html @@ -45,8 +45,12 @@

U

{{ object.title|striptags }}

{% with object.next_time as next_time %} + {% with object.is_scheduled_to_start_this_year as scheduled_start_this_year %} + {% with object.is_scheduled_to_end_this_year as scheduled_end_this_year %} {% include "events/includes/time_tag.html" %} {% endwith %} + {% endwith %} + {% endwith %} {% if object.venue %} {% if object.venue.url %}{% endif %}{{ object.venue.name }}{% if object.venue.url %}{% endif %}{% if object.venue.address %}, {{ object.venue.address }}{% endif %} @@ -65,8 +69,12 @@

You just missed...

{{ object.title|striptags }}

{% with object.previous_time as next_time %} + {% with object.is_scheduled_to_start_this_year as scheduled_start_this_year %} + {% with object.is_scheduled_to_end_this_year as scheduled_end_this_year %} {% include "events/includes/time_tag.html" %} {% endwith %} + {% endwith %} + {% endwith %} {% if object.venue %} {% if object.venue.url %}{% endif %}{{ object.venue.name }}{% if object.venue.url %}{% endif %}{% if object.venue.address %}, {{ object.venue.address }}{% endif %} From 31ed8d54e16c7c90ddd9d3753ee8b831eb327a3e Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 03:33:24 +0100 Subject: [PATCH 4/7] Update dev-requirements.txt And .gitignore Selenium is used for running functional tests on the rendering of the events page. In the absence of a physical browser, the test will be done 'headless'. --- .gitignore | 1 + dev-requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6d3828530..5ad66799a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ __pycache__ # Ignore Microsoft Visual Studio Code's and Jetbrain's Pycharm Files .vscode/ .idea/ +sass/ \ No newline at end of file diff --git a/dev-requirements.txt b/dev-requirements.txt index 8716fc0dd..16fcd66c1 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -6,6 +6,7 @@ factory-boy==2.9.2 Faker==0.8.1 tblib==1.3.2 responses==0.10.5 +selenium==3.141.0 # Extra stuff required for local dev From 5918efbbf5567afd49249ab48fdf8d62ace33aaf Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 03:35:17 +0100 Subject: [PATCH 5/7] Insert New Test Data And Update test_views.py More events are created to test particular scenarios of events especially events set to start or end at a future year. --- events/tests/test_views.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/events/tests/test_views.py b/events/tests/test_views.py index 691817036..b8603bfdf 100644 --- a/events/tests/test_views.py +++ b/events/tests/test_views.py @@ -6,7 +6,7 @@ from django.test import TestCase from django.utils import timezone -from ..models import Calendar, Event, EventCategory, EventLocation, RecurringRule +from ..models import Calendar, Event, EventCategory, EventLocation, RecurringRule, OccurringRule from ..templatetags.events import get_events_upcoming from users.factories import UserFactory @@ -18,6 +18,11 @@ def setUpTestData(cls): cls.calendar = Calendar.objects.create(creator=cls.user, slug="test-calendar") cls.event = Event.objects.create(creator=cls.user, calendar=cls.calendar) cls.event_past = Event.objects.create(title='Past Event', creator=cls.user, calendar=cls.calendar) + cls.event_single_day = Event.objects.create(title="Single Day Event", creator=cls.user, calendar=cls.calendar) + cls.event_future_start_following_year = Event.objects.create(title='Event Starts Following Year', + creator=cls.user, calendar=cls.calendar) + cls.event_future_end_following_year = Event.objects.create(title='Event Ends Following Year', + creator=cls.user, calendar=cls.calendar) cls.now = timezone.now() @@ -34,12 +39,27 @@ def setUpTestData(cls): begin=cls.now - datetime.timedelta(days=2), finish=cls.now - datetime.timedelta(days=1), ) - + cls.rule_single_day = OccurringRule.objects.create( + event=cls.event_single_day, + dt_start=recurring_time_dtstart, + dt_end=recurring_time_dtstart + ) + cls.rule_future_start_year = OccurringRule.objects.create( + event=cls.event_future_start_following_year, + dt_start=recurring_time_dtstart + datetime.timedelta(weeks=52), + dt_end=recurring_time_dtstart + datetime.timedelta(weeks=53), + ) + cls.rule_future_end_year = OccurringRule.objects.create( + event=cls.event_future_end_following_year, + dt_start=recurring_time_dtstart, + dt_end=recurring_time_dtend + datetime.timedelta(weeks=52) + ) def test_events_homepage(self): url = reverse('events:events') response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context['object_list']), 1) + self.assertEqual(len(response.context['object_list']), 4) + self.assertIn(Event.objects.last().title, response.content.decode()) def test_calendar_list(self): calendars_count = Calendar.objects.count() @@ -54,7 +74,7 @@ def test_event_list(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context['object_list']), 1) + self.assertEqual(len(response.context['object_list']), 4) url = reverse('events:event_list_past', kwargs={"calendar_slug": 'unexisting'}) response = self.client.get(url) @@ -114,7 +134,7 @@ def test_event_list_date(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['object'], dt.date()) - self.assertEqual(len(response.context['object_list']), 2) + self.assertEqual(len(response.context['object_list']), 5) def test_eventlocation_list(self): venue = EventLocation.objects.create( @@ -150,12 +170,12 @@ def test_event_detail(self): self.assertEqual(self.event, response.context['object']) def test_upcoming_tag(self): - self.assertEqual(len(get_events_upcoming()), 1) + self.assertEqual(len(get_events_upcoming()), 4) self.assertEqual(len(get_events_upcoming(only_featured=True)), 0) self.rule.begin = self.now - datetime.timedelta(days=3) self.rule.finish = self.now - datetime.timedelta(days=2) self.rule.save() - self.assertEqual(len(get_events_upcoming()), 0) + self.assertEqual(len(get_events_upcoming()), 3) class EventSubmitTests(TestCase): From 588f1c8f938945e959568ce7d19fefcf33239676 Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 03:38:22 +0100 Subject: [PATCH 6/7] Time Tag Now Shows Year For Events With Details Not Within The Current Year The time tag now displays the year when an event will occur. This is only for events that have been scheduled to start or end in at a future year. The accompanying functional tests have also been included. --- events/tests/test_events_functional_test.py | 41 +++++++++++++++++++++ templates/events/includes/time_tag.html | 31 +++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 events/tests/test_events_functional_test.py diff --git a/events/tests/test_events_functional_test.py b/events/tests/test_events_functional_test.py new file mode 100644 index 000000000..2813316d7 --- /dev/null +++ b/events/tests/test_events_functional_test.py @@ -0,0 +1,41 @@ +from django.test import LiveServerTestCase, TestCase +from django.utils import timezone +from selenium.common.exceptions import WebDriverException +from selenium.webdriver import Chrome + +from .test_views import EventsViewsTests +from ..models import Event + + +class EventsPageFunctionalTests(LiveServerTestCase, TestCase): + @classmethod + def setUpClass(cls): + EventsViewsTests().setUpTestData() + super().setUpClass() + cls.now = timezone.now() + + def setUp(self) -> None: + try: + self.browser = Chrome() + self.browser.implicitly_wait(5) + except WebDriverException: # GitHub Actions Django CI + from selenium import webdriver + self.browser = webdriver.FirefoxOptions() + self.browser.headless = True + webdriver.Firefox(options=self.browser) + + def tearDown(self) -> None: + self.browser.quit() + + def test_event_starting_future_year_displays_year(self): + event = Event.objects.get(title=f"Event Starts Following Year") + self.browser.get(self.live_server_url + '/events/') + future_event_span_value = self.browser.find_element_by_id(str(event.id)) + self.assertIn(str(event.next_time.dt_start.year), future_event_span_value.text) + + def test_event_ending_future_year_displays_year(self): + event = Event.objects.get(title=f"Event Ends Following Year") + self.browser.get(self.live_server_url + '/events/') + future_event_span_value = self.browser.find_element_by_id(str(event.id)) + self.assertIn(str(event.next_time.dt_end.year), future_event_span_value.text) + diff --git a/templates/events/includes/time_tag.html b/templates/events/includes/time_tag.html index 078fcf1dc..c79d0b810 100644 --- a/templates/events/includes/time_tag.html +++ b/templates/events/includes/time_tag.html @@ -1,5 +1,32 @@ {% if next_time.single_day %} - + {% else %} - + {% endif %} \ No newline at end of file From 6fdb2960e3a68ca9ee804360b5e8a2776b92245b Mon Sep 17 00:00:00 2001 From: Nwokolo Godwin Date: Fri, 25 Dec 2020 06:09:42 +0100 Subject: [PATCH 7/7] Move All Test Data To Functional Test All test data concerning the provision of data to serve the functional tests have been moved to the functional test. As it improves readability. All other test data at test_views.py was reset to accommodate for the reduction in number of test data instances. --- events/tests/test_events_functional_test.py | 51 +++++++++++++++------ events/tests/test_views.py | 25 +++------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/events/tests/test_events_functional_test.py b/events/tests/test_events_functional_test.py index 2813316d7..f07146a9b 100644 --- a/events/tests/test_events_functional_test.py +++ b/events/tests/test_events_functional_test.py @@ -1,18 +1,38 @@ -from django.test import LiveServerTestCase, TestCase +import datetime + +from django.contrib.auth import get_user_model +from django.test import LiveServerTestCase from django.utils import timezone from selenium.common.exceptions import WebDriverException from selenium.webdriver import Chrome -from .test_views import EventsViewsTests -from ..models import Event +from ..models import Event, OccurringRule, Calendar -class EventsPageFunctionalTests(LiveServerTestCase, TestCase): +class EventsPageFunctionalTests(LiveServerTestCase): @classmethod def setUpClass(cls): - EventsViewsTests().setUpTestData() - super().setUpClass() cls.now = timezone.now() + cls.user = get_user_model().objects.create_user(username='username', password='password') + cls.calendar = Calendar.objects.create(creator=cls.user, slug="test-calendar-2") + cls.event_future_start_following_year = Event.objects.create(title='Event Starts Following Year', + creator=cls.user, calendar=cls.calendar) + cls.event_future_end_following_year = Event.objects.create(title='Event Ends Following Year', + creator=cls.user, calendar=cls.calendar) + recurring_time_dtstart = cls.now + datetime.timedelta(days=3) + recurring_time_dtend = recurring_time_dtstart + datetime.timedelta(days=5) + + cls.rule_future_start_year = OccurringRule.objects.create( + event=cls.event_future_start_following_year, + dt_start=recurring_time_dtstart + datetime.timedelta(weeks=52), + dt_end=recurring_time_dtstart + datetime.timedelta(weeks=53), + ) + cls.rule_future_end_year = OccurringRule.objects.create( + event=cls.event_future_end_following_year, + dt_start=recurring_time_dtstart, + dt_end=recurring_time_dtend + datetime.timedelta(weeks=52) + ) + super(EventsPageFunctionalTests, cls).setUpClass() def setUp(self) -> None: try: @@ -25,17 +45,18 @@ def setUp(self) -> None: webdriver.Firefox(options=self.browser) def tearDown(self) -> None: - self.browser.quit() + super().tearDown() + try: + self.browser.quit() + except Exception: + pass - def test_event_starting_future_year_displays_year(self): - event = Event.objects.get(title=f"Event Starts Following Year") + def test_event_starting_and_ending_future_year_displays_year(self): + event = self.event_future_start_following_year self.browser.get(self.live_server_url + '/events/') future_event_span_value = self.browser.find_element_by_id(str(event.id)) self.assertIn(str(event.next_time.dt_start.year), future_event_span_value.text) - def test_event_ending_future_year_displays_year(self): - event = Event.objects.get(title=f"Event Ends Following Year") - self.browser.get(self.live_server_url + '/events/') - future_event_span_value = self.browser.find_element_by_id(str(event.id)) - self.assertIn(str(event.next_time.dt_end.year), future_event_span_value.text) - + event_2 = Event.objects.get(title="Event Ends Following Year") + future_event_span_value = self.browser.find_element_by_id(str(event_2.id)) + self.assertIn(str(event_2.next_time.dt_end.year), future_event_span_value.text) diff --git a/events/tests/test_views.py b/events/tests/test_views.py index b8603bfdf..e111419b8 100644 --- a/events/tests/test_views.py +++ b/events/tests/test_views.py @@ -19,10 +19,6 @@ def setUpTestData(cls): cls.event = Event.objects.create(creator=cls.user, calendar=cls.calendar) cls.event_past = Event.objects.create(title='Past Event', creator=cls.user, calendar=cls.calendar) cls.event_single_day = Event.objects.create(title="Single Day Event", creator=cls.user, calendar=cls.calendar) - cls.event_future_start_following_year = Event.objects.create(title='Event Starts Following Year', - creator=cls.user, calendar=cls.calendar) - cls.event_future_end_following_year = Event.objects.create(title='Event Ends Following Year', - creator=cls.user, calendar=cls.calendar) cls.now = timezone.now() @@ -44,21 +40,12 @@ def setUpTestData(cls): dt_start=recurring_time_dtstart, dt_end=recurring_time_dtstart ) - cls.rule_future_start_year = OccurringRule.objects.create( - event=cls.event_future_start_following_year, - dt_start=recurring_time_dtstart + datetime.timedelta(weeks=52), - dt_end=recurring_time_dtstart + datetime.timedelta(weeks=53), - ) - cls.rule_future_end_year = OccurringRule.objects.create( - event=cls.event_future_end_following_year, - dt_start=recurring_time_dtstart, - dt_end=recurring_time_dtend + datetime.timedelta(weeks=52) - ) + def test_events_homepage(self): url = reverse('events:events') response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context['object_list']), 4) + self.assertEqual(len(response.context['object_list']), 2) self.assertIn(Event.objects.last().title, response.content.decode()) def test_calendar_list(self): @@ -74,7 +61,7 @@ def test_event_list(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context['object_list']), 4) + self.assertEqual(len(response.context['object_list']), 2) url = reverse('events:event_list_past', kwargs={"calendar_slug": 'unexisting'}) response = self.client.get(url) @@ -134,7 +121,7 @@ def test_event_list_date(self): response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['object'], dt.date()) - self.assertEqual(len(response.context['object_list']), 5) + self.assertEqual(len(response.context['object_list']), 3) def test_eventlocation_list(self): venue = EventLocation.objects.create( @@ -170,12 +157,12 @@ def test_event_detail(self): self.assertEqual(self.event, response.context['object']) def test_upcoming_tag(self): - self.assertEqual(len(get_events_upcoming()), 4) + self.assertEqual(len(get_events_upcoming()), 2) self.assertEqual(len(get_events_upcoming(only_featured=True)), 0) self.rule.begin = self.now - datetime.timedelta(days=3) self.rule.finish = self.now - datetime.timedelta(days=2) self.rule.save() - self.assertEqual(len(get_events_upcoming()), 3) + self.assertEqual(len(get_events_upcoming()), 1) class EventSubmitTests(TestCase):