From 813db2c4748376680a4899264bf6cdd583ea8cfd Mon Sep 17 00:00:00 2001 From: FreneticScribbler Date: Thu, 21 May 2020 22:48:46 +0100 Subject: [PATCH] Initial refactor of event item testing --- PyRIGS/tests/regions.py | 12 +++ RIGS/tests/pages.py | 12 +++ RIGS/tests/regions.py | 28 +++++++ RIGS/tests/test_functional.py | 128 ---------------------------- RIGS/tests/test_rigs.py | 152 +++++++++++++++------------------- 5 files changed, 121 insertions(+), 211 deletions(-) diff --git a/PyRIGS/tests/regions.py b/PyRIGS/tests/regions.py index eaba96aa..63325a1e 100644 --- a/PyRIGS/tests/regions.py +++ b/PyRIGS/tests/regions.py @@ -217,3 +217,15 @@ class Modal(Region): form_element.set_value(value) else: self.__dict__[name] = value + + +# TODO Move to RIGS regions +class ItemModal(Modal): + _header_selector = (By.TAG_NAME, 'h4') + + form_items = { + 'name': (TextBox, (By.ID, 'item_name')), + 'description': (TextBox, (By.ID, 'item_description')), + 'quantity': (TextBox, (By.ID, 'item_quantity')), + 'price': (TextBox, (By.ID, 'item_cost')) + } diff --git a/RIGS/tests/pages.py b/RIGS/tests/pages.py index 7c4718a8..857e5457 100644 --- a/RIGS/tests/pages.py +++ b/RIGS/tests/pages.py @@ -4,8 +4,10 @@ from selenium.webdriver.support import expected_conditions from selenium.webdriver import Chrome from django.urls import reverse from PyRIGS.tests import regions +from RIGS.tests import regions as rigs_regions from PyRIGS.tests.pages import BasePage, FormPage from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support import expected_conditions as EC class Index(BasePage): URL_TEMPLATE = reverse('index') @@ -59,6 +61,7 @@ class CreateEvent(FormPage): _mic_selector_selector = (By.XPATH, '//*[@id="form-hws"]/div[7]/div[1]/div/div') _add_person_selector = (By.XPATH, '//a[@data-target="#id_person" and contains(@href, "add")]') + _add_item_selector = (By.XPATH, '//button[contains(@class, "item-add")]') form_items = { 'description': (regions.TextBox, (By.ID, 'id_description')), @@ -81,6 +84,9 @@ class CreateEvent(FormPage): def select_event_type(self, type_name): self.find_element(By.XPATH, '//button[.="' + type_name + '"]').click() + def item_row(self, ID): + return rigs_regions.ItemRow(self, self.find_element(By.ID, "item-" + ID)) + @property def is_expanded(self): return self.find_element(*self._bottom_save_selector).is_displayed() @@ -101,6 +107,12 @@ class CreateEvent(FormPage): self.find_element(*self._add_person_selector).click() return regions.Modal(self, self.driver.find_element_by_id('modal')) + def add_event_item(self): + self.find_element(*self._add_item_selector).click() + element = self.driver.find_element_by_id('itemModal') + self.wait.until(EC.visibility_of(element)) + return regions.ItemModal(self, element) + @property def success(self): return '/create' not in self.driver.current_url diff --git a/RIGS/tests/regions.py b/RIGS/tests/regions.py index aec64bcf..63fc31eb 100644 --- a/RIGS/tests/regions.py +++ b/RIGS/tests/regions.py @@ -10,3 +10,31 @@ import datetime class Header(Region): def find_link(self, link_text): return self.driver.find_element_by_partial_link_text(link_text) + + +class ItemRow(Region): + _name_locator = (By.XPATH, '//span[@class="name"]') + _description_locator = (By.XPATH, '//div[@class="item-description"]') + _price_locator = (By.XPATH, '//span[@class="cost"]') + _quantity_locator = (By.XPATH, '//td[@class="quantity"]') + _subtotal_locator = (By.XPATH, '//span[@class="sub-total"]') + + @property + def name(self): + return self.find_element(*self._name_locator).text + + @property + def description(self): + return self.find_element(*self._description_locator).text + + @property + def price(self): + return self.find_element(*self._price_locator).text + + @property + def quantity(self): + return self.find_element(*self._quantity_locator).text + + @property + def subtotal(self): + return self.find_element(*self._subtotal_locator).text diff --git a/RIGS/tests/test_functional.py b/RIGS/tests/test_functional.py index 69843c35..7b30c6c9 100644 --- a/RIGS/tests/test_functional.py +++ b/RIGS/tests/test_functional.py @@ -64,92 +64,6 @@ class EventTest(LiveServerTestCase): self.assertEqual(self.live_server_url + n, self.browser.current_url) - def testRigCreate(self): - # Requests address - self.browser.get(self.live_server_url + '/event/create/') - # Gets redirected to login and back - self.authenticate('/event/create/') - - wait = WebDriverWait(self.browser, 3) # setup WebDriverWait to use later (to wait for animations) - - wait.until(animation_is_finished()) - - # Check has slided up correctly - second save button hidden - save = self.browser.find_element_by_xpath( - '(//button[@type="submit"])[3]') - self.assertFalse(save.is_displayed()) - - # Click Rig button - self.browser.find_element_by_xpath('//button[.="Rig"]').click() - - # Slider expands and save button visible - self.assertTrue(save.is_displayed()) - form = self.browser.find_element_by_xpath('/html/body/div[2]/div[1]/form') - - # For now, just check that HTML5 Client validation is in place TODO Test needs rewriting to properly test all levels of validation. - self.assertTrue(self.browser.find_element_by_id('id_name').get_attribute('required') is not None) - - # Set title - e = self.browser.find_element_by_id('id_name') - e.send_keys('Test Event Name') - - # Set start date/time - form.find_element_by_id('id_start_date').send_keys('25/05/3015') - form.find_element_by_id('id_start_time').send_keys('06:59') - - # Set end date/time - form.find_element_by_id('id_end_date').send_keys('27/06/4000') - form.find_element_by_id('id_end_time').send_keys('07:00') - - # Add item - form.find_element_by_xpath('//button[contains(@class, "item-add")]').click() - wait.until(animation_is_finished()) - modal = self.browser.find_element_by_id("itemModal") - modal.find_element_by_id("item_name").send_keys("Test Item 1") - modal.find_element_by_id("item_description").send_keys( - "This is an item description\nthat for reasons unknown spans two lines") - e = modal.find_element_by_id("item_quantity") - e.click() - e.send_keys(Keys.UP) - e.send_keys(Keys.UP) - e = modal.find_element_by_id("item_cost") - e.send_keys("23.95") - e.send_keys(Keys.ENTER) # enter submit - - # Confirm item has been saved to json field - objectitems = self.browser.execute_script("return objectitems;") - self.assertEqual(1, len(objectitems)) - testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID - self.assertEqual("Test Item 1", testitem['name']) - self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields - - # See new item appear in table - row = self.browser.find_element_by_id('item--1') # ID number is known, see above - self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text) - self.assertIn("This is an item description", - row.find_element_by_xpath('//div[@class="item-description"]').text) - self.assertEqual('£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text) - self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text) - self.assertEqual('£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text) - - # Check totals - self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').text) - self.assertIn("(TBC)", self.browser.find_element_by_id('vat-rate').text) - self.assertEqual("9.58", self.browser.find_element_by_id('vat').text) - self.assertEqual("57.48", self.browser.find_element_by_id('total').text) - - save = self.browser.find_element_by_xpath( - '(//button[@type="submit"])[3]') - save.click() - - # TODO Testing of requirement for contact details - - # TODO Something seems broken with the CI tests here. - # See redirected to success page - # successTitle = self.browser.find_element_by_xpath('//h1').text - # event = models.Event.objects.get(name='Test Event Name') - # self.assertIn("N%05d | Test Event Name" % event.pk, successTitle) - def testEventDuplicate(self): client = models.Person.objects.create(name='Duplicate Test Person', email='duplicate@functional.test') testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, @@ -369,48 +283,6 @@ class EventTest(LiveServerTestCase): self.assertIn("N%05d | Test Event Name" % event.pk, successTitle) - def testRigNonRig(self): - self.browser.get(self.live_server_url + '/event/create/') - # Gets redirected to login and back - self.authenticate('/event/create/') - - wait = WebDriverWait(self.browser, 3) # setup WebDriverWait to use later (to wait for animations) - self.browser.implicitly_wait(3) # Set session-long wait (only works for non-existant DOM objects) - - wait.until(animation_is_finished()) - - # Click Non-Rig button - self.browser.find_element_by_xpath('//button[.="Non-Rig"]').click() - - # Click Rig button - self.browser.find_element_by_xpath('//button[.="Rig"]').click() - - form = self.browser.find_element_by_xpath('/html/body/div[2]/div[1]/form') - save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]') - - # Set title - e = self.browser.find_element_by_id('id_name') - e.send_keys('Test Event Name') - - # Set person - person = models.Person.objects.create(name='Rig Non-Rig Person', email='rignonrig@functional.test') - person_select = form.find_element_by_xpath( - '//button[@data-id="id_person"]') - person_select.send_keys(person.name) - person_dropped = form.find_element_by_xpath( - '//ul[contains(@class, "dropdown-menu")]//span[contains(text(), "%s")]' % person.name) - person_dropped.click() - - # Set an arbitrary date - self.browser.execute_script("document.getElementById('id_start_date').value='3015-04-24'") - - # Save the rig - wait.until(animation_is_finished()) - save.click() - detail_panel = self.browser.find_element_by_xpath("//div[@id='content']/div/div[6]/div/div") - self.assertTrue(detail_panel.is_displayed()) - self.assertIn("Event Detail", detail_panel.text) - def testEventDetail(self): with transaction.atomic(), reversion.create_revision(): person = models.Person(name="Event Detail Person", email="eventdetail@person.tests.rigs", phone="123 123") diff --git a/RIGS/tests/test_rigs.py b/RIGS/tests/test_rigs.py index 237497b5..e34fce31 100644 --- a/RIGS/tests/test_rigs.py +++ b/RIGS/tests/test_rigs.py @@ -17,7 +17,7 @@ from RIGS.tests import regions import datetime from datetime import date, time, timedelta from django.utils import timezone -from selenium.webdriver.support.select import Select +from selenium.webdriver.common.action_chains import ActionChains class TestRigboard(AutoLoginTest): def setUp(self): @@ -148,97 +148,67 @@ class TestEventCreate(AutoLoginTest): self.wait.until(EC.invisibility_of_element_located((By.ID, 'modal'))) self.assertFalse(modal.is_open) - person2 = models.Person.objects.get(name=person_name) - options = list((x for x in self.page.person_selector.options if x.selected)) - self.assertTrue(len(options) == 1) - self.assertEqual(person2.name, options[0].name) - # and backend - # self.assertEqual(person1.pk, int(self.page.person_selector.get_attribute("value"))) + # TODO - # Was right the first time, change it back - self.page.person_selector.search(person1.name) - # TODO Check multiple cannot be selected? Is that necessary? - self.page.person_selector.set_option(person1.name, True) + def test_event_item_creation(self): + self.wait.until(animation_is_finished()) + self.assertFalse(self.page.is_expanded) + self.page.select_event_type("Rig") + self.wait.until(animation_is_finished()) + self.assertTrue(self.page.is_expanded) - options = list((x for x in self.page.person_selector.options if x.selected)) - self.assertTrue(len(options) == 1) - self.assertEqual(person2.name, options[0].name) - # and backend - # self.assertEqual(person1.pk, int(self.page.person_selector.get_attribute("value"))) + self.page.name = "Test Event with Items" - pass + self.page.person_selector.toggle() + self.assertTrue(self.page.person_selector.is_open) + self.page.person_selector.search(self.client.name) + self.page.person_selector.set_option(self.client.name, True) + # TODO This should not be necessary, normally closes automatically + self.page.person_selector.toggle() + self.assertFalse(self.page.person_selector.is_open) - # Edit Person 1 to have a better name - form.find_element_by_xpath( - '//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click() - wait.until(animation_is_finished()) - self.assertTrue(modal.is_displayed()) - self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text) - name = modal.find_element_by_xpath( - '//div[@id="modal"]//input[@id="id_name"]') - self.assertEqual(person1.name, name.get_attribute('value')) - name.clear() - name.send_keys('Rig ' + person1.name) - name.send_keys(Keys.ENTER) + self.page.start_date = datetime.date(1984, 1, 1) - wait.until(animation_is_finished()) + modal = self.page.add_event_item() + self.wait.until(animation_is_finished()) + # See modal has opened + self.assertTrue(modal.is_open) + self.assertIn("New Event", modal.header) - self.assertFalse(modal.is_displayed()) - person1 = models.Person.objects.get(pk=person1.pk) - self.assertEqual(person1.name, form.find_element_by_xpath( - '//button[@data-id="id_person"]/span').text) + modal.name = "Test Item 1" + modal.description = "This is an item description\nthat for reasons unknown spans two lines" + modal.quantity = "2" + modal.price = "23.95" + modal.submit() + self.wait.until(animation_is_finished()) - # Create organisation - wait.until(animation_is_finished()) - add_button = self.browser.find_element_by_xpath( - '//a[@data-target="#id_organisation" and contains(@href, "add")]') - add_button.click() - modal = self.browser.find_element_by_id('modal') - wait.until(animation_is_finished()) - self.assertTrue(modal.is_displayed()) - self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text) - modal.find_element_by_xpath( - '//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation") - modal.find_element_by_xpath( - '//div[@id="modal"]//input[@type="submit"]').click() + # Confirm item has been saved to json field + objectitems = self.driver.execute_script("return objectitems;") + self.assertEqual(1, len(objectitems)) + testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID + self.assertEqual("Test Item 1", testitem['name']) + self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields - # See it is selected - wait.until(animation_is_finished()) - self.assertFalse(modal.is_displayed()) - obj = models.Organisation.objects.get(name="Test Organisation") - self.assertEqual(obj.name, form.find_element_by_xpath( - '//button[@data-id="id_organisation"]/span').text) - # and backend - option = form.find_element_by_xpath( - '//select[@id="id_organisation"]//option[@selected="selected"]') - self.assertEqual(obj.pk, int(option.get_attribute("value"))) + total = self.driver.find_element_by_id('total') + ActionChains(self.driver).move_to_element(total).perform() - # Create venue - wait.until(animation_is_finished()) - add_button = self.browser.find_element_by_xpath( - '//a[@data-target="#id_venue" and contains(@href, "add")]') - wait.until(animation_is_finished()) - add_button.click() - wait.until(animation_is_finished()) - modal = self.browser.find_element_by_id('modal') - wait.until(animation_is_finished()) - self.assertTrue(modal.is_displayed()) - self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text) - modal.find_element_by_xpath( - '//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue") - modal.find_element_by_xpath( - '//div[@id="modal"]//input[@type="submit"]').click() + # See new item appear in table + row = self.page.item_row("-1") # ID number is known, see above + # Scroll into view + self.assertIn("Test Item 1", row.name) + self.assertIn("This is an item description", + row.description) + self.assertEqual('23.95', row.price) + self.assertEqual("2", row.quantity) + self.assertEqual('47.90', row.subtotal) - # See it is selected - wait.until(animation_is_finished()) - self.assertFalse(modal.is_displayed()) - obj = models.Venue.objects.get(name="Test Venue") - self.assertEqual(obj.name, form.find_element_by_xpath( - '//button[@data-id="id_venue"]/span').text) - # and backend - option = form.find_element_by_xpath( - '//select[@id="id_venue"]//option[@selected="selected"]') - self.assertEqual(obj.pk, int(option.get_attribute("value"))) + # Check totals TODO convert to page properties + self.assertEqual("47.90", self.driver.find_element_by_id('sumtotal').text) + self.assertIn("(TBC)", self.driver.find_element_by_id('vat-rate').text) + self.assertEqual("9.58", self.driver.find_element_by_id('vat').text) + self.assertEqual("57.48", total.text) + + self.page.submit() # TODO Testing of internal rig (approval system interface) @@ -249,7 +219,23 @@ class TestEventCreate(AutoLoginTest): self.wait.until(animation_is_finished()) self.assertTrue(self.page.is_expanded) - # self.assertFalse(self.page.person_selector.is_displayed()) + self.assertFalse(self.page.person_selector.is_open) + + rig_name = "Test Non-Rig" + self.page.name = rig_name + + # Double-check we don't lose data when swapping + self.page.select_event_type("Rig") + self.wait.until(animation_is_finished()) + self.assertEquals(self.page.name, rig_name) + self.wait.until(animation_is_finished()) + self.page.select_event_type("Non-Rig") + + self.page.start_date = datetime.date(2020, 1, 1) + self.page.status = "Confirmed" + + self.page.submit() + self.assertTrue(self.page.success) def test_subhire_creation(self): pass