From 9ce725ed2fc7ff8a27e537872377d079027bcc42 Mon Sep 17 00:00:00 2001 From: emil farisan Date: Tue, 15 Oct 2019 00:15:24 +0700 Subject: [PATCH 1/3] Moved Fts into their own individual files --- functional_tests/base.py | 29 +++++ functional_tests/test_layout_and_styling.py | 30 +++++ functional_tests/test_list_item_validation.py | 23 ++++ ...{tests.py => test_simple_list_creation.py} | 104 ++++++++++-------- 4 files changed, 138 insertions(+), 48 deletions(-) create mode 100644 functional_tests/base.py create mode 100644 functional_tests/test_layout_and_styling.py create mode 100644 functional_tests/test_list_item_validation.py rename functional_tests/{tests.py => test_simple_list_creation.py} (54%) diff --git a/functional_tests/base.py b/functional_tests/base.py new file mode 100644 index 0000000..5c49983 --- /dev/null +++ b/functional_tests/base.py @@ -0,0 +1,29 @@ +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from selenium import webdriver +from selenium.common.exceptions import WebDriverException +import time + +MAX_WAIT = 10 + + +class FunctionalTest(StaticLiveServerTestCase): + + def setUp(self): + self.browser = webdriver.Firefox() + self.browser.implicitly_wait(3) + + def tearDown(self): + self.browser.quit() + + def wait_for_row_in_list_table(self, row_text): + start_time = time.time() + while True: + try: + table = self.browser.find_element_by_id('id_nothing') + rows = table.find_elements_by_tag_name('tr') + self.assertIn(row_text, [row.text for row in rows]) + return + except (AssertionError, WebDriverException) as e: + if time.time() - start_time > MAX_WAIT: + raise e + time.sleep(0.5) diff --git a/functional_tests/test_layout_and_styling.py b/functional_tests/test_layout_and_styling.py new file mode 100644 index 0000000..1a5ea5e --- /dev/null +++ b/functional_tests/test_layout_and_styling.py @@ -0,0 +1,30 @@ +from selenium.webdriver.common.keys import Keys +from .base import FunctionalTest + + +class LayoutAndStylingTest(FunctionalTest): + + def test_layout_and_styling(self): + # Edith goes to the home page + self.browser.get(self.live_server_url) + self.browser.set_window_size(1024, 768) + + # She notices the input box is nicely centered + inputbox = self.browser.find_element_by_id('id_new_item') + self.assertAlmostEqual( + inputbox.location['x'] + inputbox.size['width'] / 2, + 512, + delta=10 + ) + + # She starts a new list and sees the input is nicely + # centered there too + inputbox.send_keys('testing') + inputbox.send_keys(Keys.ENTER) + self.wait_for_row_in_list_table('1: testing') + inputbox = self.browser.find_element_by_id('id_new_item') + self.assertAlmostEqual( + inputbox.location['x'] + inputbox.size['width'] / 2, + 512, + delta=10 + ) diff --git a/functional_tests/test_list_item_validation.py b/functional_tests/test_list_item_validation.py new file mode 100644 index 0000000..9faa6ef --- /dev/null +++ b/functional_tests/test_list_item_validation.py @@ -0,0 +1,23 @@ +from selenium.webdriver.common.keys import Keys +from unittest import skip +from .base import FunctionalTest + + +class ItemValidationTest(FunctionalTest): + + @skip + def test_cannot_add_empty_list_items(self): + # Edith goes to the home page and accidentally tries to submit + # an empty list item. She hits Enter on the empty input box + + # The home page refreshes, and there is an error message saying + # that list items cannot be blank + + # She tries again with some text for the item, which now works + + # Perversely, she now decides to submit a second blank list item + + # She receives a similar warning on the list page + + # And she can correct it by filling some text in + self.fail('write me!') diff --git a/functional_tests/tests.py b/functional_tests/test_simple_list_creation.py similarity index 54% rename from functional_tests/tests.py rename to functional_tests/test_simple_list_creation.py index 1c2f3fa..f92c865 100644 --- a/functional_tests/tests.py +++ b/functional_tests/test_simple_list_creation.py @@ -1,57 +1,10 @@ from django.contrib.staticfiles.testing import StaticLiveServerTestCase from selenium import webdriver -from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.keys import Keys -import time - -MAX_WAIT = 10 +from selenium.webdriver.chrome.options import Options class NewVisitorTest(StaticLiveServerTestCase): - def setUp(self): - self.browser = webdriver.Firefox() - self.browser.implicitly_wait(3) - - def tearDown(self): - self.browser.quit() - - def wait_for_row_in_list_table(self, row_text): - start_time = time.time() - while True: - try: - table = self.browser.find_element_by_id('id_nothing') - rows = table.find_elements_by_tag_name('tr') - self.assertIn(row_text, [row.text for row in rows]) - return - except (AssertionError, WebDriverException) as e: - if time.time() - start_time > MAX_WAIT: - raise e - time.sleep(0.5) - - def test_layout_and_styling(self): - # Edith goes to the home page - self.browser.get(self.live_server_url) - self.browser.set_window_size(1024, 768) - - # She notices the input box is nicely centered - inputbox = self.browser.find_element_by_id('id_new_item') - self.assertAlmostEqual( - inputbox.location['x'] + inputbox.size['width'] / 2, - 512, - delta=10 - ) - - # She starts a new list and sees the input is nicely - # centered there too - inputbox.send_keys('testing') - inputbox.send_keys(Keys.ENTER) - self.wait_for_row_in_list_table('1: testing') - inputbox = self.browser.find_element_by_id('id_new_item') - self.assertAlmostEqual( - inputbox.location['x'] + inputbox.size['width'] / 2, - 512, - delta=10 - ) def test_can_start_a_list_and_retrieve_it_later(self): # Edith has heard about a cool new online to-do app. She goes @@ -98,3 +51,58 @@ class NewVisitorTest(StaticLiveServerTestCase): # She visits that URL - her to-do list is still there. # Satisfied, she goes back to sleep + + def test_multiple_users_can_start_lists_at_different_urls(self): + # Edith starts a new to-do list + self.browser.get(self.live_server_url) + inputbox = self.browser.find_element_by_id('id_new_item') + inputbox.send_keys('Buy peacock feathers') + inputbox.send_keys(Keys.ENTER) + self.wait_for_row_in_list_table('1: Buy peacock feathers') + + # She notices that her list has a unique URL + edith_list_url = self.browser.current_url + self.assertRegex(edith_list_url, '/lists/.+') + + # Now a new user, Francis, comes along to the site. + + # We use a new browser session to make sure that no information + # of Edith's is coming through from cookies etc + self.browser.quit() + + # For local need + # self.browser = webdriver.Firefox() + + # For deployed need + options = Options() + options.add_argument('--dns-prefetch-disable') + options.add_argument('--no-sandbox') + options.add_argument('--headless') + options.add_argument('disable-gpu') + self.browser = webdriver.Chrome(executable_path="./chromedriver", options=options) + + # Francis visits the home page. There is no sign of Edith's + # list + self.browser.get(self.live_server_url) + page_text = self.browser.find_element_by_tag_name('body').text + self.assertNotIn('Buy peacock feathers', page_text) + self.assertNotIn('make a fly', page_text) + + # Francis starts a new list by entering a new item. He + # is less interesting than Edith... + inputbox = self.browser.find_element_by_id('id_new_item') + inputbox.send_keys('Buy milk') + inputbox.send_keys(Keys.ENTER) + self.wait_for_row_in_list_table('1: Buy milk') + + # Francis gets his own unique URL + francis_list_url = self.browser.current_url + self.assertRegex(francis_list_url, '/lists/.+') + self.assertNotEqual(francis_list_url, edith_list_url) + + # Again, there is no trace of Edith's list + page_text = self.browser.find_element_by_tag_name('body').text + self.assertNotIn('Buy peacock feathers', page_text) + self.assertIn('Buy milk', page_text) + + # Satisfied, they both go back to sleep -- GitLab From a7d5ce485bacc55eed7d8414ec940e9a79699ad9 Mon Sep 17 00:00:00 2001 From: emil farisan Date: Tue, 15 Oct 2019 00:38:37 +0700 Subject: [PATCH 2/3] Move unit tests into a folder with single file --- lists/tests/__init__.py | 0 lists/{tests.py => tests/test_all.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lists/tests/__init__.py rename lists/{tests.py => tests/test_all.py} (100%) diff --git a/lists/tests/__init__.py b/lists/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lists/tests.py b/lists/tests/test_all.py similarity index 100% rename from lists/tests.py rename to lists/tests/test_all.py -- GitLab From 4a734003bca4daabfe966ad7ff40a6fcca25fdbb Mon Sep 17 00:00:00 2001 From: emil farisan Date: Tue, 15 Oct 2019 00:53:27 +0700 Subject: [PATCH 3/3] Split out unit tests into two files --- functional_tests/base.py | 10 +++++ functional_tests/test_list_item_validation.py | 20 ++++++++- lists/tests/{test_all.py => test_models.py} | 2 +- lists/tests/test_views.py | 41 +++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) rename lists/tests/{test_all.py => test_models.py} (98%) create mode 100644 lists/tests/test_views.py diff --git a/functional_tests/base.py b/functional_tests/base.py index 5c49983..5cd878a 100644 --- a/functional_tests/base.py +++ b/functional_tests/base.py @@ -27,3 +27,13 @@ class FunctionalTest(StaticLiveServerTestCase): if time.time() - start_time > MAX_WAIT: raise e time.sleep(0.5) + + def wait_for(self, fn): + start_time = time.time() + while True: + try: + return fn() + except (AssertionError, WebDriverException) as e: + if time.time() - start_time > MAX_WAIT: + raise e + time.sleep(0.5) diff --git a/functional_tests/test_list_item_validation.py b/functional_tests/test_list_item_validation.py index 9faa6ef..44ffb4f 100644 --- a/functional_tests/test_list_item_validation.py +++ b/functional_tests/test_list_item_validation.py @@ -5,19 +5,35 @@ from .base import FunctionalTest class ItemValidationTest(FunctionalTest): - @skip def test_cannot_add_empty_list_items(self): # Edith goes to the home page and accidentally tries to submit # an empty list item. She hits Enter on the empty input box + self.browser.get(self.live_server_url) + self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER) # The home page refreshes, and there is an error message saying # that list items cannot be blank + self.wait_for(lambda: self.assertEqual( + self.browser.find_element_by_css_selector('.has-error').text, + "You can't have an empty list item" + )) # She tries again with some text for the item, which now works + self.browser.find_element_by_id('id_new_item').send_keys('Buy milk') + self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER) + self.wait_for_row_in_list_table('1: Buy milk') # Perversely, she now decides to submit a second blank list item + self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER) # She receives a similar warning on the list page + self.wait_for(lambda: self.assertEqual( + self.browser.find_element_by_css_selector('.has-error').text, + "You can't have an empty list item" + )) # And she can correct it by filling some text in - self.fail('write me!') + self.browser.find_element_by_id('id_new_item').send_keys('Make tea') + self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER) + self.wait_for_row_in_list_table('1: Buy milk') + self.wait_for_row_in_list_table('2: Make tea') diff --git a/lists/tests/test_all.py b/lists/tests/test_models.py similarity index 98% rename from lists/tests/test_all.py rename to lists/tests/test_models.py index fbdcc9b..72a264e 100644 --- a/lists/tests/test_all.py +++ b/lists/tests/test_models.py @@ -1,5 +1,5 @@ from django.test import TestCase -from lists.models import Item +from lists.models import Item, List class HomePageTest(TestCase): diff --git a/lists/tests/test_views.py b/lists/tests/test_views.py new file mode 100644 index 0000000..8027c72 --- /dev/null +++ b/lists/tests/test_views.py @@ -0,0 +1,41 @@ +from django.test import TestCase +from lists.models import Item + + +class HomePageTest(TestCase): + def test_uses_home_template(self): + response = self.client.get('/') + self.assertTemplateUsed(response, 'home.html') + + def test_can_save_a_POST_request(self): + self.client.post('/', data={'item_text': 'A new list item'}) + + self.assertEqual(Item.objects.count(), 1) + new_item = Item.objects.first() + self.assertEqual(new_item.text, 'A new list item') + + def test_redirects_after_POST(self): + response = self.client.post('/', data={'item_text': 'A new list item'}) + self.assertEqual(response.status_code, 302) + self.assertEqual(response['location'], '/') + + def test_home_page_returns_correct_html(self): + response = self.client.get('/') + html = response.content.decode('utf8') + self.assertTrue(html.startswith('')) + self.assertIn('To-Do lists', html) + self.assertTrue(html.strip().endswith('')) + self.assertTemplateUsed(response, 'home.html') + + def test_only_saves_items_when_necessary(self): + self.client.get('/') + self.assertEqual(Item.objects.count(), 0) + + def test_displays_all_list_items(self): + Item.objects.create(text='itemey 1') + Item.objects.create(text='itemey 2') + + response = self.client.get('/') + + self.assertIn('itemey 1', response.content.decode()) + self.assertIn('itemey 2', response.content.decode()) -- GitLab