diff --git a/PyRIGS/tests/base.py b/PyRIGS/tests/base.py index 4beb1eeb..da7f4eb5 100644 --- a/PyRIGS/tests/base.py +++ b/PyRIGS/tests/base.py @@ -34,3 +34,17 @@ class AutoLoginTest(BaseTest): self.profile.save() loginPage = pages.LoginPage(self.driver, self.live_server_url).open() loginPage.login("EventTest", "EventTestPassword") + + +# Checks if animation is done +class animation_is_finished(object): + def __init__(self): + pass + + def __call__(self, driver): + numberAnimating = driver.execute_script('return $(":animated").length') + finished = numberAnimating == 0 + if finished: + import time + time.sleep(0.1) + return finished diff --git a/RIGS/test_functional.py b/RIGS/tests/test_functional.py similarity index 87% rename from RIGS/test_functional.py rename to RIGS/tests/test_functional.py index 7cd04926..086a36a2 100644 --- a/RIGS/test_functional.py +++ b/RIGS/tests/test_functional.py @@ -23,170 +23,12 @@ from RIGS import models from reversion import revisions as reversion from django.urls import reverse from django.core import mail, signing -from PyRIGS.tests.base import create_browser +from PyRIGS.tests.base import create_browser, animation_is_finished from django.conf import settings import sys -class UserRegistrationTest(LiveServerTestCase): - def setUp(self): - self.browser = create_browser() - - self.browser.implicitly_wait(3) # Set implicit wait session wide - os.environ['RECAPTCHA_TESTING'] = 'True' - - def tearDown(self): - self.browser.quit() - os.environ['RECAPTCHA_TESTING'] = 'False' - - def test_registration(self): - # Navigate to the registration page - self.browser.get(self.live_server_url + '/user/register/') - title_text = self.browser.find_element_by_tag_name('h3').text - self.assertIn("User Registration", title_text) - - # Check the form invites correctly - username = self.browser.find_element_by_id('id_username') - self.assertEqual(username.get_attribute('placeholder'), 'Username') - email = self.browser.find_element_by_id('id_email') - self.assertEqual(email.get_attribute('placeholder'), 'E-mail') - # If this is correct we don't need to test it later - self.assertEqual(email.get_attribute('type'), 'email') - password1 = self.browser.find_element_by_id('id_password1') - self.assertEqual(password1.get_attribute('placeholder'), 'Password') - self.assertEqual(password1.get_attribute('type'), 'password') - password2 = self.browser.find_element_by_id('id_password2') - self.assertEqual( - password2.get_attribute('placeholder'), 'Password confirmation') - self.assertEqual(password2.get_attribute('type'), 'password') - first_name = self.browser.find_element_by_id('id_first_name') - self.assertEqual(first_name.get_attribute('placeholder'), 'First name') - last_name = self.browser.find_element_by_id('id_last_name') - self.assertEqual(last_name.get_attribute('placeholder'), 'Last name') - initials = self.browser.find_element_by_id('id_initials') - self.assertEqual(initials.get_attribute('placeholder'), 'Initials') - # No longer required for new users - # phone = self.browser.find_element_by_id('id_phone') - # self.assertEqual(phone.get_attribute('placeholder'), 'Phone') - - # Fill the form out incorrectly - username.send_keys('TestUsername') - email.send_keys('test@example.com') - password1.send_keys('correcthorsebatterystaple') - # deliberate mistake - password2.send_keys('correcthorsebatterystapleerror') - first_name.send_keys('John') - last_name.send_keys('Smith') - initials.send_keys('JS') - # phone.send_keys('0123456789') - self.browser.execute_script( - "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") - - # Submit incorrect form - submit = self.browser.find_element_by_xpath("//input[@type='submit']") - submit.click() - - # Restablish error fields - password1 = self.browser.find_element_by_id('id_password1') - password2 = self.browser.find_element_by_id('id_password2') - - # Read what the error is - alert = self.browser.find_element_by_css_selector( - 'div.alert-danger').text - # TODO Use regex matching to handle smart/unsmart quotes... - self.assertIn("password fields didn", alert) - - # Passwords should be empty - self.assertEqual(password1.get_attribute('value'), '') - self.assertEqual(password2.get_attribute('value'), '') - - # Correct error - password1.send_keys('correcthorsebatterystaple') - password2.send_keys('correcthorsebatterystaple') - self.browser.execute_script("console.log('Hello, world!')") - self.browser.execute_script( - "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") - - # Submit again - password2.send_keys(Keys.ENTER) - - # Check we have a success message - alert = self.browser.find_element_by_css_selector( - 'div.alert-success').text - self.assertIn('register', alert) - self.assertIn('email', alert) - - # Check Email - self.assertEqual(len(mail.outbox), 1) - email = mail.outbox[0] - self.assertIn('John Smith "JS" activation required', email.subject) - urls = re.findall( - r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body) - self.assertEqual(len(urls), 1) - - mail.outbox = [] # empty this for later - - # Follow link - self.browser.get(urls[0]) # go to the first link - - # Complete registration - title_text = self.browser.find_element_by_tag_name('h2').text - self.assertIn('Complete', title_text) - - # Test login - self.browser.get(self.live_server_url + '/user/login') - username = self.browser.find_element_by_id('id_username') - self.assertEqual(username.get_attribute('placeholder'), 'Username') - password = self.browser.find_element_by_id('id_password') - self.assertEqual(password.get_attribute('placeholder'), 'Password') - self.assertEqual(password.get_attribute('type'), 'password') - - # Expected to fail as not approved - username.send_keys('TestUsername') - password.send_keys('correcthorsebatterystaple') - self.browser.execute_script( - "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") - password.send_keys(Keys.ENTER) - - # Test approval - profileObject = models.Profile.objects.all()[0] - self.assertFalse(profileObject.is_approved) - - # Read what the error is - alert = self.browser.find_element_by_css_selector( - 'div.alert-danger').text - self.assertIn("approved", alert) - - # Approve the user so we can proceed - profileObject.is_approved = True - profileObject.save() - - # Retry login - self.browser.get(self.live_server_url + '/user/login') - username = self.browser.find_element_by_id('id_username') - username.send_keys('TestUsername') - password = self.browser.find_element_by_id('id_password') - password.send_keys('correcthorsebatterystaple') - self.browser.execute_script( - "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") - password.send_keys(Keys.ENTER) - - # Check we are logged in - udd = self.browser.find_element_by_class_name('navbar').text - self.assertIn('Hi John', udd) - - # Check all the data actually got saved - self.assertEqual(profileObject.username, 'TestUsername') - self.assertEqual(profileObject.first_name, 'John') - self.assertEqual(profileObject.last_name, 'Smith') - self.assertEqual(profileObject.initials, 'JS') - # self.assertEqual(profileObject.phone, '0123456789') - self.assertEqual(profileObject.email, 'test@example.com') - - # All is well - - class EventTest(LiveServerTestCase): def setUp(self): self.profile = models.Profile( @@ -1056,21 +898,6 @@ class IcalTest(LiveServerTestCase): # Wow - that was a lot of tests -class animation_is_finished(object): - """ Checks if animation is done """ - - def __init__(self): - pass - - def __call__(self, driver): - numberAnimating = driver.execute_script('return $(":animated").length') - finished = numberAnimating == 0 - if finished: - import time - time.sleep(0.1) - return finished - - class ClientEventAuthorisationTest(TestCase): auth_data = { 'name': 'Test ABC', diff --git a/RIGS/test_models.py b/RIGS/tests/test_models.py similarity index 70% rename from RIGS/test_models.py rename to RIGS/tests/test_models.py index 5eb39de0..9918f9be 100644 --- a/RIGS/test_models.py +++ b/RIGS/tests/test_models.py @@ -395,187 +395,3 @@ class EventAuthorisationTestCase(TestCase): name="Test Auth", amount=self.event.total, sent_by=self.profile) self.assertIsNotNone(auth.last_edited_at) - - -class RIGSVersionTestCase(TestCase): - def setUp(self): - models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01') - - self.profile = models.Profile.objects.get_or_create( - first_name='Test', - last_name='TEC User', - username='eventauthtest', - email='teccie@functional.test', - is_superuser=True # lazily grant all permissions - )[0] - with reversion.create_revision(): - reversion.set_user(self.profile) - self.person = models.Person.objects.create(name='Authorisation Test Person') - - with reversion.create_revision(): - reversion.set_user(self.profile) - self.organisation = models.Organisation.objects.create(name='Authorisation Test Organisation') - - with reversion.create_revision(): - reversion.set_user(self.profile) - self.event = models.Event.objects.create(name="AuthorisationTestCase", person=self.person, - start_date=date.today()) - - with reversion.create_revision(): - reversion.set_user(self.profile) - self.event.notes = "A new note on the event" - self.event.save() - - def test_find_parent_version(self): - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - self.assertEqual(currentVersion._object_version.object.notes, "A new note on the event") - - # Check the prev version is loaded correctly - previousVersion = currentVersion.parent - self.assertEqual(previousVersion._object_version.object.notes, None) - - # Check that finding the parent of the first version fails gracefully - self.assertFalse(previousVersion.parent) - - def test_changes_since(self): - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - - changes = currentVersion.changes - self.assertEqual(len(changes.field_changes), 1) - - def test_manager(self): - objs = versioning.RIGSVersion.objects.get_for_multiple_models( - [models.Event, models.Person, models.Organisation]) - self.assertEqual(len(objs), 4) - - def test_text_field_types(self): - with reversion.create_revision(): - reversion.set_user(self.profile) - self.event.name = "New event name" # Simple text - self.event.description = "hello world" # Long text - self.event.save() - - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - diff = currentVersion.changes - - # There are two changes - self.assertEqual(len(diff.field_changes), 2) - self.assertFalse(currentVersion.changes.items_changed) - self.assertTrue(currentVersion.changes.fields_changed) - self.assertTrue(currentVersion.changes.anything_changed) - - # Only one has "linebreaks" - self.assertEqual(sum([x.linebreaks for x in diff.field_changes]), 1) - - # None are "long" (email address) - self.assertEqual(sum([x.long for x in diff.field_changes]), 0) - - # Try changing email field in person - with reversion.create_revision(): - reversion.set_user(self.profile) - self.person.email = "hello@world.com" - self.person.save() - - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.person).latest('revision__date_created') - diff = currentVersion.changes - - # Should be declared as long - self.assertTrue(diff.field_changes[0].long) - - def test_text_diff(self): - with reversion.create_revision(): - reversion.set_user(self.profile) - self.event.notes = "An old note on the event" # Simple text - self.event.save() - - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - - # Check the diff is correct - self.assertEqual(currentVersion.changes.field_changes[0].diff, - [{'type': 'equal', 'text': "A"}, - {'type': 'delete', 'text': " new"}, - {'type': 'insert', 'text': "n old"}, - {'type': 'equal', 'text': " note on the event"} - ]) - - def test_choice_field(self): - with reversion.create_revision(): - reversion.set_user(self.profile) - self.event.status = models.Event.CONFIRMED - self.event.save() - - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - self.assertEqual(currentVersion.changes.field_changes[0].old, 'Provisional') - self.assertEqual(currentVersion.changes.field_changes[0].new, 'Confirmed') - - def test_creation_behaviour(self): - firstVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created').parent - diff = firstVersion.changes - - # Mainly to check for exceptions: - self.assertTrue(len(diff.field_changes) > 0) - - def test_event_items(self): - with reversion.create_revision(): - reversion.set_user(self.profile) - item1 = models.EventItem.objects.create(event=self.event, name="TI I1", quantity=1, cost=1.00, order=1) - self.event.save() - - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - - diffs = currentVersion.changes.item_changes - - self.assertEqual(len(diffs), 1) - self.assertTrue(currentVersion.changes.items_changed) - self.assertFalse(currentVersion.changes.fields_changed) - self.assertTrue(currentVersion.changes.anything_changed) - - self.assertTrue(diffs[0].old is None) - self.assertEqual(diffs[0].new.name, "TI I1") - - # Edit the item - with reversion.create_revision(): - reversion.set_user(self.profile) - item1.name = "New Name" - item1.save() - self.event.save() - - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - - diffs = currentVersion.changes.item_changes - - self.assertEqual(len(diffs), 1) - - self.assertEqual(diffs[0].old.name, "TI I1") - self.assertEqual(diffs[0].new.name, "New Name") - - # Check the diff - self.assertEqual(currentVersion.changes.item_changes[0].field_changes[0].diff, - [{'type': 'delete', 'text': "TI I1"}, - {'type': 'insert', 'text': "New Name"}, - ]) - - # Delete the item - - with reversion.create_revision(): - item1.delete() - self.event.save() - - # Find the most recent version - currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') - - diffs = currentVersion.changes.item_changes - - self.assertEqual(len(diffs), 1) - self.assertTrue(currentVersion.changes.items_changed) - self.assertFalse(currentVersion.changes.fields_changed) - self.assertTrue(currentVersion.changes.anything_changed) - - self.assertEqual(diffs[0].old.name, "New Name") - self.assertTrue(diffs[0].new is None) diff --git a/RIGS/test_unit.py b/RIGS/tests/test_unit.py similarity index 87% rename from RIGS/test_unit.py rename to RIGS/tests/test_unit.py index 985accd4..5049ed38 100644 --- a/RIGS/test_unit.py +++ b/RIGS/tests/test_unit.py @@ -255,85 +255,6 @@ class TestPrintPaperwork(TestCase): self.assertEqual(response.status_code, 200) -class TestVersioningViews(TestCase): - @classmethod - def setUpTestData(cls): - cls.profile = models.Profile.objects.create(username="testuser1", email="1@test.com", is_superuser=True, - is_active=True, is_staff=True) - - cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1') - - cls.events = {} - - with reversion.create_revision(): - reversion.set_user(cls.profile) - cls.events[1] = models.Event.objects.create(name="TE E1", start_date=date.today()) - - with reversion.create_revision(): - reversion.set_user(cls.profile) - cls.events[2] = models.Event.objects.create(name="TE E2", start_date='2014-03-05') - - with reversion.create_revision(): - reversion.set_user(cls.profile) - cls.events[1].description = "A test description" - cls.events[1].save() - - def setUp(self): - self.profile.set_password('testuser') - self.profile.save() - self.assertTrue(self.client.login(username=self.profile.username, password='testuser')) - - def test_event_history_loads_successfully(self): - request_url = reverse('event_history', kwargs={'pk': self.events[1].pk}) - - response = self.client.get(request_url, follow=True) - self.assertEqual(response.status_code, 200) - - def test_activity_feed_loads_successfully(self): - request_url = reverse('activity_feed') - - response = self.client.get(request_url, follow=True) - self.assertEqual(response.status_code, 200) - - def test_activity_table_loads_successfully(self): - request_url = reverse('activity_table') - - response = self.client.get(request_url, follow=True) - self.assertEqual(response.status_code, 200) - - # Some edge cases that have caused server errors in the past - def test_deleted_event(self): - request_url = reverse('activity_feed') - - self.events[2].delete() - - response = self.client.get(request_url, follow=True) - self.assertContains(response, "TE E2") - self.assertEqual(response.status_code, 200) - - def test_deleted_relation(self): - request_url = reverse('activity_feed') - - with reversion.create_revision(): - person = models.Person.objects.create(name="Test Person") - with reversion.create_revision(): - self.events[1].person = person - self.events[1].save() - - # Check response contains person - response = self.client.get(request_url, follow=True) - self.assertContains(response, "Test Person") - self.assertEqual(response.status_code, 200) - - # Delete person - person.delete() - - # Check response still contains person - response = self.client.get(request_url, follow=True) - self.assertContains(response, "Test Person") - self.assertEqual(response.status_code, 200) - - class TestEmbeddedViews(TestCase): @classmethod def setUpTestData(cls): diff --git a/assets/tests/test_assets.py b/assets/tests/test_assets.py index 2647d0f3..fbe83a73 100644 --- a/assets/tests/test_assets.py +++ b/assets/tests/test_assets.py @@ -13,7 +13,7 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait -from RIGS.test_functional import animation_is_finished +from PyRIGS.tests.base import animation_is_finished import datetime from django.utils import timezone diff --git a/users/tests/test_users.py b/users/tests/test_users.py new file mode 100644 index 00000000..a938aa9a --- /dev/null +++ b/users/tests/test_users.py @@ -0,0 +1,188 @@ +import os +import re +from datetime import date, time, datetime, timedelta + +import pytz +from django.conf import settings +from django.core import mail, signing +from django.db import transaction +from django.http import HttpResponseBadRequest +from django.test import LiveServerTestCase, TestCase +from django.test.client import Client +from django.urls import reverse +from reversion import revisions as reversion +from selenium import webdriver +from selenium.common.exceptions import StaleElementReferenceException +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support.ui import WebDriverWait + +from RIGS import models + +from reversion import revisions as reversion +from django.urls import reverse +from django.core import mail, signing +from PyRIGS.tests.base import create_browser +from django.conf import settings + +import sys + + +# Functional Tests +class UserRegistrationTest(LiveServerTestCase): + def setUp(self): + self.browser = create_browser() + + self.browser.implicitly_wait(3) # Set implicit wait session wide + os.environ['RECAPTCHA_TESTING'] = 'True' + + def tearDown(self): + self.browser.quit() + os.environ['RECAPTCHA_TESTING'] = 'False' + + def test_registration(self): + # Navigate to the registration page + self.browser.get(self.live_server_url + '/user/register/') + title_text = self.browser.find_element_by_tag_name('h3').text + self.assertIn("User Registration", title_text) + + # Check the form invites correctly + username = self.browser.find_element_by_id('id_username') + self.assertEqual(username.get_attribute('placeholder'), 'Username') + email = self.browser.find_element_by_id('id_email') + self.assertEqual(email.get_attribute('placeholder'), 'E-mail') + # If this is correct we don't need to test it later + self.assertEqual(email.get_attribute('type'), 'email') + password1 = self.browser.find_element_by_id('id_password1') + self.assertEqual(password1.get_attribute('placeholder'), 'Password') + self.assertEqual(password1.get_attribute('type'), 'password') + password2 = self.browser.find_element_by_id('id_password2') + self.assertEqual( + password2.get_attribute('placeholder'), 'Password confirmation') + self.assertEqual(password2.get_attribute('type'), 'password') + first_name = self.browser.find_element_by_id('id_first_name') + self.assertEqual(first_name.get_attribute('placeholder'), 'First name') + last_name = self.browser.find_element_by_id('id_last_name') + self.assertEqual(last_name.get_attribute('placeholder'), 'Last name') + initials = self.browser.find_element_by_id('id_initials') + self.assertEqual(initials.get_attribute('placeholder'), 'Initials') + # No longer required for new users + # phone = self.browser.find_element_by_id('id_phone') + # self.assertEqual(phone.get_attribute('placeholder'), 'Phone') + + # Fill the form out incorrectly + username.send_keys('TestUsername') + email.send_keys('test@example.com') + password1.send_keys('correcthorsebatterystaple') + # deliberate mistake + password2.send_keys('correcthorsebatterystapleerror') + first_name.send_keys('John') + last_name.send_keys('Smith') + initials.send_keys('JS') + # phone.send_keys('0123456789') + self.browser.execute_script( + "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") + + # Submit incorrect form + submit = self.browser.find_element_by_xpath("//input[@type='submit']") + submit.click() + + # Restablish error fields + password1 = self.browser.find_element_by_id('id_password1') + password2 = self.browser.find_element_by_id('id_password2') + + # Read what the error is + alert = self.browser.find_element_by_css_selector( + 'div.alert-danger').text + # TODO Use regex matching to handle smart/unsmart quotes... + self.assertIn("password fields didn", alert) + + # Passwords should be empty + self.assertEqual(password1.get_attribute('value'), '') + self.assertEqual(password2.get_attribute('value'), '') + + # Correct error + password1.send_keys('correcthorsebatterystaple') + password2.send_keys('correcthorsebatterystaple') + self.browser.execute_script("console.log('Hello, world!')") + self.browser.execute_script( + "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") + + # Submit again + password2.send_keys(Keys.ENTER) + + # Check we have a success message + alert = self.browser.find_element_by_css_selector( + 'div.alert-success').text + self.assertIn('register', alert) + self.assertIn('email', alert) + + # Check Email + self.assertEqual(len(mail.outbox), 1) + email = mail.outbox[0] + self.assertIn('John Smith "JS" activation required', email.subject) + urls = re.findall( + r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body) + self.assertEqual(len(urls), 1) + + mail.outbox = [] # empty this for later + + # Follow link + self.browser.get(urls[0]) # go to the first link + + # Complete registration + title_text = self.browser.find_element_by_tag_name('h2').text + self.assertIn('Complete', title_text) + + # Test login + self.browser.get(self.live_server_url + '/user/login') + username = self.browser.find_element_by_id('id_username') + self.assertEqual(username.get_attribute('placeholder'), 'Username') + password = self.browser.find_element_by_id('id_password') + self.assertEqual(password.get_attribute('placeholder'), 'Password') + self.assertEqual(password.get_attribute('type'), 'password') + + # Expected to fail as not approved + username.send_keys('TestUsername') + password.send_keys('correcthorsebatterystaple') + self.browser.execute_script( + "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") + password.send_keys(Keys.ENTER) + + # Test approval + profileObject = models.Profile.objects.all()[0] + self.assertFalse(profileObject.is_approved) + + # Read what the error is + alert = self.browser.find_element_by_css_selector( + 'div.alert-danger').text + self.assertIn("approved", alert) + + # Approve the user so we can proceed + profileObject.is_approved = True + profileObject.save() + + # Retry login + self.browser.get(self.live_server_url + '/user/login') + username = self.browser.find_element_by_id('id_username') + username.send_keys('TestUsername') + password = self.browser.find_element_by_id('id_password') + password.send_keys('correcthorsebatterystaple') + self.browser.execute_script( + "return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()") + password.send_keys(Keys.ENTER) + + # Check we are logged in + udd = self.browser.find_element_by_class_name('navbar').text + self.assertIn('Hi John', udd) + + # Check all the data actually got saved + self.assertEqual(profileObject.username, 'TestUsername') + self.assertEqual(profileObject.first_name, 'John') + self.assertEqual(profileObject.last_name, 'Smith') + self.assertEqual(profileObject.initials, 'JS') + # self.assertEqual(profileObject.phone, '0123456789') + self.assertEqual(profileObject.email, 'test@example.com') + + # All is well + diff --git a/versioning/tests/test_versioning.py b/versioning/tests/test_versioning.py new file mode 100644 index 00000000..e13a2bbc --- /dev/null +++ b/versioning/tests/test_versioning.py @@ -0,0 +1,277 @@ +import pytz +from reversion import revisions as reversion +from django.conf import settings +from django.core.exceptions import ValidationError +from django.test import TestCase +from RIGS import models, versioning +from datetime import date, timedelta, datetime, time +from decimal import * +from PyRIGS.tests.base import create_browser + + +# Model Tests +class RIGSVersionTestCase(TestCase): + def setUp(self): + models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01') + + self.profile = models.Profile.objects.get_or_create( + first_name='Test', + last_name='TEC User', + username='eventauthtest', + email='teccie@functional.test', + is_superuser=True # lazily grant all permissions + )[0] + with reversion.create_revision(): + reversion.set_user(self.profile) + self.person = models.Person.objects.create(name='Authorisation Test Person') + + with reversion.create_revision(): + reversion.set_user(self.profile) + self.organisation = models.Organisation.objects.create(name='Authorisation Test Organisation') + + with reversion.create_revision(): + reversion.set_user(self.profile) + self.event = models.Event.objects.create(name="AuthorisationTestCase", person=self.person, + start_date=date.today()) + + with reversion.create_revision(): + reversion.set_user(self.profile) + self.event.notes = "A new note on the event" + self.event.save() + + def test_find_parent_version(self): + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + self.assertEqual(currentVersion._object_version.object.notes, "A new note on the event") + + # Check the prev version is loaded correctly + previousVersion = currentVersion.parent + self.assertEqual(previousVersion._object_version.object.notes, None) + + # Check that finding the parent of the first version fails gracefully + self.assertFalse(previousVersion.parent) + + def test_changes_since(self): + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + + changes = currentVersion.changes + self.assertEqual(len(changes.field_changes), 1) + + def test_manager(self): + objs = versioning.RIGSVersion.objects.get_for_multiple_models( + [models.Event, models.Person, models.Organisation]) + self.assertEqual(len(objs), 4) + + def test_text_field_types(self): + with reversion.create_revision(): + reversion.set_user(self.profile) + self.event.name = "New event name" # Simple text + self.event.description = "hello world" # Long text + self.event.save() + + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + diff = currentVersion.changes + + # There are two changes + self.assertEqual(len(diff.field_changes), 2) + self.assertFalse(currentVersion.changes.items_changed) + self.assertTrue(currentVersion.changes.fields_changed) + self.assertTrue(currentVersion.changes.anything_changed) + + # Only one has "linebreaks" + self.assertEqual(sum([x.linebreaks for x in diff.field_changes]), 1) + + # None are "long" (email address) + self.assertEqual(sum([x.long for x in diff.field_changes]), 0) + + # Try changing email field in person + with reversion.create_revision(): + reversion.set_user(self.profile) + self.person.email = "hello@world.com" + self.person.save() + + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.person).latest('revision__date_created') + diff = currentVersion.changes + + # Should be declared as long + self.assertTrue(diff.field_changes[0].long) + + def test_text_diff(self): + with reversion.create_revision(): + reversion.set_user(self.profile) + self.event.notes = "An old note on the event" # Simple text + self.event.save() + + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + + # Check the diff is correct + self.assertEqual(currentVersion.changes.field_changes[0].diff, + [{'type': 'equal', 'text': "A"}, + {'type': 'delete', 'text': " new"}, + {'type': 'insert', 'text': "n old"}, + {'type': 'equal', 'text': " note on the event"} + ]) + + def test_choice_field(self): + with reversion.create_revision(): + reversion.set_user(self.profile) + self.event.status = models.Event.CONFIRMED + self.event.save() + + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + self.assertEqual(currentVersion.changes.field_changes[0].old, 'Provisional') + self.assertEqual(currentVersion.changes.field_changes[0].new, 'Confirmed') + + def test_creation_behaviour(self): + firstVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created').parent + diff = firstVersion.changes + + # Mainly to check for exceptions: + self.assertTrue(len(diff.field_changes) > 0) + + def test_event_items(self): + with reversion.create_revision(): + reversion.set_user(self.profile) + item1 = models.EventItem.objects.create(event=self.event, name="TI I1", quantity=1, cost=1.00, order=1) + self.event.save() + + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + + diffs = currentVersion.changes.item_changes + + self.assertEqual(len(diffs), 1) + self.assertTrue(currentVersion.changes.items_changed) + self.assertFalse(currentVersion.changes.fields_changed) + self.assertTrue(currentVersion.changes.anything_changed) + + self.assertTrue(diffs[0].old is None) + self.assertEqual(diffs[0].new.name, "TI I1") + + # Edit the item + with reversion.create_revision(): + reversion.set_user(self.profile) + item1.name = "New Name" + item1.save() + self.event.save() + + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + + diffs = currentVersion.changes.item_changes + + self.assertEqual(len(diffs), 1) + + self.assertEqual(diffs[0].old.name, "TI I1") + self.assertEqual(diffs[0].new.name, "New Name") + + # Check the diff + self.assertEqual(currentVersion.changes.item_changes[0].field_changes[0].diff, + [{'type': 'delete', 'text': "TI I1"}, + {'type': 'insert', 'text': "New Name"}, + ]) + + # Delete the item + + with reversion.create_revision(): + item1.delete() + self.event.save() + + # Find the most recent version + currentVersion = versioning.RIGSVersion.objects.get_for_object(self.event).latest('revision__date_created') + + diffs = currentVersion.changes.item_changes + + self.assertEqual(len(diffs), 1) + self.assertTrue(currentVersion.changes.items_changed) + self.assertFalse(currentVersion.changes.fields_changed) + self.assertTrue(currentVersion.changes.anything_changed) + + self.assertEqual(diffs[0].old.name, "New Name") + self.assertTrue(diffs[0].new is None) + +# Unit Tests +class TestVersioningViews(TestCase): + @classmethod + def setUpTestData(cls): + cls.profile = models.Profile.objects.create(username="testuser1", email="1@test.com", is_superuser=True, + is_active=True, is_staff=True) + + cls.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1') + + cls.events = {} + + with reversion.create_revision(): + reversion.set_user(cls.profile) + cls.events[1] = models.Event.objects.create(name="TE E1", start_date=date.today()) + + with reversion.create_revision(): + reversion.set_user(cls.profile) + cls.events[2] = models.Event.objects.create(name="TE E2", start_date='2014-03-05') + + with reversion.create_revision(): + reversion.set_user(cls.profile) + cls.events[1].description = "A test description" + cls.events[1].save() + + def setUp(self): + self.profile.set_password('testuser') + self.profile.save() + self.assertTrue(self.client.login(username=self.profile.username, password='testuser')) + + def test_event_history_loads_successfully(self): + request_url = reverse('event_history', kwargs={'pk': self.events[1].pk}) + + response = self.client.get(request_url, follow=True) + self.assertEqual(response.status_code, 200) + + def test_activity_feed_loads_successfully(self): + request_url = reverse('activity_feed') + + response = self.client.get(request_url, follow=True) + self.assertEqual(response.status_code, 200) + + def test_activity_table_loads_successfully(self): + request_url = reverse('activity_table') + + response = self.client.get(request_url, follow=True) + self.assertEqual(response.status_code, 200) + + # Some edge cases that have caused server errors in the past + def test_deleted_event(self): + request_url = reverse('activity_feed') + + self.events[2].delete() + + response = self.client.get(request_url, follow=True) + self.assertContains(response, "TE E2") + self.assertEqual(response.status_code, 200) + + def test_deleted_relation(self): + request_url = reverse('activity_feed') + + with reversion.create_revision(): + person = models.Person.objects.create(name="Test Person") + with reversion.create_revision(): + self.events[1].person = person + self.events[1].save() + + # Check response contains person + response = self.client.get(request_url, follow=True) + self.assertContains(response, "Test Person") + self.assertEqual(response.status_code, 200) + + # Delete person + person.delete() + + # Check response still contains person + response = self.client.get(request_url, follow=True) + self.assertContains(response, "Test Person") + self.assertEqual(response.status_code, 200) + + +#Functional Tests +