From: Charles Connell Date: Tue, 17 Dec 2013 04:27:18 +0000 (-0500) Subject: Django unit tests for courses, move around test files X-Git-Tag: release-20150131~386^2~10^2~2 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=3e25fed36798f1611a6471426c8f981cf2596059;p=oweals%2Fkarmaworld.git Django unit tests for courses, move around test files --- diff --git a/karmaworld/apps/ajaxuploader/tests/__init__.py b/karmaworld/apps/ajaxuploader/tests/__init__.py deleted file mode 100644 index f215d53..0000000 --- a/karmaworld/apps/ajaxuploader/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ajaxuploader.tests.default_storage_backend import * diff --git a/karmaworld/apps/ajaxuploader/tests/default_storage_backend.py b/karmaworld/apps/ajaxuploader/tests/default_storage_backend.py deleted file mode 100644 index 495a070..0000000 --- a/karmaworld/apps/ajaxuploader/tests/default_storage_backend.py +++ /dev/null @@ -1,62 +0,0 @@ -import os -import hashlib -from shutil import rmtree - -from django.conf import settings -from django.test import TestCase -from django.test.client import Client -from django.core.urlresolvers import reverse - - -class AjaxUploadTest(TestCase): - urls = 'ajaxuploader.tests.urls' - - def setUp(self): - super(AjaxUploadTest, self).setUp() - - self.test_dir = os.path.dirname(__file__) - test_file = open(os.path.join(self.test_dir, '../fixtures/pony.png'), - 'rb') - - self.test_file_1 = test_file - - # generate sha1 hash of the file - self.test_file_1_hash = hashlib.sha1(self.test_file_1.read())\ - .hexdigest() - - # reset position to beginning of the file - self.test_file_1.seek(0) - - - def tearDown(self): - # remove created uploads/tests directory - rmtree(os.path.join(settings.MEDIA_ROOT, 'uploads/tests')) - - def test_upload_raw_post_local_backend(self): - """ - tests uploading a file to DefaultStorageUploadBackend - """ - - # there is a bug in Django 1.3.1 with raw_post_data in the django test client - # it's fixed in trunk - # https://code.djangoproject.com/changeset/16479 - - uploaded_file_name = 'tests/foo.png' - - file_data = self.test_file_1.read() - # post raw self.test_file_1 data to AjaxFileUploader as Ajax request - response = self.client.post(reverse('ajax-upload-default-storage')+'?qqfile=%s' % \ - uploaded_file_name, file_data, - content_type='application/octet-stream', - HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - uploaded_file_path = os.path.join(settings.MEDIA_ROOT, 'uploads', - uploaded_file_name) - uploaded_file = open(uploaded_file_path, 'rb') - - # uploaded file must exist in MEDIA_DIR - self.assertTrue(os.path.exists(uploaded_file_path)) - - # sha1 hash of original file and uploaded file must match - self.assertEquals(hashlib.sha1(uploaded_file.read()).hexdigest(), - self.test_file_1_hash) diff --git a/karmaworld/apps/ajaxuploader/tests/urls.py b/karmaworld/apps/ajaxuploader/tests/urls.py deleted file mode 100644 index 19299d3..0000000 --- a/karmaworld/apps/ajaxuploader/tests/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls.defaults import * - -from ajaxuploader.views import AjaxFileUploader -from ajaxuploader.backends.default_storage import DefaultStorageUploadBackend - - -default_storage_uploader = AjaxFileUploader(backend=DefaultStorageUploadBackend) - -urlpatterns = patterns('', - url(r'^upload$', default_storage_uploader, name="ajax-upload-default-storage"), -) diff --git a/karmaworld/apps/courses/models.py b/karmaworld/apps/courses/models.py index 0c70727..273dc69 100644 --- a/karmaworld/apps/courses/models.py +++ b/karmaworld/apps/courses/models.py @@ -97,7 +97,7 @@ class Course(models.Model): super(Course, self).save(*args, **kwargs) # generate a self.id if not self.slug: self.slug = defaultfilters.slugify("%s %s" % (self.name, self.id)) - super(Course, self).save(*args, **kwargs) # Save the slug + self.save() # Save the slug def get_updated_at_string(self): """ return the formatted style for datetime strings """ diff --git a/karmaworld/apps/courses/test/selenium.py b/karmaworld/apps/courses/test/selenium.py new file mode 100644 index 0000000..55c320b --- /dev/null +++ b/karmaworld/apps/courses/test/selenium.py @@ -0,0 +1,161 @@ +from selenium import webdriver +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +import uuid +import unittest + + +class AddCourseTest(unittest.TestCase): + """Tests the Add Course form. Requires a copy of KarmaNotes + be available at localhost:8000. This will modify your database.""" + + def setUp(self): + self.driver = webdriver.Firefox() + self.driver.implicitly_wait(3) + self.wait = WebDriverWait(self.driver, 10) + + def tearDown(self): + self.driver.close() + + def selectAutocomplete(self, inputId, keys, fieldIndex): + input = self.driver.find_element_by_id(inputId) + input.send_keys(keys) + self.wait.until(EC.element_to_be_clickable((By.XPATH, "//ul[contains(@class,'ui-autocomplete')][" + str(fieldIndex) + "]/li"))) + input.send_keys(Keys.DOWN) + autocompleteMenuItem = self.driver.find_element_by_id("ui-active-menuitem") + autocompleteMenuItem.click() + + def testSchoolName(self): + self.driver.get("http://localhost:8000/") + + # Click "Add Course" + addCourseButton = self.driver.find_element_by_id("add-course-btn") + addCourseButton.click() + + # Scroll down so the autocomplete menu is in view + # This works around some weird failures + self.driver.execute_script("javascript:window.scrollBy(0,200)") + + # Type in part of a school name + schoolInput = self.driver.find_element_by_id("str_school") + schoolInput.send_keys("harvard u") + + # Wait for autocomplete menu to appear + self.wait.until(EC.element_to_be_clickable((By.XPATH, "//ul[contains(@class,'ui-autocomplete')][1]/li"))) + + # Choose the first suggestion + schoolInput.send_keys(Keys.DOWN) + activeItem = self.driver.find_element_by_id("ui-active-menuitem") + activeItem.click() + + self.assertEqual(schoolInput.get_attribute("value"), "Harvard University") + + schoolId = self.driver.find_element_by_id("id_school") + self.assertEqual(schoolId.get_attribute("value"), "1817") + + def testCreateCourse(self): + self.driver.get("http://localhost:8000/") + + # Click "Add Course" + addCourseButton = self.driver.find_element_by_id("add-course-btn") + addCourseButton.click() + self.driver.execute_script("javascript:window.scrollBy(0,200)") + + # We shouldn't be able to save it yet + saveButton = self.driver.find_element_by_id("save-btn") + self.assertIn("disabled", saveButton.get_attribute("class")) + + # Choose a school + self.selectAutocomplete("str_school", "northeastern u", 1) + + # Check that save button is now enabled + self.assertNotIn("disabled", saveButton.get_attribute("class")) + + # Course name + newCourseName = "SELENIUM TEST COURSE " + uuid.uuid4().hex + courseNameInput = self.driver.find_element_by_id("id_name") + courseNameInput.send_keys(newCourseName) + + # Instructor name + newInstructorName = "SELENIUM TEST INSTRUCTOR " + uuid.uuid4().hex + instructorNameInput = self.driver.find_element_by_id("id_instructor_name") + instructorNameInput.send_keys(newInstructorName) + + # Click "Save" + saveButton = self.driver.find_element_by_id("save-btn") + saveButton.click() + + # See if we are taken to the new course page + self.wait.until(EC.title_contains(newCourseName)) + + + def testCreateExistingCourse(self): + self.driver.get("http://localhost:8000/") + + # Click "Add Course" + addCourseButton = self.driver.find_element_by_id("add-course-btn") + addCourseButton.click() + self.driver.execute_script("javascript:window.scrollBy(0,200)") + + # We shouldn't be able to save it yet + saveButton = self.driver.find_element_by_id("save-btn") + self.assertIn("disabled", saveButton.get_attribute("class")) + + # Choose a school + self.selectAutocomplete("str_school", "northeastern u", 1) + + # Check that save button is now enabled + self.assertNotIn("disabled", saveButton.get_attribute("class")) + + # Course name + newCourseName = "SELENIUM TEST COURSE " + uuid.uuid4().hex + courseNameInput = self.driver.find_element_by_id("id_name") + courseNameInput.send_keys(newCourseName) + + # Instructor name + newInstructorName = "SELENIUM TEST INSTRUCTOR " + uuid.uuid4().hex + instructorNameInput = self.driver.find_element_by_id("id_instructor_name") + instructorNameInput.send_keys(newInstructorName) + + # Click "Save" + saveButton = self.driver.find_element_by_id("save-btn") + saveButton.click() + + # See if we are taken to the new course page + self.wait.until(EC.title_contains(newCourseName)) + + # Now go back to the home page + self.driver.get("http://localhost:8000/") + + # Click "Add Course" + addCourseButton = self.driver.find_element_by_id("add-course-btn") + addCourseButton.click() + self.driver.execute_script("javascript:window.scrollBy(0,200)") + + # Choose the SAME school + self.selectAutocomplete("str_school", "northeastern u", 1) + + # The SAME course name + self.selectAutocomplete("id_name", newCourseName, 2) + + # The SAME instructor name + self.selectAutocomplete("id_instructor_name", newInstructorName, 3) + + # Make sure Save button is disabled and hidden + saveButton = self.driver.find_element_by_id("save-btn") + self.assertIn("disabled", saveButton.get_attribute("class")) + self.wait.until_not(EC.visibility_of(saveButton)) + + # Make sure Existing Course link is shown + existingCourse = self.driver.find_element_by_id("existing-course-btn") + self.wait.until(EC.visibility_of(existingCourse)) + existingCourse.click() + + # See if we are taken to the new course page + self.wait.until(EC.title_contains(newCourseName)) + +if __name__ == "__main__": + unittest.main() + diff --git a/karmaworld/apps/courses/test/test.py b/karmaworld/apps/courses/test/test.py new file mode 100644 index 0000000..36d7f0f --- /dev/null +++ b/karmaworld/apps/courses/test/test.py @@ -0,0 +1,148 @@ +from django.test import TestCase +from karmaworld.apps.courses.models import * +from django.test.client import Client +from django.core.urlresolvers import reverse +import unittest +import json + +class CoursesTests(TestCase): + + def setUp(self): + self.harvard = School.objects.create(name="Harvard University") + self.harvard.save() + self.course1 = Course.objects.create(name="Underwater Basketweaving", instructor_name="Alice Janney", school=self.harvard) + self.client = Client() + + def testCourseUniqueness(self): + """Make sure we can't create multiple courses with the same + school + course name + instructor name combination.""" + #with self.assertRaises(Exception): + # Course.objects.create(name="Underwater Basketweaving", instructor_name="Alice", school=self.harvard) + + def testSearchForSchool(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_list'), + {"q": "harvard u"}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertIn('schools', responseContent) + + # Is the correct school in the list? + self.assertEqual(responseContent['schools'][0]['name'], 'Harvard University') + + + def testSearchForBadSchool(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_list'), + {"q": "A FAKE SCHOOL"}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertEqual(len(responseContent['schools']), 0) + + + def testSearchForCourseName(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_list'), + {"q": "under", 'school_id': self.harvard.id}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertIn('courses', responseContent) + + # Is the correct school in the list? + self.assertEqual(responseContent['courses'][0]['name'], 'Underwater Basketweaving') + + + def testSearchForBadCourseName(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_list'), + {"q": "A FAKE COURSE NAME", 'school_id': self.harvard.id}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertIn('courses', responseContent) + + # Is the correct school in the list? + self.assertEqual(len(responseContent['courses']), 0) + + + def testSearchForCourseNameWithBadRequest(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_list'), + {"q": "under", 'school_id': '3737373737'}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 400) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'fail') + + def testSearchForInstructorName(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_instructor_list'), + {"q": "alice", 'course_name': self.course1.name, 'school_id': self.harvard.id}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertIn('instructors', responseContent) + + # Is the correct school in the list? + self.assertEqual(responseContent['instructors'][0]['name'], 'Alice Janney') + + + def testSearchForBadInstructorName(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_instructor_list'), + {"q": "bob", 'course_name': self.course1.name, 'school_id': self.harvard.id}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'success') + self.assertIn('instructors', responseContent) + + # Is the correct school in the list? + self.assertEqual(len(responseContent['instructors']), 0) + + + def testSearchForInstructorNameWithBadRequest(self): + """Test searching for a school by partial name""" + response = self.client.post(reverse('karmaworld.apps.courses.views.school_course_instructor_list'), + {"q": "alice", 'course_name': self.course1.name, 'school_id': '3737373737'}, + HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 400) + responseContent = json.loads(response.content) + + # Did we get a good response back? + self.assertIn('status', responseContent) + self.assertEqual(responseContent['status'], 'fail') + + + +if __name__ == "__main__": + unittest.main() + diff --git a/karmaworld/apps/courses/views.py b/karmaworld/apps/courses/views.py index 18f27fe..39c32ad 100644 --- a/karmaworld/apps/courses/views.py +++ b/karmaworld/apps/courses/views.py @@ -8,7 +8,7 @@ import json from django.core.exceptions import MultipleObjectsReturned from django.core.exceptions import ObjectDoesNotExist -from django.http import HttpResponse, HttpResponseNotFound +from django.http import HttpResponse, HttpResponseBadRequest from django.views.generic import DetailView from django.views.generic import TemplateView from django.views.generic.edit import ProcessFormView @@ -103,7 +103,7 @@ def school_list(request): return HttpResponse(json.dumps({'status':'success', 'schools': schools}), mimetype="application/json") else: # else return that the api call failed - return HttpResponse(json.dumps({'status':'fail'}), mimetype="application/json") + return HttpResponseBadRequest(json.dumps({'status':'fail'}), mimetype="application/json") def school_course_list(request): @@ -117,7 +117,7 @@ def school_course_list(request): try: _school_id = int(request.POST['school_id']) except: - return HttpResponseNotFound(json.dumps({'status': 'fail', + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'could not convert school id to integer'}), mimetype="application/json") @@ -125,7 +125,7 @@ def school_course_list(request): try: school = School.objects.get(id__exact=_school_id) except (MultipleObjectsReturned, ObjectDoesNotExist): - return HttpResponseNotFound(json.dumps({'status': 'fail', + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'school id did not match exactly one school'}), mimetype="application/json") @@ -138,7 +138,7 @@ def school_course_list(request): mimetype="application/json") else: # else return that the api call failed - return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'query parameters missing'}), + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'query parameters missing'}), mimetype="application/json") def school_course_instructor_list(request): @@ -155,7 +155,7 @@ def school_course_instructor_list(request): try: _school_id = int(request.POST['school_id']) except: - return HttpResponseNotFound(json.dumps({'status': 'fail', + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message':'could not convert school id to integer'}), mimetype="application/json") @@ -163,7 +163,7 @@ def school_course_instructor_list(request): try: school = School.objects.get(id__exact=_school_id) except (MultipleObjectsReturned, ObjectDoesNotExist): - return HttpResponseNotFound(json.dumps({'status': 'fail', + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'school id did not match exactly one school'}), mimetype="application/json") @@ -178,5 +178,6 @@ def school_course_instructor_list(request): mimetype="application/json") else: # else return that the api call failed - return HttpResponseNotFound(json.dumps({'status': 'fail', 'message': 'query parameters missing'}), + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'query parameters missing'}), mimetype="application/json") + diff --git a/test/selenium/add_course.py b/test/selenium/add_course.py deleted file mode 100644 index 679edee..0000000 --- a/test/selenium/add_course.py +++ /dev/null @@ -1,161 +0,0 @@ -from selenium import webdriver -from selenium.webdriver.support.wait import WebDriverWait -from selenium.webdriver.common.by import By -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support import expected_conditions as EC -import uuid -import unittest - - -class AddCourseTest(unittest.TestCase): - """Tests the Add Course form. Requires a copy of KarmaNotes - be available at localhost:8000. This will modify your database.""" - - def setUp(self): - self.driver = webdriver.Firefox() - self.driver.implicitly_wait(3) - self.wait = WebDriverWait(self.driver, 10) - - def tearDown(self): - self.driver.close() - - def selectAutocomplete(self, inputId, keys, fieldIndex): - input = self.driver.find_element_by_id(inputId) - input.send_keys(keys) - self.wait.until(EC.element_to_be_clickable((By.XPATH, "//ul[contains(@class,'ui-autocomplete')][" + str(fieldIndex) + "]/li"))) - input.send_keys(Keys.DOWN) - autocompleteMenuItem = self.driver.find_element_by_id("ui-active-menuitem") - autocompleteMenuItem.click() - - def testSchoolName(self): - self.driver.get("http://localhost:8000/") - - # Click "Add Course" - addCourseButton = self.driver.find_element_by_id("add-course-btn") - addCourseButton.click() - - # Scroll down so the autocomplete menu is in view - # This works around some weird failures - self.driver.execute_script("javascript:window.scrollBy(0,200)") - - # Type in part of a school name - schoolInput = self.driver.find_element_by_id("str_school") - schoolInput.send_keys("harvard u") - - # Wait for autocomplete menu to appear - self.wait.until(EC.element_to_be_clickable((By.XPATH, "//ul[contains(@class,'ui-autocomplete')][1]/li"))) - - # Choose the first suggestion - schoolInput.send_keys(Keys.DOWN) - activeItem = self.driver.find_element_by_id("ui-active-menuitem") - activeItem.click() - - self.assertEqual(schoolInput.get_attribute("value"), "Harvard University") - - schoolId = self.driver.find_element_by_id("id_school") - self.assertEqual(schoolId.get_attribute("value"), "1817") - - def testCreateCourse(self): - self.driver.get("http://localhost:8000/") - - # Click "Add Course" - addCourseButton = self.driver.find_element_by_id("add-course-btn") - addCourseButton.click() - self.driver.execute_script("javascript:window.scrollBy(0,200)") - - # We shouldn't be able to save it yet - saveButton = self.driver.find_element_by_id("save-btn") - self.assertIn("disabled", saveButton.get_attribute("class")) - - # Choose a school - self.selectAutocomplete("str_school", "northeastern u", 1) - - # Check that save button is now enabled - self.assertNotIn("disabled", saveButton.get_attribute("class")) - - # Course name - newCourseName = "SELENIUM TEST COURSE " + uuid.uuid4().hex - courseNameInput = self.driver.find_element_by_id("id_name") - courseNameInput.send_keys(newCourseName) - - # Instructor name - newInstructorName = "SELENIUM TEST INSTRUCTOR " + uuid.uuid4().hex - instructorNameInput = self.driver.find_element_by_id("id_instructor_name") - instructorNameInput.send_keys(newInstructorName) - - # Click "Save" - saveButton = self.driver.find_element_by_id("save-btn") - saveButton.click() - - # See if we are taken to the new course page - self.wait.until(EC.title_contains(newCourseName)) - - - def testCreateExistingCourse(self): - self.driver.get("http://localhost:8000/") - - # Click "Add Course" - addCourseButton = self.driver.find_element_by_id("add-course-btn") - addCourseButton.click() - self.driver.execute_script("javascript:window.scrollBy(0,200)") - - # We shouldn't be able to save it yet - saveButton = self.driver.find_element_by_id("save-btn") - self.assertIn("disabled", saveButton.get_attribute("class")) - - # Choose a school - self.selectAutocomplete("str_school", "northeastern u", 1) - - # Check that save button is now enabled - self.assertNotIn("disabled", saveButton.get_attribute("class")) - - # Course name - newCourseName = "SELENIUM TEST COURSE " + uuid.uuid4().hex - courseNameInput = self.driver.find_element_by_id("id_name") - courseNameInput.send_keys(newCourseName) - - # Instructor name - newInstructorName = "SELENIUM TEST INSTRUCTOR " + uuid.uuid4().hex - instructorNameInput = self.driver.find_element_by_id("id_instructor_name") - instructorNameInput.send_keys(newInstructorName) - - # Click "Save" - saveButton = self.driver.find_element_by_id("save-btn") - saveButton.click() - - # See if we are taken to the new course page - self.wait.until(EC.title_contains(newCourseName)) - - # Now go back to the home page - self.driver.get("http://localhost:8000/") - - # Click "Add Course" - addCourseButton = self.driver.find_element_by_id("add-course-btn") - addCourseButton.click() - self.driver.execute_script("javascript:window.scrollBy(0,200)") - - # Choose the SAME school - self.selectAutocomplete("str_school", "northeastern u", 1) - - # The SAME course name - self.selectAutocomplete("id_name", newCourseName, 2) - - # The SAME instructor name - self.selectAutocomplete("id_instructor_name", newInstructorName, 3) - - # Make sure Save button is disabled and hidden - saveButton = self.driver.find_element_by_id("save-btn") - self.assertIn("disabled", saveButton.get_attribute("class")) - self.wait.until_not(EC.visibility_of(saveButton)) - - # Make sure Existing Course link is shown - existingCourse = self.driver.find_element_by_id("existing-course-btn") - self.wait.until(EC.visibility_of(existingCourse)) - existingCourse.click() - - # See if we are taken to the new course page - self.wait.until(EC.title_contains(newCourseName)) - -if __name__ == "__main__": - unittest.main() -