[tests] refactored live server tests to prevent race conditions

django-5.0
Thomas Leichtfuß 2020-09-13 16:27:42 +02:00
parent 868c54212f
commit b8bf183ba9
1 changed files with 134 additions and 86 deletions

View File

@ -1,4 +1,5 @@
import time
from django.contrib.auth.models import User
from django.urls import reverse
@ -10,17 +11,87 @@ from selenium.webdriver.support.ui import Select
from ..management.commands.createtestdata import create_test_data
class FilterPage:
WAIT_FOR_RELOAD = 1
URL_PATH = reverse('admin:testapp_modela_changelist')
# ul-indexes
MULTISELECT_UL = 3
MULTISELECT_RELATED_UL = 7
def __init__(self, selenium, base_url):
self.base_url = base_url
self.url = base_url + self.URL_PATH
self.selenium = selenium
self.current_url = self.selenium.current_url
def login(self, client):
# login to selenium - using a cookie from the django test client
admin = User.objects.get(username='admin')
client.force_login(admin)
cookie = client.cookies['sessionid']
#selenium will set cookie domain based on current page domain
self.selenium.get(self.base_url + '/admin/')
self.selenium.add_cookie({'name': 'sessionid', 'value': cookie.value, 'secure': False, 'path': '/'})
#need to update page for logged in user
self.selenium.refresh()
def get(self, url_query=str()):
return self.selenium.get(self.url + '?' + url_query)
def wait_for_reload(self):
now = time.time()
while self.current_url == self.selenium.current_url:
self.selenium.refresh()
if time.time() - now < self.WAIT_FOR_RELOAD:
msg = "Could not reload live server page. Waited {} sec."
raise RuntimeError(msg.format(self.WAIT_FOR_RELOAD))
else:
self.current_url = self.selenium.current_url
return True
@property
def item_count(self):
return len(self.selenium.find_elements_by_xpath('//*[@id="result_list"]/tbody/tr'))
@property
def url_query(self):
return self.selenium.current_url.split('?')[-1].replace('%2C', ',')
def get_selected_li_count(self, ul):
return len(ul.find_elements_by_css_selector('li.selected'))
def use_dropdown_filter(self, select_id, option):
select = Select(self.selenium.find_element_by_id(select_id))
select.select_by_visible_text(option)
self.wait_for_reload()
return Select(self.selenium.find_element_by_id(select_id))
def use_multiselect_filter(self, ul_num, title):
ul_xpath = '//*[@id="changelist-filter"]/ul[{}]'.format(ul_num)
a_css = 'li a[title="{}"]'.format(title)
ul = self.selenium.find_element_by_xpath(ul_xpath)
ul.find_element_by_css_selector(a_css).click()
self.wait_for_reload()
return self.selenium.find_element_by_xpath(ul_xpath)
def use_multiselect_dropdown_filter(self, field, options):
select = Select(self.selenium.find_element_by_id(field + '_select'))
for value in options:
select.select_by_value(value)
self.selenium.find_element_by_id(field + '_submit').click()
self.wait_for_reload()
return Select(self.selenium.find_element_by_id(field + '_select'))
class LiveFilterTest(StaticLiveServerTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
options = Options()
options.headless = True
cls.selenium = WebDriver(options=options)
cls.selenium.implicitly_wait(10)
cls.url_path = reverse('admin:testapp_modela_changelist')
create_test_data()
@classmethod
def tearDownClass(cls):
@ -28,105 +99,82 @@ class LiveFilterTest(StaticLiveServerTestCase):
super().tearDownClass()
def setUp(self):
# login to selenium - using a cookie from the django test client
admin = User.objects.get(username='admin')
self.client.force_login(admin)
cookie = self.client.cookies['sessionid']
self.selenium.get(self.live_server_url + '/admin/') #selenium will set cookie domain based on current page domain
self.selenium.add_cookie({'name': 'sessionid', 'value': cookie.value, 'secure': False, 'path': '/'})
self.selenium.refresh() #need to update page for logged in user
create_test_data()
self.page = FilterPage(self.selenium, self.live_server_url)
self.page.login(self.client)
def get_item_count(self):
return len(self.selenium.find_elements_by_xpath('//*[@id="result_list"]/tbody/tr'))
def get_url_query(self):
return self.selenium.current_url.split('?')[-1].replace('%2C', ',')
def get_selected_list_items(self, ul_num):
xpath = '//*[@id="changelist-filter"]/ul[{}]/li[@class="selected"]'.format(ul_num)
return self.selenium.find_elements_by_xpath(xpath)
def use_dropdown_filter(self, select_id, option, url_query, item_count):
select = Select(self.selenium.find_element_by_id(select_id))
select.select_by_visible_text(option)
self.selenium.refresh()
select = Select(self.selenium.find_element_by_id(select_id))
self.assertEqual(self.get_item_count(), item_count)
self.assertEqual(self.get_url_query(), url_query)
def check_dropdown_filter(self, select_id, query_key, query_value, option, count):
select = self.page.use_dropdown_filter(select_id, option)
self.assertEqual(self.page.item_count, count)
self.assertEqual(select.first_selected_option.text, option)
if option == 'All':
self.assertNotIn(query_key, self.page.url_query)
else:
self.assertIn(query_key + query_value, self.page.url_query)
def use_multiselect_link(self, ul_num, title, item_count, selected_count, url_query):
link = '//*[@id="changelist-filter"]/ul[{}]/li/a[@title="{}"]'.format(ul_num, title)
self.selenium.find_element_by_xpath(link).click()
self.selenium.refresh()
self.assertIn(url_query, self.get_url_query())
self.assertEqual(self.get_item_count(), item_count)
self.assertEqual(len(self.get_selected_list_items(ul_num)), selected_count)
def test_01_dropdown_filter(self):
self.page.get()
def use_multiselect_dropdown_filter(self, field, options, url_param, count):
select = Select(self.selenium.find_element_by_id(field + '_select'))
for value in options:
select.select_by_value(value)
self.selenium.find_element_by_id(field + '_submit').click()
self.selenium.refresh()
select = Select(self.selenium.find_element_by_id(field + '_select'))
self.assertIn(url_param + '=' + ','.join(options), self.get_url_query())
self.assertEqual(len(select.all_selected_options), len(options))
self.assertEqual(self.get_item_count(), count)
select.deselect_all()
# check simple dropdown filter
select_id, query_key = 'dropdown-gt3_filter_select', 'dropdown_gt3='
self.check_dropdown_filter(select_id, query_key, '2', '2', 9)
self.check_dropdown_filter(select_id, query_key, '', 'All', 36)
def test_01_check_filter(self):
self.selenium.get(self.live_server_url + self.url_path)
# Check choices dropdown filter:
select_id, query_key = 'choices-dropdown_filter_select', 'choices_dropdown__exact='
self.check_dropdown_filter(select_id, query_key, '3', 'three', 4)
self.check_dropdown_filter(select_id, query_key, '', 'All', 36)
# Check the simple dropdown filter:
select_id = 'dropdown-gt3_filter_select'
url_query = 'dropdown_gt3=2'
self.use_dropdown_filter(select_id, '2', url_query, 9)
self.use_dropdown_filter(select_id, 'All', '', 36)
# Check related dropdown filter:
select_id, query_key = 'related-dropdown_filter_select', 'related_dropdown__id__exact='
self.check_dropdown_filter(select_id, query_key, '9', 'ModelB 9', 1)
self.check_dropdown_filter(select_id, query_key, '', 'All', 36)
# Check the choices dropdown filter:
select_id = 'choices-dropdown_filter_select'
url_query = 'choices_dropdown__exact=3'
self.use_dropdown_filter(select_id, 'three', url_query, 4)
self.use_dropdown_filter(select_id, 'All', '', 36)
def check_multiselect_filter(self, ul_num, query_key, query_value, option, count, selected):
ul = self.page.use_multiselect_filter(ul_num, option)
self.assertEqual(self.page.item_count, count)
self.assertEqual(self.page.get_selected_li_count(ul), selected)
if option == 'All':
self.assertNotIn(query_key, self.page.url_query)
else:
self.assertIn(query_key + query_value, self.page.url_query)
# # Check the related dropdown filter:
select_id = 'related-dropdown_filter_select'
url_query = 'related_dropdown__id__exact=9'
self.use_dropdown_filter(select_id, 'ModelB 9', url_query, 1)
self.use_dropdown_filter(select_id, 'All', '', 36)
def test_02_multiselect_filter(self):
# start with an already filtered changelist
self.page.get('dropdown_gt3=2')
# Start tests with activated dropdown_gt3 filter
self.selenium.get(self.live_server_url + self.url_path + '?dropdown_gt3=2')
# Check the simple multiselect filter
self.use_multiselect_link(3, '4', 2, 1, 'multiselect__in=4')
self.use_multiselect_link(3, '3', 3, 2, 'multiselect__in=4,3')
self.use_multiselect_link(3, '2', 5, 3, 'multiselect__in=4,3,2')
self.use_multiselect_link(3, '3', 4, 2, 'multiselect__in=4,2')
self.use_multiselect_link(3, 'All', 9, 1, '')
self.assertNotIn('multiselect__in', self.get_url_query())
# check simple multiselect filter
ul_num, query_key = self.page.MULTISELECT_UL, 'multiselect__in='
self.check_multiselect_filter(ul_num, query_key, '4', '4', 2, 1)
self.check_multiselect_filter(ul_num, query_key, '4,3', '3', 3, 2)
self.check_multiselect_filter(ul_num, query_key, '4,3,2', '2', 5, 3)
self.check_multiselect_filter(ul_num, query_key, '', 'All', 9, 1)
# check the multiselect related filter
self.use_multiselect_link(7, 'ModelB 34', 1, 1, 'multiselect_related__id__in=34')
self.use_multiselect_link(7, 'ModelB 30', 2, 2, 'multiselect_related__id__in=34,30')
self.use_multiselect_link(7, 'ModelB 26', 3, 3, 'multiselect_related__id__in=34,30,26')
self.use_multiselect_link(7, 'ModelB 34', 2, 2, 'multiselect_related__id__in=30,26')
self.use_multiselect_link(7, 'All', 9, 1, '')
self.assertNotIn('multiselect_related__id__in', self.get_url_query())
ul_num, query_key = self.page.MULTISELECT_RELATED_UL, 'multiselect_related__id__in='
self.check_multiselect_filter(ul_num, query_key, '34', 'ModelB 34', 1, 1)
self.check_multiselect_filter(ul_num, query_key, '34,30', 'ModelB 30', 2, 2)
self.check_multiselect_filter(ul_num, query_key, '34,30,26', 'ModelB 26', 3, 3)
self.check_multiselect_filter(ul_num, query_key, '30,26', 'ModelB 34', 2, 2)
self.check_multiselect_filter(ul_num, query_key, '', 'All', 9, 1)
# Start tests without any filter.
self.selenium.get(self.live_server_url + self.url_path)
def check_multiselect_dropdown_filter(self, field, options, query_key, count):
select = self.page.use_multiselect_dropdown_filter(field, options)
self.assertEqual(len(select.all_selected_options), len(options))
self.assertEqual(self.page.item_count, count)
self.assertIn(query_key + ','.join(options), self.page.url_query)
select.deselect_all()
def test_03_multiselect_dropdown_filter(self):
self.page.get()
# check multiselect-dropdown
field = 'multiselect-dropdown'
url_param = 'multiselect_dropdown__in'
field, query_key = 'multiselect-dropdown', 'multiselect_dropdown__in='
options = [str(i) for i in range(2, 5)]
self.use_multiselect_dropdown_filter(field, options, url_param, 18)
self.check_multiselect_dropdown_filter(field, options, query_key, 18)
# check multiselect-related-dropdown
# (multiselect-dropdown filter is still effectual)
field = 'multiselect-related-dropdown'
url_param = 'multiselect_related_dropdown__id__in'
field, query_key = 'multiselect-related-dropdown', 'multiselect_related_dropdown__id__in='
options = [str(i) for i in range(1, 9)]
self.use_multiselect_dropdown_filter(field, options, url_param, 4)
self.check_multiselect_dropdown_filter(field, options, query_key, 4)