diff --git a/aut_docs/Design_Document.md b/aut_docs/Design_Document.md index 219089e..515387c 100644 --- a/aut_docs/Design_Document.md +++ b/aut_docs/Design_Document.md @@ -47,3 +47,34 @@ The QA process is divided as follows: - To follow up changes in UI with changes in tests, the modifications need to be made only in the relevant locators/urls/page file. + +- Addition of any new view implies that a pom `page` and `locator` need to be created. + +- Similarly, modifying any view implies that the corresponding `page` and `locator` will + also need to be modified. + +## Important points regarding creation of new Test Class: + +- As mentioned earlier, each test class corresponds to a view which has a corresponding + pom page and locator. + +- When creating a new test class, first identify the view the class is being created for, + and create corresponding pom page and locator. + +- Similarly, if you are modifying the existing templates make sure you update the corresponding + pom page and locators. + +- Each Test Class has `setUpClass` and `tearDownClass` class methods which should initiate and + quit the WebDriver objects respectively. + +- POM page should be linked to the Test Class in the `setUpClass` method itself and WebDriverWait + if needed in the tests should also be initiated in this method only. + +- If in the tests you are logging in as admin or volunteer make sure to `logout` in the `tearDown` + method of the Test Class. + +- Use of implicit waits should always be avoided unless needed in an extreme case and has the + approval of a maintainer. If wait is needed use explicit waits instead. + +- Tests in normal mode might fail if all are executed at once, but if a test is fails in + `HEADLESS` mode then the test is wrong and should be corrected accordingly. diff --git a/aut_docs/Documented_Failures.md b/aut_docs/Documented_Failures.md new file mode 100644 index 0000000..e728861 --- /dev/null +++ b/aut_docs/Documented_Failures.md @@ -0,0 +1,18 @@ +There are a few tests which have been commented out currently to avoid Travis CI build failure: + +| File | App/Model | Test name | Reason/Related issue | +|:----------------------------:|:-----------------:|:-------------------------------------------------------------------:|:-------------------------------------------------:| +| test_settings.py | Administrator | test_duplicate_event | Logic not yet implemented | +| test_settings.py | Administrator | test_duplicate_job | Logic not yet implemented | +| test_formFields.py | Administrator | test_field_value_retention_for_event | [#742](https://github.com/systers/vms/issues/742) | +| test_formFields.py | Administrator | test_field_value_retention_for_job | [#742](https://github.com/systers/vms/issues/742) | +| test_formFields.py | Administrator | test_field_value_retention_for_shift | [#742](https://github.com/systers/vms/issues/742) | +| test_report.py | Administrator | test_check_intersection_of_fields | Test is giving inconsistent results, probably issue in logic| +| test_volunteerProfile.py | Volunteer | test_valid_upload_resume | [#776](https://github.com/systers/vms/issues/776)| +| test_volunteerProfile.py | Volunteer | test_corrupt_resume_uploaded | [#776](https://github.com/systers/vms/issues/776)| +| test_functional_admin.py | Registration | test_field_value_retention_in_first_name_state_phone_organization | [#763](https://github.com/systers/vms/issues/763)| +| test_functional_admin.py | Registration | test_field_value_retention_in_last_name_address_city_country | [#763](https://github.com/systers/vms/issues/763)| +| test_functional_volunteer.py | Registration | test_field_value_retention_in_first_name_state_phone_organization | [#763](https://github.com/systers/vms/issues/763)| +| test_functional_volunteer.py | Registration | test_field_value_retention_in_last_name_address_city_country | [#763](https://github.com/systers/vms/issues/763)| +| test_unit.py | Shift | test_invalid_model_create | [#743](https://github.com/systers/vms/issues/743)| +| test_unit.py | VolunteerShift | test_invalid_model_create | [#743](https://github.com/systers/vms/issues/743)| diff --git a/aut_docs/Documented_failures.md b/aut_docs/Documented_failures.md deleted file mode 100644 index 0149c98..0000000 --- a/aut_docs/Documented_failures.md +++ /dev/null @@ -1,15 +0,0 @@ -There are several tests/parts of tests which have been commented out currently to avoid travis build failure: - -|File |Tests |Reason/Related issue | -|------------------------------|:------------------:|:------------------------: | -| test_formFields.py | test_null_values_in_edit_event| [345](https://github.com/systers/vms/issues/345)| -| test_formFields.py | test_field_value_retention_for_event, test_field_value_retention_for_job, test_field_value_retention_for_shift| [#350](https://github.com/systers/vms/issues/350)| -| test_formFields.py | test_simplify_job|Cause of failure is still unclear| -| test_report.py | test_null_values_with_dataset, test_check_intersection_of_fields| [#327](https://github.com/systers/vms/issues/327)| -| test_settings.py | test_duplicate_event, test_duplicate_job|[#329](https://github.com/systers/vms/issues/329), [#330](https://github.com/systers/vms/issues/330)| -| test_shiftSignUp.py | test_search_event| [#337](https://github.com/systers/vms/issues/337)| -| test_functional.py | test_admin_cannot_access_volunteer_urls, test_volunteer_cannot_access_admin_urls| [#325](https://github.com/systers/vms/issues/325)| -| test_functional_volunteer.py | test_location_fields|[#336](https://github.com/systers/vms/issues/336)| -| test_viewVolunteerShift.py | test_access_another_existing_volunteer_view| [#326](https://github.com/systers/vms/issues/326)| -| test_volunteerProfile.py |test_upload_resume, test_invalid_resume_format| [#305](https://github.com/systers/vms/issues/305) | -| test_volunteerReport.py |test_report_with_empty_fields, test_date_field, test_event_field, test_job_field, test_intersection_of_fields| [#327](https://github.com/systers/vms/issues/327) | diff --git a/aut_docs/Installation_Setup.md b/aut_docs/Installation_Setup.md new file mode 100644 index 0000000..ebb6833 --- /dev/null +++ b/aut_docs/Installation_Setup.md @@ -0,0 +1,95 @@ +## Steps to run tests: + +A one-time setup requires the following four steps: + +- Install python, + ```bash + sudo apt-get install python3.6 + ``` + +- Install virtual environment + ```bash + sudo apt-get install virtualenv + ``` + +- Clone the VMS project + ```bash + git clone https://github.com/systers/vms.git + ``` + +- Create python3.6 virtual environment + ```bash + virtualenv -p python3.6 venv + ``` + +Following points are needed to start a testing session: + +- Activate virtual environment + ```bash + source venv/bin/activate + ``` +- Install all python dependencies + ```bash + pip install -r requirements.txt + ``` + + :Note: If you face any errors, do not open a new issue and ask for help on slack with full error logs. + +- Change directory to VMS code + ```bash + cd vms/ + ``` + +- Create migrations for database + ```bash + python manage.py makemigrations auth volunteer administrator organization event job shift registration + ``` + +- Apply migrations to database + ```bash + python manage.py migrate --noinput --traceback --settings=vms.settings + ``` + +- Check that the project is running correctly by browsing to + ``` + http://127.0.0.1:8000 + ``` + after running the command + ```bash + python manage.py runserver + ``` + +- Automated tests in VMS require you to setup geckodriver in your path. For that, either run this command in root of project: + ```bash + bash setup-geckodriver.sh + ``` + OR run these commands: + ```bash + wget https://github.com/mozilla/geckodriver/releases/download/v0.20.1/geckodriver-v0.20.1-linux64.tar.gz + tar -xzvf geckodriver-v0.20.1-linux64.tar.gz + sudo mv geckodriver /usr/local/bin + ``` + :Note: If you are using Windows then see this link to configure geckodriver in your environment https://stackoverflow.com/a/40208762 + +- To execute all tests VMS, use this command: + ```bash + python manage.py test -v 2 + ``` + +- To execute tests in a particular file use: + ```bash + python manage.py test -v 2 + ``` + +- To execute a test file inside a app use: + ```bash + python manage.py test .tests. -v 2 + ``` + +- For the automated tests, f geckodriver has been configured correctly then during simulation of tests the firefox browser will automatically open up and perform the actions and close at the end of the test. + +- If all tests pass, `OK` will be received at the end. + +- For automated tests, if any of the tests fail its not necessary that there is something wrong. To confirm if the the test is actually wrong you have to test it in headless mode. + +:Note: For automated testing, currently VMS uses the Firefox version 60, selenium version 3.4.0 and geckodriver version 0.20.1 diff --git a/aut_docs/Setup.md b/aut_docs/Setup.md deleted file mode 100644 index 59c1361..0000000 --- a/aut_docs/Setup.md +++ /dev/null @@ -1,20 +0,0 @@ -## Steps to run tests: - -- Currently, used `python 2.7` -- Clone project: `git clone https://github.com/systers/vms.git` -- In the root folder of the project, startup a new virtual environment - `virtualenv -p /usr/bin/python2.7 venv` -- Activate virtualenv, `source venv/bin/activate` -- Install dependencies: `pip install -r requirements.txt` -- `cd vms` -- To run, `python manage.py runserver`. Browse - `http://127.0.0.1:8000` -- Before running tests, make sure to download the latest geckodriver. Unpack and move the binary to `/usr/local/bin` -- To execute tests `python manage.py test`. This will run all selenium tests, unit-tests and - all functional-tests across all apps. To execute tests of only a particular - app, run `python manage.py test ` -- If all tests pass, `OK` will be received at the end. -- For functional tests, a firefox window for each test will open up - automatically and close after simulation of tests. - -Note: The current setup uses one of the latest versions of Selenium. You will run into errors if the this version is incompatible with your firefox version and does not support it. In that case, follow [this](https://support.mozilla.org/en-US/kb/find-what-version-firefox-you-are-using) guide to find out your browser version and accordingly install a Selenium version compatible with it. diff --git a/aut_docs/Tutorial.md b/aut_docs/Tutorial.md new file mode 100644 index 0000000..adbfa17 --- /dev/null +++ b/aut_docs/Tutorial.md @@ -0,0 +1,215 @@ +## This tutorial will guide you to get started with automated testing. + +Consider this testcase for tutorial; + +You are an administrator of an organization and want to create a new event +for your organization. + +Before diving into the code, we need to first break any testcase into +sub-parts of actions. This testcase can be broken as follows: + +- Initiate WebDriver to open Firefox session. +- Create an administrator. +- Redirect to login page. +- Login as administrator with correct credentials. +- Redirect to event's view page. +- Redirect to create events form. +- Fill and submit the event form. +- Retrieve the details of the event created. +- Assert the results. +- Quit the browser session. + +Now, since the action map is planned, it just needs to be converted it into code statements now. + +Before starting it is crucial to decide which test case to use. Django provides inbuilt testcase of which two are used a lot `LiveServerTestCase` and `StaticLiveServerTestCase`. Both work in the same manner which is they create a server for the test to run in but the difference is that the later one displays the CSS instead of just loading it. + +Lets start by importing this TestCase and a few other necessary imports. +```python + from selenium import webdriver + from django.contrib.staticfiles.testing import LiveServerTestCase + from django.contrib.auth.models import User + from administrator.models import Administrator +``` + +1. Initiate WebDriver to open Firefox session. + + Usually this is done only once per test suite i.e. at class level since all tests can be executed withing a single session. + This can be done as follows: + ```python + class LearningAutomatedTesting(LiveServerTestCase): + @classmethod + def setUpClass(cls): + cls.driver = webdriver.Firefox() + cls.driver.implicitly_wait(5) + cls.driver.maximize_window() + # Initiate POM pages here + super(LearningAutomatedTesting, cls).setUpClass() + ``` + +2. Create an administrator. + + Next step is to create an administrator. + + ```python + def test_learn_automated_testing(self): + # Creating administrator + user_1 = User.objects.create_user(username='admin', password='admin') + Administrator.objects.create(user=user_1, address='address', city='city', + state='state', country='country', phone_number='9999999999', + email='admin@admin.com', unlisted_organization='organization') + ``` + +3. Redirect to login page. + + After creating an administrator next step is to redirecting to login page to Log In. + ```python + def test_learn_automated_testing(self): + # Earlier code... + self.get_page(self.live_server_url, '/authentication/login/') + ``` + +4. Login as administrator with correct credentials. + + Now after redirecting to login page, the credentials need to sent to the login form and submit the form to authorize and redirect to home page. + ```python + def test_learn_automated_testing(self): + # Earlier code... + self.send_value_to_element_id('id_login', 'admin') + self.send_value_to_element_id('id_password', 'admin') + self.element_by_xpath('//form[1]').submit() + ``` + +5. Redirect to event's view page. + + After logging in with correct credentials, the home page will appear. The next task is to click on `Events` item present on the navbar to redirect to the event display view. + ```python + def test_learn_automated_testing(self): + # Earlier code... + element = self.driver.find_element_by_link_text('Events') + element.click() + ``` + +6. Redirect to create events form. + + Now from event details view next step is to click on `Create Event` button to redirect to the event creation form view. + ```python + def test_learn_automated_testing(self): + # Earlier code... + element = self.driver.find_element_by_link_text('Create Event') + element.click() + ``` + +7. Fill and submit the event form. + + After the form is open next task is to send valid values to the input fields and submit the form. Note that if any invalid value is submitted the form will raise errors. + ```python + def test_learn_automted_testing(self): + # Earlier code... + # Clear fields for values to be sent. + self.driver.find_element_by_xpath('//input[@placeholder = "Event Name"]').clear() + self.driver.find_element_by_xpath('//input[@name = "start_date"]').clear() + self.driver.find_element_by_xpath('//input[@name = "end_date"]').clear() + # Send values. + self.driver.find_element_by_xpath('//input[@placeholder = "Event Name"]').send_keys('event-name') + self.driver.find_element_by_xpath('//input[@name = "start_date"]').send_keys('2050-08-21') + self.driver.find_element_by_xpath('//input[@name = "end_date"]').send_keys('2050-08-28') + # Submit form. + self.driver.find_element_by_xpath('//form[1]').submit() + ``` + +8. Retrieve the details of the event created. + + The event is created and the values are visible in the view. Next is to retrieve those values from view. + ```python + def test_learn_automated_testing(self): + # Earlier code... + event_name = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[1]').text + event_start_date = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[2]').text + event_end_date = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[3]').text + ``` + +9. Assert the results. + + Final step is to assert the results obtained from views against the values sent earlier to form. + ```python + def test_learn_automated_testing(self): + # Earlier code... + self.assertEqual(event_name, 'event-name') + self.assertEqual(event_start_date, 'Aug. 21, 2050') + self.assertEqual(event_end_date, 'Aug. 28, 2050') + ``` + +10. Quit the browser session. + + Like initiation this step is also done at class level and only once for a test suite. + ```python + @classmethod + def tearDownClass(cls): + cls.driver.quit() + super(LearningAutomatedTesting, cls).tearDownClass() + ``` + +After compiling all the above code snippets the test finally will look like: + +```python + from selenium import webdriver + from django.contrib.staticfiles.testing import LiveServerTestCase + from django.contrib.auth.models import User + from administrator.models import Administrator + + + class LearningAutomatedTesting(LiveServerTestCase): + @classmethod + def setUpClass(cls): + cls.driver = webdriver.Firefox() + cls.driver.implicitly_wait(5) + cls.driver.maximize_window() + # Initiate POM pages here + super(LearningAutomatedTesting, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + cls.driver.quit() + super(LearningAutomatedTesting, cls).tearDownClass() + + def test_learn_automated_testing(self): + # Creating administrator + user_1 = User.objects.create_user(username='admin', password='admin') + Administrator.objects.create(user=user_1, address='address', city='city', + state='state', country='country', phone_number='9999999999', + email='admin@admin.com', unlisted_organization='organization') + + self.get_page(self.live_server_url, '/authentication/login/') + + self.send_value_to_element_id('id_login', 'admin') + self.send_value_to_element_id('id_password', 'admin') + self.element_by_xpath('//form[1]').submit() + + element = self.driver.find_element_by_link_text('Events') + element.click() + + element = self.driver.find_element_by_link_text('Create Event') + element.click() + + # Clear fields for values to be sent. + self.driver.find_element_by_xpath('//input[@placeholder = "Event Name"]').clear() + self.driver.find_element_by_xpath('//input[@name = "start_date"]').clear() + self.driver.find_element_by_xpath('//input[@name = "end_date"]').clear() + # Send values. + self.driver.find_element_by_xpath('//input[@placeholder = "Event Name"]').send_keys('event-name') + self.driver.find_element_by_xpath('//input[@name = "start_date"]').send_keys('2050-08-21') + self.driver.find_element_by_xpath('//input[@name = "end_date"]').send_keys('2050-08-28') + # Submit form. + self.driver.find_element_by_xpath('//form[1]').submit() + + event_name = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[1]').text + event_start_date = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[2]').text + event_end_date = self.driver.find_element_by_xpath('//table//tbody//tr[1]//td[3]').text + + self.assertEqual(event_name, 'event-name') + self.assertEqual(event_start_date, 'Aug. 21, 2050') + self.assertEqual(event_end_date, 'Aug. 28, 2050') +``` + + +For more information and resources related to automated testing in selenium visit [documentation](https://wiki.saucelabs.com/display/DOCS/Getting+Started+with+Selenium+for+Automated+Website+Testing) of [Sauce Labs]() diff --git a/vms/administrator/tests/test_formFields.py b/vms/administrator/tests/test_formFields.py index 6f7faef..88ab1f8 100644 --- a/vms/administrator/tests/test_formFields.py +++ b/vms/administrator/tests/test_formFields.py @@ -19,13 +19,20 @@ class FormFields(LiveServerTestCase): """ Contains Tests for - - checking if value in forms are saved for event, shift - and job forms - - validation of number of volunteers field + - Null values filled in event, job and shift forms. + - Job and event linked correctly with newly created shift + - Event linked correctly with newly created job. + - Field values retained in event, job and shift forms + if invalid entries are filled """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -37,24 +44,46 @@ def setUpClass(cls): super(FormFields, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(FormFields, cls).tearDownClass() def check_event_form_values(self, event): + """ + Utility function to perform assertion for details of + events against the event list received as param. + :param event: Iterable consisting values for events. + """ settings = self.settings self.assertEqual(settings.get_event_name_value(), event[0]) self.assertEqual(settings.get_event_start_date_value(), event[1]) self.assertEqual(settings.get_event_end_date_value(), event[2]) def check_job_form_values(self, job): + """ + Utility function to perform assertion for details of + job against the job list received as param. + :param job: Iterable consisting values for job. + """ settings = self.settings self.assertEqual(settings.get_job_name_value(), job[1]) self.assertEqual(settings.get_job_description_value(), job[2]) @@ -62,6 +91,11 @@ def check_job_form_values(self, job): self.assertEqual(settings.get_job_end_date_value(), job[4]) def check_shift_form_values(self, shift): + """ + Utility function to perform assertion for details of + shift against the shift list received as param. + :param shift: Iterable consisting values for shift. + """ settings = self.settings self.assertEqual(settings.get_shift_date_value(), shift[0]) self.assertEqual(settings.get_shift_start_time_value(), shift[1]) @@ -69,6 +103,9 @@ def check_shift_form_values(self, shift): self.assertEqual(settings.get_shift_max_volunteers(), shift[3]) def login_admin(self): + """ + Utility function to login as administrator with correct credentials. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'admin', @@ -76,6 +113,10 @@ def login_admin(self): }) def test_null_values_in_create_event(self): + """ + Test null values in event form will give error messages + for the non-nullable fields while creating a new event. + """ self.settings.go_to_events_page() event = ['', '', '', 'in!valid', 'in!valid'] settings = self.settings @@ -95,6 +136,10 @@ def test_null_values_in_create_event(self): self.assertEqual(settings.get_event_venue_error(), settings.ENTER_VALID_VALUE) def test_null_values_in_edit_event(self): + """ + Test null values in event form will give error messages + for the non-nullable fields while editing an existing event. + """ event = ['event-name', '2018-05-24', '2018-05-28'] created_event = create_event_with_details(event) self.settings.go_to_events_page() @@ -118,6 +163,10 @@ def test_null_values_in_edit_event(self): self.assertEqual(settings.get_event_end_date_error(), settings.FIELD_REQUIRED) def test_null_values_in_create_job(self): + """ + Test null values in job form will give error messages + for the non-nullable fields while creating a new job. + """ # Register Event event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) @@ -143,6 +192,10 @@ def test_null_values_in_create_job(self): self.assertEqual(settings.get_job_end_date_error(), settings.FIELD_REQUIRED) def test_null_values_in_edit_job(self): + """ + Test null values in job form will give error messages + for the non-nullable fields while editing an existing job. + """ # Register Event event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) @@ -171,6 +224,10 @@ def test_null_values_in_edit_job(self): self.assertEqual(settings.get_job_end_date_error(), settings.FIELD_REQUIRED) def test_null_values_in_create_shift(self): + """ + Test null values in shift form will give error messages + for the non-nullable fields while creating a new shift. + """ # Register Event event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) @@ -202,6 +259,10 @@ def test_null_values_in_create_shift(self): self.assertEqual(settings.get_shift_venue_error(), settings.ENTER_VALID_VALUE) def test_null_values_in_edit_shift(self): + """ + Test null values in shift form will give error messages + for the non-nullable fields while editing an existing shift. + """ # Register Event event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) @@ -234,6 +295,9 @@ def test_null_values_in_edit_shift(self): self.assertEqual(settings.get_shift_max_volunteer_error(), settings.FIELD_REQUIRED) def test_max_volunteer_field(self): + """ + Test shift can not have maximum number of volunteers less than one. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -276,6 +340,9 @@ def test_max_volunteer_field(self): self.assertEqual(settings.get_shift_max_volunteer_error(), 'Ensure this value is greater than or equal to 1.') def test_simplify_shift(self): + """ + Test shift is linked correctly with the existing job and event. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -305,6 +372,9 @@ def test_simplify_shift(self): self.assertEqual(settings.get_shift_job_end_date(), 'May 28, 2050') def test_simplify_job(self): + """ + Test job is linked correctly with the existing event. + """ event = ['event', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -324,12 +394,15 @@ def test_simplify_job(self): self.assertEqual(element.get_attribute('start_date'), 'Aug. 21, 2050') self.assertEqual(element.get_attribute('end_date'), 'Sept. 28, 2050') - """ + ''' # Retention tests are buggy. # The results change every time a new build starts # i.e. The values in forms are not always retained. def test_field_value_retention_for_event(self): + """ + Test field values are retained after filling invalid values in event form. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -382,6 +455,9 @@ def test_field_value_retention_for_event(self): # i.e. The values in forms are not always retained. def test_field_value_retention_for_job(self): + """ + Test field values are retained after filling invalid values in job form. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -440,6 +516,9 @@ def test_field_value_retention_for_job(self): # i.e. The values in forms are not always retained. def test_field_value_retention_for_shift(self): + """ + Test field values are retained after filling invalid values in shift form. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -484,4 +563,4 @@ def test_field_value_retention_for_shift(self): break except StaleElementReferenceException: pass - """ + ''' diff --git a/vms/administrator/tests/test_report.py b/vms/administrator/tests/test_report.py index 38be3c0..fc6e5af 100644 --- a/vms/administrator/tests/test_report.py +++ b/vms/administrator/tests/test_report.py @@ -22,9 +22,22 @@ class Report(LiveServerTestCase): + """ + Contains Tests for + - Report generation with data filled + - Report generation with data empty + - Only shift with logged hours are shown + - Report details verified against the filled details. + """ @classmethod def setUpClass(cls): + + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -36,18 +49,33 @@ def setUpClass(cls): super(Report, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(Report, cls).tearDownClass() def login_admin(self): + """ + Utility function to login as administrator with correct credentials. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'admin', @@ -55,12 +83,20 @@ def login_admin(self): }) def verify_shift_details(self, total_shifts, hours): + """ + Utility function to verify the shift details. + :param total_shifts: Total number of shifts as filled in form. + :param hours: Total number of hours as filled in form. + """ total_no_of_shifts = self.report_page.get_shift_summary().split(' ')[10].strip('\nTotal') total_no_of_hours = self.report_page.get_shift_summary().split(' ')[-1].strip('\n') self.assertEqual(total_no_of_shifts, total_shifts) self.assertEqual(total_no_of_hours, hours) def test_null_values_with_dataset(self): + """ + Test null values filled in report generation form with the valid data. + """ self.report_page.go_to_admin_report() # Register dataset org = create_organization_with_details('organization-one') @@ -97,6 +133,9 @@ def test_null_values_with_dataset(self): self.assertEqual(report_page.element_by_xpath(self.elements.HOURS).text, '3.0') def test_null_values_with_empty_dataset(self): + """ + Test null values filled in report generation form with the empty data. + """ # Should return no entries self.report_page.go_to_admin_report() report_page = self.report_page @@ -106,6 +145,9 @@ def test_null_values_with_empty_dataset(self): self.assertEqual(report_page.get_alert_box_text(), report_page.no_results_message) def test_only_logged_shifts_are_reported(self): + """ + Test only shifts with logged hours are reported from form. + """ report_page = self.report_page # Register dataset org = create_organization_with_details('organization-one') @@ -141,6 +183,10 @@ def test_only_logged_shifts_are_reported(self): @staticmethod def register_dataset(parameters): + """ + Utility function to register the data received in param parameters. + :param parameters: Iterable consisting data in dictionary format. + """ # Register dataset # Register dataset volunteer = create_volunteer_with_details_dynamic_password(parameters['volunteer']) @@ -163,6 +209,9 @@ def register_dataset(parameters): log_hours_with_details(volunteer, created_shift, parameters['vshift'][0], parameters['vshift'][0]) def create_dataset(self): + """ + Utility function to register data from external test JSON. + """ orgs = Organization.create_multiple_organizations(4) test_data = open('test_data.json').read() @@ -192,11 +241,14 @@ def create_dataset(self): parameters[7]["org"] = orgs[3] self.register_dataset(parameters[7]) - """ + ''' Test giving inconsistent results for log hours and total shifts For log hours: Possibly https://github.com/systers/vms/issues/327 wasn't fixed correctly. def test_check_intersection_of_fields(self): + """ + Test the shift report details generated from form search against the filled data. + """ self.create_dataset() report_page = self.report_page @@ -226,4 +278,4 @@ def test_check_intersection_of_fields(self): search_parameters_5 = ['', 'sherlock', 'two', '', ''] report_page.fill_report_form(search_parameters_5) self.verify_shift_details('1','2.0') - """ + ''' diff --git a/vms/administrator/tests/test_settings.py b/vms/administrator/tests/test_settings.py index 74fd77c..efac20a 100644 --- a/vms/administrator/tests/test_settings.py +++ b/vms/administrator/tests/test_settings.py @@ -62,6 +62,11 @@ class Settings(LiveServerTestCase): @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -73,18 +78,33 @@ def setUpClass(cls): super(Settings, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(Settings, cls).tearDownClass() def login_admin(self): + """ + Utility function to login as administrator with correct credentials. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'admin', @@ -92,6 +112,9 @@ def login_admin(self): }) def delete_event_from_list(self): + """ + Utility function to delete a particular event. + """ settings = self.settings self.assertEqual(settings.element_by_xpath(self.elements.DELETE_EVENT).text, 'Delete') settings.element_by_xpath(self.elements.DELETE_EVENT + '//a').click() @@ -100,6 +123,9 @@ def delete_event_from_list(self): settings.submit_form() def delete_job_from_list(self): + """ + Utility function to delete a particular job. + """ settings = self.settings self.assertEqual(settings.element_by_xpath(self.elements.DELETE_JOB).text, 'Delete') settings.element_by_xpath(self.elements.DELETE_JOB + '//a').click() @@ -109,6 +135,9 @@ def delete_job_from_list(self): settings.submit_form() def delete_shift_from_list(self): + """ + Utility function to delete a particular shift. + """ settings = self.settings self.assertEqual(settings.element_by_xpath(self.elements.DELETE_SHIFT).text, 'Delete') settings.element_by_xpath(self.elements.DELETE_SHIFT + '//a').click() @@ -119,6 +148,9 @@ def delete_shift_from_list(self): settings.submit_form() def delete_organization_from_list(self): + """ + Utility function to delete a particular organization. + """ settings = self.settings self.assertEqual(settings.element_by_xpath(self.elements.DELETE_ORG).text, 'Delete') settings.element_by_xpath(self.elements.DELETE_ORG + '//a').click() @@ -129,12 +161,18 @@ def delete_organization_from_list(self): settings.submit_form() def test_event_tab(self): + """ + Test event details view with no events registered. + """ self.settings.go_to_events_page() settings = self.settings self.assertEqual(settings.get_message_context(), 'There are currently no events. Please create events first.') def test_job_tab_and_create_job_without_event(self): + """ + Test job details view with no events registered. + """ self.settings.go_to_events_page() settings = self.settings settings.click_link(settings.jobs_tab) @@ -146,6 +184,9 @@ def test_job_tab_and_create_job_without_event(self): self.assertEqual(settings.get_message_context(), 'Please add events to associate with jobs first.') def test_shift_tab_and_create_shift_without_job(self): + """ + Test shift details view with no jobs registered. + """ self.settings.go_to_events_page() settings = self.settings settings.click_link(settings.shift_tab) @@ -153,6 +194,9 @@ def test_shift_tab_and_create_shift_without_job(self): self.assertEqual(settings.get_message_context(), 'There are currently no jobs. Please create jobs first.') def test_create_event(self): + """ + Test event creation with valid values. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -166,6 +210,9 @@ def test_create_event(self): self.assertEqual(settings.get_event_name(), 'event-name') def test_edit_event(self): + """ + Test event edit with valid values. + """ event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -187,6 +234,9 @@ def test_edit_event(self): self.assertEqual(settings.get_event_name(), 'new-event-name') def test_create_and_edit_event_with_invalid_start_date(self): + """ + Test event creation and edit with invalid start date. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -214,6 +264,9 @@ def test_create_and_edit_event_with_invalid_start_date(self): self.assertEqual(settings.get_warning_context(), "Start date should be today's date or later.") def test_edit_event_with_elapsed_start_date(self): + """ + Test edit of an event which is currently going on. + """ elapsed_event = ['event-name', '2016-05-21', '2050-08-09'] # Create an event with elapsed start date @@ -236,6 +289,9 @@ def test_edit_event_with_elapsed_start_date(self): self.assertNotEqual(self.driver.current_url, self.live_server_url + settings.event_list_page) def test_edit_event_with_invalid_job_date(self): + """ + Test edit of event with invalid date such that the job dates do not lie in it. + """ event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -262,6 +318,9 @@ def test_edit_event_with_invalid_job_date(self): 'lies within the new date range :') def test_delete_event_with_no_associated_job(self): + """ + Test deletion of events with no jobs linked. + """ event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -281,6 +340,9 @@ def test_delete_event_with_no_associated_job(self): settings.get_results() def test_delete_event_with_associated_job(self): + """ + Test deletion of events with linked jobs. + """ event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -308,6 +370,9 @@ def test_delete_event_with_associated_job(self): self.assertEqual(settings.get_event_name(), 'event-name') def test_create_job(self): + """ + Test creation of job with valid values. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -328,6 +393,9 @@ def test_create_job(self): self.assertEqual(settings.get_job_event(), created_event.name) def test_edit_job(self): + """ + Test edit of job with valid values. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -351,6 +419,9 @@ def test_edit_job(self): self.assertEqual(settings.get_job_name(), 'changed job name') def test_create_job_with_invalid_event_date(self): + """ + Test creation of job with date not lying in event's date. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] create_event_with_details(event) @@ -380,6 +451,9 @@ def test_create_job_with_invalid_event_date(self): self.assertEqual(settings.get_warning_context(), 'Job dates should lie within Event dates') def test_edit_job_with_invalid_event_date(self): + """ + Test edit of job with date not lying in event's date. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -413,6 +487,10 @@ def test_edit_job_with_invalid_event_date(self): self.assertEqual(settings.get_warning_context(), 'Job dates should lie within Event dates') def test_edit_job_with_invalid_shift_date(self): + """ + Test edit of job with date not lying in shift's date. + """ + # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -443,6 +521,9 @@ def test_edit_job_with_invalid_shift_date(self): 'You cannot edit this job as 1 associated shift no longer lies within the new date range') def test_delete_job_without_associated_shift(self): + """ + Test deletion of job with shifts not linked. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -468,6 +549,9 @@ def test_delete_job_without_associated_shift(self): settings.get_results() def test_delete_job_with_associated_shifts(self): + """ + Test deletion of job with shifts linked. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -497,6 +581,9 @@ def test_delete_job_with_associated_shifts(self): self.assertEqual(settings.get_job_name(), 'job') def test_create_shift(self): + """ + Test creation of shift with valid values. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -522,6 +609,9 @@ def test_create_shift(self): settings.get_help_block() def test_create_shift_with_invalid_timings(self): + """ + Test creation of shift with invalid time. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -545,6 +635,9 @@ def test_create_shift_with_invalid_timings(self): self.assertEqual(settings.get_help_block().text, 'Start time must be before the end time') def test_edit_shift_with_invalid_timings(self): + """ + Test edit of shift with invalid time. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -571,6 +664,9 @@ def test_edit_shift_with_invalid_timings(self): self.assertEqual(settings.get_help_block().text, 'Start time must be before the end time') def test_create_shift_with_invalid_date(self): + """ + Test creation of shift with date not lying in job's date. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -594,6 +690,9 @@ def test_create_shift_with_invalid_date(self): self.assertEqual(settings.get_warning_context(), 'Shift date should lie within Job dates') def test_edit_shift_with_invalid_date(self): + """ + Test edit of shift with date not lying in job's date. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -620,6 +719,9 @@ def test_edit_shift_with_invalid_date(self): self.assertEqual(settings.get_warning_context(), 'Shift date should lie within Job dates') def test_edit_shift(self): + """ + Test edit of shift with valid values. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -648,6 +750,9 @@ def test_edit_shift(self): self.assertEqual(settings.get_shift_date(), 'Aug. 25, 2050') def test_delete_shift(self): + """ + Test deletion of shift. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -674,6 +779,9 @@ def test_delete_shift(self): self.assertEqual(settings.get_message_context(), 'There are currently no shifts. Please create shifts first.') def test_delete_shift_with_volunteer(self): + """ + Test deletion of shift with volunteer linked with it. + """ # register event first to create job event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -703,6 +811,9 @@ def test_delete_shift_with_volunteer(self): 'You cannot delete a shift that a volunteer has signed up for.') def test_organization(self): + """ + Test creation of organization with valid values. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -720,6 +831,9 @@ def test_organization(self): self.assertEqual(settings.get_org_name(), 'Org-name 92:4 CA') def test_replication_of_organization(self): + """ + Test creation of organization with name same as that of existing one. + """ self.settings.go_to_events_page() settings = self.settings settings.live_server_url = self.live_server_url @@ -736,6 +850,9 @@ def test_replication_of_organization(self): self.assertEqual(settings.get_help_block().text, 'Organization with this Name already exists.') def test_edit_org(self): + """ + Test edit of organization with valid values. + """ # create org create_organization() self.settings.go_to_events_page() @@ -756,6 +873,9 @@ def test_edit_org(self): self.assertTrue('changed-organization' in org_list) def test_delete_org_without_associated_users(self): + """ + Test deletion of organization with no users linked with it. + """ # create org create_organization() self.settings.go_to_events_page() @@ -771,6 +891,9 @@ def test_delete_org_without_associated_users(self): settings.element_by_xpath('//table//tbody//tr[1]') def test_delete_org_with_associated_users(self): + """ + Test deletion of organization with users linked with it. + """ # create org org = create_organization() volunteer = create_volunteer() @@ -791,8 +914,11 @@ def test_delete_org_with_associated_users(self): 'You cannot delete an organization that users are currently associated with.') # Feature not yet added. - """ + ''' def test_duplicate_event(self): + """ + Test creation of duplicate event with same details. + """ event = ['event-name', '2050-08-21', '2050-09-28'] created_event = create_event_with_details(event) @@ -810,6 +936,9 @@ def test_duplicate_event(self): # Feature not yet implemented def test_duplicate_job(self): + """ + Test creation of duplicate job with same details. + """ # register event first to create job event = ['event-name', '2017-08-21', '2017-09-28'] created_event = create_event_with_details(event) @@ -832,4 +961,4 @@ def test_duplicate_job(self): # TBA here - more checks depending on logic that should be reflected # check job not created - commented out due to bug self.assertNotEqual(self.driver.current_url, self.live_server_url + settings.job_list_page) - """ + ''' diff --git a/vms/event/tests/test_event.py b/vms/event/tests/test_event.py index 1532cc5..201ab66 100644 --- a/vms/event/tests/test_event.py +++ b/vms/event/tests/test_event.py @@ -13,12 +13,21 @@ class EventDetails(LiveServerTestCase): """ - Contains Tests for Job app in aspect of - an admin's view of website. + Contains tests for event app from administrator view: + - Event details view + - Event creation with valid and invalid values + - Event deletion + - Start date of event after end date """ @classmethod def setUpClass(cls): + + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -30,22 +39,41 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(EventDetails, cls).tearDownClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @staticmethod def register_valid_event(): + """ + Utility function to create a valid event. + :return: Event type object + """ created_event = create_event_with_details(['event', '2050-06-11', '2050-06-19']) return created_event def check_error_messages(self): + """ + Utility function to check event errors raised after form filling + """ event_details_page = self.event_details_page self.assertEqual(len(event_details_page.get_help_blocks()), 3) self.assertEqual(event_details_page.get_event_name_error(), event_details_page.FIELD_REQUIRED) @@ -53,6 +81,9 @@ def check_error_messages(self): self.assertEqual(event_details_page.get_event_end_date_error(), event_details_page.FIELD_REQUIRED) def login_admin(self): + """ + Utility function to login as administrator with correct credentials. + """ authentication_page = self.authentication_page authentication_page.server_url = self.live_server_url authentication_page.login( @@ -63,6 +94,9 @@ def login_admin(self): ) def test_event_details_view(self): + """ + Test event details view for existing events. + """ # Navgate to event view event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url @@ -81,6 +115,9 @@ def test_event_details_view(self): self.assertEqual(event_details_page.get_event_end_date(), 'June 19, 2050') def test_valid_event_create(self): + """ + Test event create with valid details. + """ created_event = EventDetails.register_valid_event() event_details_page = self.event_details_page @@ -93,6 +130,9 @@ def test_valid_event_create(self): self.assertEqual(event_details_page.get_event_end_date(), 'June 19, 2050') def test_invalid_event_create(self): + """ + Test event create with invalid values. + """ event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url event_details_page.go_to_events_page() @@ -106,6 +146,9 @@ def test_invalid_event_create(self): self.check_error_messages() def test_invalid_event_edit(self): + """ + Test event edit with invalid values. + """ registered_event = EventDetails.register_valid_event() event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url @@ -118,6 +161,9 @@ def test_invalid_event_edit(self): self.check_error_messages() def test_valid_event_edit(self): + """ + Test event edit with valid values. + """ registered_event = EventDetails.register_valid_event() event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url @@ -133,6 +179,9 @@ def test_valid_event_edit(self): self.assertEqual(event_details_page.get_event_end_date(), 'June 20, 2050') def test_event_delete(self): + """ + Test event delete. + """ registered_event = EventDetails.register_valid_event() event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url @@ -144,6 +193,9 @@ def test_event_delete(self): event_details_page.submit_form() def test_start_date_after_end_date(self): + """ + Test event start date after its end date. + """ event_details_page = self.event_details_page event_details_page.live_server_url = self.live_server_url event_details_page.go_to_events_page() diff --git a/vms/event/tests/test_model.py b/vms/event/tests/test_model.py index 1a8d7e2..72d7ee3 100644 --- a/vms/event/tests/test_model.py +++ b/vms/event/tests/test_model.py @@ -12,20 +12,42 @@ class EventModelTests(TestCase): + """ + Contains database tests for + - event create with valid and invalid values. + - event edit with valid and invalid values. + - event delete. + - event mode representation. + """ def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ pass def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ pass @staticmethod def create_event(): + """ + Utility function to create a valid event. + :return: Event type object + """ event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) return created_event def test_valid_model_create(self): + """ + Database test for model creation with valid values. + """ event = ['event-name', '2050-05-24', '2050-05-28', 'event address', 'event venue'] create_event_with_details(event) @@ -46,6 +68,7 @@ def test_invalid_name_in_model_create(self): """ event_data = ['event~name', '2050-05-21', '2050-05-24'] event = create_event_with_details(event_data) + self.assertRaisesRegexp(ValidationError, EventsPage.ENTER_VALID_VALUE, event.full_clean) # def test_invalid_start_date_in_model_create(self): @@ -67,6 +90,9 @@ def test_invalid_name_in_model_create(self): # self.assertRaisesRegexp(ValidationError, EventsPage.ENTER_VALID_VALUE, event.full_clean) def test_model_edit_with_valid_values(self): + """ + Database test for model edit with valid values. + """ created_event = EventModelTests.create_event() # Check db for instance creation @@ -86,6 +112,9 @@ def test_model_edit_with_valid_values(self): self.assertEqual(len(Event.objects.all()), 1) def test_model_edit_with_invalid_values(self): + """ + Database test for model edit with invalid values. + """ created_event = EventModelTests.create_event() # Check db for instance creation @@ -107,6 +136,9 @@ def test_model_edit_with_invalid_values(self): self.assertNotEqual(len(Event.objects.all()), 0) def test_model_delete(self): + """ + Database test for model deletion. + """ created_event = EventModelTests.create_event() # Check db for instance creation @@ -123,6 +155,9 @@ def test_model_delete(self): self.assertEqual(len(Event.objects.all()), 0) def test_model_representation(self): + """ + Database test for model representation. + """ EventModelTests.create_event() # Check db for instance creation diff --git a/vms/event/tests/test_services.py b/vms/event/tests/test_services.py index e0522e1..ec29830 100644 --- a/vms/event/tests/test_services.py +++ b/vms/event/tests/test_services.py @@ -72,9 +72,9 @@ def tearDownModule(): class EventTests(unittest.TestCase): - ''' + """ Contains tests which require only event objects - ''' + """ @classmethod def setup_test_data(cls): @@ -146,9 +146,9 @@ def test_get_events_ordered_by_name(self): class EventWithJobTests(unittest.TestCase): - ''' + """ Contains tests which require jobs and shifts - ''' + """ @classmethod def setup_test_data(cls): @@ -236,9 +236,9 @@ def test_delete_event(self): class EventWithVolunteerTest(unittest.TestCase): - ''' + """ Contains tests which require only volunteer objects - ''' + """ @classmethod def setup_test_data(cls): diff --git a/vms/event/tests/test_shiftSignUp.py b/vms/event/tests/test_shiftSignUp.py index 415b95e..9ca8f5c 100644 --- a/vms/event/tests/test_shiftSignUp.py +++ b/vms/event/tests/test_shiftSignUp.py @@ -18,12 +18,21 @@ class ShiftSignUp(LiveServerTestCase): """ - Tests dealing with Event app in aspect - of Volunteer's view of website. + Contains tests for for event app from volunteer view: + - + - + - + - """ @classmethod def setUpClass(cls): + + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -34,19 +43,33 @@ def setUpClass(cls): super(ShiftSignUp, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_volunteer() self.login_volunteer() def tearDown(self): - pass + """ + Method consists of statements to be executed at + end of each test. + """ + self.authentication_page.logout() @classmethod def tearDownClass(cls): - cls.authentication_page.logout() + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(ShiftSignUp, cls).tearDownClass() def login_volunteer(self): + """ + Utility function to login as volunteer with correct credentials. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'volunteer', @@ -54,11 +77,17 @@ def login_volunteer(self): }) def test_events_page_with_no_events(self): + """ + Test event view with no registered events. + """ sign_up_page = self.sign_up_page sign_up_page.navigate_to_sign_up() self.assertEqual(sign_up_page.get_info_box().text, sign_up_page.no_event_message) def test_signup_shifts_with_registered_shifts(self): + """ + Test volunteer signing for a shift which is registered. + """ registered_event = register_event_utility() registered_job = register_job_utility() registered_shift = register_shift_utility() @@ -90,6 +119,9 @@ def test_signup_shifts_with_registered_shifts(self): self.assertEqual(sign_up_page.get_shift_end_time(), '3 p.m.') def test_signup_for_same_shift_again(self): + """ + Test volunteer signing up for the same shift again. + """ registered_event = register_event_utility() registered_job = register_job_utility() registered_shift = register_shift_utility() @@ -125,6 +157,9 @@ def test_signup_for_same_shift_again(self): sign_up_page.find_table_tag() def test_empty_events(self): + """ + Test no events present in the event view. + """ registered_event = register_event_utility() sign_up_page = self.sign_up_page # Open Shift Sign Up @@ -145,6 +180,9 @@ def test_empty_events(self): sign_up_page.find_table_tag() def test_shift_sign_up_with_outdated_shifts(self): + """ + Test signing up for the shifts whose date have passed. + """ registered_event = register_event_utility() registered_job = register_job_utility() sign_up_page = self.sign_up_page @@ -165,6 +203,9 @@ def test_shift_sign_up_with_outdated_shifts(self): sign_up_page.get_message_shift_not_available_for_job('job')) def test_shift_sign_up_with_no_slots(self): + """ + Test signing up for a shift for which volunteer needed is zero. + """ registered_event = register_event_utility() registered_job = register_job_utility() @@ -189,6 +230,9 @@ def test_shift_sign_up_with_no_slots(self): self.assertEqual(sign_up_page.get_info_box().text, sign_up_page.no_event_message) def test_search_event_both_date_present(self): + """ + Test search of event with both using both date. + """ register_event_utility() register_job_utility() register_shift_utility() @@ -203,7 +247,10 @@ def test_search_event_both_date_present(self): # Verify that the event shows up self.assertEqual(sign_up_page.get_event_name(), 'event') - def test_search_event_start_date_presesnt(self): + def test_search_event_start_date_present(self): + """ + Test search of event with only start date. + """ register_event_utility() register_job_utility() register_shift_utility() @@ -218,6 +265,9 @@ def test_search_event_start_date_presesnt(self): self.assertEqual(sign_up_page.get_event_name(), 'event') def test_search_event_end_date_present(self): + """ + Test search of event with only end date. + """ register_event_utility() register_job_utility() register_shift_utility() diff --git a/vms/job/tests/test_jobDetails.py b/vms/job/tests/test_jobDetails.py index b686b0a..a09a8b3 100644 --- a/vms/job/tests/test_jobDetails.py +++ b/vms/job/tests/test_jobDetails.py @@ -15,10 +15,20 @@ class JobDetails(LiveServerTestCase): """ Contains Tests for Job app. + - Creation with valid and invalid values. + - Edit with valid and invalid values. + - Deletion of registered job. + - Registering job with no event registered + - Registering with start date after end date. """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -30,27 +40,51 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(JobDetails, cls).tearDownClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ self.admin = create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @staticmethod def register_valid_event(): + """ + Utility function to register event with valid details. + :return: Event type object. + """ created_event = create_event_with_details(['event', '2050-06-11', '2050-06-19']) return created_event @staticmethod def register_valid_job(created_event): + """ + Utility function to register job with valid details. + :param created_event: Event type object. + :return: Job type object. + """ created_job = create_job_with_details(['job', '2050-06-15', '2050-06-18', '', created_event]) return created_job def check_error_messages(self): + """ + Utility function to check error messages which appear in job form. + """ job_details_page = self.job_details_page error_message = job_details_page.FIELD_REQUIRED self.assertEqual(len(job_details_page.get_help_blocks()), 3) @@ -59,6 +93,9 @@ def check_error_messages(self): self.assertEqual(job_details_page.get_job_end_date_error(), error_message) def login_admin(self): + """ + Utility function to login as administrator. + """ authentication_page = self.authentication_page authentication_page.server_url = self.live_server_url authentication_page.login( @@ -69,6 +106,9 @@ def login_admin(self): ) def test_job_details_view(self): + """ + Test job details view table with registered job. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() @@ -86,6 +126,9 @@ def test_job_details_view(self): self.assertEqual(job_details_page.get_event_name(), created_event.name) def test_valid_job_create(self): + """ + Test job creation with valid values. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() created_job = JobDetails.register_valid_job(created_event) @@ -99,6 +142,9 @@ def test_valid_job_create(self): self.assertEqual(job_details_page.get_event_name(), created_event.name) def test_invalid_job_create(self): + """ + Test job creation with invalid values. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() @@ -115,6 +161,9 @@ def test_invalid_job_create(self): self.check_error_messages() def test_invalid_job_edit(self): + """ + Test job edit with invalid values. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() JobDetails.register_valid_job(created_event) @@ -129,6 +178,9 @@ def test_invalid_job_edit(self): self.check_error_messages() def test_valid_job_edit(self): + """ + Test job edit with valid values. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() JobDetails.register_valid_job(created_event) @@ -146,6 +198,9 @@ def test_valid_job_edit(self): self.assertEqual(job_details_page.get_description(), edit_job[2]) def test_job_delete(self): + """ + Test job deletion. + """ job_details_page = self.job_details_page job_details_page.live_server_url = self.live_server_url @@ -160,6 +215,9 @@ def test_job_delete(self): job_details_page.submit_form() def test_create_job_with_no_event_present(self): + """ + Test job creation with no registered events present. + """ job_details_page = self.job_details_page job_details_page.navigate_to_event_list_view() job_details_page.click_link(job_details_page.jobs_tab) @@ -175,6 +233,9 @@ def test_create_job_with_no_event_present(self): job_details_page.ADD_EVENTS_TO_JOB) def test_start_date_after_end_date(self): + """ + Test start date of job after end date. + """ created_event = JobDetails.register_valid_event() self.job_details_page.navigate_to_event_list_view() diff --git a/vms/job/tests/test_model.py b/vms/job/tests/test_model.py index 9d24943..cb35d1f 100644 --- a/vms/job/tests/test_model.py +++ b/vms/job/tests/test_model.py @@ -1,5 +1,3 @@ -# third party - # Django from django.core.exceptions import ValidationError from django.db.models import Q @@ -13,25 +11,51 @@ class JobModelTests(TestCase): + """ + Contains database tests for + - job create with valid and invalid values. + - job edit with valid and invalid values. + - job delete. + - job mode representation. + """ def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ self.event = self.create_event() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ pass @staticmethod def create_event(): + """ + Utility function to create an event with valid values. + :return: Event type object. + """ event = ['event-name', '2050-05-24', '2050-05-28'] created_event = create_event_with_details(event) return created_event def create_job(self): + """ + Utility function to create a job with valid values. + :return: Job type object. + """ job = ['job-name', '2050-05-25', '2050-05-26', 'job-description', self.event] created_job = create_job_with_details(job) return created_job def test_valid_model_create(self): + """ + Test creation of job model with valid values. + """ job = ['job-name', '2050-05-25', '2050-05-26', 'job-description', self.event] created_job = create_job_with_details(job) @@ -49,11 +73,12 @@ def test_valid_model_create(self): self.assertEqual(str(job_in_db.end_date), job[2]) self.assertEqual(job_in_db.description, job[3]) - def test_invalid_model_create(self): + def test_invalid_name_in_model_create(self): """ Database test for model creation with invalid name. """ job = ['job~name', '2050-05-25', '2050-05-26', 'job description', self.event] + created_job = create_job_with_details(job) self.assertRaisesRegexp(ValidationError, JobDetailsPage.ENTER_VALID_VALUE, @@ -92,6 +117,9 @@ def test_invalid_description_in_model_create(self): created_job.full_clean) def test_model_edit_with_valid_values(self): + """ + Test edit of job model with valid values. + """ job = self.create_job() # Check db for instance creation @@ -112,6 +140,9 @@ def test_model_edit_with_valid_values(self): self.assertEqual(len(Job.objects.all()), 1) def test_model_edit_with_invalid_values(self): + """ + Test edit of job model with invalid values. + """ job = ['job-name', '2016-05-25', '2016-05-26', 'job-description', self.event] created_job = create_job_with_details(job) @@ -134,6 +165,9 @@ def test_model_edit_with_invalid_values(self): self.assertNotEqual(len(Job.objects.all()), 0) def test_model_delete(self): + """ + Test deletion of registered job model. + """ job = self.create_job() # Check db for instance creation @@ -151,6 +185,9 @@ def test_model_delete(self): self.assertEqual(len(Job.objects.all()), 0) def test_model_representation(self): + """ + Test database representation of registered job. + """ self.create_job() # Check db for instance creation diff --git a/vms/organization/tests/test_model.py b/vms/organization/tests/test_model.py index 1440ad0..ad06e7b 100644 --- a/vms/organization/tests/test_model.py +++ b/vms/organization/tests/test_model.py @@ -1,5 +1,3 @@ -# third party - # Django from django.core.exceptions import ValidationError from django.db import IntegrityError @@ -13,14 +11,33 @@ class OrganizationModelTests(TestCase): + """ + Contains database tests for + - Creation of organization with valid and invalid values. + - Edit organization with valid and invalid values. + - Deletion of organization. + - Creation of multiple organization. + - Database representation of organization. + """ def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ pass def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ pass def test_valid_organization_create(self): + """ + Test creation of organization with valid values. + """ # Create Organization org = create_organization_with_details('DummyOrg') @@ -32,6 +49,9 @@ def test_valid_organization_create(self): self.assertEqual(org_in_db.name, org.name) def test_invalid_organization_create(self): + """ + Test creation of organization with invalid values. + """ # Create Organization org = create_organization_with_details('Dummy~Org') @@ -40,6 +60,9 @@ def test_invalid_organization_create(self): self.assertRaisesRegexp(ValidationError, error_message, org.full_clean) def test_creating_duplicate_organization(self): + """ + Test creation of organization with existing name. + """ # Create Organization create_organization_with_details('DummyOrg') @@ -52,6 +75,9 @@ def test_creating_duplicate_organization(self): self.assertRaisesRegexp(IntegrityError, error_message, error_statement, name='DummyOrg') def test_organization_edit_with_valid_values(self): + """ + Test edit of organization with valid values. + """ # Create Organization org = create_organization_with_details('DummyOrg') @@ -69,6 +95,9 @@ def test_organization_edit_with_valid_values(self): self.assertNotEqual(org_in_db.name, org.name) def test_organization_edit_with_invalid_values(self): + """ + Test edit of organization with invalid values. + """ # Create Organization create_organization_with_details('DummyOrg') @@ -83,6 +112,9 @@ def test_organization_edit_with_invalid_values(self): self.assertRaisesRegexp(ValidationError, error_message, org_in_db.full_clean) def test_organization_delete(self): + """ + Test deletion of registered organization. + """ # Create Organization create_organization_with_details('DummyOrg') @@ -97,6 +129,9 @@ def test_organization_delete(self): self.assertEqual(len(Organization.objects.all()), 0) def test_create_multiple_organization_method(self): + """ + Test creation of multiple organization using fake factory function. + """ org_list = Organization.create_multiple_organizations(3) # Check number of orgs created @@ -108,6 +143,9 @@ def test_create_multiple_organization_method(self): self.assertEqual(org_list[2].name, 'org-3') def test_model_representation(self): + """ + Test model representation of registered organization. + """ # Create Organization org = create_organization_with_details('DummyOrg') diff --git a/vms/organization/tests/test_organization.py b/vms/organization/tests/test_organization.py index 158f7e6..e6c4532 100644 --- a/vms/organization/tests/test_organization.py +++ b/vms/organization/tests/test_organization.py @@ -17,16 +17,20 @@ class OrganizationTest(LiveServerTestCase): """ - E2E Tests for Organization views: - - Create Organization - - Edit Organization - - Check duplicate Organization - - Delete Org with registered volunteers - - Delete Org without registered volunteers + Contains Tests for Organization app: + - Creation of organization with valid and invalid values + - Edit organization with valid and invalid values + - Deletion of organization with volunteers registered + - Deletion of organization with volunteers not registered """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ firefox_options = Options() firefox_options.add_argument('-headless') cls.driver = webdriver.Firefox(firefox_options=firefox_options) @@ -38,18 +42,33 @@ def setUpClass(cls): super(OrganizationTest, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(OrganizationTest, cls).tearDownClass() def login_admin(self): + """ + Utility function to login as administrator with correct credentials. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'admin', @@ -57,6 +76,9 @@ def login_admin(self): }) def delete_organization_from_list(self): + """ + Utility function to delete organization using form. + """ organization_page = self.organization_page self.assertEqual(organization_page.element_by_xpath(self.elements.DELETE_ORG).text, 'Delete') organization_page.element_by_xpath(self.elements.DELETE_ORG + '//a').click() @@ -68,6 +90,9 @@ def delete_organization_from_list(self): organization_page.submit_form() def test_view_organization(self): + """ + Test display of registered organization. + """ self.organization_page.go_to_events_page() organization_page = self.organization_page organization_page.live_server_url = self.live_server_url @@ -84,6 +109,9 @@ def test_view_organization(self): self.assertEqual(organization_page.get_org_name(), organization.name) def test_create_valid_organization(self): + """ + Test creation of organization with valid values. + """ self.organization_page.go_to_events_page() organization_page = self.organization_page organization_page.live_server_url = self.live_server_url @@ -98,6 +126,9 @@ def test_create_valid_organization(self): self.assertEqual(organization_page.get_org_name(), 'Systers Open-Source Community') def test_create_duplicate_organization(self): + """ + Test creation of organization with existing name. + """ self.organization_page.go_to_events_page() organization_page = self.organization_page organization_page.live_server_url = self.live_server_url @@ -118,6 +149,9 @@ def test_create_duplicate_organization(self): self.assertEqual(organization_page.get_help_block().text, 'Organization with this Name already exists.') def test_create_invalid_organization(self): + """ + Test creation of organization with invalid values. + """ self.organization_page.go_to_events_page() organization_page = self.organization_page organization_page.live_server_url = self.live_server_url @@ -133,6 +167,9 @@ def test_create_invalid_organization(self): self.assertEqual(organization_page.get_organization_name_error(), 'Enter a valid value.') def test_edit_organization_with_invalid_value(self): + """ + Test edit of organization with invalid values. + """ # Create Organization org = create_organization() @@ -153,6 +190,9 @@ def test_edit_organization_with_invalid_value(self): self.assertEqual(organization_page.get_organization_name_error(), 'Enter a valid value.') def test_edit_organization_with_valid_value(self): + """ + Test edit of organization with valid values. + """ # Create Organization org = create_organization() @@ -173,6 +213,9 @@ def test_edit_organization_with_valid_value(self): self.assertEqual(organization_page.get_org_name(), 'New Organization') def test_delete_organization_without_users_linked(self): + """ + Test deletion of organization with no users linked to it. + """ # Create org org = create_organization() @@ -191,6 +234,9 @@ def test_delete_organization_without_users_linked(self): organization_page.element_by_xpath('//table//tbody//tr[1]') def test_delete_org_with_users_linked(self): + """ + Test deletion of organization with users linked to it. + """ # Create Organization org = create_organization()