Initial refactor of event item testing

This commit is contained in:
2020-05-21 22:48:46 +01:00
parent 919975e1ba
commit 813db2c474
5 changed files with 121 additions and 211 deletions

View File

@@ -217,3 +217,15 @@ class Modal(Region):
form_element.set_value(value) form_element.set_value(value)
else: else:
self.__dict__[name] = value 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'))
}

View File

@@ -4,8 +4,10 @@ from selenium.webdriver.support import expected_conditions
from selenium.webdriver import Chrome from selenium.webdriver import Chrome
from django.urls import reverse from django.urls import reverse
from PyRIGS.tests import regions from PyRIGS.tests import regions
from RIGS.tests import regions as rigs_regions
from PyRIGS.tests.pages import BasePage, FormPage from PyRIGS.tests.pages import BasePage, FormPage
from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
class Index(BasePage): class Index(BasePage):
URL_TEMPLATE = reverse('index') 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') _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_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 = { form_items = {
'description': (regions.TextBox, (By.ID, 'id_description')), 'description': (regions.TextBox, (By.ID, 'id_description')),
@@ -81,6 +84,9 @@ class CreateEvent(FormPage):
def select_event_type(self, type_name): def select_event_type(self, type_name):
self.find_element(By.XPATH, '//button[.="' + type_name + '"]').click() 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 @property
def is_expanded(self): def is_expanded(self):
return self.find_element(*self._bottom_save_selector).is_displayed() 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() self.find_element(*self._add_person_selector).click()
return regions.Modal(self, self.driver.find_element_by_id('modal')) 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 @property
def success(self): def success(self):
return '/create' not in self.driver.current_url return '/create' not in self.driver.current_url

View File

@@ -10,3 +10,31 @@ import datetime
class Header(Region): class Header(Region):
def find_link(self, link_text): def find_link(self, link_text):
return self.driver.find_element_by_partial_link_text(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

View File

@@ -64,92 +64,6 @@ class EventTest(LiveServerTestCase):
self.assertEqual(self.live_server_url + n, self.browser.current_url) 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): def testEventDuplicate(self):
client = models.Person.objects.create(name='Duplicate Test Person', email='duplicate@functional.test') 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, 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) 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): def testEventDetail(self):
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
person = models.Person(name="Event Detail Person", email="eventdetail@person.tests.rigs", phone="123 123") person = models.Person(name="Event Detail Person", email="eventdetail@person.tests.rigs", phone="123 123")

View File

@@ -17,7 +17,7 @@ from RIGS.tests import regions
import datetime import datetime
from datetime import date, time, timedelta from datetime import date, time, timedelta
from django.utils import timezone from django.utils import timezone
from selenium.webdriver.support.select import Select from selenium.webdriver.common.action_chains import ActionChains
class TestRigboard(AutoLoginTest): class TestRigboard(AutoLoginTest):
def setUp(self): def setUp(self):
@@ -148,97 +148,67 @@ class TestEventCreate(AutoLoginTest):
self.wait.until(EC.invisibility_of_element_located((By.ID, 'modal'))) self.wait.until(EC.invisibility_of_element_located((By.ID, 'modal')))
self.assertFalse(modal.is_open) self.assertFalse(modal.is_open)
person2 = models.Person.objects.get(name=person_name) # TODO
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")))
# Was right the first time, change it back def test_event_item_creation(self):
self.page.person_selector.search(person1.name) self.wait.until(animation_is_finished())
# TODO Check multiple cannot be selected? Is that necessary? self.assertFalse(self.page.is_expanded)
self.page.person_selector.set_option(person1.name, True) 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.page.name = "Test Event with Items"
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")))
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 self.page.start_date = datetime.date(1984, 1, 1)
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)
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()) modal.name = "Test Item 1"
person1 = models.Person.objects.get(pk=person1.pk) modal.description = "This is an item description\nthat for reasons unknown spans two lines"
self.assertEqual(person1.name, form.find_element_by_xpath( modal.quantity = "2"
'//button[@data-id="id_person"]/span').text) modal.price = "23.95"
modal.submit()
self.wait.until(animation_is_finished())
# Create organisation # Confirm item has been saved to json field
wait.until(animation_is_finished()) objectitems = self.driver.execute_script("return objectitems;")
add_button = self.browser.find_element_by_xpath( self.assertEqual(1, len(objectitems))
'//a[@data-target="#id_organisation" and contains(@href, "add")]') testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
add_button.click() self.assertEqual("Test Item 1", testitem['name'])
modal = self.browser.find_element_by_id('modal') self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
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()
# See it is selected total = self.driver.find_element_by_id('total')
wait.until(animation_is_finished()) ActionChains(self.driver).move_to_element(total).perform()
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")))
# Create venue # See new item appear in table
wait.until(animation_is_finished()) row = self.page.item_row("-1") # ID number is known, see above
add_button = self.browser.find_element_by_xpath( # Scroll into view
'//a[@data-target="#id_venue" and contains(@href, "add")]') self.assertIn("Test Item 1", row.name)
wait.until(animation_is_finished()) self.assertIn("This is an item description",
add_button.click() row.description)
wait.until(animation_is_finished()) self.assertEqual('23.95', row.price)
modal = self.browser.find_element_by_id('modal') self.assertEqual("2", row.quantity)
wait.until(animation_is_finished()) self.assertEqual('47.90', row.subtotal)
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 it is selected # Check totals TODO convert to page properties
wait.until(animation_is_finished()) self.assertEqual("47.90", self.driver.find_element_by_id('sumtotal').text)
self.assertFalse(modal.is_displayed()) self.assertIn("(TBC)", self.driver.find_element_by_id('vat-rate').text)
obj = models.Venue.objects.get(name="Test Venue") self.assertEqual("9.58", self.driver.find_element_by_id('vat').text)
self.assertEqual(obj.name, form.find_element_by_xpath( self.assertEqual("57.48", total.text)
'//button[@data-id="id_venue"]/span').text)
# and backend self.page.submit()
option = form.find_element_by_xpath(
'//select[@id="id_venue"]//option[@selected="selected"]')
self.assertEqual(obj.pk, int(option.get_attribute("value")))
# TODO Testing of internal rig (approval system interface) # TODO Testing of internal rig (approval system interface)
@@ -249,7 +219,23 @@ class TestEventCreate(AutoLoginTest):
self.wait.until(animation_is_finished()) self.wait.until(animation_is_finished())
self.assertTrue(self.page.is_expanded) 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): def test_subhire_creation(self):
pass pass