2 from nose import with_setup
3 from selenium import webdriver
4 from selenium.webdriver.support.wait import WebDriverWait
5 from selenium.webdriver.common.by import By
6 from selenium.webdriver.common.keys import Keys
7 from selenium.webdriver.support import expected_conditions as EC
8 from django.test import LiveServerTestCase
9 from karmaworld.apps.courses.models import *
13 class AddCourseTest(LiveServerTestCase):
14 """Tests the Add Course form."""
17 def __init__(self, field, value, autocomplete, error_expected):
20 self.autocomplete = autocomplete
21 self.error_expected = error_expected
24 return "{f}: {v}".format(f=self.field, v=self.value)
26 class CompositeFieldAction:
27 def __init__(self, subactions, error_expected):
28 self.subactions = subactions
29 self.error_expected = error_expected
31 SCHOOL_FIELD_NAME = 'DepartmentForm-school_text'
32 COURSE_FIELD_NAME = 'CourseForm-name'
33 DEPARTMENT_FIELD_NAME = 'DepartmentForm-name_text'
34 PROFESSOR_FIELD_NAME = 'ProfessorForm-name_text'
35 PROFESSOR_EMAIL_FIELD_NAME = 'ProfessorForm-email_text'
36 COURSE_URL_FIELD_NAME = 'CourseForm-url'
37 HONEYPOT_FIELD_NAME = 'CourseForm-instruction_url'
39 EXAMPLE_SCHOOL = 'Northeastern University'
40 EXAMPLE_NEW_DEPARTMENT = 'College of Arts and Sciences'
41 EXAMPLE_EXISTING_DEPARTMENT = 'College of Computer and Information Sciences'
42 EXAMPLE_NEW_PROFESSOR = 'Prof. X'
43 EXAMPLE_NEW_PROFESSOR_EMAIL = 'xavier@xmen.edu'
44 EXAMPLE_EXISTING_PROFESSOR = 'Prof. Einstein'
45 EXAMPLE_EXISTING_PROFESSOR_EMAIL = 'einstein@princeton.edu'
46 EXAMPLE_NEW_COURSE_NAME = 'Algorithms and Data'
47 EXAMPLE_EXISTING_COURSE_NAME = 'Theory of Computation'
48 EXAMPLE_NEW_COURSE_URL = 'http://neu.edu/stuff'
49 EXAMPLE_HONEYPOT_VALUE = 'Free drugs!'
51 SCHOOL_FIELD_OPTIONS = (
52 # Choose a school from autocomplete
53 FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=True, error_expected=False),
54 # Type in a school without choosing from autocomplete
55 FieldAction(SCHOOL_FIELD_NAME, EXAMPLE_SCHOOL, autocomplete=False, error_expected=True),
57 FieldAction(SCHOOL_FIELD_NAME, '', autocomplete=False, error_expected=True)
60 DEPARTMENT_FIELD_OPTIONS = (
61 # Type in a new department
62 FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_NEW_DEPARTMENT, autocomplete=False, error_expected=False),
63 # Choose an existing department
64 FieldAction(DEPARTMENT_FIELD_NAME, EXAMPLE_EXISTING_DEPARTMENT, autocomplete=True, error_expected=False)
67 PROFESSOR_FIELDS_OPTIONS = (
68 # New name and email typed in
69 CompositeFieldAction([
70 FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_NEW_PROFESSOR, autocomplete=False, error_expected=False),
71 FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False)],
72 error_expected=False),
73 # existing Professor Name selected, matching Professor Email selected
74 CompositeFieldAction([
75 FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False),
76 FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False)],
77 error_expected=False),
78 # existing Professor Name selected, no Email selected
79 CompositeFieldAction([
80 FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=True, error_expected=False)],
81 error_expected=False),
82 # existing Professor Email selected, no Name selected
83 CompositeFieldAction([
84 FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR_EMAIL, autocomplete=True, error_expected=False)],
85 error_expected=False),
86 # existing Professor Name selected, different Professor Email selected
87 CompositeFieldAction([
88 FieldAction(PROFESSOR_FIELD_NAME, EXAMPLE_EXISTING_PROFESSOR, autocomplete=False, error_expected=False),
89 FieldAction(PROFESSOR_EMAIL_FIELD_NAME, EXAMPLE_NEW_PROFESSOR_EMAIL, autocomplete=False, error_expected=False)],
93 COURSE_FIELD_OPTIONS = (
95 FieldAction(COURSE_FIELD_NAME, EXAMPLE_NEW_COURSE_NAME, autocomplete=False, error_expected=False),
97 FieldAction(COURSE_FIELD_NAME, '', autocomplete=False, error_expected=True)
100 COURSE_URL_OPTIONS = (
102 FieldAction(COURSE_URL_FIELD_NAME, '', autocomplete=False, error_expected=False),
104 FieldAction(COURSE_URL_FIELD_NAME, EXAMPLE_NEW_COURSE_URL, autocomplete=False, error_expected=False)
107 HONEYPOT_FIELD_OPTIONS = (
108 # something in the honeypot
109 FieldAction(HONEYPOT_FIELD_NAME, EXAMPLE_HONEYPOT_VALUE, autocomplete=False, error_expected=True),
110 # nothing in the honeypot
111 FieldAction(HONEYPOT_FIELD_NAME, '', autocomplete=False, error_expected=False)
116 cls.driver = webdriver.Firefox()
117 cls.driver.implicitly_wait(3)
118 cls.wait = WebDriverWait(cls.driver, 200)
119 super(AddCourseTest, cls).setUpClass()
122 def tearDownClass(cls):
124 super(AddCourseTest, cls).tearDownClass()
127 self.northeastern = School.objects.create(name=self.EXAMPLE_SCHOOL, usde_id=33333)
128 self.department = Department.objects.create(name=self.EXAMPLE_EXISTING_DEPARTMENT, school=self.northeastern)
129 self.professor = Professor.objects.create(name=self.EXAMPLE_EXISTING_PROFESSOR, email=self.EXAMPLE_EXISTING_PROFESSOR_EMAIL)
130 self.course = Course.objects.create(name=self.EXAMPLE_EXISTING_COURSE_NAME, department=self.department)
133 School.objects.all().delete()
134 Department.objects.all().delete()
135 Professor.objects.all().delete()
136 Course.objects.all().delete()
138 def select_autocomplete(self, name, keys):
139 """Type in the characters into the given field, and then choose
140 the first item in the autocomplete menu that appears."""
141 input = self.driver.find_element_by_name(name)
142 input.send_keys(keys)
143 self.wait.until(EC.element_to_be_clickable(
144 (By.XPATH, "//ul[contains(@style,'display: block')]/li[contains(@class,'ui-menu-item')][1]")))
145 input.send_keys(Keys.DOWN)
146 autocomplete_menu_item = self.driver.find_element_by_id("ui-active-menuitem")
147 autocomplete_menu_item.click()
150 def flatten_actions(actions):
152 for action in actions:
153 if isinstance(action, AddCourseTest.CompositeFieldAction):
154 results.extend(AddCourseTest.flatten_actions(action.subactions))
156 results.append(action)
160 def fill_out_form(self, field_actions):
161 """Fill out the Add Course form with the given actions."""
162 add_course_button = self.driver.find_element_by_id("add-course-btn")
163 add_course_button.click()
164 self.driver.execute_script("javascript:window.scrollBy(0,200)")
166 for action in AddCourseTest.flatten_actions(field_actions):
167 if action.autocomplete:
168 self.select_autocomplete(action.field, action.value)
170 field = self.driver.find_element_by_name(action.field)
171 field.send_keys(action.value)
174 save_button = self.driver.find_element_by_id("save-btn")
177 def expect_error(self, actions):
179 for action in actions:
180 if isinstance(action, AddCourseTest.CompositeFieldAction) and \
181 self.expect_error(action.subactions):
183 elif action.error_expected:
188 def check_object_exists(self, value, field, exists=True):
189 desired_count = 1 if exists else 0
191 if field == self.COURSE_FIELD_NAME:
192 self.assertEqual(Course.objects.filter(name=value).count(), desired_count)
193 elif field == self.DEPARTMENT_FIELD_NAME:
194 self.assertEqual(Department.objects.filter(name=value).count(), desired_count)
195 elif field == self.PROFESSOR_FIELD_NAME:
196 self.assertEqual(Professor.objects.filter(name=value).count(), desired_count)
197 elif field == self.PROFESSOR_EMAIL_FIELD_NAME:
198 self.assertEqual(Professor.objects.filter(email=value).count(), desired_count)
199 elif field == self.COURSE_URL_FIELD_NAME:
200 self.assertEqual(Course.objects.filter(url=value).count(), desired_count)
202 def actions_test_and_check(self, actions):
204 self.driver.get(self.live_server_url)
205 error_expected = self.expect_error(actions)
206 self.fill_out_form(actions)
208 for action in AddCourseTest.flatten_actions(actions):
209 self.check_object_exists(action.value, action.field, exists=False)
211 for action in AddCourseTest.flatten_actions(actions):
212 self.check_object_exists(action.value, action.field, exists=True)
215 def test_combinations(self):
216 field_options_combinations = itertools.product(self.SCHOOL_FIELD_OPTIONS,
217 self.DEPARTMENT_FIELD_OPTIONS,
218 self.PROFESSOR_FIELDS_OPTIONS,
219 self.COURSE_FIELD_OPTIONS,
220 self.COURSE_URL_OPTIONS,
221 self.HONEYPOT_FIELD_OPTIONS)
223 for actions in field_options_combinations:
224 self.actions_test_and_check(actions)