class TestGenerateReports(unittest.TestCase):
    """T1.68 - Generate Reports."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin.login()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.delete()
        except:
            pass

    # Case C8361 - 001 - Admin | Export research data to OwnCloud Research
    @pytest.mark.skipif(str(8361) not in TESTS, reason='Excluded')
    def test_admin_export_research_data_to_own_cloud_research_8361(self):
        """Export research data to OwnCloud Research.

        Steps:
        Open the user menu by clicking on the user's name
        Click on the 'Admin' button
        Click the 'Research Data' button
        Click on the 'Export Data' button

        Expected Result:
        The page is reloaded and a confirmation message is displayed.
        """
        self.ps.test_updates['name'] = 't1.68.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.68', 't1.68.001', '8361']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.open_user_menu()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Admin')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Research Data")]').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Export Data"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//div[contains(@class,"alert-info")]')

        self.ps.test_updates['passed'] = True
class TestEpicName(unittest.TestCase):
    """Product.Epic - Epic Text."""

    def setUp(self):
        """Pretest settings."""

        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case CaseID - Story# - UserType
    @pytest.mark.skipif(str(CaseID) not in TESTS, reason='Excluded')
    def test_usertype_storytext_CaseID(self):
        """Story Text.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 'product.epic.story' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'product',
            'product.epic',
            'product.epic.story',
            'CaseID'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestAnalyzeCollegeWorkflow(unittest.TestCase):
    """T2.05 - Analyze College Workflow."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities,
            existing_driver=self.teacher.driver
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.student = None
            self.teacher.delete()
        except:
            pass

    # 14645 - 001 - Student | All work is visible for college students
    # not just "This Week"
    @pytest.mark.skipif(str(14645) not in TESTS, reason='Excluded')
    def test_student_all_work_is_visible_for_college_students_14645(self):
        """All work is visible for college students, not just 'This Week'.

        Steps:
        Log into tutor-qa as student
        Click on a college course

        Expected Result:
        Can view assignments due later than this week
        """
        self.ps.test_updates['name'] = 't2.05.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.001',
            '14645'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.login()
        self.student.select_course(appearance='physics')
        assert('list/' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.sleep(5)

        page = self.student.driver.page_source
        assert('Coming Up' in page or 'No upcoming events' in page), \
            'No Coming Up/No upcoming events text is visible/present'

        self.ps.test_updates['passed'] = True

    # 14646 - 002 - Teacher | Create a link to the OpenStax Dashboard
    @pytest.mark.skipif(str(14646) not in TESTS, reason='Excluded')
    def test_teacher_create_a_link_to_the_openstax_dashboard_14646(self):
        """Create a link to the OpenStax Dashboard.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.05.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.002',
            '14646'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14647 - 003 - Teacher | Create a link to the OpenStax Dashboard
    @pytest.mark.skipif(str(14647) not in TESTS, reason='Excluded')
    def test_teacher_create_a_link_to_the_openstax_dashboard_14647(self):
        """Create a link to the OpenStax Dashboard.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.05.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.003',
            '14647'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14648 - 004 - Teacher | Create links to assigned readings in their LMS
    @pytest.mark.skipif(str(14648) not in TESTS, reason='Excluded')
    def test_teacher_create_links_to_assigned_readings_in_lms_14648(self):
        """Create links to assigned readings in their LMS.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name
        Click on a published reading assignment on the calendar dashboard
        Click "Get Assignment Link"

        Expected Result:
        The user is presented with links to assigned readings
        """
        self.ps.test_updates['name'] = 't2.05.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.004',
            '14648'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()

        self.teacher.select_course(appearance='physics')
        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'add-assignment')
            )
        ).click()
        self.teacher.find(By.PARTIAL_LINK_TEXT, 'Add Reading').click()
        assert('readings' in self.teacher.current_url()), \
            'Not on the add a homework page'

        self.teacher.find(
            By.XPATH, "//input[@id = 'reading-title']").send_keys('Epic 5-4')
        self.teacher.find(
            By.XPATH, "//input[@id = 'hide-periods-radio']").click()

        # Choose the second date calendar[1], first is calendar[0]
        self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__input-container']")[1].click()
        while(self.teacher.find(
            By.XPATH,
            "//span[@class = 'datepicker__current-month']"
        ).text != 'December 2016'):
            self.teacher.find(
                By.XPATH, "//a[@class = 'datepicker__navigation datepicker__" +
                "navigation--next']").click()

        # Choose the due date of December 31, 2016
        weekends = self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__day datepicker__day--weekend']")
        for day in weekends:
            if day.text == '31':
                due = day
                due.click()
                break

        self.teacher.sleep(3)

        # Choose reading sections
        self.teacher.find(
            By.XPATH, "//button[@id='reading-select']").click()
        self.teacher.find(
            By.XPATH, "//span[@class = 'chapter-checkbox']").click()
        self.teacher.find(
            By.XPATH,
            "//button[@class='-show-problems btn btn-primary']").click()
        self.teacher.sleep(10)

        # Publish the assignment
        self.teacher.driver.execute_script('window.scrollBy(0, -200);')
        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button -publish btn btn-primary']").click()

        # Give the assignment time to publish
        self.teacher.sleep(60)

        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        spans = self.teacher.driver.find_elements_by_tag_name('span')
        for element in spans:
            if element.text.endswith('2016'):
                month = element

        # Change the calendar date if necessary
        while (month.text != 'December 2016'):
            self.teacher.find(
                By.XPATH,
                "//a[@class = 'calendar-header-control next']").click()

        # Select the newly created assignment, get the LMS link, and delete it
        assignments = self.teacher.driver.find_elements_by_tag_name('label')
        for assignment in assignments:
            if assignment.text == 'Epic 5-4':
                assignment.click()
                self.teacher.find(
                    By.PARTIAL_LINK_TEXT, "Get assignment link").click()
                self.teacher.find(
                    By.XPATH,
                    "//div[@class = 'fade in lms-sharable-link popover top']")
                self.teacher.sleep(5)
                self.teacher.find(
                    By.XPATH,
                    "//a[@class='btn btn-default -edit-assignment']").click()
                self.teacher.sleep(5)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='async-button delete-link pull-" +
                    "right btn btn-default']").click()
                self.teacher.find(
                    By.XPATH, "//button[@class='btn btn-primary']").click()
                self.teacher.sleep(5)
                break

        self.teacher.driver.refresh()
        deleted = True

        # Verfiy the assignment was deleted
        spans = self.teacher.driver.find_elements_by_tag_name('span')
        for element in spans:
            if element.text.endswith('2016'):
                month = element

        while (month.text != 'December 2016'):
            self.teacher.find(
                By.XPATH,
                "//a[@class = 'calendar-header-control next']").click()

        assignments = self.teacher.driver.find_elements_by_tag_name('label')
        for assignment in assignments:
            if assignment.text == 'Epic 5-4':
                deleted = False
                break

        if deleted:
            self.ps.test_updates['passed'] = True

    # 14649 - 005 - Teacher | Create links to assigned homework in their LMS
    @pytest.mark.skipif(str(14649) not in TESTS, reason='Excluded')
    def test_teacher_create_links_to_assigned_homework_in_lms_14649(self):
        """Create links to assigned homework in their LMS.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name
        Click on a published homework assignment on the calendar dashboard
        Click "Get Assignment Link"

        Expected Result:
        The user is presented with links to assigned homework
        """
        self.ps.test_updates['name'] = 't2.05.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.005',
            '14649'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()

        self.teacher.select_course(appearance='physics')
        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'add-assignment')
            )
        ).click()
        self.teacher.find(By.PARTIAL_LINK_TEXT, 'Add Homework').click()
        assert('homeworks' in self.teacher.current_url()), \
            'Not on the add a homework page'

        self.teacher.find(
            By.XPATH, "//input[@id = 'reading-title']").send_keys('Epic 5-5')
        self.teacher.find(
            By.XPATH, "//input[@id = 'hide-periods-radio']").click()

        # Choose the second date calendar[1], first is calendar[0]
        self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__input-container']")[1].click()
        while(self.teacher.find(
            By.XPATH,
            "//span[@class = 'datepicker__current-month']"
        ).text != 'December 2016'):
            self.teacher.find(
                By.XPATH, "//a[@class = 'datepicker__navigation datepicker__" +
                "navigation--next']").click()

        # Choose the due date of December 31, 2016
        weekends = self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__day datepicker__day--weekend']")
        for day in weekends:
            if day.text == '31':
                due = day
                due.click()
                break

        self.teacher.sleep(3)

        # Open the select problem cards
        self.teacher.find(
            By.XPATH, "//button[@id = 'problems-select']").click()
        self.teacher.find(
            By.XPATH, "//span[@class = 'chapter-checkbox']").click()
        self.teacher.find(
            By.XPATH,
            "//button[@class='-show-problems btn btn-primary']").click()
        self.teacher.sleep(10)

        # Choose a problem for the assignment
        element = self.teacher.find(
            By.XPATH, "//div[@class = 'controls-overlay'][1]")
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(element)
        actions.perform()
        self.teacher.find(By.XPATH, "//div[@class = 'action include']").click()
        self.teacher.find(
            By.XPATH,
            "//button[@class='-review-exercises btn btn-primary']").click()
        self.teacher.sleep(2)

        # Publish the assignment
        self.teacher.driver.execute_script('window.scrollBy(0, -200);')
        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button -publish btn btn-primary']").click()

        # Give the assignment time to publish
        self.teacher.sleep(60)

        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        spans = self.teacher.driver.find_elements_by_tag_name('span')
        for element in spans:
            if element.text.endswith('2016'):
                month = element

        # Change the calendar date if necessary
        while (month.text != 'December 2016'):
            self.teacher.find(
                By.XPATH,
                "//a[@class = 'calendar-header-control next']").click()

        # Select the newly created assignment, get the LMS link, and delete it
        assignments = self.teacher.driver.find_elements_by_tag_name('label')
        for assignment in assignments:
            if assignment.text == 'Epic 5-5':
                assignment.click()
                self.teacher.find(
                    By.PARTIAL_LINK_TEXT, "Get assignment link").click()
                self.teacher.find(
                    By.XPATH,
                    "//div[@class = 'fade in lms-sharable-link popover top']")
                self.teacher.sleep(5)
                self.teacher.find(
                    By.XPATH,
                    "//a[@class='btn btn-default -edit-assignment']").click()
                self.teacher.sleep(5)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='async-button delete-link pull-" +
                    "right btn btn-default']").click()
                self.teacher.find(
                    By.XPATH, "//button[@class='btn btn-primary']").click()
                self.teacher.sleep(5)
                break

        self.teacher.driver.refresh()
        deleted = True

        # Verfiy the assignment was deleted
        spans = self.teacher.driver.find_elements_by_tag_name('span')
        for element in spans:
            if element.text.endswith('2016'):
                month = element

        while (month.text != 'December 2016'):
            self.teacher.find(
                By.XPATH,
                "//a[@class = 'calendar-header-control next']").click()

        assignments = self.teacher.driver.find_elements_by_tag_name('label')
        for assignment in assignments:
            if assignment.text == 'Epic 5-5':
                deleted = False
                break

        if deleted:
            self.ps.test_updates['passed'] = True

    # 14650 - 006 - Teacher | View instructions on how to export summary grade
    # for my student's OpenStax practice to my LMS
    @pytest.mark.skipif(str(14650) not in TESTS, reason='Excluded')
    def test_teacher_view_instructions_on_how_to_export_summary_14650(self):
        """View instructions on how to export summary grade into LMS.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.05.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.05',
            't2.05.006',
            '14650'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestImproveLoginREgistrationEnrollment(unittest.TestCase):
    """T2.09 - Improve Login, Registration, Enrollment."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.Teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # C14758 - 001 - User | Create an account that maps to the OS Product I use
    @pytest.mark.skipif(str(14758) not in TESTS, reason='Excluded')
    def test_teacher_view_a_scores_export_for_my_students_work_14758(self):
        """Create an account that maps to the OS Product I use.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.001',
            '14758'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14760 - 002 - User | Create an openstax.org account and get directed to
    # Concept Coach or Tutor
    @pytest.mark.skipif(str(14760) not in TESTS, reason='Excluded')
    def test_user_create_an_openstax_account_and_get_directed_to_14760(self):
        """Create an openstax.org account and get directed to CC or Tutor.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.002',
            '14760'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14761 - 003 - Teacher | Create a custom URL for student registration
    @pytest.mark.skipif(str(14761) not in TESTS, reason='Excluded')
    def test_teacher_create_a_custom_url_for_student_registration_14761(self):
        """Create a custom URL for student registration.

        Steps:
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the user menu

        Expected Result:
        The user is presented with a custom URL for student registration
        beneath the period tabs
        """
        self.ps.test_updates['name'] = 't2.09.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.003',
            '14761'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14762 - 004 - Student | Register for Tutor with a custom URL
    @pytest.mark.skipif(str(14762) not in TESTS, reason='Excluded')
    def test_student_register_for_tutor_with_a_custom_url_14762(self):
        """Register for Tutor with a custom URL.

        Steps:
        Enter the custom URL into the search bar
        Sign in or sign up
        Enter a school-issued ID or skip the step for now

        Expected Result:
        The user is presented with the student dashboard with the message
        "Enrollment successful! It may take a few minutes to build your
        assignments."
        (if student is already enrolled in course message notifies student of
        this)
        """
        self.ps.test_updates['name'] = 't2.09.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.004',
            '14762'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14763 - 005 - System | Students have a verified email
    @pytest.mark.skipif(str(14763) not in TESTS, reason='Excluded')
    def test_system_students_have_a_verified_email_14763(self):
        """Student has a verified email.

        Steps:
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Enter the student account in the username and password text boxes
        Click on the 'Sign in' button
        Click "My Account" from the user menu

        Expected Result:
        There is no "Click to verify" link next to the email
        """
        self.ps.test_updates['name'] = 't2.09.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.005',
            '14763'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14764 - 006 - User | Verify email using the new PIN approach
    @pytest.mark.skipif(str(14764) not in TESTS, reason='Excluded')
    def test_user_verify_email_using_the_new_pin_approach_14764(self):
        """Verify email using the new PIN approach.

        Steps:
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a Tutor course name
        Click "Verify now" on the orange header that pops up
        Enter a 6 digit verification code into the text box from the email
        Click "Go"

        Expected Result:
        A message confirming email verification pops up
        """
        self.ps.test_updates['name'] = 't2.09.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.006',
            '14764'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14767 - 007 - Teacher | Register for teaching a Tutor course as new
    # faculty
    @pytest.mark.skipif(str(14767) not in TESTS, reason='Excluded')
    def test_teacher_register_for_teaching_a_tutor_course_as_new_14767(self):
        """Register for teaching a Tutor course as new faculty.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.007',
            '14767'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14768 - 008 - Teacher | Register for teaching a Tutor course as
    # returning faculty
    @pytest.mark.skipif(str(14768) not in TESTS, reason='Excluded')
    def test_teacher_register_for_teaching_a_tutor_course_as_retur_14768(self):
        """Register for teaching a Tutor course as returning faculty.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.008',
            '14768'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14772 - 009 - Student | Agree to join or drop from each research
    # protocol that is running in my course
    @pytest.mark.skipif(str(14772) not in TESTS, reason='Excluded')
    def test_student_agree_to_join_or_drop_from_each_research_14772(self):
        """Agree to join or drop from each research protocol.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.009',
            '14772'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14773 - 010 - Researcher | Gather electronic parental consent for minors
    @pytest.mark.skipif(str(14773) not in TESTS, reason='Excluded')
    def test_researcher_gather_electronic_parental_consent_from_mi_14773(self):
        """Gather electronic parental consent from minors.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.010',
            '14773'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14774 - 011 - Admin | Gather electronic parental consent from minors
    @pytest.mark.skipif(str(14774) not in TESTS, reason='Excluded')
    def test_admin_gather_electronic_parental_consent_from_minors_14774(self):
        """Gather electronic parental consent from minors.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.011',
            '14774'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14776 - 012 - Researcher | Enable/Disable 'ask me later' for consent
    @pytest.mark.skipif(str(14776) not in TESTS, reason='Excluded')
    def test_researcher_enable_or_disable_ask_me_later_for_consent_14776(self):
        """Enable/Disable 'ask me later' for consent.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.012' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.012',
            '14776'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14777 - 013 - Admin | Enable/Disable 'ask me later' for consent
    @pytest.mark.skipif(str(14777) not in TESTS, reason='Excluded')
    def test_admin_enable_or_disable_ask_me_later_for_consent_14777(self):
        """Enable/Disable 'ask me later' for consent.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.013' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.013',
            '14777'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14778 - 014 - Researcher | Reprompt 'ask me later' to students on a
    # schedule
    @pytest.mark.skipif(str(14778) not in TESTS, reason='Excluded')
    def test_researcher_reprompt_ask_me_later_to_students_on_a_sch_14778(self):
        """Reprompt 'ask me later' to students on a schedule.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.014' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.014',
            '14778'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14779 - 015 - Admit | Reprompt 'ask me later' to students on a
    # schedule
    @pytest.mark.skipif(str(14779) not in TESTS, reason='Excluded')
    def test_admin_reprompt_ask_me_later_to_students_on_a_schedule_14779(self):
        """Reprompt 'ask me later' to students on a schedule.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.015' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.015',
            '14779'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14780 - 016 - Student | Reprompt 'ask me later' by pressing a button
    @pytest.mark.skipif(str(14780) not in TESTS, reason='Excluded')
    def test_student_reprompt_ask_me_later_by_pressing_a_button_14780(self):
        """Reprompt 'ask me later' by pressing a button.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.016' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.016',
            '14780'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14781 - 017 - Researcher | View number of students who have opted-in,
    # opted-out, ask-me-later
    @pytest.mark.skipif(str(14781) not in TESTS, reason='Excluded')
    def test_researcher_view_number_of_students_who_have_opted_in_14781(self):
        """View number of students who have opted-in, opted-out.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.017' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.017',
            '14781'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14782 - 018 - Admin | View number of students who have opted-in,
    # opted-out, ask-me-latered
    @pytest.mark.skipif(str(14782) not in TESTS, reason='Excluded')
    def test_admin_view_number_of_students_who_have_optedin_14782(self):
        """View number of students who have opted-in, opted-out.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.018' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.018',
            '14782'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14783 - 019 -  Researcher | Apply one protocol to multiple courses
    @pytest.mark.skipif(str(14783) not in TESTS, reason='Excluded')
    def test_researcher_apply_one_protocol_to_multiple_courses_14783(self):
        """Apply one protocol to multiple courses.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.019' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.019',
            '14783'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14784 - 020 -  Admin | Apply one protocol to multiple courses
    @pytest.mark.skipif(str(14784) not in TESTS, reason='Excluded')
    def test_admin_apply_one_protocol_to_multiple_courses_14784(self):
        """Apply one protocol to multiple courses.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.020' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.020',
            '14784'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14785 - 021 - Researcher | Set time bounds on when students can be asked
    # for consent
    @pytest.mark.skipif(str(14785) not in TESTS, reason='Excluded')
    def test_researcher_set_time_bounds_on_when_students_can_be_as_14785(self):
        """Set time bounds on when students can be asked for consent.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.021' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.021',
            '14785'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14786 - 022 - Admin | Set time bounds on when students can be asked
    # for consent
    @pytest.mark.skipif(str(14786) not in TESTS, reason='Excluded')
    def test_admin_set_time_bounds_on_when_students_can_be_asked_14786(self):
        """Set time bounds on when students can be asked for consent.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.022' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.022',
            '14786'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14787 - 023 - Researcher | Set if a protocol requires an e-signature
    @pytest.mark.skipif(str(14787) not in TESTS, reason='Excluded')
    def test_researcher_set_if_a_protocol_requires_an_esignature_14787(self):
        """Set if a protocol requires an e-signature.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.023' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.023',
            '14787'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14788 - 024 -  Admin | Set if a protocol requires an e-signature
    @pytest.mark.skipif(str(14788) not in TESTS, reason='Excluded')
    def test_admin_set_if_a_protocol_requires_an_esignature_14788(self):
        """Set if a protocol requires an e-signature.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.024' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.024',
            '14788'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14789 - 025 - User | Reset password with an unverified email address
    @pytest.mark.skipif(str(14789) not in TESTS, reason='Excluded')
    def test_user_reset_password_with_an_unverified_email_address_14789(self):
        """Reset password with an unverified email address.

        Steps:
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Enter any user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a Tutor course name
        Click "My Account" from the user menu
        Click on the pencil next to the password
        Enter a new password
        Click the checkmark

        Expected Result:
        The user is presented with the message that confirms password change
        """
        self.ps.test_updates['name'] = 't2.09.025' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.025',
            '14789'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14790 - 026 - User | Disable login for X minutes after Y unsuccessful
    # login attempts
    @pytest.mark.skipif(str(14790) not in TESTS, reason='Excluded')
    def test_user_disable_login_for_x_minutes_after_y_unsuccessful_14790(self):
        """Disable login for X minutes after Y unsuccessful login attempts.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.026' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.026',
            '14790'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14791 - 027 - Security | Rate limit login URLs based on IP address
    @pytest.mark.skipif(str(14791) not in TESTS, reason='Excluded')
    def test_security_rate_limit_login_urls_based_on_ip_address_14791(self):
        """Rate limit login URLs based on IP address.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.027' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.027',
            '14791'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14792 - 028 - Security | Require recent login when adding/changing
    # authentications
    @pytest.mark.skipif(str(14792) not in TESTS, reason='Excluded')
    def test_security_require_recent_login_when_adding_or_changing_14792(self):
        """Require recent login when adding/changing authentications.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.028' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.028',
            '14792'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14793 - 029 - Security | Deactivate accounts with no courses
    @pytest.mark.skipif(str(14793) not in TESTS, reason='Excluded')
    def test_security_deactivate_accounts_with_no_courses_14793(self):
        """Deactivate accounts with no courses.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.029' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.029',
            '14793'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14794 - 030 - Security | Log out Accounts admins after X mins of
    # inactivity
    @pytest.mark.skipif(str(14794) not in TESTS, reason='Excluded')
    def test_security_log_out_accounts_admins_after_x_mins_of_inac_14794(self):
        """Log out Accounts admins after X mins of inactivity.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.030' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.030',
            '14794'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14795 - 031 - Admin | Register faculty for Tutor using the CC method
    @pytest.mark.skipif(str(14795) not in TESTS, reason='Excluded')
    def test_admin_register_faculty_for_tutor_using_the_cc_method_14795(self):
        """Register faculty for Tutor using the Concept Coach method.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.031' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.031',
            '14795'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # C14796 - 032 - Teacher | Correct a student ID
    @pytest.mark.skipif(str(14796) not in TESTS, reason='Excluded')
    def test_teacher_correct_a_student_id_14796(self):
        """Correct a student ID.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.09.032' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.09',
            't2.09.032',
            '14796'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestChooseCourse(unittest.TestCase):
    """T1.38 - Choose Course."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.user = None

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.user.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.user.delete()
        except:
            pass

    # Case C8254 - 001 - Student | Select a course
    @pytest.mark.skipif(str(8254) not in TESTS, reason='Excluded')
    def test_student_select_a_course_8254(self):
        """Select a course.

        Steps:
        Click on a Tutor course name

        Expected Result:
        The user selects a course and is presented with the dashboard.
        """
        self.ps.test_updates['name'] = 't1.38.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.38',
            't1.38.001',
            '8254'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.user = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.user.login()
        self.user.select_course(appearance='physics')

        assert('list' in self.user.current_url()), \
            'Not in a course'

        self.ps.test_updates['passed'] = True

    # Case C8255 - 002 - Student | Bypass the course picker
    @pytest.mark.skipif(str(8255) not in TESTS, reason='Excluded')
    def test_student_bypass_the_course_picker_8255(self):
        """Bypass the course picker.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the student user account qas_01
        Click on the 'Sign in' button

        Expected Result:
        The user bypasses the course picker and is presented with the
        dashboard (because qas_01 is only enrolled in one course)
        """
        self.ps.test_updates['name'] = 't1.38.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.38',
            't1.38.002',
            '8255'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.user = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.user.login(username="******")
        assert('list' in self.user.current_url()), \
            'Not in a course'

        self.ps.test_updates['passed'] = True

    # Case C8256 - 003 - Teacher | Select a course
    @pytest.mark.skipif(str(8256) not in TESTS, reason='Excluded')
    def test_teacher_select_a_course_8256(self):
        """Select a course.

        Steps:
        Click on a Tutor course name

        Expected Result:
        The user selects a course and is presented with the calendar dashboard
        """
        self.ps.test_updates['name'] = 't1.38.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.38',
            't1.38.003',
            '8256'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.user = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.user.login()
        self.user.select_course(appearance='physics')
        assert('calendar' in self.user.current_url()), \
            'Not in a course'

        self.ps.test_updates['passed'] = True

    # Case C8257 - 004 - Teacher | Bypass the course picker
    @pytest.mark.skipif(str(8257) not in TESTS, reason='Excluded')
    def test_teacher_bypass_the_course_picker_8257(self):
        """Bypass the course picker.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account [ qateacher | password ] in the
            username and password text boxes
        Click on the 'Sign in' button

        Expected Result:
        The user bypasses the course picker and is presented with the
        calendar dashboard (because qateacher only has one course)
        """
        self.ps.test_updates['name'] = 't1.38.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.38',
            't1.38.004',
            '8257'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.user = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.user.login(username="******")
        assert('calendar' in self.user.current_url()), \
            'Not in a course'

        self.ps.test_updates['passed'] = True
class TestContractControls(unittest.TestCase):
    """T1.35 - Contract Controls."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin.login()
        # make sure there are no new terms to accept
        try:
            self.admin.driver.find_element(
                By.ID, 'i_agree'
            ).click()
            self.admin.driver.find_element(
                By.ID, 'agreement_submit'
            ).click()
        except NoSuchElementException:
            pass
        # go to admin console
        self.wait = WebDriverWait(self.admin.driver, 15)
        self.admin.open_user_menu()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Admin')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Legal")]').click()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.delete()
        except:
            pass

    # Case C8228 - 001 - Admin | Add a new contract
    @pytest.mark.skipif(str(8228) not in TESTS, reason='Excluded')
    def test_admin_add_a_new_contract_8228(self):
        """Add a new contract.

        Steps:
        Click on the 'Terms' option
        Click on the "New Contract" Link
        Enter information into the Name, Title, and Content text boxes
        Click on the 'Create contract' button

        Expected Result:
        Contract is created as a draft.
        User is shown the contract they just made,
        and has options on what to do with it next
        """
        self.ps.test_updates['name'] = 't1.35.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.001', '8228']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_001')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_001')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_001')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//h1[contains(text(),"Details")]').click()

        self.ps.test_updates['passed'] = True

    # Case C8229 - 002 - Admin | Cancel adding a new contract
    @pytest.mark.skipif(str(8229) not in TESTS, reason='Excluded')
    def test_admin_cancel_adding_a_new_contract_8229(self):
        """Cancel adding a new contract.

        Steps:
        Click on the 'Terms' option
        Click on the "New Contract" Link
        Enter information into the Name, Title, and Content text boxes
        Click on the 'Create contract' button
        Click on the Delete link

        Expected Result:
        Contract is deleted. User is taken back to the Contracts page.
        """
        self.ps.test_updates['name'] = 't1.35.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.002', '8229']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_002')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_002')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_002')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="Delete"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH, '//div[contains(@class,"alert-info")]')
        contracts = self.admin.driver.find_elements(
            By.XPATH, '//a[contains(text(),"test_contract_title_002")]')
        assert(len(contracts) == 0), 'contract not cancled'

        self.ps.test_updates['passed'] = True

    # Case C8230 - 003 - Admin | Publish a draft contract
    @pytest.mark.skipif(str(8230) not in TESTS, reason='Excluded')
    def test_admin_publish_a_draft_contract_8230(self):
        """Publish a draft contract.

        Steps:
        Click on the 'Terms' option
        Create a draft contract and return to contract list
        Click on the draft contract
        Click on the Publish link
        Click ok

        Expected Result:
        Draft contract is published
        """
        self.ps.test_updates['name'] = 't1.35.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.003', '8230']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_003')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_003')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_003')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="List"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//li//a[contains(text(),"test_contract_title_003")]').click()
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Publish")]').click()
        try:
            WebDriverWait(self.admin.driver, 3). \
                until(
                    expect.alert_is_present(),
                    'Timed out waiting for alert.'
                )
            alert = self.admin.driver.switch_to_alert()
            alert.accept()
            print('alert accepted')
        except TimeoutException:
            print('no alert')

        self.ps.test_updates['passed'] = True

    # Case C8231 - 004 - Admin | Delete a draft contract
    @pytest.mark.skipif(str(8231) not in TESTS, reason='Excluded')
    def test_admin_delete_a_draft_contract_8231(self):
        """Delete a draft contract.

        Steps:
        Click on the 'Terms' option
        Create a draft contract and return to the contract list
        Click on the draft contract
        Click on Delete next to chosen draft contract

        Expected Result:
        Draft contract is deleted
        """
        self.ps.test_updates['name'] = 't1.35.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.004', '8231']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        contracts_original = self.admin.driver.find_elements(
            By.XPATH, '//a[contains(text(),"test_contract_title_004")]')

        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_004')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_004')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_004')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="List"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//li//a[contains(text(),"test_contract_title_004")]').click()
        self.admin.page.wait_for_page_load()
        self.admin.sleep(2)
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Delete")]').click()
        self.admin.sleep(2)
        try:
            WebDriverWait(self.admin.driver, 3). \
                until(
                    expect.alert_is_present(),
                    'Timed out waiting for alert.'
                )
            alert = self.admin.driver.switch_to_alert()
            alert.accept()
            print('alert accepted')
        except TimeoutException:
            print('no alert')
        self.admin.page.wait_for_page_load()
        contracts = self.admin.driver.find_elements(
            By.XPATH, '//a[contains(text(),"test_contract_title_004")]')
        self.admin.page.wait_for_page_load()
        assert(len(contracts) == len(contracts_original)), \
            'contract not deleted'

        self.ps.test_updates['passed'] = True

    # Case C8232 - 005 - Admin | View a current contract
    @pytest.mark.skipif(str(8232) not in TESTS, reason='Excluded')
    def test_admin_view_a_current_contract_8232(self):
        """View a current contract.

        Steps:
        Click on the 'Terms' option
        Create a contract and then return to contract list
        Click on chosen contract

        Expected Result:
        Displays the information of chosen contract.
        """
        self.ps.test_updates['name'] = 't1.35.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.005', '8232']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_005')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_005')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_005')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="List"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//li//a[contains(text(),"test_contract_title_005")]').click()
        self.admin.driver.find_element(
            By.XPATH, '//h2[contains(text(),"test_contract_title_005")]')

        self.ps.test_updates['passed'] = True

    # Case C8233 - 006 - Admin | Add a new version of a current contract
    @pytest.mark.skipif(str(8233) not in TESTS, reason='Excluded')
    def test_admin_add_a_new_version_of_a_current_contract_8233(self):
        """Add a new version of a current contract.

        Steps:
        Click on the 'Terms' option
        Click on New version next to chosen contract
        Update information in the Name, Title, and Content text boxes.
        Click on the 'Create Contract' button

        Expected Result:
        New version of contract is saved as a draft.
        """
        self.ps.test_updates['name'] = 't1.35.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.006', '8233']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="New Version"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('NEW_006')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('NEW_006')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('NEW_006')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//h2[contains(text(),"NEW_006")]')

        self.ps.test_updates['passed'] = True

    # Case C8234 - 007 - Admin | View a contract's signatories
    @pytest.mark.skipif(str(8234) not in TESTS, reason='Excluded')
    def test_admin_view_a_contracts_signatures_8234(self):
        """View a contract's signatories.

        Steps:
        Click on the 'Terms' option
        Click on Signatures next to chosen draft contract

        Expected Result:
        Displays list of signatures for the chosen contract.
        """
        self.ps.test_updates['name'] = 't1.35.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.007', '8234']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        wait = WebDriverWait(self.admin.driver, 45)
        self.admin.driver.find_element(
            By.XPATH, '//a[text()="Signatures"]').click()
        wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//div[contains(@class,"signature_index")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C8235 - 008 - Admin | Terminate a signatory's contract
    @pytest.mark.skipif(str(8235) not in TESTS, reason='Excluded')
    def test_admin_terminate_a_signnatorys_contract_8235(self):
        """Terminate a signatory's contract.

        Steps:
        Click on the 'Terms' option
        Click on Signatures next to chosen draft contract
        Click on Terminate next to chosen user
        Click on the 'ok' button

        Expected Result:
        Selected user's signing of contract is terminated.
        """
        self.ps.test_updates['name'] = 't1.35.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.008', '8235']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH, '//a[text()="Signatures"]').click()
        # is it okay to just terminate some random person's signature
        wait = WebDriverWait(self.admin.driver, 45)
        wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//td//a[contains(text(),"Terminate")]')
            )
        ).click()
        try:
            WebDriverWait(self.admin.driver, 3). \
                until(expect.alert_is_present(),
                      'Timed out waiting for PA creation ' +
                      'confirmation popup to appear.')
            alert = self.admin.driver.switch_to_alert()
            alert.accept()
            print('alert accepted')
        except TimeoutException:
            print('no alert')

        self.ps.test_updates['passed'] = True

    # Case C8236 - 009 - Admin | Add a targeted contract
    @pytest.mark.skipif(str(8236) not in TESTS, reason='Excluded')
    def test_admin_add_a_targeted_contract_8236(self):
        """Add a targeted contract.

        Steps:
        Click on the 'Targeted Contracts' option
        Click on the 'Add Target Contract' button
        Click the 'Submit' button

        Expected Result:
        User taken back to Targeted contracts page.
        New Targeted Contract is added
        """
        self.ps.test_updates['name'] = 't1.35.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.009', '8236']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Targeted Contracts")]')
            )
        ).click()
        orig_contracts = self.admin.driver.find_elements(By.XPATH, '//tr')
        self.admin.driver.find_element(
            By.XPATH, '//a[text()="Add Targeted Contract"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Submit"]').click()
        end_contracts = self.admin.driver.find_elements(By.XPATH, '//tr')
        assert(len(orig_contracts) == len(end_contracts)-1), \
            'targeted contract not added'

        self.ps.test_updates['passed'] = True

    # Case C8237 - 010 - Admin | Delete a targeted contract
    @pytest.mark.skipif(str(8237) not in TESTS, reason='Excluded')
    def test_admin_delete_a_targeted_contract_8237(self):
        """Delete a targeted contract.

        Steps:
        Click on the user's name in the top right corner to open drop down menu
        Click on the 'Admin' option of the drop down menu
        Click on 'Legal' on the bar across the top to open drop down menu
        Click on the 'Targeted Contracts' option
        Create a targeted contract and return to the list of targed contracts
        Click on delete next to chosen contract
        Click on the 'ok' button

        Expected Result:
        Targeted contract is deleted
        """
        self.ps.test_updates['name'] = 't1.35.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.010', '8237']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Targeted Contracts")]')
            )
        ).click()
        orig_contracts = self.admin.driver.find_elements(By.XPATH, '//tr')
        # create contract
        self.admin.driver.find_element(
            By.XPATH, '//a[text()="Add Targeted Contract"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Submit"]').click()
        # delete contract
        deletes = self.admin.driver.find_elements(
            By.XPATH, '//a[contains(text(),"delete")]')
        deletes[-1].click()
        try:
            WebDriverWait(self.admin.driver, 3).until(
                expect.alert_is_present(),
                'Timed out waiting for alert.'
            )
            alert = self.admin.driver.switch_to_alert()
            alert.accept()
            print('alert accepted')
        except TimeoutException:
            print('no alert')

        end_contracts = self.admin.driver.find_elements(By.XPATH, '//tr')
        assert(len(orig_contracts) == len(end_contracts)), \
            'targeted contract not added'

        self.ps.test_updates['passed'] = True

    # Case C8389 - 011 - Admin | Edit a draft contract
    @pytest.mark.skipif(str(8389) not in TESTS, reason='Excluded')
    def test_admin_edit_a_draft_contract_8389(self):
        """Edit a draft contract.

        Steps:
        Click on the 'Terms' option
        Create a new contract and return to list of contracts
        Click on Edit next to chosen draft contract
        Enter new information into the Name, Title, and Content text boxes
        Click on the 'Update Contract' button

        Expected Result:
        User is taken to Details page for selected contract.
        """
        self.ps.test_updates['name'] = 't1.35.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.35', 't1.35.011', '8389']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Terms")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"links")]/a[text()="New Contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[text()="New Contract"]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('test_contract_name_011')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('test_contract_title_011')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('test_contract_content_011')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Create contract"]').click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="List"]')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[contains(text(),"test_contract_title_011")]')
            )
        ).click()
        self.admin.sleep(1)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="Edit"]')
            )
        ).click()
        self.admin.sleep(1)
        self.admin.driver.find_element(
            By.ID, 'contract_name').send_keys('_New')
        self.admin.driver.find_element(
            By.ID, 'contract_title').send_keys('_New')
        self.admin.driver.find_element(
            By.ID, 'contract_content').send_keys('_New')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Update contract"]').click()
        self.admin.sleep(1)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//h2[contains(text(),"test_contract_title_011_New")]')
            )
        )

        self.ps.test_updates['passed'] = True
class TestTeacherViews(unittest.TestCase):
    """CC1.13 - Teacher Views."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C7609 - 001 - Teacher | View the Concept Coach dashboard
    @pytest.mark.skipif(str(7609) not in TESTS, reason='Excluded')
    def test_teacher_view_the_concept_coach_dashboard_7609(self):
        """View the Concept Coach dashboard.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name

        Expected Result:
        The user is presented with the Concept Coach dashbaord
        """
        self.ps.test_updates['name'] = 'cc1.13.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.001', '7609']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        assert('cc-dashboard' in self.teacher.current_url()), \
            'not at Concept Coach Dashboard'

        self.ps.test_updates['passed'] = True

    # Case C7610 - 002 - Teacher | Switch between concurrently running courses
    @pytest.mark.skipif(str(7610) not in TESTS, reason='Excluded')
    def test_teacher_switch_between_concurrently_running_courses_7610(self):
        """Able to switch between concurrently running courses.

        Steps:
        Click on the OpenStax logo in the left corner of the header

        Expected Result:
        The user is presented with a list of Concept Coach courses
        Is able to switch to another course
        """
        self.ps.test_updates['name'] = 'cc1.13.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.002', '7610']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        url1 = self.teacher.current_url().split('courses')[1]
        self.teacher.driver.find_element(
            By.XPATH, '//a//i[@class="ui-brand-logo"]'
        ).click()
        try:
            self.teacher.driver.find_element(
                By.XPATH,
                '//a[contains(@href,"/cc-dashboard") ' +
                'and not(contains(@href,"'+str(url1)+'"))]'
            ).click()
        except NoSuchElementException:
            print('Only one CC course, cannot go to another')
            raise Exception
        assert('cc-dashboard' in self.teacher.current_url()), \
            'not at Concept Coach Dashboard'
        assert(url1 != self.teacher.current_url()), \
            'went to same course'

        self.ps.test_updates['passed'] = True

    # Case C7611 - 003 - Teacher | View links on dashboard to course materials
    @pytest.mark.skipif(str(7611) not in TESTS, reason='Excluded')
    def test_teacher_view_links_on_dashboard_to_course_materials_7611(self):
        """View links on dashboard to course materials.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name

        Expected Result:
        On header there is a link to 'Homework PDF', and 'Online Book'
        """
        self.ps.test_updates['name'] = 'cc1.13.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.003', '7611']
        self.ps.test_updates['passed'] = False

        # HW pdf
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Homework PDF")]'
        ).click()
        coursename = self.teacher.driver.find_element(
            By.XPATH, '//div[@class="cc-dashboard"]/div'
        ).get_attribute('data-appearance')
        coursename = coursename.replace('_', '-')
        home = os.getenv("HOME")
        files = os.listdir(home + '/Downloads')
        for i in range(len(files)):
            if (coursename in files[i]) and (files[i][-4:] == '.pdf'):
                break
            else:
                if i == len(files)-1:
                    raise Exception
        # online book
        self.teacher.driver.find_element(
            By.XPATH, '//a//span[contains(text(),"Online Book")]'
        ).click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        assert('cnx' in self.teacher.current_url()), \
            'Not viewing the textbook PDF'
        self.teacher.driver.switch_to_window(
            self.teacher.driver.window_handles[0])
        # assignment links
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Assignment Links")]'
        ).click()
        assert('assignment-links' in self.teacher.current_url()), \
            'not viewing Assignment Links'

        self.ps.test_updates['passed'] = True

    # Case C7612 - 004 - Teacher | Able to copy a system-generated message
    # with a student code, links, and other information
    @pytest.mark.skipif(str(7612) not in TESTS, reason='Excluded')
    def test_able_to_copy_a_system_generated_message_with_a_student_7612(self):
        """Copy a system-generated message with a student code, links, etc.

        Steps:
        Click on the user menu in the right corner of the header
        Click "Course Roster"
        Click "Get Student Enrollment Code"
        Copy the system generated message

        Expected Result:
        The user is able to copy the system generated message
        """
        self.ps.test_updates['name'] = 'cc1.13.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.004', '7612']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Course Settings and Roster")]'
        ).click()
        self.teacher.driver.find_element(
            By.XPATH, '//span[contains(text(),"student enrollment code")]'
        ).click()
        self.teacher.driver.find_element(
            By.XPATH,
            '//*[contains(text(),"Send the following enrollment instruction")]'
        )

        element = self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"enrollment-code-modal")]'
        )
        element.find_element(
            By.XPATH,
            './/*[contains(text(),"To register for Concept Coach:")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7613 - 005 - Teacher | Periods are relabeled as sections for all
    # courses
    @pytest.mark.skipif(str(7613) not in TESTS, reason='Excluded')
    def test_teacher_periods_are_relabeled_as_sections_for_all_cour_7613(self):
        """Period is relabeled as section for college courses.

        Steps:
        Go to user menu
        Click on course roster
        Check that there is an '+ add section' button instead
            of an '+ add period' button

        Expected Result:
        There is an '+ add section' button instead of an '+ add period' button
        """
        self.ps.test_updates['name'] = 'cc1.13.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.005', '7613']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Course Settings and Roster")]'
        ).click()
        self.teacher.driver.find_element(
            By.XPATH,
            '//li[contains(@class,"add-period")]//span[text()="Section"]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7614 - 006 - Teacher | View a score report
    @pytest.mark.skipif(str(7614) not in TESTS, reason='Excluded')
    def test_teacher_view_a_score_report_7614(self):
        """View a score report.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"

        Expected Result:
        The user is presented with a score report
        """
        self.ps.test_updates['name'] = 'cc1.13.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.006', '7614']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7615 - 007 - Teacher | View a report showing an individual
    # student's work pages
    @pytest.mark.skipif(str(7615) not in TESTS, reason='Excluded')
    def test_teacher_view_a_report_showing_an_individual_students_7615(self):
        """View a report showing an individual student's work pages.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Click on the percentage in the "Score" column

        Expected Result:
        Individual student's work is shown
        """
        self.ps.test_updates['name'] = 'cc1.13.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.007', '7614']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"scores-cell")]' +
            '/div[@class="score"]'
        ).click()
        assert('steps' in self.teacher.current_url()), \
            "Not taken to individual student's work for assignment"

        self.ps.test_updates['passed'] = True

    # Case C7616 - 008 - Teacher | View a summary report showing a class's work
    # pages
    @pytest.mark.skipif(str(7616) not in TESTS, reason='Excluded')
    def test_teacher_view_a_summary_report_showing_a_class_work_pag_7616(self):
        """View a summary report showing a class's work pages.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Click on the desired period tab

        Expected Result:
        The user is presented with a summary report
        """
        self.ps.test_updates['name'] = 'cc1.13.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.008', '7616']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        periods = self.teacher.driver.find_elements(
            By.XPATH, '//span[contains(@class,"tab-item-period-name")]'
        )
        for period in periods:
            period.click()

        self.ps.test_updates['passed'] = True

    # Case C7617 - 009 - Teacher | View the aggregate student scores
    @pytest.mark.skipif(str(7617) not in TESTS, reason='Excluded')
    def test_teacher_view_the_aggregate_student_scores_7617(self):
        """View the aggregate student scores.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"

        Expected Result:
        The user is presented with Student scores
        """
        self.ps.test_updates['name'] = 'cc1.13.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.009', '7617']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH, '//div[contains(@class,"course-scores-container")]')

        self.ps.test_updates['passed'] = True

    # Case C7618 - 010 - Teacher | View scores for an individual student's
    # scores
    @pytest.mark.skipif(str(7618) not in TESTS, reason='Excluded')
    def test_teacher_view_scores_for_an_individual_student_scores_7618(self):
        """View scores for an individual student's scores.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Scroll to the desired student

        Expected Result:
        The user is presented with scores for an individual student
        """
        self.ps.test_updates['name'] = 'cc1.13.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.010', '7618']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"name-cell")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7619 - 011 - Teacher | View an individual student's question set
    # for an assignment
    @pytest.mark.skipif(str(7619) not in TESTS, reason='Excluded')
    def test_teacher_view_an_individual_student_question_set_7619(self):
        """View an individual student's question set for an assignment.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Click on a student's score for the desired assignment

        Expected Result:
        The user is presented with a student's question set for the assignment
        """
        self.ps.test_updates['name'] = 'cc1.13.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.011', '7619']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"scores-cell")]' +
            '/div[@class="score"]'
        ).click()
        breadcrumbs = self.teacher.driver.find_elements(
            By.XPATH, '//span[contains(@class,"openstax-breadcrumbs-")]'
        )
        for i in range(len(breadcrumbs)-1):
            self.teacher.driver.find_element(
                By.XPATH,
                '//span[contains(@class,"openstax-breadcrumbs-")' +
                'and contains(@data-reactid,"step-' + str(i) + '")]'
            ).click()

        self.ps.test_updates['passed'] = True

    # Case C7620 - 012 - Teacher | View an assignment summary
    @pytest.mark.skipif(str(7620) not in TESTS, reason='Excluded')
    def test_teacher_view_an_assignment_summary_7620(self):
        """View an assignment summary.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Click on a student's score for the desired assignment
        Click "Summary"

        Expected Result:
        The user is presented with an assignmnent summary
        """
        self.ps.test_updates['name'] = 'cc1.13.012' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.012', '7620']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"scores-cell")]' +
            '/div[@class="score"]'
        ).click()
        self.teacher.driver.find_element(
            By.XPATH,
            '//span[contains(@class,"openstax-breadcrumbs-")' +
            'and contains(@data-reactid,"-end-")]'
        ).click()
        self.teacher.sleep(0.5)
        breadcrumbs_answered = self.teacher.driver.find_elements(
            By.XPATH,
            '//span[contains(@class,"openstax-breadcrumbs-")' +
            'and contains(@class,"completed")]'
        )
        question_cards = self.teacher.driver.find_elements(
            By.XPATH, '//div[contains(@class,"openstax-exercise-card")]'
        )
        assert(len(question_cards) == len(breadcrumbs_answered)), \
            'all answered questions not in summary'

        self.ps.test_updates['passed'] = True

    # Case C7622 - 013 - Teacher | Download student scores
    @pytest.mark.skipif(str(7622) not in TESTS, reason='Excluded')
    def test_teacher_download_student_scores_7622(self):
        """Download student scores.

        Steps:
        Click the user menu in the right corner of the header
        Click "Student Scores"
        Click "Export"

        Expected Result:
        Student scores are downloaded in an excel spreadsheet
        """
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH, '//div[contains(@class,"export-button")]//button'
        ).click()
        # wait for it to export. It says generating when still not done
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[contains(@class,"export-button")]//button' +
                 '//span[text()="Export"]')
            )
        )
        # check that it was downloaded
        coursename = self.teacher.driver.find_element(
            By.XPATH, '//div[@class="course-name"]').text
        coursename = coursename.replace(' ', '_') + "_Scores"
        home = os.getenv("HOME")
        files = os.listdir(home + '/Downloads')
        for i in range(len(files)):
            if (coursename in files[i]) and (files[i][-5:] == '.xlsx'):
                break
            else:
                if i == len(files)-1:
                    raise Exception

        self.ps.test_updates['passed'] = True

    # Case C7624 - 014 - Teacher | Exercise IDs are shown for each assessment
    @pytest.mark.skipif(str(7624) not in TESTS, reason='Excluded')
    def test_teacher_exercise_ids_are_shown_for_each_assessment_7624(self):
        """Exercise IDs are shown for each assessment.

        Steps:
        Click the user menu in the right corner of the header
        Click "Question Library"
        Select a chapter
        Click "Show Questions"

        Expected Result:
        Exercise IDs are shown for each assessment in the bottom right hand
        corner of the box holding the question.
        """
        self.ps.test_updates['name'] = 'cc1.13.014' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.13', 'cc1.13.014', '7624']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(text(),"Student Scores")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Student Scores"]')
            )
        )
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[contains(@class,"scores-cell")]' +
            '/div[@class="score"]'
        ).click()
        breadcrumbs = self.teacher.driver.find_elements(
            By.XPATH, '//span[contains(@class,"openstax-breadcrumbs-")]'
        )
        for i in range(len(breadcrumbs)-1):
            self.teacher.driver.find_element(
                By.XPATH,
                '//span[contains(@class,"exercise-identifier-link")]' +
                '//span[contains(text(),"ID")]'
            )
            self.teacher.driver.find_element(
                By.XPATH,
                '//span[contains(@class,"openstax-breadcrumbs-")' +
                'and contains(@data-reactid,"step-' + str(i) + '")]'
            ).click()

        self.ps.test_updates['passed'] = True
class TestCreateNewQuestionAndAssignmentTypes(unittest.TestCase):
    """T2.12 - Create New Question and Assignment Types."""

    def setUp(self):
        """Pretest settings."""

        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student = Student(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        self.student = None
        try:
            self.teacher.delete()
        except:
            pass

    # 14739 - 001 - Teacher | Vocabulary question is a question type
    @pytest.mark.skipif(str(14739) not in TESTS, reason='Excluded')
    def test_teacher_vocabulary_question_is_a_question_type_14739(self):
        """Vocabulary question is a question type.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher account in the username and password text boxes
        Click on the 'Sign in' button
        Click "Write a new exercise"
        Click "New Vocabulary Term"

        Expected Result:
        The user is presented with a page where a new vocabulary question can
        be created
        """
        self.ps.test_updates['name'] = 't2.12.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.12', 't2.12.001', '14739']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get("https://exercises-qa.openstax.org/")
        # login
        self.teacher.find(
            By.XPATH, '//div[@id="account-bar-content"]//a[text()="Sign in"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'auth_key'
        ).send_keys(self.teacher.username)
        self.teacher.find(
            By.ID, 'password'
        ).send_keys(self.teacher.password)
        self.teacher.find(
            By.XPATH, '//button[text()="Sign in"]'
        ).click()
        # create new vocab
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//a[@href="/exercises/new"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//a[text()="New Vocabulary Term"]')
            )
        ).click()
        assert('/vocabulary/new' in self.teacher.current_url()), \
            'not at new vocab page'

        self.ps.test_updates['passed'] = True

    # 14741 - 002 - Teacher | True/False is a question type
    @pytest.mark.skipif(str(14741) not in TESTS, reason='Excluded')
    def test_teacher_truefalse_is_a_question_type_14741(self):
        """True/False is a question type.

        Steps:
        Click "Write a new exercise"
        Click on the "True/False" radio button

        Expected Result:
        The user is presented with a page where a True/False question can be
        created
        """
        self.ps.test_updates['name'] = 't2.12.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.12', 't2.12.002', '14741']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get("https://exercises-qa.openstax.org/")
        # login
        self.teacher.find(
            By.XPATH, '//div[@id="account-bar-content"]//a[text()="Sign in"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'auth_key'
        ).send_keys(self.teacher.username)
        self.teacher.find(
            By.ID, 'password'
        ).send_keys(self.teacher.password)
        self.teacher.find(
            By.XPATH, '//button[text()="Sign in"]'
        ).click()
        # create new vocab
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//a[@href="/exercises/new"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//input[@label="True/False"]')
            )
        ).click()
        self.teacher.find(
            By.XPATH, '//span[text()="True/False"]'
        )
        self.ps.test_updates['passed'] = True

    # possibly changed implementation on site
    # no info icon found
    # 14742 - 003 - System | Display embedded videos with attribution and link
    # back to author
    @pytest.mark.skipif(str(14742) not in TESTS, reason='Excluded')
    def test_system_display_embedded_videos_with_attribution_14742(self):
        """Display embedded videos with attribution and a link back to author.

        Steps:
        Go to Tutor
        Click Login
        Sign in as student01
        Click "HS AP Physics LG"
        Click on a homework assignment
        Click through it until you get to a video
        Click on the info icon on the video

        Expected Result:
        Attribution and links are displayed
        """
        self.ps.test_updates['name'] = 't2.12.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.12', 't2.12.003', '14742']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # NOT DONE
    # create hw helper still not working
    # but works for manually created assignemnt, add assignemnt commented out
    # 14743 - 004 - Teacher | Each part of a multi-part question counts as a
    # seperate problem when scored
    @pytest.mark.skipif(str(14743) not in TESTS, reason='Excluded')
    def test_teacher_each_part_of_a_multipart_question_counts_as_14743(self):
        """Multi-part questions count as seperate problems when scored.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Log in as teacher03
        Click "College Introduction to Sociology"
        Go to "Student Scores"
        Pick a homework that has multipart question
        Click "Review"

        Expected Result:
        There is a breadcrumb for each part of a multipart question
        """
        self.ps.test_updates['name'] = 't2.12.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.12', 't2.12.004', '14743']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        # create a hw with a multi part question, and gice it a randomized name
        # ID: 12061@6 is multi part
        self.teacher.login()
        self.teacher.find(
            By.XPATH,
            '//div[@data-appearance="intro_sociology"]' +
            '//a[not(contains(@href,"/cc-dashboard"))]'
        ).click()
        assignment_name = "homework-%s" % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=0)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=100)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='homework',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'problems': {'1.1': ['12024@10'], },
                'status': 'publish',
            }
        )
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Student Scores'
        ).click()
        self.teacher.page.wait_for_page_load()
        # can just click the first review because assignemnt just created
        # and should be the most recent one
        self.teacher.find(
            By.LINK_TEXT, 'Review'
        ).click()
        cards = self.teacher.find_all(
            By.XPATH, '//div[contains(@class,"card-body")]')
        questions = self.teacher.find_all(
            By.XPATH, '//div[contains(@class,"openstax-question")]')
        breadcrumbs = self.teacher.find_all(
            By.XPATH, '//span[contains(@class,"openstax-breadcrumb")]')
        assert(len(questions) == len(breadcrumbs)), \
            'breadcrumbs and questions not equal'
        assert(len(cards) < len(breadcrumbs)), \
            'multipart question card has multiple questions,' + \
            'not matching up with  breadcrumbs'

        self.ps.test_updates['passed'] = True

    # NOT DONE
    # same issue as above w/ add_homework helper
    # but works for manually created assignemnt
    # (add assignemnt gets commented out, manual assignemnt name added)
    # 14744 - 005 - Student | Each part of a multi-part question counts as a
    # seperate problem when scored
    @pytest.mark.skipif(str(14744) not in TESTS, reason='Excluded')
    def test_student_each_part_of_a_multipart_question_counts_as_14744(self):
        """Multi-part questions count as seperate problems when scored.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Log in as abarnes
        Click "College Introduction to Sociology"
        Click on a homework assignment
        Go through the questions

        Expected Result:
        There is a breadcrumb for each part in the multipart question and the
        progress/score is out of the total number of questions, rather than
        counting the multipart question as one question
        """
        self.ps.test_updates['name'] = 't2.12.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.12', 't2.12.005', '14744']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        # create a hw with a multi part question, and give it a randomized name
        # ID: 12252@5 is multi part
        self.teacher.login()
        self.teacher.find(
            By.XPATH,
            '//div[@data-appearance="intro_sociology"]' +
            '//a[not(contains(@href,"/cc-dashboard"))]'
        ).click()
        assignment_name = "homework-%s" % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=0)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=100)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='homework',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'problems': {'1.1': ['12024@10'], },
                'status': 'publish',
            }
        )
        self.teacher.logout()
        # assignemnt name put here for manual testing
        # assignment_name = 'hw w/ video and multi part question'
        # login as student and go to same class
        self.student.login()
        self.teacher.find(
            By.XPATH,
            '//div[@data-appearance="intro_sociology"]' +
            '//a[not(contains(@href,"/cc-dashboard"))]'
        ).click()
        self.student.page.wait_for_page_load()
        # go to assignment (find my assignemnt_name)
        self.student.find(
            By.XPATH,
            '//a[contains(@class,"homework workable")]' +
            '//span[text()="' + assignment_name + '"]'
        ).click()
        # go through all questions
        breadcrumbs = self.teacher.find_all(
            By.XPATH,
            '//span[contains(@class,"openstax-breadcrumb")' +
            ' and not(contains(@class,"intro"))' +
            ' and not(contains(@class,"personalized"))'
            ' and not(contains(@class,"end"))]')
        total_questions = 0
        found_multipart = False
        i = 0
        while i < len(breadcrumbs):
            breadcrumbs[i].click()
            try:
                self.student.find(
                    By.XPATH, '//span[text()="Multi-part question"]')
                found_multipart = True
                questions = self.teacher.find_all(
                    By.XPATH, '//div[contains(@class,"openstax-question")]')
                total_questions += len(questions)
                i += len(questions)
            except NoSuchElementException:
                i += 1
                questions = self.teacher.find_all(
                    By.XPATH, '//div[contains(@class,"openstax-question")]')
                total_questions += len(questions)
        # check that everything worked out
        assert(found_multipart), 'no multipart question found'
        assert(total_questions == len(breadcrumbs)), \
            'breadcrumbs and questions not equal'

        self.ps.test_updates['passed'] = True
class TestDeliveringAssignments(unittest.TestCase):
    """CC1.12 - Delivering Assignments."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.student = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.student.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.student.delete()
        except:
            pass

    # Case C7738 - 001 - System | PDF is available for download for
    # CC derived copy
    @pytest.mark.skipif(str(7738) not in TESTS, reason='Excluded')
    def test_system_pdf_is_available_for_download_7738(self):
        """PDF is available for download for a Concept Coach derived copy.

        Steps:
        got to https://cnx.org/
        select a textbook
        Scroll to the bottom of the page
        Click on the 'Downloads' button
        Click on the 'PDF' link
        Click on 'Download for Free'

        Expected Result:
        The book is downloaded as a PDF.
        """
        self.ps.test_updates['name'] = 'cc1.12.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.001', '7738']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.driver.get('https://cnx.org/')
        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"book")]/a/img')

            )
        ).click()
        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"media-header")]')
            )
        )
        self.student.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.student.driver.find_element(
            By.XPATH, '//div[@class="media-footer"]//li[@id="downloads-tab"]'
        ).click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="downloads tab-content"]' +
                 '//td//a[contains(text(),".pdf")]')
            )
        ).click()
        self.student.page.wait_for_page_load()
        element = self.student.driver.find_element(
            By.XPATH,
            '//a[contains(text(),"Download for Free")]'
        )
        coursename = element.get_attribute('href')
        coursename = coursename.split('/')[-1]
        element.click()
        self.student.sleep(1)
        # check that it was downloaded
        home = os.getenv("HOME")
        print(home + '/Downloads' + coursename)
        os.path.isfile(home + '/Downloads' + coursename)

        self.ps.test_updates['passed'] = True

    # Case C7741 - 002 - System | Webview table of contents matches the PDF
    # numbering
    @pytest.mark.skipif(str(7741) not in TESTS, reason='Excluded')
    def test_system_webview_table_of_contents_matches_the_pdf_numbe_7741(self):
        """Webview table of contents matches the PDF numbering.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the student user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name
        Click the 'Online Book' button
        Return to initial tab/window with tutor
        Click on 'HW PDF' -- a pdf will be downloaded

        Expected Result:
        The table of content numberings match between the web view and PDF.
        """
        self.ps.test_updates['name'] = 'cc1.12.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.002', '7741']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C7742 - 003 - Student | Find the CC book from an online search
    @pytest.mark.skipif(str(7742) not in TESTS, reason='Excluded')
    def test_student_find_the_cc_book_from_an_online_search_7742(self):
        """Find the Concept Coach book from an online search.

        Steps:
        Search the title of the book, with 'openstax' through a search engine

        Expected Result:
        The search returns a link to the book
        """
        self.ps.test_updates['name'] = 'cc1.12.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.003', '7742']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.driver.get('https://www.google.com')
        self.student.page.wait_for_page_load()
        actions = ActionChains(self.student.driver)
        actions.send_keys('openstax concept coach biology')
        actions.send_keys(Keys.RETURN)
        actions.perform()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//a[contains(text(),"Biology with Concept Coach")]')
            )
        )
        self.student.driver.find_element(
            By.XPATH, '//cite[contains(text(),"https://cnx.org/")]')

        self.ps.test_updates['passed'] = True

    # Case C7743 - 004 - Student | Find the Concept Coach book from CNX
    @pytest.mark.skipif(str(7743) not in TESTS, reason='Excluded')
    def test_student_find_the_cc_book_from_cnx_7743(self):
        """Find the Concept Coach book from CNX.

        Steps:
        Go to CNX
        Click search
        Click Advance Search
        Search the name of the book in the title text box
        (include 'with Concept Coach' in the search)

        Expected Result:
        The book is displayed in the results
        """
        self.ps.test_updates['name'] = 'cc1.12.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.004', '7743']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.driver.get('https://cnx.org/browse')
        self.student.page.wait_for_page_load()
        self.student.driver.find_element(
            By.XPATH, '//a[contains(text(),"Search") and @href="/browse"]'
        ).click()
        self.student.page.wait_for_page_load()
        self.student.driver.find_element(
            By.XPATH, '//a[contains(@class,"advanced-search btn")]'
        ).click()
        self.student.page.wait_for_page_load()
        self.student.driver.find_element(
            By.XPATH, '//input[@name="title"]'
        ).send_keys('Biology with Concept Coach')
        self.student.driver.find_element(
            By.XPATH, '//button[@type="submit"]'
        ).click()
        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//td//a[contains(text(),"Biology with Concept Coach")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7746 - 005 - User | View the chapter and section number before the
    # CNX page module title
    @pytest.mark.skipif(str(7746) not in TESTS, reason='Excluded')
    def test_user_view_the_chapter_and_section_number_before_cnx_7746(self):
        """View the chapter and section number before the CNX page module title.

        Steps:
        Go to a Concept Coach book
        If the contents is not already open, Click on contents
        Click on a chapter
        Click on a section

        Expected Result:
        The chapter and section appear before the name of the module.
        """
        self.ps.test_updates['name'] = 'cc1.12.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.005', '7746']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.driver.get('https://cnx.org/')
        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"book")]/a/img')

            )
        ).click()
        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"media-header")]')
            )
        )
        self.student.driver.find_element(
            By.XPATH,
            '//div[@class="media-toolbar"]' +
            '//button[contains(@class,"toggle")]' +
            '//span[contains(text(),"Contents")]'
        ).click()
        self.student.sleep(0.5)
        self.student.driver.find_element(
            By.XPATH, '//span[@class="chapter-number" and text()="1.1"]'
        ).click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[@class="title-chapter" and text()="1.1"]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7747 - 006 - System | Display correct PDF numbering when the print
    # style is CCAP
    @pytest.mark.skipif(str(7747) not in TESTS, reason='Excluded')
    def test_system_display_correct_pdf_numbering_when_the_print_7747(self):
        """Display correct PDF numbering when the print style is CCAP.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.12.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.12', 'cc1.12.006', '7747']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestGuideMonitorSupportAndTrainUsers(unittest.TestCase):
    """T2.18 - Guide, Monitor, Support, and Train Users."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities["name"] = self.id()
        self.teacher = Teacher(use_env_vars=True, pasta_user=self.ps, capabilities=self.desired_capabilities)

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(job_id=str(self.teacher.driver.session_id), **self.ps.test_updates)
        try:
            self.teacher.delete()
        except:
            pass

    # 14752 - 001 - User | In-app Notification of downtime
    @pytest.mark.skipif(str(14752) not in TESTS, reason="Excluded")
    def test_user_inapp_notification_of_downtime_14752(self):
        """In-app Notification of downtime.

        Steps:

        Go to Tutor
        Log in as admin
        Click "Admin" from the user menu
        Click "System Setting"
        Click "Notifications"
        Enter a new notification into the text box
        Click "Add"
        Log out of admin
        Log in as teacher01

        Expected Result:
        An orange header with the notification pops up when you sign in
        """
        self.ps.test_updates["name"] = "t2.18.001" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.001", "14752"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 14751 - 002 - Teacher | Directed to a "No Courses" page when not in any
    # courses yet
    @pytest.mark.skipif(str(14751) not in TESTS, reason="Excluded")
    def test_teacher_directed_to_a_no_courses_page_when_not_in_any_14751(self):
        """Directed to a "No Courses" page when not in any courses yet.

        Steps:
        Go to tutor-qa.openstax.org
        Sign in as demo_teacher; password

        Expected Result:
        The message "We cannot find an OpenStax course associated with your
        account" displays with help links below
        """
        self.ps.test_updates["name"] = "t2.18.002" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.002", "14751"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58279 - 003 - Teacher | View "Getting Started with Tutor" Guide
    @pytest.mark.skipif(str(58279) not in TESTS, reason="Excluded")
    def test_teacher_view_getting_started_with_tutor_guide_58279(self):
        """View "Getting Started with Tutor" Guide.

        Steps:
        Click "Tutor Instructors. Get help"

        Expected Result:
        Tutor Help Center opens in another tab with the Getting Started guide
        """
        self.ps.test_updates["name"] = "t2.18.003" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.003", "58279"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58280 - 004 - Teacher | Access Tutor Help Center after registering for
    # a course
    @pytest.mark.skipif(str(58280) not in TESTS, reason="Excluded")
    def test_teacher_access_tutor_help_center_after_registering_58280(self):
        """Access Tutor Help Center after registering for a course.

        Steps:
        Go to Tutor
        Sign in as teacher01
        Click on a Tutor course if the user is in more than one
        Click "Get Help" from the user menu in the upper right corner of the
            screen

        Expected Result:
        The user is presented with the Tutor Help Center
        """
        self.ps.test_updates["name"] = "t2.18.004" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.004", "58280"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58284 - 005 - Teacher | Submit a question
    @pytest.mark.skipif(str(58284) not in TESTS, reason="Excluded")
    def test_teacher_submit_a_question_58284(self):
        """Submit a question.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter

        Expected Result:
        The user is presented with search results
        """
        self.ps.test_updates["name"] = "t2.18.005" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.005", "58284"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58352 - 006 - Teacher | View "Contact Us" button after submitting a
    # question
    @pytest.mark.skipif(str(58352) not in TESTS, reason="Excluded")
    def test_teacher_view_contact_us_button_after_submitting_quest_58352(self):
        """View "Contact Us" button after submitting a question.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Scroll to the bottom of the screen

        Expected Result:
        "Contact Us" button exists
        """
        self.ps.test_updates["name"] = "t2.18.006" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.006", "58352"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58288 - 007 - Teacher | View an article after submitting a question
    @pytest.mark.skipif(str(58288) not in TESTS, reason="Excluded")
    def test_teacher_view_an_article_after_submitting_a_question_58288(self):
        """View an article after submitting a question.

        Steps:

        Click "Get Help" from the user menu in the upper right corner of the
        screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result

        Expected Result:
        The user is presented with an article containing answer to the question
        """
        self.ps.test_updates["name"] = "t2.18.007" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.007", "58288"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58313 - 008 - Teacher | Indicate that the article was helpful
    @pytest.mark.skipif(str(58313) not in TESTS, reason="Excluded")
    def test_teacher_indicate_that_the_article_was_helpful_58313(self):
        """Indicate that the article was helpful.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "Yes"

        Expected Result:
        A message that says "Thanks for your feedback!" is displayed
        """
        self.ps.test_updates["name"] = "t2.18.008" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.008", "58313"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58314 - 009 - Teacher | Negative feedback renders a feedback popup box
    @pytest.mark.skipif(str(58314) not in TESTS, reason="Excluded")
    def test_teacher_negative_feedback_renders_feedback_popup_box_58314(self):
        """Negative feedback renders a feedback popup box.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"

        Expected Result:
        The user is presented with a popup box that allows them to input
        feedback
        """
        self.ps.test_updates["name"] = "t2.18.009" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.009", "58314"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58315 - 010 - Teacher | Submit feedback for an article
    @pytest.mark.skipif(str(58315) not in TESTS, reason="Excluded")
    def test_teacher_submit_feedback_for_an_article_58315(self):
        """Submit feedback for an article.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        Enter feedback into the box that pops up
        Click "Submit"

        Expected Result:
        A message that says "Thanks for your feedback!" is displayed in the box
        """
        self.ps.test_updates["name"] = "t2.18.010" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.010", "58315"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58322 - 011 - Teacher | Close window after submitting feedback for an
    # article
    @pytest.mark.skipif(str(58322) not in TESTS, reason="Excluded")
    def test_teacher_close_window_after_submitting_feedback_for_58322(self):
        """Close window after submitting feedback for an article.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        Enter feedback into the box that pops up
        Click "Submit"
        Click "Close window"

        Expected Result:
        The popup box closes and the message "Thanks for your feedback"
        displays beneath "Feedback"
        """
        self.ps.test_updates["name"] = "t2.18.011" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.011", "58322"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58316 - 012 - Teacher | Cancel feedback
    @pytest.mark.skipif(str(58316) not in TESTS, reason="Excluded")
    def test_teacher_cancel_feedback_before_making_changes_58316(self):
        """Cancel feedback.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        [optional] Enter feedback into the text box
        Click "Cancel"

        Expected Result:
        The popup box closes
        """
        self.ps.test_updates["name"] = "t2.18.012" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.012", "58316"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58318 - 013 - Teacher | View related articles
    @pytest.mark.skipif(str(58318) not in TESTS, reason="Excluded")
    def test_teacher_view_related_articles_58318(self):
        """View related articles.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Related Articles"
        Click on one of the articles (if any)

        Expected Result:
        The user is presented with the related article
        """
        self.ps.test_updates["name"] = "t2.18.013" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.013", "58318"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58319 - 014 - Teacher | Submit a question to Customer Support
    @pytest.mark.skipif(str(58319) not in TESTS, reason="Excluded")
    def test_teacher_submit_a_question_to_customer_support_58319(self):
        """Submit a question to Customer Support.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        CLick "Search" or press enter
        Click on a search result
        Scroll to the bottom of the page
        CLick "Contact Us"
        Fill out the required fields
        Enter "Submit"

        Expected Result:
        The message "Thank you for your message! We'll be back to you within
        one business day" is displayed
        """
        self.ps.test_updates["name"] = "t2.18.014" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.014", "58319"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 14755 - 015 - Teacher | View guided tutorials of Tutor
    @pytest.mark.skipif(str(14755) not in TESTS, reason="Excluded")
    def test_teacher_view_guided_tutorials_of_concept_coach_14755(self):
        """View guided tutorials of Tutor.

        Steps:


        Expected Result:

        """
        self.ps.test_updates["name"] = "t2.18.015" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.015", "14755"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 14750 - 016 - Student | Directed to a "No Courses" page when not in any
    # courses yet
    @pytest.mark.skipif(str(14750) not in TESTS, reason="Excluded")
    def test_student_directed_to_a_no_courses_page_when_not_in_any_14750(self):
        """Directed to a "No Courses" page when not in any courses yet.

        Steps:
        Go to Tutor
        Log in as qa_student_37003

        Expected Result:
        The message "We cannot find an OpenStax course associated with your
        account" displays with help links
        """
        self.ps.test_updates["name"] = "t2.18.016" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.016", "14750"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58336 - 017 - Student | View "Getting Started with Tutor" Guide
    @pytest.mark.skipif(str(58336) not in TESTS, reason="Excluded")
    def test_student_view_getting_started_with_tutor_guide_58336(self):
        """View "Getting Started with Tutor" Guide.

        Steps:
        Click "Tutor Students. Get help"

        Expected Result:
        Tutor Help Center opens in another tab with the Getting Started guide
        """
        self.ps.test_updates["name"] = "t2.18.017" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.017", "58336"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58337 - 018 - Student | Access Tutor Help Center after registering for a
    # course
    @pytest.mark.skipif(str(58337) not in TESTS, reason="Excluded")
    def test_student_access_tutor_help_center_after_registering_58337(self):
        """Access Tutor Help Center after registering for a course.

        Steps:
        Go to Tutor
        Sign in as student01
        Click on a Tutor course if the user is in more than one
        Click "Get Help" from the user menu in the upper right corner of the
            screen

        Expected Result:
        The user is presented with the Tutor Help Center
        """
        self.ps.test_updates["name"] = "t2.18.018" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.018", "58337"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58338 - 019 - Student | Submit a question
    @pytest.mark.skipif(str(58338) not in TESTS, reason="Excluded")
    def test_student_submit_a_question_58338(self):
        """Submit a question.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter

        Expected Result:
        The user is presented with search results
        """
        self.ps.test_updates["name"] = "t2.18.019" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.019", "58338"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58353 - 020 - Student | View "Contact Us" button after submitting a
    # question
    @pytest.mark.skipif(str(58353) not in TESTS, reason="Excluded")
    def test_student_view_contact_us_button_after_submitting_quest_58353(self):
        """View "Contact Us" button after submitting a question.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Scroll to the bottom of the page

        Expected Result:
        "Contact Us" button exists
        """
        self.ps.test_updates["name"] = "t2.18.020" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.020", "58353"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58339 - 021 - Student | View an article after submitting a question
    @pytest.mark.skipif(str(58339) not in TESTS, reason="Excluded")
    def test_student_view_an_article_after_submitting_a_question_58339(self):
        """View an article after submitting a question.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result

        Expected Result:
        The user is presented with an article containing answer to the question
        """
        self.ps.test_updates["name"] = "t2.18.021" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.021", "58339"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58340 - 022 - Student | Indicate that the article was helpful
    @pytest.mark.skipif(str(58340) not in TESTS, reason="Excluded")
    def test_student_indicate_that_the_article_was_helpful_58340(self):
        """Indicate that the article was helpful.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "Yes"

        Expected Result:
        A message that says "Thanks for your feedback!" is displayed
        """
        self.ps.test_updates["name"] = "t2.18.022" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.022", "58340"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58341 - 023 - Student | Negative feedback renders a feedback popup box
    @pytest.mark.skipif(str(58341) not in TESTS, reason="Excluded")
    def test_student_negative_feedback_renders_feedback_popup_box_58341(self):
        """Negative feedback renders a feedback popup box.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"

        Expected Result:
        The user is presented with a popup box that allows them to input
        feedback
        """
        self.ps.test_updates["name"] = "t2.18.023" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.023", "58341"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58342 - 024 - Student | Submit feedback for an article
    @pytest.mark.skipif(str(58342) not in TESTS, reason="Excluded")
    def test_student_submit_feedback_for_an_article_58342(self):
        """Submit feedback for an article.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        Enter feedback into the box that pops up
        Click "Submit"

        Expected Result:
        A message that says "Thanks for your feedback!" is displayed in the box
        """
        self.ps.test_updates["name"] = "t2.18.024" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.024", "58342"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58343 - 025 - Student | Close window after submitting feedback for an
    # article
    @pytest.mark.skipif(str(58343) not in TESTS, reason="Excluded")
    def test_student_close_window_after_submitting_feedback_for_58343(self):
        """Close window after submitting feedback for an article.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        Enter feedback into the box that pops up
        Click "Submit"
        Click "Close window"

        Expected Result:
        The popup box closes and the message "Thanks for your feedback"
        displays beneath "Feedback"
        """
        self.ps.test_updates["name"] = "t2.18.025" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.025", "58343"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58344 - 026 - Student | Cancel feedback
    @pytest.mark.skipif(str(58344) not in TESTS, reason="Excluded")
    def test_student_cancel_feedback_58344(self):
        """Cancel feedback.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Feedback"
        Click "No"
        [optional] Enter feedback into text box
        Click "Cancel"

        Expected Result:
        The popup box closes
        """
        self.ps.test_updates["name"] = "t2.18.026" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.026", "58344"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58346 - 027 - Student | View related articles
    @pytest.mark.skipif(str(58346) not in TESTS, reason="Excluded")
    def test_student_view_related_articles_58346(self):
        """View related articles.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to "Related Articles"
        Click on one of the articles (if any)

        Expected Result:
        The user is presented with the related article
        """
        self.ps.test_updates["name"] = "t2.18.027" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.027", "58346"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58347 - 028 - Student | Submit a question to Customer Support
    @pytest.mark.skipif(str(58347) not in TESTS, reason="Excluded")
    def test_student_submit_a_question_to_customer_support_58347(self):
        """Submit a question to Customer Support.

        Steps:
        Click "Get Help" from the user menu in the upper right corner of the
            screen
        Enter a question or search words into the search engine
        Click "Search" or press enter
        Click on a search result
        Scroll to the bottom of the page
        Click "Contact Us"
        Fill out the required fields
        Enter "Submit"

        Expected Result:
        The message "Thank you for your message! We'll be back to you within
        one business day" is displayed
        """
        self.ps.test_updates["name"] = "t2.18.028" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.028", "58347"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True

    # 58348 - 029 - Student | View guided tutorials of Tutor
    @pytest.mark.skipif(str(58348) not in TESTS, reason="Excluded")
    def test_student_view_guided_tutorials_of_concept_coach_58348(self):
        """View guided tutorial of Tutor.

        Steps:


        Expected Result:

        """
        self.ps.test_updates["name"] = "t2.18.029" + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates["tags"] = ["t2", "t2.18", "t2.18.029", "58348"]
        self.ps.test_updates["passed"] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates["passed"] = True
class TestContentPreparationAndImport(unittest.TestCase):
    """CC1.03 - Content Preparation and Import."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.content = ContentQA(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities,
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.content.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.content.delete()
        except:
            pass

    # Case C7603 - 001 - Content Analyst | Import content into Tutor
    @pytest.mark.skipif(str(7603) not in TESTS, reason='Excluded')
    def test_content_analyst_import_content_into_tutor_7603(self):
        """Import content into Tutor.

        Steps:
        Go to tutor-qa
        login as content
        Select Content Analyst from the dropdown menu on the name
        Click on Ecosystems in the header
        Click "Download Manifest" for the desired course
        Scroll down and click Import a new Ecosystem button.
        Click "Choose File"
        Select the downloaded
        In comment section add today's date and your name. Eg: 2016-03-03 Kajal
        Click on the button Import
        Now wait for at most 5 mins.

        Expected Result:
        The message "Ecosystem import job queued" appears at the top
        """
        self.ps.test_updates['name'] = 'cc1.03.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.001',
            '7603'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.LINK_TEXT, "Content Analyst"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.LINK_TEXT, "Ecosystems"
        ).click()
        # download a manifest to test with
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, "Download Manifest")
            )
        ).click()
        # import a new ecosystem
        self.content.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.content.driver.find_element(
            By.LINK_TEXT, "Import a new Ecosystem"
        ).click()
        # find a downloaded manifest
        home = os.getenv("HOME")
        files = os.listdir(home + '/Downloads')
        file = ''
        for i in range(len(files)):
            if (files[i][-4:] == '.yml'):
                file = files[i]
                break
            else:
                if i == len(files)-1:
                    print('no .yml file found in downloads')
                    raise Exception
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.ID, "ecosystem_manifest")
            )
        ).send_keys(home + '/Downloads/' + file)
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.ID, "ecosystem_comments")
            )
        ).send_keys(str(datetime.date.today()) + ' automated-contentqa')
        self.content.driver.find_element(
            By.XPATH, "//input[@type='submit']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"alert-info")]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7604 - 002 - Admin | Import content into Tutor
    @pytest.mark.skipif(str(7604) not in TESTS, reason='Excluded')
    def test_admin_import_content_into_tutor_7604(self):
        """Import content into Tutor.

        Steps:
        Select Customer Analyst from the dropdown menu on the name
        Click on Ecosystems in the header
        Click "Download Manifest" for the desired course
        Scroll down and click Import a new Ecosystem button.
        Click "Choose File"
        Select the downloaded file
        In comment section add today's date and your name. Eg: 2016-03-03 Kajal
        Click on the button Import
        Now wait for at most 5 mins.

        Expected Result:
        The message "Ecosystem import job queued" appears at the top
        """
        self.ps.test_updates['name'] = 'cc1.03.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.002',
            '7604'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        admin = Admin(
            existing_driver=self.content.driver,
            username=os.getenv('ADMIN_USER'),
            password=os.getenv('ADMIN_PASSWORD'),
            pasta_user=self.ps,
            capabilities=self.desired_capabilities,
        )
        admin.login()
        admin.open_user_menu()
        admin.driver.find_element(
            By.LINK_TEXT, "Content Analyst"
        ).click()
        admin.page.wait_for_page_load()
        admin.driver.find_element(
            By.LINK_TEXT, "Ecosystems"
        ).click()
        # download a manifest to test with
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, "Download Manifest")
            )
        ).click()
        # import a new ecosystem
        admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        admin.driver.find_element(
            By.LINK_TEXT, "Import a new Ecosystem"
        ).click()
        # find a downloaded manifest
        home = os.getenv("HOME")
        files = os.listdir(home + '/Downloads')
        file = ''
        for i in range(len(files)):
            if (files[i][-4:] == '.yml'):
                file = files[i]
                break
            else:
                if i == len(files)-1:
                    print('no .yml file found in downloads')
                    raise Exception
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.ID, "ecosystem_manifest")
            )
        ).send_keys(home + '/Downloads/' + file)
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.ID, "ecosystem_comments")
            )
        ).send_keys(str(datetime.date.today()) + ' automated-admin')
        admin.driver.find_element(
            By.XPATH, "//input[@type='submit']"
        ).click()
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"alert-info")]')
            )
        )
        admin.delete()
        self.ps.test_updates['passed'] = True

    # Case C7962 - 003 - Content Analyst| Verify question availability for
    # CC-Derived Biology
    @pytest.mark.skipif(str(7962) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_bio_7962(self):
        """Verify question availability for CC-Derived Biology.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Biology
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.003',
            '7962'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH, "//span[contains(text(),'Biology with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()
        self.ps.test_updates['passed'] = True

    # Case C7963 - 004 - Content Analyst| Verify question availability for
    # CC-Derived College Physics
    @pytest.mark.skipif(str(7963) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_phys_7963(self):
        """Verify question availability for CC-Derived College Physics.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived College Physics
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.004',
            '7963'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH, "//span[contains(text(),'Physics with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()
        self.ps.test_updates['passed'] = True

    # Case C7964 - 005 - Content Analyst| Verify question availability for
    # CC-Derived Concepts of Biology
    @pytest.mark.skipif(str(7964) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_avilability_for_concep_7964(self):
        """Verify question availability for CC-Derived Concepts of Biology.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Concepts of Biology
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.005',
            '7964'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text(),'Concepts of Biology with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7965 - 006 - Content Analyst| Verify question availability for
    # CC-Derived Anatomy & Physiology
    @pytest.mark.skipif(str(7965) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_ap_7965(self):
        """Verify question availability for CC-Derived Anatomy & Physiology.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Anatomy and Physiology
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.006',
            '7965'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text()," +
            "'Anatomy & Physiology with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7966 - 007 - Content Analyst| Verify question availability for
    # CC-Derived Macroeconomics
    @pytest.mark.skipif(str(7966) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_macro_7966(self):
        """Verify question availability for CC-Derived Macroeconomics.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Macroeconomics
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.007',
            '7966'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text(),'Macroeconomics with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7967 - 008 - Content Analyst| Verify question availability for
    # CC-Derived Microeconomics
    @pytest.mark.skipif(str(7967) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_micro_7967(self):
        """Verify question availability for CC-Derived Microeconomics.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Microeconomics
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.008',
            '7967'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text(),'Microeconomics with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7968 - 009 - Content Analyst| Verify question availability for
    # CC-Derived Principles of Economics
    @pytest.mark.skipif(str(7968) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_princ_7968(self):
        """Verify question availability for CC-Derived Principles of Economics.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Principles of Economics
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.009',
            '7968'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text()," +
            "'Principles of Economics with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7969 - 010 - Content Analyst| Verify question availability for
    # CC-Derived Introduction to Sociology
    @pytest.mark.skipif(str(7969) not in TESTS, reason='Excluded')
    def test_content_analyst_verify_question_availability_for_soci_7969(self):
        """Verify question availability for CC-Der Introduction to Sociology.

        Steps:
        Click QA content
        Click Available Books
        Select CC-Derived Introcution to Sociology
        Click on a section in the table of contents

        Expected Result:
        Questions are available
        """
        self.ps.test_updates['name'] = 'cc1.03.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.03',
            'cc1.03.010',
            '7969'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.content.login()
        self.content.open_user_menu()
        self.content.driver.find_element(
            By.PARTIAL_LINK_TEXT, "QA Content"
        ).click()
        self.content.page.wait_for_page_load()
        self.content.driver.find_element(
            By.ID, "available-books"
        ).click()
        element = self.content.driver.find_element(
            By.XPATH,
            "//span[contains(text()," +
            "'Introduction to Sociology 2e with Concept Coach')]"
        )
        self.content.sleep(0.5)
        self.content.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.content.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.content.sleep(0.5)
        self.content.driver.find_element(
            By.XPATH, "//span[@class='section-number' and text()='1.1']"
        ).click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[contains(@class,'openstax-exercise-preview')]")
            )
        ).click()

        self.ps.test_updates['passed'] = True
class TestImproveCourseManagement(unittest.TestCase):
    """T2.07 - Improve Course Management."""
    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(use_env_vars=True,
                               pasta_user=self.ps,
                               capabilities=self.desired_capabilities)
        self.admin = Admin(use_env_vars=True,
                           pasta_user=self.ps,
                           capabilities=self.desired_capabilities,
                           existing_driver=self.teacher.driver)

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(job_id=str(self.teacher.driver.session_id),
                           **self.ps.test_updates)
        try:
            self.admin = None
            self.teacher.delete()
        except:
            pass

    # 14651 - 001 - Admin | View Student Use Statistics for Concept Coach
    # college assessments
    @pytest.mark.skipif(str(14651) not in TESTS, reason='Excluded')
    def test_admin_view_student_use_statistics_for_cc_college_asse_14651(self):
        """View Student Use Statistics for Concept Coach college assessments.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin account in the username and password text boxes
        Click on the 'Sign in' button
        Click "Admin" in the user menu
        Click "Stats"
        Click "Concept Coach"

        Expected Result:
        The user is presented with Concept Coach statistics
        """
        self.ps.test_updates['name'] = 't2.07.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.001', '14651']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.goto_admin_control()
        self.admin.sleep(5)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Stats'))).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Concept Coach'))).click()

        assert('/stats/concept_coach' in self.admin.current_url()), \
            'Not viewing Concept Coach stats'

        self.ps.test_updates['passed'] = True

    # 14652 - 002 - Teacher | Delegate teaching tasks to supporting instructors
    @pytest.mark.skipif(str(14652) not in TESTS, reason='Excluded')
    def test_teacher_delegate_teaching_tasks_to_supporting_instruc_14652(self):
        """Delegate teaching tasks to supporting instructors.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.002', '14652']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14653 - 003 - Teacher | Move a student and their data to a new section
    @pytest.mark.skipif(str(14653) not in TESTS, reason='Excluded')
    def test_teacher_move_a_student_and_their_data_to_new_section_14653(self):
        """Move a student and their data to a new section.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the user menu
        Click "Change Period" for the desired student and select a period

        Expected Result:
        Student is moved to new section with their data
        """
        self.ps.test_updates['name'] = 't2.07.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.003', '14653']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Move the student to another period
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Change Period").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, "//ul[@class='nav nav-pills nav-stacked']/li/a").click()

        self.teacher.sleep(5)

        # Verify the move, then move the student back to the original period
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[2]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")
        index = 0
        for student in roster:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Change Period")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//ul[@class='nav nav-pills nav-stacked']/li/a").click()
                break
            index += 1

        self.teacher.sleep(2)
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[1]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")

        assert(first in roster[0].text and last in roster[0].text), \
            'error'

        self.ps.test_updates['passed'] = True

    # 14655 - 004 - Teacher | Drop a student from a section and hide their data
    @pytest.mark.skipif(str(14655) not in TESTS, reason='Excluded')
    def test_teacher_drop_student_from_section_and_hide_their_data_14655(self):
        """Drop a student from a section and hide their data.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the user menu
        Click "Drop" for the desired student

        Expected Result:
        The student appears under the "Dropped Students" section
        """
        self.ps.test_updates['name'] = 't2.07.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.004', '14655']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Drop the student
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text
        self.teacher.find(By.PARTIAL_LINK_TEXT, "Drop").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH,
            "//button[@class='-drop-student btn btn-danger']").click()

        self.teacher.sleep(5)

        # Verify the student was dropped and add back to active roster
        dropped = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='settings-section dropped-students']/table[@class" +
            "='roster table table-striped table-bordered table-condensed " +
            "table-hover']/tbody/tr")
        index = 0
        for student in dropped:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Add Back to Active Roster")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='-undrop-student btn btn-success']"
                ).click()
                self.teacher.sleep(20)
                break
            index += 1

        self.ps.test_updates['passed'] = True

    # 14656 - 005 - Teacher | Drop a student from a section and don't hide
    # their data
    @pytest.mark.skipif(str(14656) not in TESTS, reason='Excluded')
    def test_teacher_drop_a_student_from_section_and_dont_hide_dat_14656(self):
        """Drop a student from a section and don't hide their data.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.005', '14656']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14657 - 006 - Teacher | In Student Scores dropped students are not
    # displayed
    @pytest.mark.skipif(str(14657) not in TESTS, reason='Excluded')
    def test_teacher_in_student_scores_dropped_students_are_not_14657(self):
        """In Student Scores dropped students are not displayed.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the calendar dashboard
        Click "Drop" for the desired student
        Click "Student Scores" from the user menu
        Click on the period from which you have dropped the student

        Expected Result:
        Dropped student should not be displayed in Student Scores
        """
        self.ps.test_updates['name'] = 't2.07.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.006', '14657']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Drop the student
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Drop").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH,
            "//button[@class='-drop-student btn btn-danger']").click()

        self.teacher.sleep(5)

        # Go to student scores, verify the student is not seen
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT, "Student Scores").click()
        self.teacher.sleep(10)

        odd_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedData" +
            "TableRow_main public_fixedDataTableRow_even public_fixedDataTa" +
            "ble_bodyRow']/div[@class='fixedDataTableRowLayout_body']/div" +
            "[@class='fixedDataTableCellGroupLayout_cellGroupWrapper'][1]/d" +
            "iv[@class='fixedDataTableCellGroupLayout_cellGroup']/div[@clas" +
            "s='fixedDataTableCellLayout_main public_fixedDataTableCell_" +
            "main'][1]/div[@class='fixedDataTableCellLayout_wrap1 public_fi" +
            "xedDataTableCell_wrap1']/div[@class='fixedDataTableCellLayout_w" +
            "rap2 public_fixedDataTableCell_wrap2']/div[@class='fixedDataTab" +
            "leCellLayout_wrap3 public_fixedDataTableCell_wrap3']/div[@class" +
            "='name-cell']/a[@class='student-name public_fixedDataTableCell" +
            "_cellContent']")
        even_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedDataTab" +
            "leRow_main public_fixedDataTableRow_highlighted public_fixedDa" +
            "taTableRow_odd public_fixedDataTable_bodyRow']/div[@class='fix" +
            "edDataTableRowLayout_body']/div[@class='fixedDataTableCellGrou" +
            "pLayout_cellGroupWrapper'][1]/div[@class='fixedDataTableCellGr" +
            "oupLayout_cellGroup']/div[@class='fixedDataTableCellLayout_mai" +
            "n public_fixedDataTableCell_main'][1]/div[@class='fixedDataTab" +
            "leCellLayout_wrap1 public_fixedDataTableCell_wrap1']/div[@clas" +
            "s='fixedDataTableCellLayout_wrap2 public_fixedDataTableCell_wr" +
            "ap2']/div[@class='fixedDataTableCellLayout_wrap3 public_fixedD" +
            "ataTableCell_wrap3']/div[@class='name-cell']/a[@class='student" +
            "-name public_fixedDataTableCell_cellContent']")

        found = False
        for student in odd_scores:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                found = True
                break

        if not found:
            for stud in even_scores:
                if stud.text.find(first) >= 0 and stud.text.find(last) >= 0:
                    found = True
                    break

        # Add back to active roster
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        dropped = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='settings-section dropped-students']/table[@class" +
            "='roster table table-striped table-bordered table-condensed ta" +
            "ble-hover']/tbody/tr")
        index = 0
        for student in dropped:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Add Back to Active Roster")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='-undrop-student btn btn-success']"
                ).click()
                self.teacher.sleep(20)
                break
            index += 1

        if not found:
            self.ps.test_updates['passed'] = True

    # 14850 - 007 - Teacher | In Student Scores view moved students
    @pytest.mark.skipif(str(14850) not in TESTS, reason='Excluded')
    def test_teacher_in_student_scores_view_moved_students_14850(self):
        """In Student Scores view moved students.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the calendar dashboard
        Click "Change Period" for the desired student
        Click on the desired period
        Click "Student Scores" from the user menu
        Click on the period to which the student was moved

        Expected Result:
        The user is presented with the moved student under their new period
        """
        self.ps.test_updates['name'] = 't2.07.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.007', '14850']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Move the student to another period
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Change Period").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, "//ul[@class='nav nav-pills nav-stacked']/li/a").click()

        self.teacher.sleep(5)

        # Go to student scores, verify the student is seen
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT, "Student Scores").click()
        self.teacher.sleep(10)
        self.teacher.find(
            By.XPATH,
            "//nav[@class='collapse in']/ul[@class='nav nav-tabs']/li[2]/a"
        ).click()

        odd_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedData" +
            "TableRow_main public_fixedDataTableRow_even public_fixedDataTa" +
            "ble_bodyRow']/div[@class='fixedDataTableRowLayout_body']/div" +
            "[@class='fixedDataTableCellGroupLayout_cellGroupWrapper'][1]/d" +
            "iv[@class='fixedDataTableCellGroupLayout_cellGroup']/div[@clas" +
            "s='fixedDataTableCellLayout_main public_fixedDataTableCell_" +
            "main'][1]/div[@class='fixedDataTableCellLayout_wrap1 public_fi" +
            "xedDataTableCell_wrap1']/div[@class='fixedDataTableCellLayout_w" +
            "rap2 public_fixedDataTableCell_wrap2']/div[@class='fixedDataTab" +
            "leCellLayout_wrap3 public_fixedDataTableCell_wrap3']/div[@class" +
            "='name-cell']/a[@class='student-name public_fixedDataTableCell" +
            "_cellContent']")
        even_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedDataTab" +
            "leRow_main public_fixedDataTableRow_highlighted public_fixedDa" +
            "taTableRow_odd public_fixedDataTable_bodyRow']/div[@class='fix" +
            "edDataTableRowLayout_body']/div[@class='fixedDataTableCellGrou" +
            "pLayout_cellGroupWrapper'][1]/div[@class='fixedDataTableCellGr" +
            "oupLayout_cellGroup']/div[@class='fixedDataTableCellLayout_mai" +
            "n public_fixedDataTableCell_main'][1]/div[@class='fixedDataTab" +
            "leCellLayout_wrap1 public_fixedDataTableCell_wrap1']/div[@clas" +
            "s='fixedDataTableCellLayout_wrap2 public_fixedDataTableCell_wr" +
            "ap2']/div[@class='fixedDataTableCellLayout_wrap3 public_fixedD" +
            "ataTableCell_wrap3']/div[@class='name-cell']/a[@class='student" +
            "-name public_fixedDataTableCell_cellContent']")

        found = False
        for student in odd_scores:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                found = True
                break

        if found:
            for stud in even_scores:
                if stud.text.find(first) >= 0 and stud.text.find(last) >= 0:
                    found = True
                    break

        # Add student back to original period
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(10)
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[2]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")
        index = 0
        for student in roster:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Change Period")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//ul[@class='nav nav-pills nav-stacked']/li/a").click()
                break
            index += 1

        if found:
            self.ps.test_updates['passed'] = True

    # 14658 - 008 - Teacher | Require emails for all students for roster import
    @pytest.mark.skipif(str(14658) not in TESTS, reason='Excluded')
    def test_teacher_require_emails_for_all_students_for_roster_14658(self):
        """Require emails for all students for roster imports.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.008', '14658']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14660 - 009 - Teacher | Set time zone for a course
    @pytest.mark.skipif(str(14660) not in TESTS, reason='Excluded')
    def test_teacher_set_time_zone_for_a_course_14660(self):
        """Set time zone for a course.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster"
        Click "Change Course Timezone"
        Select the desired timezone
        Click Save

        Expected Result:
        The time zone is set
        """
        self.ps.test_updates['name'] = 't2.07.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.009', '14660']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.PARTIAL_LINK_TEXT,
                          "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Change the timezone
        self.teacher.driver.find_elements_by_xpath(
            "//button[@class='edit-course btn btn-link']")[1].click()
        self.teacher.sleep(2)
        self.teacher.find(By.XPATH,
                          "//div[@class='tutor-radio']/label").click()
        self.teacher.find(
            By.XPATH, "//button[@class='async-button -edit-course-" +
            "confirm btn btn-default']").click()
        self.teacher.sleep(5)

        # Verify the change and change the time back to Central
        self.teacher.driver.find_elements_by_xpath(
            "//button[@class='edit-course btn btn-link']")[1].click()

        assert('Central Time' not in self.teacher.find(
            By.XPATH, "//div[@class='tutor-radio active']/label").text), \
            'Not viewing Concept Coach stats'

        self.teacher.sleep(2)
        options = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='tutor-radio']/label")

        for timezone in options:
            if timezone.text.find('Central Time') >= 0:
                timezone.click()
                break

        self.teacher.find(
            By.XPATH, "//button[@class='async-button -edit-course-" +
            "confirm btn btn-default']").click()

        self.ps.test_updates['passed'] = True

    # 14661 - 010 - System | Distinguish between high school and college
    # courses
    @pytest.mark.skipif(str(14661) not in TESTS, reason='Excluded')
    def test_system_distinguish_between_hs_and_college_courses_14661(self):
        """Distinguish between high school and college courses.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.07', 't2.07.010', '14661']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestImproveLoginREgistrationEnrollment(unittest.TestCase):
    """T2.09 - Improve Login, Registration, Enrollment."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.teacher = Teacher(
                use_env_vars=True,
                pasta_user=self.ps,
                capabilities=self.desired_capabilities
            )
            self.student = Student(
                use_env_vars=True,
                pasta_user=self.ps,
                capabilities=self.desired_capabilities
            )
            self.admin = Admin(
                use_env_vars=True,
                pasta_user=self.ps,
                capabilities=self.desired_capabilities
            )
        else:
            self.teacher = Teacher(
                use_env_vars=True,
            )
            self.student = Student(
                use_env_vars=True,
                existing_driver=self.teacher.driver
            )
            self.admin = Admin(
                use_env_vars=True,
                existing_driver=self.teacher.driver
            )

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(
                job_id=str(self.teacher.driver.session_id),
                **self.ps.test_updates
            )
        try:
            self.teacher.delete()
        except:
            pass

    def test_custom_url_student(self):
        """
        Enter the custom URL into the search bar
        Sign in or sign up as student
        Enter a school-issued ID or skip the step for now

        ***The user is presented with the student dashboard with the message
        "Enrollment successful!
        It may take a few minutes to build your assignments."
        (If student is already enrolled in course message notifies student of
        this)(t2.09.04)***

        Click on a course
        Open the user menu
        click on "Change Student ID"
        Enter an new Student ID
        Click save
        ***Student ID changed (t2.09.33)***

        Corresponds to...
        t2.09 04,33
        """
        # t2.09.04 -->The user is presented with the
        # student dashboard with the message "Enrollment successful!
        # It may take a few minutes to build your assignments."
        # If student is already enrolled in course message notifies student of
        # this)(t2.09.04)***

        self.teacher.login()
        # self.teacher.find(By.XPATH, '//p[@data-is-beta="true"]').click()
        # self.teacher.open_user_menu()
        # self.teacher.find(By.LINK_TEXT, 'Course Settings and Roster').click()
        # IDK if above code is necessary for going to Course settings ^
        # make sure class is tutor
        self.teacher.find(
            By.XPATH,
            "//p[contains(text(),'Tutor')]"
        ).click()

        # get name of course for later reference by the student
        enrollment_course_name = self.teacher.find(
            By.CSS_SELECTOR,
            '.title'
        ).text
        print(enrollment_course_name)

        # go to roster
        self.teacher.goto_course_settings()
        self.teacher.find(
            By.XPATH,
            '//a[h2[contains(text(), "ACCESS")]]'
        ).click()
        try:
            self.teacher.find(
                By.XPATH,
                '//a[.//p[contains(text(), "direct")]]'
            ).click()
            try:
                self.teacher.find(
                    By.XPATH,
                    '//button[contains(text(), "sure")]'
                ).click()
            except:
                pass
            enrollment_url = self.teacher.get_enrollment_code()
        except:
            raise ElementNotSelectableException("Can't get URL")
        """
        try:
            enrollment_url = enrollment_url.get_attribute('value')
        except:
            enrollment_url = enrollment_url[randint(0, len(enrollment_url))] \
                .get_attribute('value')
        """
        self.teacher.logout()

        # use the url as a student
        self.student.login()
        print(enrollment_url)
        custom_url = self.student.get(enrollment_url)
        print(custom_url)
        self.student.sleep(5)
        try:
            get_started = self.student.find(
                By.XPATH,
                "//a[contains(text(),'Get started')]"
            )
            get_started.click()

            # student id "Add Later"
            add_later = self.student.find(
                By.XPATH,
                "//button[contains(text(),'later')]"
            )
            add_later.click()
        except:
            pass

        # t2.09.33 --> Student ID changed
        # self.student.find(By.XPATH, '//p[@data-is-beta="true"]').click()
        self.student.open_user_menu()
        self.student.find(By.LINK_TEXT, 'Change Student ID').click()
        old_id = self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//input[@placeholder="School issued ID"]')
            )
        ).get_attribute("value")
        print("Old ID: %s" % old_id)

        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//input[@placeholder="School issued ID"]')
            )
        ).send_keys("new_student_id")

        self.student.find(
            By.XPATH, '//button[text()="Save"]'
        ).click()

        # change the student ID back
        self.student.sleep(3)
        self.student.open_user_menu()
        self.student.find(By.LINK_TEXT, 'Dashboard').click()
        self.student.open_user_menu()
        self.student.find(By.LINK_TEXT, 'Change Student ID').click()
        new_id = self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//input[@placeholder="School issued ID"]')
            )
        ).get_attribute("value")
        print("New ID: %s" % new_id)

        assert(old_id+"new_student_id" == new_id), "ID not changed"

        for _ in range(14):
            self.student.wait.until(
                expect.visibility_of_element_located(
                    (By.XPATH, '//input[@placeholder="School issued ID"]')
                )
            ).send_keys(Keys.BACKSPACE)
        self.student.find(
            By.XPATH, '//button[text()="Save"]'
        ).click()
class TestViewTheListDashboard(unittest.TestCase):
    """Student - Navigation Shortcuts."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.student = Student(
                use_env_vars=True,
                pasta_user=self.ps,
                capabilities=self.desired_capabilities
            )
        else:
            self.student = Student(
                use_env_vars=True
            )
        self.student.login()

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(
                job_id=str(self.student.driver.session_id),
                **self.ps.test_updates
            )
        try:
            self.student.delete()
        except:
            pass

    # Case C162194 - 005 - Student | Navigation Shortcuts
    @pytest.mark.skipif(str(162194) not in TESTS, reason='Excluded')
    def test_student_select_a_course_162194(self):
        """
        #STEPS
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Enter the student username [  ] in the username text box
        Click 'Next'
        Enter the student password [  ] in the password text box
        Click on the 'Login' button
        ***The user logs into Tutor and is presented with a list of courses if
        they
        have multiple courses, or their dashboard for a course if they are only
        enrolled in one course***

        Click on a Tutor course name
        ***The user selects a course and is presented with the dashboard.***

        Open the drop down menu by clicking the menu link containing the user's
        name
        Click the 'Performance Forecast' button
        Click on the name of the course
        ***The user is returned to their dashboard.***

        Click on the OpenStax logo
        ***The user is returned to the course picker.***

        Click on the user menu on the right of the header
        Click 'Log Out'
        # EXPECTED RESULT
        ***User is logged out of tutor***

        """
        self.ps.test_updates['name'] = 't1.38.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.38',
            't1.38.001',
            '162194'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions

        # Select a Course
        self.student.select_course(appearance='intro_sociology')
        self.student.page.wait_for_page_load()

        # Click on course name to return to the dashboard

        self.student.open_user_menu()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'viewPerformanceGuide')
            )
        ).click()

        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'course-name')
            )
        ).click()

        # Click on logo to return to course picker

        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'ui-brand-logo')
            )
        ).click()

        self.ps.test_updates['passed'] = True
Esempio n. 15
0
class TestAnalyzeCollegeWorkflow(unittest.TestCase):
    """T2.05 - Analyze College Workflow."""
    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.teacher = Teacher(use_env_vars=True,
                                   pasta_user=self.ps,
                                   capabilities=self.desired_capabilities)
            self.student = Student(use_env_vars=True,
                                   pasta_user=self.ps,
                                   capabilities=self.desired_capabilities,
                                   existing_driver=self.teacher.driver)
        else:
            self.teacher = Teacher(use_env_vars=True)
            self.student = Student(use_env_vars=True,
                                   existing_driver=self.teacher.driver)

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(job_id=str(self.teacher.driver.session_id),
                               **self.ps.test_updates)
        self.student = None
        try:
            self.teacher.delete()
        except:
            pass

    # 14645 - 001 - Student | All work is visible for college students
    # not just "This Week"
    @pytest.mark.skipif(str(14645) not in TESTS, reason='Excluded')
    def test_student_all_work_is_visible_for_college_students_14645(self):
        """All work is visible for college students, not just 'This Week'.

        Steps:
        Log into tutor-qa as student
        Click on a college course

        Expected Result:
        Can view assignments due later than this week
        """
        self.ps.test_updates['name'] = 't2.05.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.05', 't2.05.001', '14645']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.login()
        self.student.select_course(title='College Physics with Courseware')

        # find either upcoming events, or a message stating there are none.
        try:
            self.teacher.wait.until(
                expect.visibility_of_element_located(
                    (By.XPATH, '//span[contains(text(),"%s")]' % "Coming Up")))
        except TimeoutException:
            self.teacher.wait.until(
                expect.visibility_of_element_located(
                    (By.XPATH,
                     '//div[contains(text(),"%s")]' % "No upcoming events")))
        self.ps.test_updates['passed'] = True

    '''
    # 14646 - 002 - Teacher | Create a link to the OpenStax Dashboard
    @pytest.mark.skipif(str(14646) not in TESTS, reason='Excluded')
    def test_teacher_create_a_link_to_the_openstax_dashboard_14646(self):
        """Create a link to the OpenStax Dashboard.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 't2.05.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.05', 't2.05.002', '14646']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
    '''
    '''
    # 14647 - 003 - Teacher | Create a link to the OpenStax Dashboard
    @pytest.mark.skipif(str(14647) not in TESTS, reason='Excluded')
    def test_teacher_create_a_link_to_the_openstax_dashboard_14647(self):
        """Create a link to the OpenStax Dashboard.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 't2.05.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.05', 't2.05.003', '14647']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
    '''

    # 14648 - 004 - Teacher | Create links to assigned readings in their LMS
    @pytest.mark.skipif(str(14648) not in TESTS, reason='Excluded')
    def test_teacher_create_links_to_assigned_readings_in_lms_14648(self):
        """Create links to assigned readings in their LMS.

        Steps:
        Login as a teacher
        If the user has more than one course, click on a tutor course name
        Click on a published reading assignment on the calendar dashboard
        Click "Get Assignment Link"

        Expected Result:
        The user is presented with links to assigned readings
        """
        self.ps.test_updates['name'] = 't2.05.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.05', 't2.05.004', '14648']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()

        self.teacher.select_course(appearance='biology')
        assignment_name = 'reading004_%d' % (randint(100, 999))
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=1)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=4)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(assignment='reading',
                                    args={
                                        'title': assignment_name,
                                        'description': 'description',
                                        'periods': {
                                            'all': (begin, end)
                                        },
                                        'reading_list': ['1.1'],
                                        'status': 'publish'
                                    })
        try:
            self.teacher.wait.until(
                expect.presence_of_element_located(
                    (By.XPATH, '//div[@class="month-wrapper"]')))
            self.teacher.find(
                By.XPATH, "//div/label[contains(text(), '" + assignment_name +
                "')]").click()
        except NoSuchElementException:
            self.teacher.find(
                By.XPATH,
                "//a[contains(@class, 'header-control next')]").click()
            self.teacher.wait.until(
                expect.presence_of_element_located(
                    (By.XPATH, '//div[@class="month-wrapper"]')))
            self.teacher.find(
                By.XPATH, "//div/label[contains(text(), '" + assignment_name +
                "')]").click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[@class="get-link"]'))).click()
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//div[@class="popover-content"]' +
                 '//input[contains(@value,"https://tutor")]')))
        self.ps.test_updates['passed'] = True

    # 14649 - 005 - Teacher | Create links to assigned homework in their LMS
    @pytest.mark.skipif(str(14649) not in TESTS, reason='Excluded')
    def test_teacher_create_links_to_assigned_homework_in_lms_14649(self):
        """Create links to assigned homework in their LMS.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name
        Click on a published homework assignment on the calendar dashboard
        Click "Get Assignment Link"

        Expected Result:
        The user is presented with links to assigned homework
        """
        self.ps.test_updates['name'] = 't2.05.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t2', 't2.05', 't2.05.005', '14649']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()

        self.teacher.select_course(appearance='biology')
        assignment_name = 'hw005_%d' % (randint(100, 999))
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=1)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=4)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(assignment='homework',
                                    args={
                                        'title': assignment_name,
                                        'description': 'description',
                                        'periods': {
                                            'all': (begin, end)
                                        },
                                        'problems': {
                                            '1.1': (2, 3),
                                        },
                                        'status': 'publish',
                                        'feedback': 'immediate'
                                    })
        try:
            self.teacher.wait.until(
                expect.presence_of_element_located(
                    (By.XPATH, '//div[@class="month-wrapper"]')))
            self.teacher.sleep(1)
            self.teacher.find(
                By.XPATH, "//div/label[contains(text(), '" + assignment_name +
                "')]").click()
        except NoSuchElementException:
            self.teacher.find(
                By.XPATH,
                "//a[contains(@class, 'header-control next')]").click()
            self.teacher.wait.until(
                expect.presence_of_element_located(
                    (By.XPATH, '//div[@class="month-wrapper"]')))
            self.teacher.find(
                By.XPATH, "//div/label[contains(text(), '" + assignment_name +
                "')]").click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[@class="get-link"]'))).click()
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//div[@class="popover-content"]' +
                 '//input[contains(@value,"https://tutor")]')))
        self.ps.test_updates['passed'] = True

    '''
class TestOpenStaxMetrics(unittest.TestCase):
    """CC1.15 - OpenStax Metrics."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.delete()
        except:
            pass

    # Case C7608 - 001 - Admin | View a report of enrolled students by course
    @pytest.mark.skipif(str(7608) not in TESTS, reason='Excluded')
    def test_admin_view_a_report_of_enrolled_students_by_course_7608(self):
        """View a report of enrolled students by course.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin user account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the 'Admin' button from the user menu
        Open the drop down menu by clicking 'Course Organization'
        Click the 'Courses' option
        Click the 'List Students' button for the chosen course

        Expected Result:
        List of students for chosen course is displayed
        """
        self.ps.test_updates['name'] = 'cc1.15.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.15',
            'cc1.15.001',
            '7608'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.open_user_menu()
        self.admin.find(
            By.LINK_TEXT, 'Admin'
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.find(
            By.LINK_TEXT, 'Course Organization'
        ).click()
        self.admin.find(
            By.LINK_TEXT, 'Courses'
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.find(
            By.LINK_TEXT, 'List Students'
        ).click()
        # assert thaken to correct page
        self.admin.find(
            By.XPATH, '//h1[contains(text(),"Students for course")]'
        )
        assert('student' in self.admin.current_url())
        self.ps.test_updates['passed'] = True
class TestTeacherLoginAndAuthentification(unittest.TestCase):
    """CC1.11 - Teacher Login and Authentification."""
    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.teacher = Teacher(use_env_vars=True,
                                   pasta_user=self.ps,
                                   capabilities=self.desired_capabilities)
        else:
            self.teacher = Teacher(use_env_vars=True)

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(job_id=str(self.teacher.driver.session_id),
                               **self.ps.test_updates)
        try:
            self.teacher.delete()
        except:
            pass

    # Case C7688 - 001 - Teacher | Log into Concept Coach
    @pytest.mark.skipif(str(7688) not in TESTS, reason='Excluded')
    def test_teacher_log_into_concept_coach_7688(self):
        """Log into Concept Coach.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name

        Expected Result:
        User is taken to the class dashboard.
        """
        self.ps.test_updates['name'] = 'cc1.11.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.11', 'cc1.11.001', '7688']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get(self.teacher.url)
        self.teacher.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.teacher.driver.get_window_size()['width'] <= \
           self.teacher.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.teacher.find(
                By.XPATH, '//button[contains(@class,"navbar-toggle")]')
            # check if the menu is collapsed and, if yes, open it
            if ('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Log in'))).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(By.ID, 'login_username_or_email').send_keys(
            self.teacher.username)
        self.teacher.find(By.CSS_SELECTOR, '.primary').click()
        self.teacher.find(By.ID,
                          'login_password').send_keys(self.teacher.password)
        self.teacher.find(By.CSS_SELECTOR, '.primary').click()
        self.teacher.page.wait_for_page_load()
        # check if a password change is required
        if 'reset your password' in self.teacher.driver.page_source.lower():
            try:
                self.teacher.find(By.ID, 'set_password_password') \
                    .send_keys(self.teacher.password)
                self.teacher.find(
                    By.ID, 'set_password_password_confirmation') \
                    .send_keys(self.teacher.password)
                self.teacher.find(By.CSS_SELECTOR, '.primary').click()
                self.teacher.sleep(1)
                self.teacher.find(By.CSS_SELECTOR, '.primary').click()
            except Exception as e:
                raise e
        self.teacher.page.wait_for_page_load()
        source = self.teacher.driver.page_source.lower()
        print('Reached Terms/Privacy')
        while 'terms of use' in source or 'privacy policy' in source:
            self.teacher.accept_contract()
            self.teacher.page.wait_for_page_load()
            source = self.teacher.driver.page_source.lower()
        assert('dashboard' in self.teacher.current_url()),\
            'Not taken to dashboard: %s' % self.teacher.current_url()

        self.teacher.driver.find_element(
            By.XPATH,
            '//p[contains(text(),"OpenStax Concept Coach")]').click()
        self.teacher.driver.find_element(By.XPATH,
                                         '//span[text()="Class Dashboard"]')

        self.ps.test_updates['passed'] = True

    # Case C7689 - 002 - Teacher | Logging out returns to the Concept Coach
    # landing page
    @pytest.mark.skipif(str(7689) not in TESTS, reason='Excluded')
    def test_teacher_logging_out_returns_to_concept_coach_landing_p_7689(self):
        """Logging out returns to the Concept Coach landing page.

        Steps:
        Click the user menu containing the user's name
        Click the 'Log Out' button

        Expected Result:
        User is taken to cc.openstax.org
        """
        self.ps.test_updates['name'] = 'cc1.11.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc1', 'cc1.11', 'cc1.11.002', '7689']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH,
            '//p[contains(text(),"OpenStax Concept Coach")]').click()
        self.teacher.open_user_menu()
        self.teacher.sleep(1)
        self.teacher.find(By.XPATH, "//a//input[@value='Log out']").click()

        assert('cc.openstax.org' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True

    '''
class TestPractice(unittest.TestCase):
    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.student = Student(use_env_vars=True,
                                   pasta_user=self.ps,
                                   capabilities=self.desired_capabilities)
        else:
            self.student = Student(use_env_vars=True)
        self.student.login()
        self.student.select_course(title='College Physics with Courseware')
        self.wait = WebDriverWait(self.student.driver, Assignment.WAIT_TIME)
        self.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//button[contains(@class,"practice")]'))).click()
        self.wait = WebDriverWait(self.student.driver, Assignment.WAIT_TIME)
        self.student.login()

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(job_id=str(self.student.driver.session_id),
                               **self.ps.test_updates)
        try:
            self.student.delete()
        except:
            pass

    # IN THE CASE THAT CLICKING THE ERRATA LINK OPENS UP A NEW WINDOW, YOU CAN
    # IMPLEMENT THIS TO BE PART OF performance_practice_student()
    @pytest.mark.skipif(str(1) not in TESTS, reason='Excluded')
    def test_assessment_errata_form(self):
        '''
        Go to https://tutor-qa.openstax.org/
        Click on the 'Login' button
        Login with student account
        Click on the 'Sign in' button
        If the user has more than one course, select a Tutor course

        Click one of the section performance bars from the dashboard
        OR
        Click on the user menu
        Click "Performance Forecast"
        Click one of the section performance bars

        Click the 'Report an error' link
        ***The user is taken to the Assessment Errata Form and the ID is
        prefilled.(t1.55.11)***

        Fill out the fields
        Click the 'Submit' button
        ***The form is submitted and the message that says "Your response has
        been recorded" is displayed (t1.55.12)***

        Corresponds to...
        t1.55.11,12
        '''
        # Test steps and verification assertions
        # t1.55.11 --> The user is taken to the Assessment Errata Form and the
        # ID is prefilled
        # Navigate to performance forecast
        self.student.select_course(title='zPhysics w Courseware')

        # Go to practice
        practice_text = self.student.find(
            By.XPATH, "//div[contains(text(),'Practice more')]")
        practice_text.click()
        # practice exercises take a realllly long time to load
        self.student.driver.wait(20)
        self.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, "//div[contains(@class,'card-body')]")))

        # find the identifier
        id_num = self.student.find(
            By.XPATH,
            '//span[@class="exercise-identifier-link"]').text.split(" |")[0]
        self.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Report an error'))).click()

        window_with_form = self.student.driver.window_handles[1]
        self.student.driver.switch_to_window(window_with_form)
        self.student.page.wait_for_page_load()
        assert("errata" in self.student.current_url()), \
            'not taken to assesment errata form'
        text_box = self.student.find(By.XPATH, '//input[@name="location"]')
        assert(id_num[4:] in text_box.get_attribute('value')), \
            'form not prefilled correctly'

        # t1.55.12 --> The form is submitted and the message that
        # says "Your response has been recorded" is displayed

        self.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Suggest a Correction")]')))
        self.student.find(By.XPATH,
                          '//input[@type="radio" and @value="Typo"]').click()
        self.student.find(
            By.XPATH,
            '//textarea[@name="detail"]').send_keys('automated qa test')
        self.student.find(By.XPATH, '//input[@type="submit"]').click()
        # find submitted message
        self.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Thanks for your help!")]')))
class TestUserLogin(unittest.TestCase):
    """T1.36 - User login."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.content = ContentQA(
            existing_driver=self.admin.driver,
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student = Student(
            existing_driver=self.admin.driver,
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher = Teacher(
            existing_driver=self.admin.driver,
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher = None
            self.student = None
            self.content = None
            self.admin.delete()
        except:
            pass

    # Case C8238 - 001 - Admin | Log into Tutor
    @pytest.mark.skipif(str(8238) not in TESTS, reason='Excluded')
    def test_admin_log_into_tutor_8238(self):
        """Log into Tutor.

        Steps:
        Click on the 'Login' button
        Enter the admin account in the username and password text boxes
        Click on the 'Sign in' button

        Expected Result:
        User is logged in
        """
        self.ps.test_updates['name'] = 't1.36.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.001', '8238']
        self.ps.test_updates['passed'] = False

        self.admin.get(self.admin.url)
        self.admin.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.admin.driver.get_window_size()['width'] <= \
                self.admin.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.admin.find(
                By.XPATH,
                '//button[contains(@class,"navbar-toggle")]'
            )
            # check if the menu is collapsed and, if yes, open it
            if('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Login')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.find(
            By.ID, 'auth_key'
        ).send_keys(self.admin.username)
        self.admin.find(
            By.ID, 'password'
        ).send_keys(self.admin.password)
        # click on the sign in button
        self.admin.find(
            By.XPATH,
            '//button[text()="Sign in"]'
        ).click()
        self.admin.page.wait_for_page_load()
        assert('dashboard' in self.admin.current_url()), \
            'Not taken to dashboard: %s' % self.admin.current_url()

        self.ps.test_updates['passed'] = True

    # Case C8239 - 002 - Admin | Access the Admin Console
    @pytest.mark.skipif(str(8239) not in TESTS, reason='Excluded')
    def test_admin_access_the_admin_console_8239(self):
        """Access the Admin console.

        Steps:
        Click on the 'Login' button
        Enter the admin account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Admin option

        Expected Result:
        User is presented with the admin console
        """
        self.ps.test_updates['name'] = 't1.36.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.002', '8239']
        self.ps.test_updates['passed'] = False

        # self.user = admin
        self.admin.login()
        self.admin.open_user_menu()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Admin')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.find(
            By.XPATH, '//h1[contains(text(),"Admin Console")]')

        self.ps.test_updates['passed'] = True

    # Case C8240 - 003 - Admin | Log out
    @pytest.mark.skipif(str(8240) not in TESTS, reason='Excluded')
    def test_admin_log_out_8240(self):
        """Log out.

        Steps:
        Click on the 'Login' button
        Enter the admin account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Log out option

        Expected Result:
        The User is signed out
        """
        self.ps.test_updates['name'] = 't1.36.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.003', '8240']
        self.ps.test_updates['passed'] = False

        self.admin.login()
        self.admin.open_user_menu()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@value,"Log Out")]')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.find(
            By.XPATH, '//div[contains(@class,"tutor-home")]')

        self.ps.test_updates['passed'] = True

    # Case C8241 - 004 - Content Analyst | Log into Tutor
    @pytest.mark.skipif(str(8241) not in TESTS, reason='Excluded')
    def test_content_analyst_log_into_tutor_8241(self):
        """Log into Tutor.

        Steps:
        Click on the 'Login' button
        Enter the content analyst account in the username and password boxes
        Click on the 'Sign in' button

        Expected Result:
        The user is signed in
        """
        self.ps.test_updates['name'] = 't1.36.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.004', '8241']
        self.ps.test_updates['passed'] = False

        self.content.get(self.content.url)
        self.content.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.content.driver.get_window_size()['width'] <= \
           self.content.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.content.find(
                By.XPATH,
                '//button[contains(@class,"navbar-toggle")]'
            )
            # check if the menu is collapsed and, if yes, open it
            if('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.content.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Login')
            )
        ).click()
        self.content.page.wait_for_page_load()
        self.content.find(
            By.ID,
            'auth_key'
        ).send_keys(self.content.username)
        self.content.find(
            By.ID,
            'password'
        ).send_keys(self.content.password)
        # click on the sign in button
        self.content.find(
            By.XPATH,
            '//button[text()="Sign in"]'
        ).click()
        self.content.page.wait_for_page_load()
        assert('dashboard' in self.content.current_url()), \
            'Not taken to dashboard: %s' % self.content.current_url()

        self.ps.test_updates['passed'] = True

    # Case C8242 - 005 - Content Analyst | Access the QA Viewer
    @pytest.mark.skipif(str(8242) not in TESTS, reason='Excluded')
    def test_content_analyst_access_the_qa_viewer_8242(self):
        """Access the QA Viewer.

        Steps:
        Click on the 'Login' button
        Enter the content analyst account in the username and password boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the QA Content option

        Expected Result:
        The user is presented with the QA viewer
        """
        self.ps.test_updates['name'] = 't1.36.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.005', '8242']
        self.ps.test_updates['passed'] = False

        self.content.login()
        self.content.open_user_menu()
        self.content.wait.until(
            expect.element_to_be_clickable((
                By.XPATH,
                '//a[contains(text(),"QA Content") and @role="menuitem"]'
            ))
        ).click()
        self.content.page.wait_for_page_load()
        assert('/qa' in self.content.current_url()), \
            'Not taken to the QA viewer: %s' % self.content.current_url()

        self.ps.test_updates['passed'] = True

    # Case C8243 - 006 - Content Analyst | Access the Content Analyst Console
    @pytest.mark.skipif(str(8243) not in TESTS, reason='Excluded')
    def test_content_analyst_access_the_content_analyst_console_8243(self):
        """Access the Content Annalyst Console.

        Steps:
        Click on the 'Login' button
        Enter the content analyst account in the username and password boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Content Analyst option

        Expected Result:
        The user is presented with the Content Analyst Console
        """
        self.ps.test_updates['name'] = 't1.36.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.006', '8243']
        self.ps.test_updates['passed'] = False

        self.content.login()
        self.content.open_user_menu()
        self.content.wait.until(
            expect.element_to_be_clickable((
                By.XPATH,
                '//a[contains(text(),"Content Analyst") and @role="menuitem"]'
            ))
        ).click()
        self.content.page.wait_for_page_load()
        self.content.find(
            By.XPATH,
            '//h1[contains(text(),"Content Analyst Console")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C8244 - 007 - Content Analyst | Log out
    @pytest.mark.skipif(str(8244) not in TESTS, reason='Excluded')
    def test_content_analyst_log_out_8244(self):
        """Log out.

        Steps:
        Click on the 'Login' button
        Enter the content analyst account in the username and password boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Log out option

        Expected Result:
        The user is logged out
        """
        self.ps.test_updates['name'] = 't1.36.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.007', '8244']
        self.ps.test_updates['passed'] = False

        self.content.login()
        self.content.open_user_menu()
        self.content.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@value,"Log Out")]')
            )
        ).click()
        self.content.page.wait_for_page_load()
        self.content.find(
            By.XPATH,
            '//div[contains(@class,"tutor-home")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C8245 - 008 - Student | Log into Tutor
    @pytest.mark.skipif(str(8245) not in TESTS, reason='Excluded')
    def test_student_log_into_tutor_8245(self):
        """Log into Tutor.

        Steps:
        Click on the 'Login' button
        Enter the student account in the username and password text boxes
        Click on the 'Sign in' button

        Expected Result:
        The user is logged in
        """
        self.ps.test_updates['name'] = 't1.36.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.008', '8245']
        self.ps.test_updates['passed'] = False

        self.student.get(self.student.url)
        self.student.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.student.driver.get_window_size()['width'] <= \
           self.student.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.student.find(
                By.XPATH,
                '//button[contains(@class,"navbar-toggle")]'
            )
            # check if the menu is collapsed and, if yes, open it
            if('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Login')
            )
        ).click()
        self.student.page.wait_for_page_load()
        self.student.find(
            By.ID,
            'auth_key'
        ).send_keys(self.student.username)
        self.student.find(
            By.ID,
            'password'
        ).send_keys(self.student.password)
        # click on the sign in button
        self.student.find(
            By.XPATH,
            '//button[text()="Sign in"]'
        ).click()
        self.student.page.wait_for_page_load()
        assert('dashboard' in self.student.current_url()), \
            'Not taken to dashboard: %s' % self.student.current_url()

        self.ps.test_updates['passed'] = True

    # Case C8246 - 009 - Teacher | Log into Tutor
    @pytest.mark.skipif(str(8246) not in TESTS, reason='Excluded')
    def test_teacher_log_into_tutor_8246(self):
        """Log into Tutor.

        Steps:
        Click on the 'Login' button
        Enter the teacher account in the username and password text boxes
        Click on the 'Sign in' button

        Expected Result:
        The user is logged in
        """
        self.ps.test_updates['name'] = 't1.36.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.009', '8246']
        self.ps.test_updates['passed'] = False

        self.teacher.get(self.teacher.url)
        self.teacher.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.teacher.driver.get_window_size()['width'] <= \
           self.teacher.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.teacher.find(
                By.XPATH,
                '//button[contains(@class,"navbar-toggle")]'
            )
            # check if the menu is collapsed and, if yes, open it
            if('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Login')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID,
            'auth_key'
        ).send_keys(self.teacher.username)
        self.teacher.find(
            By.ID,
            'password'
        ).send_keys(self.teacher.password)
        # click on the sign in button
        self.teacher.find(
            By.XPATH,
            '//button[text()="Sign in"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        assert('dashboard' in self.teacher.current_url()),\
            'Not taken to dashboard: %s' % self.teacher.current_url()

        self.ps.test_updates['passed'] = True

    # Case C58271 - 010 - Student | Log out
    @pytest.mark.skipif(str(58271) not in TESTS, reason='Excluded')
    def test_content_analyst_log_out_58271(self):
        """Log out.

        Steps:
        Click on the 'Login' button
        Enter the student account in the username and password boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Log out option

        Expected Result:
        The user is logged out
        """
        self.ps.test_updates['name'] = 't1.36.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.010', '58271']
        self.ps.test_updates['passed'] = False

        self.student.login()
        self.student.open_user_menu()
        self.student.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@value,"Log Out")]')
            )
        ).click()
        self.student.page.wait_for_page_load()
        self.student.find(
            By.XPATH,
            '//div[contains(@class,"tutor-home")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C58272 - 011 - Teacher | Log out
    @pytest.mark.skipif(str(58272) not in TESTS, reason='Excluded')
    def test_teacher_log_out_58272(self):
        """Log out.

        Steps:
        Click on the 'Login' button
        Enter the teacher account in the username and password boxes
        Click on the 'Sign in' button
        Click on the user menu
        Click on the Log out option

        Expected Result:
        The user is logged out
        """
        self.ps.test_updates['name'] = 't1.36.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.36', 't1.36.011', '58272']
        self.ps.test_updates['passed'] = False

        self.teacher.login()
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@value,"Log Out")]')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH,
            '//div[contains(@class,"tutor-home")]'
        )

        self.ps.test_updates['passed'] = True
class TestRecruitingTeachers(unittest.TestCase):
    """CC1.01 - Recruiting Teachers."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.CONDENSED_WIDTH = 1105

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C7751 - 001 - Admin | Recruitment and promo website is available
    @pytest.mark.skipif(str(7751) not in TESTS, reason='Excluded')
    def test_admin_recruitment_and_promo_website_is_available_7751(self):
        """Recruitment and promo website is available.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org/ )

        Expected Result:
        Recruitment website loads and renders
        """
        self.ps.test_updates['name'] = 'cc1.01.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.001',
            '7751'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()

        self.ps.test_updates['passed'] = True

    # Case C7752 - 002 - Teacher | Information about Concept Coach and the
    # pilot are available on the demo site
    @pytest.mark.skipif(str(7752) not in TESTS, reason='Excluded')
    def test_teacher_information_about_cc_is_available_on_demo_site_7752(self):
        """Information about CC and pilot are available on the demo site.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org/ )

        Expected Result:
        Page loads several sections describing Concept Coach
        """
        self.ps.test_updates['name'] = 'cc1.01.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.002',
            '7752'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(By.ID, 'who-we-are')

        self.ps.test_updates['passed'] = True

    # Case C7753 - 003 - Teacher | Can interact with a Concept Coach wire frame
    # for each subject
    @pytest.mark.skipif(str(7753) not in TESTS, reason='Excluded')
    def test_teacher_can_interact_with_a_cc_wire_frame_for_subjects_7753(self):
        """Can interact with a Concept Coach wire frame for each subject.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org/)
        Hover over "demos" in the header
        Click "Interactice Demo"
        CLick on a Concept Coach book title

        Expected Result:
        A new tab or window opens rendering the demo content for the selected
        book
        """
        self.ps.test_updates['name'] = 'cc1.01.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.003',
            '7753'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        demo_link = self.teacher.find(
            By.XPATH,
            '//section[@id="interactive-demo"]' +
            '//a[@class="btn" and contains(@href,"cc-mockup")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', demo_link)
        self.teacher.driver.execute_script('window.scrollBy(0, -80);')
        self.teacher.sleep(1)
        demo_link.click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        self.teacher.page.wait_for_page_load()
        assert('http://cc.openstax.org/assets/demos/cc-mockup' in
               self.teacher.current_url()), \
            'not at demo book'
        self.ps.test_updates['passed'] = True

    # # NOT DONE
    # Case C7754 - 004 - Teacher | View a Concept Coach demo video
    @pytest.mark.skipif(str(7754) not in TESTS, reason='Excluded')
    def test_teacher_view_a_concept_coach_demo_video_7754(self):
        """View a Concept Coach demo video.

        Steps:
        Open recruitment website ( http://cc.openstax.org/ )
        Hover over "demos" in the header
        Click "Interactive Demo"
        Click on a Concept Coach book title
        Scroll down until an embedded video pane is displayed
        Click on the right-pointing arrow to play the video

        Expected Result:
        The video loads and plays
        """
        self.ps.test_updates['name'] = 'cc1.01.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.004',
            '7754'
        ]
        self.ps.test_updates['passed'] = False

        raise NotImplementedError(inspect.currentframe().f_code.co_name)
        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        demo_link = self.teacher.find(
            By.XPATH,
            '//section[@id="interactive-demo"]' +
            '//a[@class="btn" and contains(@href,"cc-mockup-physics")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', demo_link)
        self.teacher.driver.execute_script('window.scrollBy(0, -80);')
        self.teacher.sleep(1)
        demo_link.click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        self.teacher.page.wait_for_page_load()
        self.teacher.sleep(2)
        # self.teacher.find(
        #     By.XPATH, '//div[@id="player"]'
        # ).click()
        title = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[contains(text(),"Inelastic Collisions")]')
            )
        )
        # self.teacher.wait.until(
        #     expect.presence_of_element_located(
        #         (By.ID, 'player')
        #     )
        # )
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(title)
        actions.move_by_offset(0, 300)
        actions.click()
        actions.perform()
        self.teacher.sleep(2)
        self.teacher.find(
            By.XPATH,
            '//div[contains(@class,"playing-mode")]'
        )
        # actions.perform()
        self.teacher.find(
            By.XPATH,
            '//div[@id="player"]/div[contains(@class,"paused-mode")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7755 - 005 - Teacher | Sample exercise questions are seen in
    # the wire frames
    @pytest.mark.skipif(str(7755) not in TESTS, reason='Excluded')
    def test_teacher_sample_exercise_questions_are_in_wire_frames_7755(self):
        """Sample exercise questions are seen in the wire frames.

        Steps:
        Open recruitment website ( http://cc.openstax.org/ )
        Hover over "demos" in the header
        Click "Interactive Demo"
        Click on a Concept Coach book title
        Scroll down until the 'CONCEPT COACH' pane is displayed

        Expected Result:
        Demo exercises are rendered and can be answered along with showing
        feedback
        """
        self.ps.test_updates['name'] = 'cc1.01.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.005',
            '7755'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        demo_link = self.teacher.find(
            By.XPATH,
            '//section[@id="interactive-demo"]' +
            '//a[@class="btn" and contains(@href,"cc-mockup-physics")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', demo_link)
        self.teacher.driver.execute_script('window.scrollBy(0, -80);')
        self.teacher.sleep(1)
        demo_link.click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        self.teacher.page.wait_for_page_load()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, '//span[contains(text(),"JUMP TO CONCEPT COACH")]'
        ).click()
        self.teacher.find(
            By.XPATH, '//div[contains(@data-label,"q1-multiple-choice")]')
        self.teacher.sleep(2)
        answer = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@data-label,"choice-1b-text")]')
            )
        )
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(answer)
        actions.click()
        actions.perform()
        self.teacher.find(
            By.XPATH, "//div[@data-label='State2']"
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 "//div[@data-label='q1-answer-b']//div[@data-label='next']")
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7756 - 006 - Teacher | Access Concept Coach help and support before
    # the teacher's course is created
    @pytest.mark.skipif(str(7756) not in TESTS, reason='Excluded')
    def test_teacher_access_cc_support_before_course_is_created_7756(self):
        """Access CC help and support before the teacher's course is created.

        Steps:
        Open the recruitment website ( http://cc.openstax.org/ )
        Click "Support" in the header

        Expected Result:
        A new tab opens with the CC Help Center
        """
        self.ps.test_updates['name'] = 'cc1.01.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.006',
            '7756'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        if self.teacher.driver.get_window_size()['width'] < \
                self.CONDENSED_WIDTH:
            self.teacher.wait.until(
                expect.visibility_of_element_located(
                    (By.XPATH, '//label[@for="mobileNavToggle" and ' +
                     'contains(@class,"fixed")]')
                )
            ).click()
            self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, '//a[contains(text(),"support")]'
        ).click()
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7757 - 007 - Teacher | Teacher registers to use a CC course
    @pytest.mark.skipif(str(7757) not in TESTS, reason='Excluded')
    def test_teacher_teacher_registers_to_use_a_cc_course_7757(self):
        """Teacher registers to use a Concept Coach course.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org )
        Click on the 'sign up now' button

        Expected Result:
        Web form renders
        """
        self.ps.test_updates['name'] = 'cc1.01.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.007',
            '7757'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        self.ps.test_updates['passed'] = True

    # Case C7758 - 008 - Teacher | Teacher uses a web form to sign up for CC
    @pytest.mark.skipif(str(7758) not in TESTS, reason='Excluded')
    def test_teacher_teacher_uses_a_web_form_to_sign_up_for_cc_7758(self):
        """Teacher uses a web form to sign up for Concept Coach.

        Steps:
        Teacher fills out the form

        Expected Result:
        Preconditions pass.
        User is presented with a confirmation message
        """
        self.ps.test_updates['name'] = 'cc1.01.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.008',
            '7758'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        self.teacher.find(
            By.ID, 'first_name'
        ).send_keys('first')
        self.teacher.find(
            By.ID, 'last_name'
        ).send_keys('last')
        self.teacher.find(
            By.ID, 'email'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.ID, 'company'
        ).send_keys('school')
        menu = self.teacher.find(
            By.XPATH,
            '//span[@id="book-select"]' +
            '//span[contains(@class,"select2-container--")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', menu)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        menu.click()
        self.teacher.sleep(0.5)
        self.teacher.find(
            By.XPATH,
            '//li[contains(@class,"select2-results__option")]'
        ).click()
        self.teacher.find(
            By.XPATH, '//input[@maxlength="255" and @required]'
        ).send_keys('25')
        self.teacher.find(
            By.XPATH, '//input[@type="submit"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Thank you")]')
            )
        )
        assert('/thank-you' in self.teacher.current_url()), \
            'not at thank you page after submitting form'

        self.ps.test_updates['passed'] = True

    # Case C7759 - 009 - Teacher | Receive error messages if required fields on
    # the sign up form are blank
    @pytest.mark.skipif(str(7759) not in TESTS, reason='Excluded')
    def test_teacher_receive_error_messages_if_required_fields_are_7759(self):
        """Receive error messages if required fields on the sign up form are blank.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org/ )
        Click on the 'sign up now' button
        Submit the form without changing any of the text fields

        Expected Result:
        Receive 'Please fill out this field' error messages in red for
        each blank required field
        """
        self.ps.test_updates['name'] = 'cc1.01.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.009',
            '7759'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        submit = self.teacher.find(
            By.XPATH, '//input[@type="submit"]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', submit)
        self.teacher.sleep(0.5)
        submit.click()
        assert('/sign-up' in self.teacher.current_url()), \
            'moved from sign up when submitting with blank required fields'
        self.teacher.find(
            By.XPATH, '//div[contains(text(),"Please fill out this field.")]'
        )

        self.ps.test_updates['passed'] = True

    # Case C7760 - 010 - Teacher | Submit a form to supply required course info
    @pytest.mark.skipif(str(7760) not in TESTS, reason='Excluded')
    def test_teacher_submit_a_form_to_supply_required_course_info_7760(self):
        """Submit a form to supply required course information.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org )
        Click on the 'sign up now' button
        Fill out the intent to participate form
        Submit the form

        Expected Result:
        Web form submits
        Displays a Thank you message panel
        """
        self.ps.test_updates['name'] = 'cc1.01.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.010',
            '7760'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        self.teacher.find(
            By.ID, 'first_name'
        ).send_keys('first')
        self.teacher.find(
            By.ID, 'last_name'
        ).send_keys('last')
        self.teacher.find(
            By.ID, 'email'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.ID, 'company'
        ).send_keys('school')
        # choose a book!
        menu = self.teacher.find(
            By.XPATH,
            '//span[@id="book-select"]' +
            '//span[contains(@class,"select2-container--")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', menu)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        menu.click()
        self.teacher.sleep(0.5)
        self.teacher.find(
            By.XPATH,
            '//li[contains(@class,"select2-results__option")]'
        ).click()
        self.teacher.find(
            By.XPATH, '//input[@maxlength="255" and @required]'
        ).send_keys('25')
        self.teacher.find(
            By.XPATH, '//input[@type="submit"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Thank you")]')
            )
        )
        assert('/thank-you' in self.teacher.current_url()), \
            'not at thank you page after submitting form'

        self.ps.test_updates['passed'] = True

    # Case C7761 - 011 - Teacher | Submit co-instructors, classes, names, etc.
    @pytest.mark.skipif(str(7761) not in TESTS, reason='Excluded')
    def test_teacher_submit_coinstructors_classes_names_etc_7761(self):
        """Submit co-instructors, classes, names and other data.

        Steps:
        Go to the recruitment and promo website ( http://cc.openstax.org/ )
        Click on the 'sign up now' button
        Click on the 'Co-Teaching class with a colleague?' circle button
        Enter the co-instructor's (or co-instructors') information
        Enter text into other fields concerning classe, names, etc.

        Expected Result:
        Input box exists for instructor information, class details and
        other data.
        The user is able to input information.
        """
        self.ps.test_updates['name'] = 'cc1.01.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.011',
            '7761'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        option = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[@class="slide-checkbox"]/label')
            )
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', option)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        option.click()
        textarea = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[@id="coteachcontact"]/textarea')
            )
        )
        textarea.send_keys('co teacher info')
        self.ps.test_updates['passed'] = True

    # Case C7762 - 012 - Teacher | Select the textbook to use in the course
    @pytest.mark.skipif(str(7762) not in TESTS, reason='Excluded')
    def test_teacher_select_the_textbook_to_use_in_the_course_7762(self):
        """Select the textbook to use in the course.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org )
        Click on the 'sign up now' button
        Select the course textbook from the 'Book' dropdown options

        Expected Result:
        Able to select any Concept Coach textbook
        """
        self.ps.test_updates['name'] = 'cc1.01.012' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.012',
            '7762'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        menu = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//span[@id="book-select"]' +
                 '//span[contains(@class,"select2-container--")]')
            )
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', menu)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        menu.click()
        self.teacher.sleep(0.5)
        book = self.teacher.find(
            By.XPATH,
            '//li[contains(@class,"select2-results__option")]'
        )
        title = book.text
        book.click()
        self.teacher.sleep(0.5)
        self.teacher.find(
            By.XPATH,
            '//span[contains(@title,"' + title + '") and ' +
            'contains(@class,"select2-selection__rendered")]'
        )
        self.ps.test_updates['passed'] = True

    # Case C7763 - 013 - Teacher | Indicate whether the teacher was recruited
    # by OpenStax
    @pytest.mark.skipif(str(7763) not in TESTS, reason='Excluded')
    def test_teacher_indicate_whether_the_teacher_was_recruited_by_7763(self):
        """Indicate if the teacher was or was not recruited by OpenStax.

        Steps:
        Go to the recruitment and promo website ( http://cc.openstax.org/ )
        Click on the 'sign up now' button ( http://cc.openstax.org/sign-up )
        Enter recruitment information into the 'Anything else we need to know?'
        text box

        Expected Result:
        Able to input recruitment information
        """
        self.ps.test_updates['name'] = 'cc1.01.013' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.013',
            '7763'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        textarea = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//textarea[@placeholder="Feedback"]')
            )
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', textarea)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        textarea.send_keys('recuitment info')
        self.ps.test_updates['passed'] = True

    # Case C7764 - 014 - Teacher | Presented a thank you page after registering
    # to use Concept Coach
    @pytest.mark.skipif(str(7764) not in TESTS, reason='Excluded')
    def test_teacher_presented_a_thank_you_page_after_registering_7764(self):
        """Presented a thank you page after registering to use Concept Coach.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org )
        Click on the 'sign up now' button
        Fill out the intent to participate form
        Submit the form

        Expected Result:
        Displays a Thank you message panel
        """
        self.ps.test_updates['name'] = 'cc1.01.014' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.014',
            '7764'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        self.teacher.find(
            By.ID, 'first_name'
        ).send_keys('first')
        self.teacher.find(
            By.ID, 'last_name'
        ).send_keys('last')
        self.teacher.find(
            By.ID, 'email'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.ID, 'company'
        ).send_keys('school')
        menu = self.teacher.find(
            By.XPATH,
            '//span[@id="book-select"]' +
            '//span[contains(@class,"select2-container--")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', menu)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        menu.click()
        self.teacher.sleep(0.5)
        self.teacher.find(
            By.XPATH,
            '//li[contains(@class,"select2-results__option")]'
        ).click()
        self.teacher.find(
            By.XPATH, '//input[@maxlength="255" and @required]'
        ).send_keys('25')
        self.teacher.find(
            By.XPATH, '//input[@type="submit"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Thank you")]')
            )
        )
        assert('/thank-you' in self.teacher.current_url()), \
            'not at thank you page after submitting form'

        self.ps.test_updates['passed'] = True

    # Case C7765 - 015 - Teacher | Sign up for an OpenStax Accounts username
    @pytest.mark.skipif(str(7765) not in TESTS, reason='Excluded')
    def test_teacher_sign_up_for_an_openstax_accounts_username_7765(self):
        """Sign up for an OpenStax Accounts username.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org )
        Click on the 'sign up now' button
        Fill out the intent to participate form
        Submit the form

        Expected Result:
        Displays a Thank you message panel
        """
        self.ps.test_updates['name'] = 'cc1.01.015' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.015',
            '7765'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//section[@id="video2"]//a[@href="/sign-up"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'signup-form'
        )
        self.teacher.find(
            By.ID, 'first_name'
        ).send_keys('first')
        self.teacher.find(
            By.ID, 'last_name'
        ).send_keys('last')
        self.teacher.find(
            By.ID, 'email'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.ID, 'company'
        ).send_keys('school')
        menu = self.teacher.find(
            By.XPATH,
            '//span[@id="book-select"]' +
            '//span[contains(@class,"select2-container--")]'
        )
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', menu)
        self.teacher.driver.execute_script('window.scrollBy(0, -120);')
        self.teacher.sleep(0.5)
        menu.click()
        self.teacher.sleep(0.5)
        self.teacher.find(
            By.XPATH,
            '//li[contains(@class,"select2-results__option")]'
        ).click()
        self.teacher.find(
            By.XPATH, '//input[@maxlength="255" and @required]'
        ).send_keys('25')
        self.teacher.find(
            By.XPATH, '//input[@type="submit"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//h1[contains(text(),"Thank you")]')
            )
        )
        assert('/thank-you' in self.teacher.current_url()), \
            'not at thank you page after submitting form'

        self.ps.test_updates['passed'] = True

    # Case C7770 - 020 - Admin | Add co-instructors to a course
    @pytest.mark.skipif(str(7770) not in TESTS, reason='Excluded')
    def test_admin_add_coinstructors_to_a_course_7770(self):
        """Add co-instructors to a course.

        Steps:
        Log into Tutor as an admin
        From the user menu, select 'Admin'
        From the 'Course Organization' menu, select 'Courses'
        In the Courses table, find the correct course and click the 'Edit'
            button on the right side of that row
        Click on the 'Teachers' tab
        In the search box, enter the teacher's name or username
        Select the teacher in the list below the search bar or hit the down
            arrow followed by the enter/return key

        Expected Result:
        Co-instructor is linked to the affected course
        """
        self.ps.test_updates['name'] = 'cc1.01.020' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.020',
            '7770'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login(
            username=os.getenv('ADMIN_USER'),
            password=os.getenv('ADMIN_PASSWORD'))
        self.teacher.open_user_menu()
        self.teacher.find(
            By.XPATH, '//a[@role="menuitem" and contains(text(),"Admin")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Course Organization')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Courses')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Edit')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Teachers')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'course_teacher')
            )
        ).send_keys('teacher0')
        element = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//ul[contains(@class,"ui-autocomplete")]' +
                 '//li[contains(text(),"(teacher0")]')
            )
        )
        teacher_name = element.text.split(' (')[0]
        element.click()
        # check that the teacher has been added to the table
        print(teacher_name)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//td[contains(text(),"' + teacher_name + '")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7771 - 021 - Teacher | Login with an Existing OpenStax Account
    @pytest.mark.skipif(str(7771) not in TESTS, reason='Excluded')
    def test_teacher_login_with_an_existing_openstax_account_7771(self):
        """Log in with an Existing OpenStax Accounts username.

        Steps:
        Go to the recruitment website ( http://cc.openstax.org/ )
        Click on faculty login
        You are redirected to the accounts page.
        Enter a username and password
        click on Login.

        Expected Result:
        Login should be successful. It should take you to the teacher course
        picker/dashboard page.
        """
        self.ps.test_updates['name'] = 'cc1.01.021' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.021',
            '7771'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get(self.teacher.url)
        self.teacher.page.wait_for_page_load()
        # check to see if the screen width is normal or condensed
        if self.teacher.driver.get_window_size()['width'] <= \
           self.teacher.CONDENSED_WIDTH:
            # get small-window menu toggle
            is_collapsed = self.teacher.find(
                By.XPATH,
                '//button[contains(@class,"navbar-toggle")]'
            )
            # check if the menu is collapsed and, if yes, open it
            if('collapsed' in is_collapsed.get_attribute('class')):
                is_collapsed.click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Login')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID,
            'auth_key'
        ).send_keys(self.teacher.username)
        self.teacher.find(
            By.ID,
            'password'
        ).send_keys(self.teacher.password)
        # click on the sign in button
        self.teacher.find(
            By.XPATH,
            '//button[text()="Sign in"]'
        ).click()
        self.teacher.page.wait_for_page_load()
        assert('dashboard' in self.teacher.current_url()),\
            'Not taken to dashboard: %s' % self.teacher.current_url()

        self.ps.test_updates['passed'] = True

    # Case C7772 - 022 - Teacher | Access the Concept Coach course
    @pytest.mark.skipif(str(7772) not in TESTS, reason='Excluded')
    def test_teacher_access_the_cc_course_7772(self):
        """Access the Concept Coach course.

        Steps:
        Once you login you will be taken to a course picker page.
        Click on the course you want to check the dashboard

        Expected Result:
        At Concept Coach teacher dashboard
        """
        self.ps.test_updates['name'] = 'cc1.01.022' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.022',
            '7772'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        assert('cc-dashboard' in self.teacher.current_url()),\
            'Not taken to dashboard: %s' % self.teacher.current_url()

        self.ps.test_updates['passed'] = True

    # Case C7773 - 023 - Admin | Distribute access codes for the course
    @pytest.mark.skipif(str(7773) not in TESTS, reason='Excluded')
    def test_admin_distribute_access_codes_for_the_course_7773(self):
        """Distribute access codes for the teacher's course.

        Steps:
        CC approves a faculty.
        Login as admin
        Click on user menu
        Click on Admin
        Click on Salesforce tab
        Click on import [Do not check the box]
        This will automatically create a course for the teacher created.
        Email is sent to the email id used when signing up with
            the unique course URL.

        Expected Result:
        Instructors are emailed the unique course url to the address provided
        when they signed up.
        """
        self.ps.test_updates['name'] = 'cc1.01.023' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.023',
            '7773'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)
        admin = Admin(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            # pasta_user=self.ps,
            # capabilities=self.desired_capabilities
        )
        admin.login()
        admin.open_user_menu()
        admin.find(By.LINK_TEXT, 'Admin').click()
        admin.page.wait_for_page_load()
        admin.find(By.LINK_TEXT, 'Salesforce').click()
        admin.page.wait_for_page_load()
        admin.find(
            By.XPATH, '//input[@vale="Import Courses"]'
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7774 - 024 - Teacher | Access CC help and support during the course
    @pytest.mark.skipif(str(7774) not in TESTS, reason='Excluded')
    def test_teacher_acccess_cc_help_and_support_during_the_course_7774(self):
        """Access Concept Coach help and support during the course.

        Steps:
        Login as teacher
        Click on the course name
        On dashboard click on the name of the teacher
        It drops down and displays several options.
        Click on Get Help

        Expected Result:
        It should open a new tab which shows the openstax.force.com
        """
        self.ps.test_updates['name'] = 'cc1.01.024' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.024',
            '7774'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Get Help"
        ).click()
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7775 - 025 - Teacher | Access CC help and support after course ends
    @pytest.mark.skipif(str(7775) not in TESTS, reason='Excluded')
    def test_teacher_access_cc_help_and_support_after_course_ends_7775(self):
        """Access Concept Coach help and support after the end of the course.

        Steps:
        Login as teacher
        Click on the course name
        On dashboard click on the name of the teacher
        It drops down and displays several options.
        Click on Get Help

        Expected Result:
        It should open a new tab which shows the CC help center
        """
        self.ps.test_updates['name'] = 'cc1.01.025' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.01',
            'cc1.01.025',
            '7775'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Get Help"
        ).click()
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        ).click()

        self.ps.test_updates['passed'] = True
class TestIImproveQuestionManagement(unittest.TestCase):
    """CC2.11 - Improve Question Management."""

    def setUp(self):
        """Pretest settings."""

        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student = Student(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        self.student = None
        try:
            self.teacher.delete()
        except:
            pass

    # 14851 - 001 - Teacher | Review all questions
    @pytest.mark.skipif(str(14851) not in TESTS, reason='Excluded')
    def test_teacher_review_all_questions_14851(self):
        """Review all questions.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a CC course name
        Click "Question Library" from the user menu
        Select a section or chapter
        Click "Show Questions"

        Expected Result:
        The user is presented with all the questions for the section or chapter
        """
        self.ps.test_updates['name'] = 'cc2.11.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.001', '14851']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Question Library'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.1"]'
        ).click()
        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.find(
            By.XPATH, '//button[text()="Show Questions"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="exercises"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # 14852 - 002 - Teacher | Exclude certain questions
    @pytest.mark.skipif(str(14852) not in TESTS, reason='Excluded')
    def test_teacher_exclude_certain_questions_14852(self):
        """Exclude certain quesitons.

        Steps:
        If the user has more than one course, click on a CC course name
        Click "Question Library" from the user menu
        Select a section or chapter
        Click "Show Questions"
        Hover over the desired question and click "Exclude question"

        Expected Result:
        Question is grayed out
        """
        self.ps.test_updates['name'] = 'cc2.11.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.002', '14852']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Question Library'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.2"]'
        ).click()
        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.find(
            By.XPATH, '//button[text()="Show Questions"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="exercises"]')
            )
        )
        self.teacher.sleep(1)
        i = 1
        question = None
        # loop finding a question that is not yet excleded
        # there are 9 question in the exact textbook and chpater this test
        # is searching. limiting loop at 7 incase questions are removed.
        while i < 8:
            question = self.teacher.find(
                By.XPATH,
                '//div[@class="exercises"]/div[' + str(i) + ']'
            )
            if ('is-selected' not in question.get_attribute('class')):
                break
            i += 1
        Assignment.scroll_to(self.teacher.driver, question)
        self.teacher.sleep(1)
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(question)
        # way to stall because not sure how to add wait in action chain
        for _ in range(50):
            actions.move_by_offset(-1, 0)
        actions.click()
        actions.move_by_offset(-50, -300)
        actions.perform()
        self.teacher.sleep(0.5)
        question_excluded = self.teacher.find(
            By.XPATH, '//div[@class="exercises"]/div[' + str(i) + ']'
        ).get_attribute('class')
        assert('is-selected' in question_excluded), 'question not excluded'
        self.ps.test_updates['passed'] = True

    # 14855 - 003 - Teacher | Pin tabs on top of screen when scrolled
    @pytest.mark.skipif(str(14855) not in TESTS, reason='Excluded')
    def test_teacher_pin_tabs_on_top_of_screen_when_scrolled_14855(self):
        """Pin tabs on top of screen when scrolled.

        Steps:
        If the user has more than one course, click on a CC course name
        Click "Question Library" from the user menu
        Select a section or chapter
        Click "Show Questions"
        Scroll down

        Expected Result:
        Tabs are pinned to top of the screen when scrolled
        """
        self.ps.test_updates['name'] = 'cc2.11.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.003', '14855']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Question Library'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.2"]'
        ).click()
        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.find(
            By.XPATH, '//button[text()="Show Questions"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="exercises"]')
            )
        )
        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="pinned-header"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # 14856 - 004 - Teacher | Make section links jumpable
    @pytest.mark.skipif(str(14856) not in TESTS, reason='Excluded')
    def test_teacher_make_section_links_jumpable_14856(self):
        """Make section links jumpable.

        Steps:
        If the user has more than one course, click on a CC course name
        Click "Question Library" from the user menu
        Select a section or chapter
        Click "Show Questions"
        Click on the section links at the top of the screen

        Expected Result:
        The screen scrolls to the selected questions
        """
        self.ps.test_updates['name'] = 'cc2.11.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.004', '14856']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Question Library'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.2"]'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.1"]'
        ).click()

        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.find(
            By.XPATH, '//button[text()="Show Questions"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="exercises"]')
            )
        )
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="pinned-header"]'
                 '//div[@class="section" and text()="1.2"]')
            )
        ).click()
        self.teacher.sleep(1)
        # click the heading as simple way to find that it is on screen
        # and not just visible but scrolled off screen
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="exercise-sections"]' +
                 '//span[@class="chapter-section" ' +
                 'and @data-chapter-section="1.2"]')
            )
        ).click()
        self.ps.test_updates['passed'] = True

    # 14858 - 005 - Teacher | Report errata about assessments in Concept Coach
    @pytest.mark.skipif(str(14858) not in TESTS, reason='Excluded')
    def test_teacher_report_errata_about_assessments_in_cc_14858(self):
        """Report errata about assessments in Concept Coach.

        Steps:
        If the user has more than one course, click on a CC course name
        Click "Question Library" from the user menu
        Select a section or chapter
        Click "Show Questions"
        Hover over the desired question and click "Question details"
        Click "Report an error"

        Expected Result:
        A new tab with the assessment errata form appears, with the assessment
        ID already filled in
        """
        self.ps.test_updates['name'] = 'cc2.11.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.005', '14858']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Question Library'
        ).click()
        self.teacher.find(
            By.XPATH,
            '//div[@class="section"]//span[@class="chapter-section" ' +
            'and @data-chapter-section="1.2"]'
        ).click()
        self.teacher.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.teacher.find(
            By.XPATH, '//button[text()="Show Questions"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="exercises"]')
            )
        )
        self.teacher.sleep(1)
        question = self.teacher.find(
            By.XPATH, '//div[@class="exercises"]/div[1]'
        )
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(question)
        # way to stall because not sure how to add wait in action chain
        for _ in range(50):
            actions.move_by_offset(1, 0)
        actions.click()
        actions.perform()
        self.teacher.sleep(0.5)
        exercise_id = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//span[@class="exercise-tag" and contains(text(),"ID:")]')
            )
        ).text
        question = self.teacher.find(
            By.XPATH, '//div[@class="action report-error"]'
        ).click()
        window_with_form = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_form)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[text()="Report Content Errors"]')
            )
        )
        self.teacher.find(
            By.XPATH, '//input[@value="' + exercise_id[4:] + '"]')

        self.ps.test_updates['passed'] = True

    # 14859 - 006 - Student | Report errata about assessments in Concept Coach
    @pytest.mark.skipif(str(14859) not in TESTS, reason='Excluded')
    def test_student_report_errata_about_assessments_in_cc_14859(self):
        """Report errata about assessments in Concept Coach.

        Steps:
        Click on a CC course, if there are more than one
        Click on a non-introductory section
        Click "Jump to Concept Coach"
        Click "Launch Concept Coach"
        Click "Report an error" on an assessment

        Expected Result:
        A new tab with the assessment errata form appears, with the assessment
        ID already filled in
        """
        self.ps.test_updates['name'] = 'cc2.11.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['cc2', 'cc2.11', 'cc2.11.006', '14859']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        # raise NotImplementedError(inspect.currentframe().f_code.co_name)
        self.student.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"cnx.org/contents/")]'
        ).click()
        # get to non-into section
        self.student.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//button//span[text()="Contents"]')
            )
        ).click()
        self.student.sleep(0.5)
        self.student.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//span[@class="chapter-number" and text()="1.1"]')
            )
        ).click()
        # open concept coach
        self.student.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Jump to Concept Coach')
            )
        ).click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[text()="Launch Concept Coach"]')
            )
        ).click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//span[contains(@class,"core breadcrumb-exercise")]')
            )
        ).click()
        exercise_id = self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//span[@class="exercise-identifier-link"]' +
                 '/span[contains(text(),"@")]')
            )
        ).text
        self.teacher.find(By.LINK_TEXT, 'Report an error').click()
        window_with_form = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_form)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[text()="Report Content Errors"]')
            )
        )
        self.teacher.find(
            By.XPATH, '//input[@value="' + exercise_id + '"]')
        self.ps.test_updates['passed'] = True
class TestAccountMaintenance(unittest.TestCase):
    """T1.37 - Account Maintenance."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin.login()
        self.admin.wait = WebDriverWait(self.admin.driver, 15)
        self.admin.open_user_menu()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Admin')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.driver.find_element(
            By.XPATH,
            '//a[contains(text(),"Users")]'
        ).click()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.delete()
        except:
            pass

    # Case C8247 - 001 - Admin | Search for a username
    @pytest.mark.skipif(str(8247) not in TESTS, reason='Excluded')
    def test_admin_search_for_a_username_8247(self):
        """Search for a username.

        Steps:
        Enter a username into the search here text box
        Click on the 'Search' button

        Expected Result:
        A list of users with the search term in their name,
        or username is displayed.
        """
        self.ps.test_updates['name'] = 't1.37.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.001', '8247']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.driver.find_element(
            By.ID, 'query').send_keys('Atticus')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//td[contains(text(),"Atticus")]')

        self.ps.test_updates['passed'] = True

    # Case C8248 - 002 - Admin | Search for a user's name
    @pytest.mark.skipif(str(8248) not in TESTS, reason='Excluded')
    def test_admin_search_for_a_users_name_8248(self):
        """Search for a user's name.

        Steps:
        Click on the user's name in the top right corner to open drop down menu
        Click on the 'Admin' option of the drop down menu
        Click on 'Users' on the bar across the top
        Enter a user's name into the search here text box
        Click on the 'Search' button

        Expected Result:
        A list of users with the search term in their name,
        or username is displayed.
        """
        self.ps.test_updates['name'] = 't1.37.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.002', '8248']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.driver.find_element(
            By.ID, 'query').send_keys('student01')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//td[text()="student01"]')

        self.ps.test_updates['passed'] = True

    # Case C8249 - 003 - Admin | Create a new user
    @pytest.mark.skipif(str(8249) not in TESTS, reason='Excluded')
    def test_admin_create_a_user_8249(self):
        """Create a new user.

        Steps:
        Scroll to the bottom of the page
        Click on the 'Create user' button
        Enter account information into:
        -Username, Password, First name, and Last name text boxes
        Click on the 'Save' button

        Expected Result:
        Takes User back to the Users screen. New user is added.
        """
        self.ps.test_updates['name'] = 't1.37.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.003', '8249']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        num = str(randint(0, 999))
        self.admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Create user")]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'user_username'))
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_username').send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_password').send_keys('password')
        self.admin.driver.find_element(
            By.ID, 'user_first_name').send_keys('first_name_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_last_name').send_keys('last_name_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # look up account to check that the account was made
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//td[text()="automated_test_user_'+num+'"]')

        self.ps.test_updates['passed'] = True

    # Case C8250 - 004 - Admin | Edit a user
    @pytest.mark.skipif(str(8250) not in TESTS, reason='Excluded')
    def test_admin_edit_a_user_8250(self):
        """Edit a user.

        Steps:
        Create a user to edit
        Enter the user's name into the search here text box
        Click on the 'Search' button
        Click on the 'Edit' button next to the user
        Enter new account information into the First name text box
        Click on the 'Save' button

        Expected Result:
        User is taken back to the User screen.
        The chosen account's information is updated
        """
        self.ps.test_updates['name'] = 't1.37.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.004', '8250']
        self.ps.test_updates['passed'] = False

        # create a user
        num = str(randint(1000, 1999))
        self.admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Create user")]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'user_username'))
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_username').send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_password').send_keys('password')
        self.admin.driver.find_element(
            By.ID, 'user_first_name').send_keys('first_name_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_last_name').send_keys('last_name_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for that user
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        # edit user
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Edit")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_first_name').send_keys('_EDITED')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for user to make sure they were updated
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.driver.find_element(
            By.XPATH, '//td[contains(text(),"first_name_' + num + '_EDITED")]')

        self.ps.test_updates['passed'] = True

    # Case C8251 - 005 - Admin | Assign elevated permissions
    @pytest.mark.skipif(str(8251) not in TESTS, reason='Excluded')
    def test_admin_assign_elevated_permissions_8251(self):
        """Assign elevated permissions.

        Steps:
        Create a user to edit
        Enter the user's username into the search here text box
        Click on the 'Search' button
        Click on the 'Edit' button next to the user
        If check box for chosen permission is not checked, click on check box.
        Click on the 'Save' button

        Expected Result:
        User is taken back to the User screen.
        The chosen account's permissions are modified.
        """
        self.ps.test_updates['name'] = 't1.37.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.005', '8251']
        self.ps.test_updates['passed'] = False

        # create a user
        num = str(randint(2000, 2999))
        self.admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Create user")]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'user_username'))
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_username').send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_password').send_keys('password')
        self.admin.driver.find_element(
            By.ID, 'user_first_name').send_keys('first_name_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_last_name').send_keys('last_name_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for that user
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        # edit user
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Edit")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_content_analyst').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for user to make sure they were updated
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        element = self.admin.driver.find_element(By.XPATH, '//tr/td[5]')
        assert(element.get_attribute('innerHTML') == 'Yes'), \
            'permission not elevated ' + element.get_attribute('innerHTML')

        self.ps.test_updates['passed'] = True

    # Case C8252 - 006 - Admin | Remove elevated permissions
    @pytest.mark.skipif(str(8252) not in TESTS, reason='Excluded')
    def test_admin_remove_elevated_permissions_8252(self):
        """Remove elevated permissions.

        Steps:
        Create a user to edit
        Enter the user's name into the search here text box
        Click on the 'Search' button
        Click on the 'Edit' button next to the user
        If check box for chosen permission is checked, click to uncheck it.
        Click on the 'Save' button

        Expected Result:
        User is taken back to the User screen.
        The chosen account's permissions are modified.
        """
        self.ps.test_updates['name'] = 't1.37.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.006', '8252']
        self.ps.test_updates['passed'] = False

        # create a user
        num = str(randint(3000, 3999))
        self.admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Create user")]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'user_username'))
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_username').send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_password').send_keys('password')
        self.admin.driver.find_element(
            By.ID, 'user_first_name').send_keys('first_name_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_last_name').send_keys('last_name_'+num)
        self.admin.driver.find_element(
            By.ID, 'user_content_analyst').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for that user
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        element = self.admin.driver.find_element(By.XPATH, '//tr/td[5]')
        assert(element.get_attribute('innerHTML') == 'Yes'), \
            'permission not elevated ' + element.get_attribute('innerHTML')
        # edit user
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Edit")]')
            )
        ).click()
        self.admin.driver.find_element(
            By.ID, 'user_content_analyst').click()
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Save"]').click()
        # search for user to make sure they were updated
        self.admin.wait.until(
            expect.element_to_be_clickable((By.ID, 'query'))
        ).send_keys('automated_test_user_'+num)
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        element = self.admin.driver.find_element(By.XPATH, '//tr/td[5]')
        assert(element.get_attribute('innerHTML') == 'No'), \
            'permission not elevated ' + element.get_attribute('innerHTML')

        self.ps.test_updates['passed'] = True

    # Case C8253 - 007 - Admin | Impersonate a user
    @pytest.mark.skipif(str(8253) not in TESTS, reason='Excluded')
    def test_admin_impersonate_a_user_8253(self):
        """Impersonate a user.

        Steps:
        Click on the 'Sign in as' button next to a user

        Expected Result:
        Signs in as chosen chosen user.
        Goes to chosen users initial screen after login
        (different depending on the user)
        """
        self.ps.test_updates['name'] = 't1.37.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.37', 't1.37.007', '8253']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.driver.find_element(By.ID, 'query').send_keys('student01')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Sign in as")]')
            )
        ).click()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//span[contains(text(),"Atticus Finch")]')
            )
        )

        self.ps.test_updates['passed'] = True
class TestImproveCourseManagement(unittest.TestCase):
    """T2.07 - Improve Course Management."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities,
            existing_driver=self.teacher.driver
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin = None
            self.teacher.delete()
        except:
            pass

    # 14651 - 001 - Admin | View Student Use Statistics for Concept Coach
    # college assessments
    @pytest.mark.skipif(str(14651) not in TESTS, reason='Excluded')
    def test_admin_view_student_use_statistics_for_cc_college_asse_14651(self):
        """View Student Use Statistics for Concept Coach college assessments.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin account in the username and password text boxes
        Click on the 'Sign in' button
        Click "Admin" in the user menu
        Click "Stats"
        Click "Concept Coach"

        Expected Result:
        The user is presented with Concept Coach statistics
        """
        self.ps.test_updates['name'] = 't2.07.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.001',
            '14651'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.goto_admin_control()
        self.admin.sleep(5)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Stats')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Concept Coach')
            )
        ).click()

        assert('/stats/concept_coach' in self.admin.current_url()), \
            'Not viewing Concept Coach stats'

        self.ps.test_updates['passed'] = True

    # 14652 - 002 - Teacher | Delegate teaching tasks to supporting instructors
    @pytest.mark.skipif(str(14652) not in TESTS, reason='Excluded')
    def test_teacher_delegate_teaching_tasks_to_supporting_instruc_14652(self):
        """Delegate teaching tasks to supporting instructors.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.002',
            '14652'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14653 - 003 - Teacher | Move a student and their data to a new section
    @pytest.mark.skipif(str(14653) not in TESTS, reason='Excluded')
    def test_teacher_move_a_student_and_their_data_to_new_section_14653(self):
        """Move a student and their data to a new section.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the user menu
        Click "Change Period" for the desired student and select a period

        Expected Result:
        Student is moved to new section with their data
        """
        self.ps.test_updates['name'] = 't2.07.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.003',
            '14653'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Move the student to another period
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Change Period").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, "//ul[@class='nav nav-pills nav-stacked']/li/a").click()

        self.teacher.sleep(5)

        # Verify the move, then move the student back to the original period
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[2]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")
        index = 0
        for student in roster:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Change Period")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//ul[@class='nav nav-pills nav-stacked']/li/a").click()
                break
            index += 1

        self.teacher.sleep(2)
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[1]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")

        assert(first in roster[0].text and last in roster[0].text), \
            'error'

        self.ps.test_updates['passed'] = True

    # 14655 - 004 - Teacher | Drop a student from a section and hide their data
    @pytest.mark.skipif(str(14655) not in TESTS, reason='Excluded')
    def test_teacher_drop_student_from_section_and_hide_their_data_14655(self):
        """Drop a student from a section and hide their data.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the user menu
        Click "Drop" for the desired student

        Expected Result:
        The student appears under the "Dropped Students" section
        """
        self.ps.test_updates['name'] = 't2.07.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.004',
            '14655'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Drop the student
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text
        self.teacher.find(By.PARTIAL_LINK_TEXT, "Drop").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH,
            "//button[@class='-drop-student btn btn-danger']").click()

        self.teacher.sleep(5)

        # Verify the student was dropped and add back to active roster
        dropped = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='settings-section dropped-students']/table[@class" +
            "='roster table table-striped table-bordered table-condensed " +
            "table-hover']/tbody/tr")
        index = 0
        for student in dropped:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Add Back to Active Roster")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='-undrop-student btn btn-success']"
                ).click()
                self.teacher.sleep(20)
                break
            index += 1

        self.ps.test_updates['passed'] = True

    # 14656 - 005 - Teacher | Drop a student from a section and don't hide
    # their data
    @pytest.mark.skipif(str(14656) not in TESTS, reason='Excluded')
    def test_teacher_drop_a_student_from_section_and_dont_hide_dat_14656(self):
        """Drop a student from a section and don't hide their data.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.005',
            '14656'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14657 - 006 - Teacher | In Student Scores dropped students are not
    # displayed
    @pytest.mark.skipif(str(14657) not in TESTS, reason='Excluded')
    def test_teacher_in_student_scores_dropped_students_are_not_14657(self):
        """In Student Scores dropped students are not displayed.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the calendar dashboard
        Click "Drop" for the desired student
        Click "Student Scores" from the user menu
        Click on the period from which you have dropped the student

        Expected Result:
        Dropped student should not be displayed in Student Scores
        """
        self.ps.test_updates['name'] = 't2.07.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.006',
            '14657'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Drop the student
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Drop").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH,
            "//button[@class='-drop-student btn btn-danger']").click()

        self.teacher.sleep(5)

        # Go to student scores, verify the student is not seen
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Student Scores").click()
        self.teacher.sleep(10)

        odd_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedData" +
            "TableRow_main public_fixedDataTableRow_even public_fixedDataTa" +
            "ble_bodyRow']/div[@class='fixedDataTableRowLayout_body']/div" +
            "[@class='fixedDataTableCellGroupLayout_cellGroupWrapper'][1]/d" +
            "iv[@class='fixedDataTableCellGroupLayout_cellGroup']/div[@clas" +
            "s='fixedDataTableCellLayout_main public_fixedDataTableCell_" +
            "main'][1]/div[@class='fixedDataTableCellLayout_wrap1 public_fi" +
            "xedDataTableCell_wrap1']/div[@class='fixedDataTableCellLayout_w" +
            "rap2 public_fixedDataTableCell_wrap2']/div[@class='fixedDataTab" +
            "leCellLayout_wrap3 public_fixedDataTableCell_wrap3']/div[@class" +
            "='name-cell']/a[@class='student-name public_fixedDataTableCell" +
            "_cellContent']")
        even_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedDataTab" +
            "leRow_main public_fixedDataTableRow_highlighted public_fixedDa" +
            "taTableRow_odd public_fixedDataTable_bodyRow']/div[@class='fix" +
            "edDataTableRowLayout_body']/div[@class='fixedDataTableCellGrou" +
            "pLayout_cellGroupWrapper'][1]/div[@class='fixedDataTableCellGr" +
            "oupLayout_cellGroup']/div[@class='fixedDataTableCellLayout_mai" +
            "n public_fixedDataTableCell_main'][1]/div[@class='fixedDataTab" +
            "leCellLayout_wrap1 public_fixedDataTableCell_wrap1']/div[@clas" +
            "s='fixedDataTableCellLayout_wrap2 public_fixedDataTableCell_wr" +
            "ap2']/div[@class='fixedDataTableCellLayout_wrap3 public_fixedD" +
            "ataTableCell_wrap3']/div[@class='name-cell']/a[@class='student" +
            "-name public_fixedDataTableCell_cellContent']")

        found = False
        for student in odd_scores:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                found = True
                break

        if not found:
            for stud in even_scores:
                if stud.text.find(first) >= 0 and stud.text.find(last) >= 0:
                    found = True
                    break

        # Add back to active roster
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        dropped = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='settings-section dropped-students']/table[@class" +
            "='roster table table-striped table-bordered table-condensed ta" +
            "ble-hover']/tbody/tr")
        index = 0
        for student in dropped:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Add Back to Active Roster")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//button[@class='-undrop-student btn btn-success']"
                ).click()
                self.teacher.sleep(20)
                break
            index += 1

        if not found:
            self.ps.test_updates['passed'] = True

    # 14850 - 007 - Teacher | In Student Scores view moved students
    @pytest.mark.skipif(str(14850) not in TESTS, reason='Excluded')
    def test_teacher_in_student_scores_view_moved_students_14850(self):
        """In Student Scores view moved students.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster" from the calendar dashboard
        Click "Change Period" for the desired student
        Click on the desired period
        Click "Student Scores" from the user menu
        Click on the period to which the student was moved

        Expected Result:
        The user is presented with the moved student under their new period
        """
        self.ps.test_updates['name'] = 't2.07.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.007',
            '14850'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Move the student to another period
        first = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[1]"
        ).text
        last = self.teacher.find(
            By.XPATH,
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr[1]/td[2]"
        ).text

        self.teacher.find(By.PARTIAL_LINK_TEXT, "Change Period").click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, "//ul[@class='nav nav-pills nav-stacked']/li/a").click()

        self.teacher.sleep(5)

        # Go to student scores, verify the student is seen
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Student Scores").click()
        self.teacher.sleep(10)
        self.teacher.find(
            By.XPATH,
            "//nav[@class='collapse in']/ul[@class='nav nav-tabs']/li[2]/a"
        ).click()

        odd_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedData" +
            "TableRow_main public_fixedDataTableRow_even public_fixedDataTa" +
            "ble_bodyRow']/div[@class='fixedDataTableRowLayout_body']/div" +
            "[@class='fixedDataTableCellGroupLayout_cellGroupWrapper'][1]/d" +
            "iv[@class='fixedDataTableCellGroupLayout_cellGroup']/div[@clas" +
            "s='fixedDataTableCellLayout_main public_fixedDataTableCell_" +
            "main'][1]/div[@class='fixedDataTableCellLayout_wrap1 public_fi" +
            "xedDataTableCell_wrap1']/div[@class='fixedDataTableCellLayout_w" +
            "rap2 public_fixedDataTableCell_wrap2']/div[@class='fixedDataTab" +
            "leCellLayout_wrap3 public_fixedDataTableCell_wrap3']/div[@class" +
            "='name-cell']/a[@class='student-name public_fixedDataTableCell" +
            "_cellContent']")
        even_scores = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='fixedDataTableRowLayout_main public_fixedDataTab" +
            "leRow_main public_fixedDataTableRow_highlighted public_fixedDa" +
            "taTableRow_odd public_fixedDataTable_bodyRow']/div[@class='fix" +
            "edDataTableRowLayout_body']/div[@class='fixedDataTableCellGrou" +
            "pLayout_cellGroupWrapper'][1]/div[@class='fixedDataTableCellGr" +
            "oupLayout_cellGroup']/div[@class='fixedDataTableCellLayout_mai" +
            "n public_fixedDataTableCell_main'][1]/div[@class='fixedDataTab" +
            "leCellLayout_wrap1 public_fixedDataTableCell_wrap1']/div[@clas" +
            "s='fixedDataTableCellLayout_wrap2 public_fixedDataTableCell_wr" +
            "ap2']/div[@class='fixedDataTableCellLayout_wrap3 public_fixedD" +
            "ataTableCell_wrap3']/div[@class='name-cell']/a[@class='student" +
            "-name public_fixedDataTableCell_cellContent']")

        found = False
        for student in odd_scores:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                found = True
                break

        if found:
            for stud in even_scores:
                if stud.text.find(first) >= 0 and stud.text.find(last) >= 0:
                    found = True
                    break

        # Add student back to original period
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(10)
        self.teacher.find(
            By.XPATH,
            "//div[@class='roster']/div[@class='settings-section periods']" +
            "/ul[@class='nav nav-tabs']/li[2]/a").click()
        roster = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='period']/table[@class='roster table table-striped" +
            " table-bordered table-condensed table-hover']/tbody/tr")
        index = 0
        for student in roster:
            if student.text.find(first) >= 0 and student.text.find(last) >= 0:
                self.teacher.driver.find_elements_by_partial_link_text(
                    "Change Period")[index].click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH,
                    "//ul[@class='nav nav-pills nav-stacked']/li/a").click()
                break
            index += 1

        if found:
            self.ps.test_updates['passed'] = True

    # 14658 - 008 - Teacher | Require emails for all students for roster import
    @pytest.mark.skipif(str(14658) not in TESTS, reason='Excluded')
    def test_teacher_require_emails_for_all_students_for_roster_14658(self):
        """Require emails for all students for roster imports.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.008',
            '14658'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # 14660 - 009 - Teacher | Set time zone for a course
    @pytest.mark.skipif(str(14660) not in TESTS, reason='Excluded')
    def test_teacher_set_time_zone_for_a_course_14660(self):
        """Set time zone for a course.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click "Course Settings and Roster"
        Click "Change Course Timezone"
        Select the desired timezone
        Click Save

        Expected Result:
        The time zone is set
        """
        self.ps.test_updates['name'] = 't2.07.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.009',
            '14660'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, "Course Settings and Roster").click()
        self.teacher.sleep(5)

        # Change the timezone
        self.teacher.driver.find_elements_by_xpath(
            "//button[@class='edit-course btn btn-link']")[1].click()
        self.teacher.sleep(2)
        self.teacher.find(
            By.XPATH, "//div[@class='tutor-radio']/label").click()
        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button -edit-course-" +
            "confirm btn btn-default']").click()
        self.teacher.sleep(5)

        # Verify the change and change the time back to Central
        self.teacher.driver.find_elements_by_xpath(
            "//button[@class='edit-course btn btn-link']")[1].click()

        assert('Central Time' not in self.teacher.find(
            By.XPATH, "//div[@class='tutor-radio active']/label").text), \
            'Not viewing Concept Coach stats'

        self.teacher.sleep(2)
        options = self.teacher.driver.find_elements_by_xpath(
            "//div[@class='tutor-radio']/label")

        for timezone in options:
            if timezone.text.find('Central Time') >= 0:
                timezone.click()
                break

        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button -edit-course-" +
            "confirm btn btn-default']").click()

        self.ps.test_updates['passed'] = True

    # 14661 - 010 - System | Distinguish between high school and college
    # courses
    @pytest.mark.skipif(str(14661) not in TESTS, reason='Excluded')
    def test_system_distinguish_between_hs_and_college_courses_14661(self):
        """Distinguish between high school and college courses.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't2.07.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't2',
            't2.07',
            't2.07.010',
            '14661'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
Esempio n. 24
0
class TestTutorStudent(unittest.TestCase):
    ''''''
    def setUp(self):
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.student = Student(use_env_vars=True)
        self.helper = StaxHelper(driver_type='chrome', pasta_user=self.ps,
                                 capabilities=self.desired_capabilities,
                                 initial_user=self.student)
        self.driver = self.helper.driver
        self.wait = WebDriverWait(self.driver, StaxHelper.DEFAULT_WAIT_TIME)
        self.driver.set_window_size(*standard_window)
        self.teacher.login()
        self.teacher.select_course(title='physics')
        self.rword = Assignment.rword
        self.screenshot_path = '/tmp/errors/'

    def tearDown(self):
        # Returns the info of exception being handled
        has_errors = self._test_has_failed()
        if has_errors:
            print(self.driver.current_url, '\n')
            date_and_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f')
            filename = 'testerr_%s.png' % date_and_time
            self.driver.save_screenshot('%s%s' % (self.screenshot_path,
                                        filename))
        self.driver.quit()
        self.ps.update_job(self.driver.session_id, passed=has_errors)

    def _test_has_failed(self):
        # for 3.4. In 3.3, can just use self._outcomeForDoCleanups.success:
        for method, error in self._outcome.errors:
            if error:
                return True
        return False

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_all_past_work(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_reference_book(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_a_standard_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_an_intro_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_a_homework(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_weakest_topics_from_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_specific_topic_from_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_complete_performance_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_all_topics_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_one_chapter_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_specific_topic_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_an_external_assignment(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_reviews_a_finished_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_reviews_a_finished_homework(self):
        ''''''
class TestTutorWorksWithCNX(unittest.TestCase):
    """T1.27 - Tutor works with CNX."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C8182 - 001 - System | CNX needs to handle LaTeX in Exercises
    @pytest.mark.skipif(str(8182) not in TESTS, reason='Excluded')
    def test_system_cnx_needs_to_handle_latex_in_exercises_8182(self):
        """CNX needs to handle LaTeX in Exercises.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't1.27.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.27',
            't1.27.001',
            '8182'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C8183 - 002 - System | CNX pulls exercises from Tutor
    @pytest.mark.skipif(str(8183) not in TESTS, reason='Excluded')
    def test_system_cnx_pulls_exercises_from_tutor_8183(self):
        """Story Text.

        Steps:


        Expected Result:

        """
        self.ps.test_updates['name'] = 't1.27.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.27',
            't1.27.002',
            '8183'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestAdminAndTeacherCourseSetup(unittest.TestCase):
    """CC1.10 - Admin and Teacher Course Setup."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin = Admin(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.driver = None
            self.teacher.delete()
        except:
            pass

    # Case C7715 - 001 - Admin | Send course setup data from Sales Force
    @pytest.mark.skipif(str(7715) not in TESTS, reason='Excluded')
    def test_admin_send_course_setup_data_from_sales_force_7715(self):
        """Send course setup data from Sales Force.

        Steps:
        Go to tutor-staging.openstax.org and login as admin
        Click on the user menu
        Select the Admin option
        Click on Salesforce on the header

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.10.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.001',
            '7715'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Admin'
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Salesforce')
            )
        ).click()
        assert('salesforce' in self.admin.current_url()), 'not at salesforce'

        self.ps.test_updates['passed'] = True

    # Case C7716 - 002 - System | Course registration codes are emailed to the
    # teacher once the course is set up
    @pytest.mark.skipif(str(7716) not in TESTS, reason='Excluded')
    def test_system_registration_codes_are_emailed_to_teacher_7716(self):
        """Registration codes are emailed to teacher once the course is set up.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.10.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.002',
            '7716'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C7717 - 003 - Teacher | Use a teacher registration code to access
    # their course
    @pytest.mark.skipif(str(7717) not in TESTS, reason='Excluded')
    def test_teacher_use_teacher_registration_code_to_access_course_7717(self):
        """Use a teacher registration code to access their course.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.10.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.003',
            '7717'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C7718 - 004 - Teacher | Create course periods
    @pytest.mark.skipif(str(7718) not in TESTS, reason='Excluded')
    def test_teacher_create_course_periods_7718(self):
        """Create course periods.

        Steps:
        go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click "+ Add section"
        Enter a section name into the section Name text box

        Expected Result:
        New course section created
        """
        self.ps.test_updates['name'] = 'cc1.10.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.004',
            '7718'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"add-period")]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys('test_period')
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Add"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="test_period"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7719 - 005 - Teacher | View student enrollment code for
    # course period
    @pytest.mark.skipif(str(7719) not in TESTS, reason='Excluded')
    def test_teacher_view_student_enrollment_code_for_course_period_7719(self):
        """View the student enrollment code for a course period.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for selected section
        Click 'Get Student Enrollment Code'

        Expected Result:
        Student Enrollment code displayed along with instruction teacher can
        send to students on how to use enrollment code
        """
        self.ps.test_updates['name'] = 'cc1.10.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.005',
            '7719'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//button[contains(@class,"show-enrollment-code")]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="enrollment-code"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7720 - 006 - Teacher | Rename a course period
    @pytest.mark.skipif(str(7720) not in TESTS, reason='Excluded')
    def test_teacher_rename_a_course_period_7720(self):
        """Rename a course period.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for selected section
        Click 'Rename section'
        Enter new section name into the section Name text box
        Click on the 'Rename' button

        Expected Result:
        Section is renamed
        """
        self.ps.test_updates['name'] = 'cc1.10.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.006',
            '7720'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        period_name = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab"]')
            )
        ).text
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[contains(@class,"rename-period")]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys('_EDIT')
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Rename"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + period_name + '_EDIT"]')
            )
        )
        # then set it back to what it was before
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[contains(@class,"rename-period")]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys(Keys.BACK_SPACE * 5)
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Rename"]'
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7721 - 007 - Teacher | Archive an empty period
    @pytest.mark.skipif(str(7721) not in TESTS, reason='Excluded')
    def test_teacher_remove_an_empty_period_7721(self):
        """Remove an empty period.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for selected empty section
        Click 'Archive section'
        Click on the 'Archive' button

        Expected Result:
        Section is archived
        """
        self.ps.test_updates['name'] = 'cc1.10.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.007',
            '7721'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        section_name = 'test_' + str(randint(0, 1000))
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # create an empty section
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"add-period")]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys(section_name)
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Add"]'
        ).click()
        # archive the section just created
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + section_name + '"]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//a[contains(@class,"archive-period")]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@role="tooltip"]//button' +
                 '//span[contains(text(),"Archive")]')
            )
        ).click()
        self.teacher.sleep(2)
        archived = self.teacher.driver.find_elements(
            By.XPATH, '//li//a[@role="tab" and text()="' + section_name + '"]')
        assert(len(archived) == 0), ' not archived'
        self.ps.test_updates['passed'] = True

    # Case C7722 - 008 - Teacher | Archive a non-empty period
    @pytest.mark.skipif(str(7722) not in TESTS, reason='Excluded')
    def test_teacher_archive_a_nonempty_periods_7722(self):
        """Error message displayed if attempting to remove a non-empty period.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for selected non-empty section
        Click 'Archive section'
        Click Archive

        Expected Result:
        Section is archived
        """
        self.ps.test_updates['name'] = 'cc1.10.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.008',
            '7722'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # name of period to archive (first tab)
        period_name = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab"]')
            )
        ).text
        # archive the section
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + period_name + '"]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//a[contains(@class,"archive-period")]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@role="tooltip"]//button' +
                 '//span[contains(text(),"Archive")]')
            )
        ).click()
        self.teacher.sleep(2)
        archived = self.teacher.driver.find_elements(
            By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]')
        assert(len(archived) == 0), ' not archived'
        # add the archived period back
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[contains(@class,"view-archived-periods")]//button')
            )
        ).click()
        periods = self.teacher.driver.find_elements(
            By.XPATH, '//div[@class="modal-content"]//tbody//tr'
        )
        for period in periods:
            try:
                period.find_element(
                    By.XPATH, ".//td[text()='" + period_name + "']")
                period.find_element(
                    By.XPATH,
                    ".//td//span[contains(@class,'restore-period')]//button"
                ).click()
                break
            except NoSuchElementException:
                if period == periods[-1]:
                    raise Exception
        self.teacher.sleep(2)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + period_name + '"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C58354 - 009 - Teacher | Unarchive a section
    @pytest.mark.skipif(str(58354) not in TESTS, reason='Excluded')
    def test_teacher_unarchive_a_section_58354(self):
        """Unarchive a section.

        Steps:
        go to tutor-qa.openstax.org
        log in as a teacher
        click on a Concept Coach book
        click on the user menu
        select course roster
        Click "View Archived Section"
        Click "Unarchive" for the desired section

        Expected Result:
        section is unarchived
        """
        self.ps.test_updates['name'] = 'cc1.10.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.009',
            '58354'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # name of period to archive (first tab)
        period_name = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab"]')
            )
        ).text
        # archive the section
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + period_name + '"]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//a[contains(@class,"archive-period")]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@role="tooltip"]//button' +
                 '//span[contains(text(),"Archive")]')
            )
        ).click()
        self.teacher.sleep(2)
        archived = self.teacher.driver.find_elements(
            By.XPATH, '//li//a[@role="tab" and text()="' + period_name + '"]')
        assert(len(archived) == 0), ' not archived'
        # add the archived period back
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[contains(@class,"view-archived-periods")]//button')
            )
        ).click()
        periods = self.teacher.driver.find_elements(
            By.XPATH, '//div[@class="modal-content"]//tbody//tr'
        )
        for period in periods:
            try:
                period.find_element(
                    By.XPATH, ".//td[text()='" + period_name + "']")
                period.find_element(
                    By.XPATH,
                    ".//td//span[contains(@class,'restore-period')]//button"
                ).click()
                break
            except NoSuchElementException:
                if period == periods[-1]:
                    raise Exception
        self.teacher.sleep(2)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li//a[@role="tab" and text()="' + period_name + '"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7723 - 010 - Teacher | Rename the course
    @pytest.mark.skipif(str(7723) not in TESTS, reason='Excluded')
    def test_teacher_rename_the_course_7723(self):
        """Rename the course.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click 'Rename Course'
        Enter a new Course name into the Course Name text box
        Click on the 'Rename' button

        Expected Result:
        Course is renamed.
        """
        self.ps.test_updates['name'] = 'cc1.10.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.010',
            '7723'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # rename section
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[@class="-rename-course-link"]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys("_EDIT")
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Rename"]'
        ).click()
        # check that the name was changed
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="course-settings-title"]' +
                 '//span[contains(text(),"_EDIT")]')
            )
        )
        # change it back
        self.teacher.sleep(1)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//span[@class="-rename-course-link"]//button')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="modal-content"]//input[@type="text"]')
            )
        ).send_keys(Keys.BACK_SPACE * 5)
        self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="modal-content"]//button/span[text()="Rename"]'
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C7724 - 011 - Teacher | Remove other teachers from the course
    @pytest.mark.skipif(str(7724) not in TESTS, reason='Excluded')
    def test_teacher_remove_other_teachers_from_the_course_7724(self):
        """Remove other teachers from the course.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on 'Remove' on the same row as selected teacher
        Click on the 'Remove' button

        Expected Result:
        Instructor is removed from the course
        """
        self.ps.test_updates['name'] = 'cc1.10.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.011',
            '7724'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.driver.get(
            'https://tutor-qa.openstax.org/admin/courses/8/edit')
        self.admin.page.wait_for_page_load()
        teacher_name = 'Trent'
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Teachers")]').click()
        self.admin.driver.find_element(
            By.ID, 'course_teacher').send_keys(teacher_name)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name)
            )
        ).click()
        self.admin.sleep(1)
        self.admin.driver.find_element(
            By.LINK_TEXT, 'Main Dashboard').click()
        self.admin.page.wait_for_page_load()
        self.admin.logout()
        # redo set-up, but make sure to go to course 8
        self.teacher.login()
        self.teacher.driver.get('https://tutor-qa.openstax.org/courses/8')
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Course Settings and Roster')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        # delete teacher
        teachers_list = self.teacher.driver.find_elements(
            By.XPATH, '//div[@class="teachers-table"]//tbody//tr')
        for x in teachers_list:
            temp_first = x.find_element(
                By.XPATH,
                './td[1]'
            ).text
            if temp_first == teacher_name:
                x.find_element(
                    By.XPATH,
                    './/td//span[contains(text(),"Remove")]'
                ).click()
                self.teacher.sleep(1)
                self.teacher.driver.find_element(
                    By.XPATH, '//div[@class="popover-content"]//button'
                ).click()
                break
            if x == teachers_list[-1]:
                print('added teacher was not found, and not deleted')
                raise Exception
        deleted_teacher = self.teacher.driver.find_elements(
            By.XPATH, '//td[contains(text(),"%s")]' % teacher_name)
        assert(len(deleted_teacher) == 0), 'teacher not deleted'

        self.ps.test_updates['passed'] = True

    # come back to this because adding teacher through admin first
    # Case C7725 - 012 - Teacher | Remove themself from the course
    @pytest.mark.skipif(str(7725) not in TESTS, reason='Excluded')
    def test_teacher_remove_themself_from_the_course_7725(self):
        """Remove themself from the course.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on 'Remove' on the same row as themselves
        Click on the 'Remove' button

        Expected Result:
        Teacher is removed from course and taken back to dashboard
        """
        self.ps.test_updates['name'] = 'cc1.10.012' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.012',
            '7725'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.driver.get(
            'https://tutor-qa.openstax.org/admin/courses/8/edit')
        self.admin.page.wait_for_page_load()
        teacher_name = 'Trent'
        self.admin.driver.find_element(
            By.XPATH, '//a[contains(text(),"Teachers")]').click()
        self.admin.driver.find_element(
            By.ID, 'course_teacher').send_keys(teacher_name)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name)
            )
        ).click()
        self.admin.sleep(1)
        self.admin.driver.find_element(
            By.LINK_TEXT, 'Main Dashboard').click()
        self.admin.page.wait_for_page_load()
        self.admin.logout()
        # redo set-up, but make sure to go to course 8
        # login as the teacher just added to the course
        teacher2 = Teacher(
            username='******',
            password=os.getenv('TEACHER_PASSWORD'),
            existing_driver=self.teacher.driver
        )
        teacher2.login()
        teacher2.driver.get('https://tutor-qa.openstax.org/courses/8')
        teacher2.open_user_menu()
        teacher2.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Course Settings and Roster')
            )
        ).click()
        teacher2.page.wait_for_page_load()
        # delete teacher
        teachers_list = teacher2.driver.find_elements(
            By.XPATH, '//div[@class="teachers-table"]//tbody//tr')
        for x in teachers_list:
            temp_first = x.find_element(
                By.XPATH,
                './td[1]'
            ).text
            if temp_first == teacher_name:
                x.find_element(
                    By.XPATH,
                    './/td//span[contains(text(),"Remove")]'
                ).click()
                teacher2.sleep(1)
                teacher2.driver.find_element(
                    By.XPATH, '//div[@class="popover-content"]//button'
                ).click()
                break
            if x == teachers_list[-1]:
                print('added teacher was not found, and not deleted')
                raise Exception
        # after removing self from course taken to dashboard
        # or course if only 1 other course
        assert('/courses/8' not in teacher2.current_url()), \
            'teacher not deleted'
        teacher2.delete()
        self.ps.test_updates['passed'] = True

    # Case C7726 - 013 - Teacher | Transfer a student to another period
    @pytest.mark.skipif(str(7726) not in TESTS, reason='Excluded')
    def test_teacher_transfer_a_student_to_another_period_7726(self):
        """Transfer a student to another period.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for section selected student is currently enrolled in
        Click on 'Change Section' on the row of the selected student
        Click on section to move student to

        Expected Result:
        Student is moved to chosen section
        """
        self.ps.test_updates['name'] = 'cc1.10.013' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.013',
            '7726'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # move student
        first_student = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="period"]//tbody/tr[1]')
            )
        )
        student_name = first_student.find_element(
            By.XPATH, './/td[1]').text
        first_student.find_element(
            By.XPATH,
            './/td[@class="actions"]/a[@aria-describedby="change-period"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="popover-content"]//li[1]')
            )
        ).click()
        # check that student was moved
        self.teacher.sleep(2)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//li[@tabindex="1"]//a[@role="tab"]')
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="period"]//tbody/tr' +
                 '//td[text()="' + student_name + '"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7727 - 014 - Teacher | Remove a student from a course
    @pytest.mark.skipif(str(7727) not in TESTS, reason='Excluded')
    def test_teacher_remove_a_student_from_a_course_7727(self):
        """Remove a student from a course.

        Steps:
        Go to Tutor
        Log in as a teacher
        Click on a Concept Coach book
        Click on the user menu
        Select course roster
        Click on tab for section selected student is currently enrolled in
        Click on 'Drop' on the row of the selected student
        Click on the 'Drop' button

        Expected Result:
        Student is dropped from the course
        """
        self.ps.test_updates['name'] = 'cc1.10.014' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.014',
            '7727'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.driver.find_element(
            By.XPATH, '//a[contains(@href,"/cc-dashboard")]'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        # drop student
        first_student = self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@class="period"]//tbody/tr[1]')
            )
        )
        student_name = first_student.find_element(
            By.XPATH, './/td[1]').text
        first_student.find_element(
            By.XPATH,
            './/td[@class="actions"]/a[@aria-describedby="drop-student"]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[@id="drop-student"]//button')
            )
        ).click()
        # check that student was removed
        self.teacher.sleep(2)
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH,
                 '//div[contains(@class,"dropped-students")]//tbody/tr' +
                 '//td[text()="' + student_name + '"]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7728 - 015 - Admin | Impersonate a teacher
    @pytest.mark.skipif(str(7728) not in TESTS, reason='Excluded')
    def test_admin_impersonate_a_teacher_7728(self):
        """Impersonate a teacher.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin user account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the user's name in the top right corner to open drop down menu
        Click on the 'Admin' option of the drop down menu
        Click on 'Users' on the bar across the top
        [optional] Enter a teacher name into the search here text box
        Click on the 'Search' button
        Click on the 'Sign in as' button next to chosen teacher

        Expected Result:
        Signs in as chosen chosen teacher.
        Goes to chosen teacher's initial screen after login
        If multiple courses list of textbooks
        If one course straight to dashboard
        """
        self.ps.test_updates['name'] = 'cc1.10.015' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.015',
            '7728'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.open_user_menu()
        self.admin.driver.find_element(
            By.LINK_TEXT, 'Admin'
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Users')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.driver.find_element(By.ID, 'query').send_keys('teacher01')
        self.admin.driver.find_element(
            By.XPATH, '//input[@value="Search"]').click()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"Sign in as")]')
            )
        ).click()
        self.admin.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//span[contains(text(),"Charles Morris")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7729 - 016 - Admin | Change a course ecosystem
    @pytest.mark.skipif(str(7729) not in TESTS, reason='Excluded')
    def test_admin_change_a_course_ecosystem_7729(self):
        """Change a course ecosystem.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin user account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the 'Admin' button from the user menu
        Open the drop down menu by clicking 'Course Organization'
        Click the 'Courses' option
        Click the 'Edit' link for the desired course
        Click on the 'Course content' tab
        Select a different option in the 'Ecosystem' drop down menu
        Click the 'Submit' button

        Expected Result:
        Course ecosystem change is put on a queue
        """
        self.ps.test_updates['name'] = 'cc1.10.016' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.016',
            '7729'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Admin'
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Course Organization')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Courses')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Edit')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Course content')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'ecosystem_id')
            )
        ).send_keys('1' + Keys.ENTER)
        # self.admin.wait.until(
        #     expect.visibility_of_element_located(
        #         (By.XPATH, '//select[@id="ecosystem_id"]//option[1]')
        #     )
        # ).click()
        self.admin.driver.find_element(
            By.XPATH, '//div[@id="content"]//input[@type="submit"]'
        ).click()
        self.admin.sleep(1)
        self.admin.driver.find_element(
            By.XPATH, '//div[contains(@class,"alert-info")]'
        )
        self.ps.test_updates['passed'] = True

    # Case C7730 - 017 - Admin | Change multiple course ecosystems in bulk
    @pytest.mark.skipif(str(7730) not in TESTS, reason='Excluded')
    def test_admin_change_multiple_course_ecosystems_in_bulk_7730(self):
        """Change multiple course ecosystems in bulk.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the admin user account in the username and password text boxes
        Click on the 'Sign in' button
        Click on the 'Admin' button from the user menu
        Open the drop down menu by clicking 'Course Organization'
        Click the 'Courses' option
        Check the checkboxes next to selected courses
        Select an option in the 'Select an ecosystem' drop down menu
        Click the 'Set Ecosystem' button

        Expected Result:
        Course ecosystem change is put on a queue
        """
        self.ps.test_updates['name'] = 'cc1.10.017' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.017',
            '7730'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.login()
        self.admin.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT, 'Admin'
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Course Organization')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, 'Courses')
            )
        ).click()
        self.admin.page.wait_for_page_load()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'courses_select_all')
            )
        ).click()
        # click the checkmarks for two courses
        courses = self.admin.driver.find_elements(
            By.XPATH, '//input[@class="course_id_select"]')
        course_1 = courses[0]
        self.admin.driver.execute_script(
            'return arguments[0].scrollIntoView();', course_1)
        self.admin.driver.execute_script('window.scrollBy(0, -120);')
        course_1.click()
        self.admin.sleep(0.5)
        course_2 = courses[1]
        self.admin.driver.execute_script(
            'return arguments[0].scrollIntoView();', course_2)
        self.admin.driver.execute_script('window.scrollBy(0, -120);')
        course_2.click()
        self.admin.sleep(0.5)
        # scroll to bottom and set bulk ecosystems
        self.admin.driver.execute_script(
            "window.scrollTo(0, document.body.scrollHeight);")
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'ecosystem_id')
            )
        ).send_keys('1' + Keys.ENTER)
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[contains(@class,"alert-info")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7731 - 018 - Teacher | Receive a notice when students register
    @pytest.mark.skipif(str(7731) not in TESTS, reason='Excluded')
    def test_teacher_receive_a_notice_when_students_register_7731(self):
        """Receive a notice when students register.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.10.018' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.10',
            'cc1.10.018',
            '7731'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestTrainingAndSupportingTeachersAndStudents(unittest.TestCase):
    """CC1.14 - Training and Supporting Teachers and Students."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student = Student(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        self.student = None
        try:
            self.teacher.delete()
        except:
            pass

    # Case C7704 - 001 - System | Concept Coach Zendesk is web-accessible
    @pytest.mark.skipif(str(7704) not in TESTS, reason='Excluded')
    def test_system_concept_coach_zendesk_is_web_accessible_7704(self):
        """Concept Coach Zendesk is web-accesible.

        Steps:
        Log in to Tutor as teacher
        If more then one course, click on a concept coach course
        In user menu in top right of header, click 'Get Help'

        Expected Result:
        In a new window or tab, zendesk help is opened
        """
        self.ps.test_updates['name'] = 'cc1.14.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.001',
            '7704'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.teacher.current_url()), 'not at help center'

        self.ps.test_updates['passed'] = True

    # Case C7705 - 002 - Teacher | Can access user support
    @pytest.mark.skipif(str(7705) not in TESTS, reason='Excluded')
    def test_teacher_can_access_user_support_7705(self):
        """Can access user support.

        Steps:
        Click on the user menu
        Click on the Get Help option

        Expected Result:
        In a new tab or window Zendesk is opened
        """
        self.ps.test_updates['name'] = 'cc1.14.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.002',
            '7705'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.teacher.current_url()), 'not at help center'

        self.ps.test_updates['passed'] = True

    # Case C7706 - 003 - Student | Can access user support
    @pytest.mark.skipif(str(7706) not in TESTS, reason='Excluded')
    def test_student_can_access_user_support_7706(self):
        """Can access user support.

        Steps:
        Click on the user menu
        Click on the Get Help option

        Expected Result:
        In a new tab or window zendesk is opened
        """
        self.ps.test_updates['name'] = 'cc1.14.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.003',
            '7706'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.login()
        self.student.open_user_menu()
        self.student.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.student.driver.window_handles[1]
        self.student.driver.switch_to_window(window_with_help)
        self.student.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.student.current_url()), 'not at help center'
        self.ps.test_updates['passed'] = True

    # Case C7707 - 004 - Non-user | Submit support questions
    @pytest.mark.skipif(str(7707) not in TESTS, reason='Excluded')
    def test_nonuser_submit_support_questions_7707(self):
        """Submit support questions.

        Steps:
        Go to the Concept Coach landing page
        click support in the header
        enter text into the search box
        click contact us
        fillout form
        click Submit

        Expected Result:
        'Message sent' displayed in help box
        """
        self.ps.test_updates['name'] = 'cc1.14.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.004',
            '7707'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.get('http://cc.openstax.org/')
        self.teacher.sleep(1)
        # number hardcoded because condenses at different size than tutor
        if self.teacher.driver.get_window_size()['width'] < 1105:
            element = self.teacher.wait.until(
                expect.visibility_of_element_located(
                    (By.XPATH, '//label[@for="mobileNavToggle"]')
                )
            )
            actions = ActionChains(self.teacher.driver)
            # use action chain because it is clicking to the wrong elemnt
            actions.move_to_element(element)
            actions.click()
            actions.perform()
        support = self.teacher.find(
            By.LINK_TEXT, 'support'
        )
        actions = ActionChains(self.teacher.driver)
        actions.move_to_element(support)
        actions.click()
        actions.perform()
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'searchAskInput'
        ).send_keys('fake_question')
        self.teacher.find(
            By.ID, 'searchAskButton'
        ).click()
        self.teacher.find(
            By.LINK_TEXT, 'Contact Us'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:firstName")]'
        ).send_keys('qa')
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:lastName")]'
        ).send_keys('test')
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:email")]'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.XPATH, '//div[@class="submit-container"]//input'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//p[contains(text(),"Thank you")]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7708 - 005 - Teacher | Submit support questions
    @pytest.mark.skipif(str(7708) not in TESTS, reason='Excluded')
    def test_teacher_submit_support_questions_7708(self):
        """Submit support questions.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If user has more than one course, click on a Concept Coach course
        Click the user menu in the right corner of the header
        Click "Get Help"
        Click "Submit a request"
        Fill out all the necessary text fields
        Click "Submit"

        Expected Result:
        The user submits support questions
        """
        self.ps.test_updates['name'] = 'cc1.14.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.005',
            '7708'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.teacher.current_url()), 'not at help center'
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.ID, 'searchAskInput'
        ).send_keys('fake_question')
        self.teacher.find(
            By.ID, 'searchAskButton'
        ).click()
        self.teacher.find(
            By.LINK_TEXT, 'Contact Us'
        ).click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:firstName")]'
        ).send_keys('qa')
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:lastName")]'
        ).send_keys('test')
        self.teacher.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:email")]'
        ).send_keys('*****@*****.**')
        self.teacher.find(
            By.XPATH, '//div[@class="submit-container"]//input'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//p[contains(text(),"Thank you")]')
            )
        )
        self.ps.test_updates['passed'] = True

    # Case C7709 - 006 - Student | Submit support questions
    @pytest.mark.skipif(str(7709) not in TESTS, reason='Excluded')
    def test_student_submit_support_questions_7709(self):
        """Submit support questions.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the student user account in the username and password text boxes
        Click on the 'Sign in' button
        Click the user menu in the right corner of the header
        Click "Get Help"
        Click "Submit a request"
        Fill out all the necessary text fields
        Click "Submit"

        Expected Result:
        The user submits support questions
        """
        self.ps.test_updates['name'] = 'cc1.14.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.006',
            '7709'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.login()
        self.student.open_user_menu()
        self.student.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.student.driver.window_handles[1]
        self.student.driver.switch_to_window(window_with_help)
        self.student.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.student.current_url()), 'not at help center'
        self.student.page.wait_for_page_load()
        self.student.find(
            By.ID, 'searchAskInput'
        ).send_keys('fake_question')
        self.student.find(
            By.ID, 'searchAskButton'
        ).click()
        self.student.find(
            By.LINK_TEXT, 'Contact Us'
        ).click()
        self.student.page.wait_for_page_load()
        self.student.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:firstName")]'
        ).send_keys('qa')
        self.student.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:lastName")]'
        ).send_keys('test')
        self.student.find(
            By.XPATH, '//input[contains(@id,"contactUsForm:email")]'
        ).send_keys('*****@*****.**')
        self.student.find(
            By.XPATH, '//div[@class="submit-container"]//input'
        ).click()
        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//p[contains(text(),"Thank you")]')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7710 - 007 - Teacher | View instructions on how to use CC
    @pytest.mark.skipif(str(7710) not in TESTS, reason='Excluded')
    def test_teacher_view_instructions_on_how_to_use_cc_7710(self):
        """View instructions on how to use Concept Coach.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If user has more than one course, click on a Concept Coach course
        Click the user menu in the right corner of the header
        Click "Get Help"
        Click "Getting Started Guide"
        * Click on the pdf link
            OR
        * Click "Getting Started" from the user menu

        Expected Result:
        The user is presented with a guide to use CC
        """
        self.ps.test_updates['name'] = 'cc1.14.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.007',
            '7710'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Getting Started'
        ).click()
        self.teacher.find(
            By.XPATH, '//h3[contains(text(),"Getting Started")]'
        ).click()
        assert('help' in self.teacher.current_url()), 'not at help center'

        self.ps.test_updates['passed'] = True

    # Case C7711 - 008 - Student | View instructions on how to use CC
    @pytest.mark.skipif(str(7711) not in TESTS, reason='Excluded')
    def test_student_view_instructions_on_how_to_use_cc_7711(self):
        """View instructions on how to use Concept Coach.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the student user account in the username and password text boxes
        Click on the 'Sign in' button
        Click the user menu in the right corner of the header
        Click "Get Help"
        Scroll down to the questions under "Students"

        Expected Result:
        The user is presented with instructions on how to use CC
        """
        self.ps.test_updates['name'] = 'cc1.14.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.008',
            '7711'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.login()
        self.student.open_user_menu()
        self.student.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.student.driver.window_handles[1]
        self.student.driver.switch_to_window(window_with_help)
        self.student.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.student.current_url()), 'not at help center'
        self.ps.test_updates['passed'] = True

    # Case C7712 - 009 - Teacher | View instructions on how to assign CC
    @pytest.mark.skipif(str(7712) not in TESTS, reason='Excluded')
    def test_teacher_view_instructions_on_how_to_assign_cc_7712(self):
        """View instructions on how to use Concept Coach.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account in the username and password text boxes
        Click on the 'Sign in' button
        If user has more than one course, click on a Concept Coach course
        Click the user menu in the right corner of the header
        Click "Get Help"

        Expected Result:
        Taken to Zendesk in a new window or tab
        Assorted help is displayed
        """
        self.ps.test_updates['name'] = 'cc1.14.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.009',
            '7712'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.login()
        self.teacher.find(
            By.XPATH, '//a[contains(@href,"/cc-dashboard/")]'
        ).click()
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Get Help'
        ).click()
        # change to window with help center
        window_with_help = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_help)
        self.teacher.find(
            By.XPATH, '//center[contains(text(),"Concept Coach Help Center")]'
        )
        assert('support' in self.teacher.current_url()), 'not at help center'

        self.ps.test_updates['passed'] = True

    # Case C7713 - 010 - Student | Get help during account registration
    @pytest.mark.skipif(str(7713) not in TESTS, reason='Excluded')
    def test_student_get_help_during_account_registration_7713(self):
        """View instructions on how to use Concept Coach.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.14.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.010',
            '7713'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C7714 - 011 - Teacher | View instructions for Legacy users
    # transitioning to Concept Coach
    @pytest.mark.skipif(str(7714) not in TESTS, reason='Excluded')
    def test_teacher_view_instructions_for_legacy_users_transition_7714(self):
        """View instructions for Legacy users transitioning to Concept Coach.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 'cc1.14.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            'cc1',
            'cc1.14',
            'cc1.14.011',
            '7714'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True
class TestViewClassPerformance(unittest.TestCase):
    """T1.22 - View Class Performance."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher.login()
        self.teacher.select_course(appearance='biology')
        self.teacher.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C8148 - 001 - Teacher | View the period Performance Forecast
    @pytest.mark.skipif(str(8148) not in TESTS, reason='Excluded')
    def test_teacher_view_the_period_performance_forecast_8148(self):
        """View the period Performance Forecast.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast" button
        on the upper right corner of the calendar OR
        click on the user drop down menu then click on the
        "Performance Forecast" button
        Click on the desired period

        Expected Result:
        The period Performance Forecast is presented to the user
        """
        self.ps.test_updates['name'] = 't1.22.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.001',
            '8148'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'

        self.ps.test_updates['passed'] = True

    # Case C8149 - 002 - Teacher | Info icon shows an explanation of the data
    @pytest.mark.skipif(str(8149) not in TESTS, reason='Excluded')
    def test_teacher_info_icon_shows_an_explanation_of_the_data_8149(self):
        """Info icon shows an explanation of the data.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast" button
            on the upper right corner of the calendar
            OR
        Click on the user drop down menu then click on the
        "Performance Forecast" button
        Hover the cursor over the info icon that is next to the
        "Performance Forecast" header

        Expected Result:
        Info icon shows an explanation of the data
        """
        self.ps.test_updates['name'] = 't1.22.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.002',
            '8149'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'info-link')
            )
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C8150 - 003 - Teacher | View the performance color key
    @pytest.mark.skipif(str(8150) not in TESTS, reason='Excluded')
    def test_teacher_view_the_performance_color_key_8150(self):
        """View the performance color key.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast"
        button on the upper right corner of the calendar OR
        click on the user drop down menu
        click on the "Performance Forecast" button

        Expected Result:
        The performance color key is presented to the user
        (next to the 'Return to Dashboard' button)
        """
        self.ps.test_updates['name'] = 't1.22.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.003',
            '8150'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'guide-key')
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C8151 - 004 - Teacher | Return to Dashboard button returns to
    # the calendar
    @pytest.mark.skipif(str(8151) not in TESTS, reason='Excluded')
    def test_teacher_return_to_dashboard_button_returns_to_the_cal_8151(self):
        """Return to Dashboard button returns to the calendar.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast"
        button on the upper right corner of the calendar OR
        Click on the user drop down menu
        Click on the "Performance Forecast" button

        Expected Result:
        The calendar dashboard is presented to the user
        """
        self.ps.test_updates['name'] = 't1.22.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.004',
            '8151'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions

        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.LINK_TEXT, 'Dashboard')
            )
        ).click()

        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True

    # Case C8152 - 005 - Teacher | Periods tabs are shown
    @pytest.mark.skipif(str(8152) not in TESTS, reason='Excluded')
    def test_teacher_period_tabs_are_shown_8152(self):
        """Period tabs are shown.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast" button
        on the upper right corner of the calendar OR
        click on the user drop down menu
        click on the "Performance Forecast" button

        Expected Result:
        The period tabs are shown to the user
        (below the "Performance Forecast" header)
        """
        self.ps.test_updates['name'] = 't1.22.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.005',
            '8152'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions

        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.find(By.CLASS_NAME, 'active')

        self.ps.test_updates['passed'] = True

    # Case C8153 - 006 - Teacher | A period with zero answers does not
    # show section breakdowns
    @pytest.mark.skipif(str(8153) not in TESTS, reason='Excluded')
    def test_teacher_a_period_w_zero_answers_does_not_show_breaks_8153(self):
        """A period with zero answers does not show section breakdowns.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast"
            button on the upper right corner of the calendar OR
        Click on the user drop down menu
        Click on the "Performance Forecast" button
        Click on the period with zero answers

        Expected Result:
        The user should see no section breakdowns as well as the words
        "There have been no questions worked for this period."
        """
        self.ps.test_updates['name'] = 't1.22.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.006',
            '8153'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        # Create an empty period to use for the test
        period_name = "22_" + str(randint(100, 999))
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, 'Course Settings and Roster').click()
        self.teacher.page.wait_for_page_load()
        self.teacher.find(
            By.XPATH, "//div[@class='control add-period']/button").click()
        self.teacher.find(
            By.XPATH,
            "//input[@class='form-control empty']").send_keys(period_name)
        self.teacher.find(
            By.XPATH,
            "//button[contains(@class,'-edit-period-confirm')]"
        ).click()
        popup = self.teacher.find(
            By.XPATH,
            '//div[@class="teacher-edit-period-modal fade in modal"]')
        self.teacher.wait.until(
            expect.staleness_of(
                (popup)
            )
        )
        # Check the new empty period in Performance Forecast
        self.teacher.open_user_menu()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.LINK_TEXT, period_name)
            )
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'no-data-message')
            )
        )
        # Archive the new period as clean up
        self.teacher.open_user_menu()
        self.teacher.find(
            By.LINK_TEXT, 'Course Settings and Roster'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located((
                By.LINK_TEXT, period_name)
            )
        ).click()
        self.teacher.find(
            By.XPATH, "//a[@class='control archive-period']").click()
        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button archive-section btn btn-default']"
        ).click()

        self.ps.test_updates['passed'] = True

    # Case C8154 - 007 - Teacher | Weaker areas shows up to
    # four problematic sections
    @pytest.mark.skipif(str(8154) not in TESTS, reason='Excluded')
    def test_teacher_weaker_shows_up_to_four_problematic_sections_8154(self):
        """Weaker areas shows up to four problematic sections.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast"
        button on the upper right corner of the calendar OR
        click on the user drop down menu
        click on the "Performance Forecast" button
        Click on the desired period

        Expected Result:
        Weaker Areas show up to four problematic sections
        """
        self.ps.test_updates['name'] = 't1.22.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.007',
            '8154'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertion
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        weak = self.teacher.find_all(
            By.XPATH,
            "//div[@class='chapter-panel weaker']/div[@class='sections']/div")
        assert(len(weak) <= 4), \
            'Not viewing performance forecast'

        self.ps.test_updates['passed'] = True

    # Case C8155 - 008 - Teacher | Chapters are listed on the left with
    # their sections to the right
    @pytest.mark.skipif(str(8155) not in TESTS, reason='Excluded')
    def test_teacher_chapters_listed_on_left_w_sections_on_right_8155(self):
        """Chapter are listed on the left with their sections to the right.

        Steps:
        On the calendar dashboard, click on the "Performance Forecast"
            button on the upper right corner of the calendar
            OR
        Click on the user drop down menu
        Click on the "Performance Forecast" button
        Click on the desired period
        Scroll to the "Individual Chapters" section

        Expected Result:
        Chapters are listed on the left with their sections to the right
        """
        self.ps.test_updates['name'] = 't1.22.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.22',
            't1.22.008',
            '8155'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        assert('guide' in self.teacher.current_url()), \
            'Not viewing performance forecast'
        self.teacher.page.wait_for_page_load()
        panels = self.teacher.find_all(By.CLASS_NAME, 'chapter-panel')
        for panel in panels:
            panel.find_elements_by_class_name('chapter')
            panel.find_elements_by_class_name('sections')

        self.ps.test_updates['passed'] = True
class TestViewStudentPerformance(unittest.TestCase):
    """T1.50 - View Student Performance."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.student = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.student.login()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.student.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.student.delete()
        except:
            pass

    # Case C8287 - 001 - Student | View the personal Performance Forecast
    @pytest.mark.skipif(str(8287) not in TESTS, reason='Excluded')
    def test_student_view_personal_performance_forecast_8287(self):
        """View the personal Performance Forecast.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"

        Expected Result:
        The user is presented with personal Performance Forecast
        """
        self.ps.test_updates['name'] = 't1.50.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.001',
            '8287'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()

        self.student.sleep(5)

        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        self.ps.test_updates['passed'] = True

    # Case C8288 - 002 - Student | Info icon shows an explanation of the data
    @pytest.mark.skipif(str(8288) not in TESTS, reason='Excluded')
    def test_student_info_icon_shows_explanation_of_the_data_8288(self):
        """Info icon shows an explanation of the data.

        Steps:
        Click on the user menu in the upper right corner of the page
        Click on "Performance Forecast"
        Hover the cursor over the info icon that is next to the
        "Performance Forecast" header

        Expected Result:
        Info icon shows an explanation of the data
        """
        self.ps.test_updates['name'] = 't1.50.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.002',
            '8288'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'info-link')
            )
        ).click()

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8289 - 003 - Student | View the performance color key
    @pytest.mark.skipif(str(8289) not in TESTS, reason='Excluded')
    def test_student_view_the_performance_color_key_8289(self):
        """View the performance color key.

        Steps:
        Click on the user menu in the upper right corner of the page
        Click on "Performance Forecast"

        Expected Result:
        The performance color key is presented to the user
        (next to the 'Return to Dashboard' button)
        """
        self.ps.test_updates['name'] = 't1.50.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.003',
            '8289'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        self.student.wait.until(
            expect.visibility_of_element_located(
                (By.CLASS_NAME, 'guide-key')
            )
        )

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8290 - 004 - Student | Return To Dashboard button
    # returns to the list dashboard
    @pytest.mark.skipif(str(8290) not in TESTS, reason='Excluded')
    def test_student_return_to_dashboard_button_8290(self):
        """Return To Dashboard button returns to the list dashboard.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"
        Click on "Return To Dashboard"

        Expected Result:
        The user is presented with the list dashboard
        """
        self.ps.test_updates['name'] = 't1.50.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.004',
            '8290'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'
        self.student.sleep(5)
        self.student.open_user_menu()
        self.student.wait.until(
            expect.presence_of_element_located(
                (By.LINK_TEXT, 'Dashboard')
            )
        ).click()

        self.student.sleep(5)

        assert('list' in self.student.current_url()), \
            'Not viewing the dashboard'

        self.ps.test_updates['passed'] = True

    # Case C8291 - 005 - Student | A student with zero answers does not
    # show section breakdowns
    @pytest.mark.skipif(str(8291) not in TESTS, reason='Excluded')
    def test_student_no_answers_does_not_show_breakdown_8291(self):
        """A student with zero answers does not show section breakdowns.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the student user account [ student532 | password ] in the
            username and password text boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a Tutor course name
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"

        Expected Result:
        The user is presented with blank performance forecast with no
        section breakdowns w/ the words "You have not worked any questions yet"
        """
        self.ps.test_updates['name'] = 't1.50.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.005',
            '8291'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.logout()
        self.student.driver.get("https://tutor-qa.openstax.org/")
        self.student.login(username="******",
                           url="https://tutor-qa.openstax.org/")

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'
        self.student.find(By.CLASS_NAME, "no-data-message")
        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8292 - 006 - Student | My Weaker Areas shows up to four problematic
    # sections
    @pytest.mark.skipif(str(8292) not in TESTS, reason='Excluded')
    def test_student_weaker_areas_shows_up_to_four_sections_8292(self):
        """My Weaker Areas shows up to four problematic sections.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"

        Expected Result:
        The user is presented with up to four problematic sections under
        My Weaker Areas
        """
        self.ps.test_updates['name'] = 't1.50.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.006',
            '8292'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        weak = self.student.driver.find_elements_by_xpath(
            "//div[@class='chapter-panel weaker']/div[@class='sections']" +
            "/div[@class='section']")

        self.student.sleep(5)

        assert(len(weak) >= 1), \
            'Less than four weaker sections'

        self.ps.test_updates['passed'] = True

    # Case C8293 - 007 - Student | Chapters are listed on the left with their
    # sections to the right
    @pytest.mark.skipif(str(8293) not in TESTS, reason='Excluded')
    def test_student_chapter_listed_on_left_with_section_on_right_8293(self):
        """Chapter are listed on the left with their sections to the right.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"
        Scroll to Individual Chapters section

        Expected Result:
        The user is presented with chapters listed on the left and their
        sections on the right
        """
        self.ps.test_updates['name'] = 't1.50.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.007',
            '8293'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        self.student.page.wait_for_page_load()

        # Get all the chapter panels
        panels = self.student.driver.find_elements_by_class_name(
            'chapter-panel')

        # Should be one chapter button for each panel, at least one section
        # button per panel
        for panel in panels:
            chapter = panel.find_elements_by_class_name('chapter')
            sections = panel.find_elements_by_class_name('sections')
            assert(len(chapter) > 0), \
                ''

            assert(len(sections) > 0), \
                ''

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8294 - 008 - Student | Clicking on a chapter bar brings up to
    # five practice assessments for that chapter
    @pytest.mark.skipif(str(8294) not in TESTS, reason='Excluded')
    def test_student_clicking_chapter_brings_up_to_five_assessments_8294(self):
        """Clicking chapter bar brings up to 5 practice assessments.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"
        Scroll to the Individual Chapters section
        Click on a chapter bar

        Expected Result:
        The user is presented with up to five practice assessments for
        that chapter
        """
        self.ps.test_updates['name'] = 't1.50.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.008',
            '8294'
        ]
        self.ps.test_updates['passed'] = False
        # btn-block btn btn-default
        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'

        self.student.page.wait_for_page_load()
        self.student.wait.until(
            expect.presence_of_element_located((
                By.XPATH,
                "//div[@class='chapter']/button"
            ))
        ).click()

        assert('practice' in self.student.current_url()), \
            'Not presented with practice problems'

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8295 - 009 - Student | Clicking on a section bar brings up to five
    # practice assessments for that section
    @pytest.mark.skipif(str(8295) not in TESTS, reason='Excluded')
    def test_student_clicking_section_brings_up_to_five_assessments_8295(self):
        """Clicking section bar brings up to 5 practice assessments.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"
        Scroll to the Individual Chapters section
        Click on a section bar

        Expected Result:
        The user is presented with up to five practice assessments for that
        section
        """
        self.ps.test_updates['name'] = 't1.50.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.009',
            '8295'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions

        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'
        self.student.find(
            By.XPATH,
            "//div[@class='chapter-panel']/div[@class='sections']" +
            "/div[@class='section']/button"
        ).click()

        assert('practice' in self.student.current_url()), \
            'Not presented with practice problems'

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8296 - 010 - Student | Bars without enough data show Practice More
    # To Get Forecast instead of a color bar
    @pytest.mark.skipif(str(8296) not in TESTS, reason='Excluded')
    def test_student_bars_without_data_show_practice_more_8296(self):
        """Bar without enough data show Practice More To Get Forecast.

        Steps:
        Click on the user menu in the upper right corner
        Click on "Performance Forecast"
        Scroll to the Individual Chapters section

        Expected Result:
        The user is presented with the "Practice More To Get Forecast"
        button under a section without enough data instead of a color bar
        """
        self.ps.test_updates['name'] = 't1.50.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.50',
            't1.50.010',
            '8296'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.student.open_user_menu()
        self.student.find(By.PARTIAL_LINK_TEXT, 'Performance Forecast').click()
        assert('guide' in self.student.current_url()), \
            'Not viewing performance forecast'
        self.student.find(By.CLASS_NAME, 'no-data')

        self.ps.test_updates['passed'] = True
class TestCourseMaintenance(unittest.TestCase):
    """T1.57 - Course Maintenance."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.admin = Admin(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.admin.login()
        self.admin.goto_admin_control()
        self.admin.sleep(5)

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.admin.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.admin.delete()
        except:
            pass

    # Case C8311 - 001 - Admin | Import courses from Salesforece
    @pytest.mark.skipif(str(8311) not in TESTS, reason='Excluded')
    def test_admin_import_courses_from_salesforce_8311(self):
        """Import courses from Salesforce.

        Steps:
        Click on the user menu
        Click on the Admin option
        Click on Salesforce on the header
        Click on the Import Courses button

        Expected Result:

        """
        self.ps.test_updates['name'] = 't1.57.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.57', 't1.57.001', '8311']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C8312 - 002 - Admin | Update Salesforce Staistics
    @pytest.mark.skipif(str(8312) not in TESTS, reason='Excluded')
    def test_admin_update_salesforce_statistice_8312(self):
        """Update Salesforce statistics.

        Steps:
        Click on the user menu
        Click on the Admin option
        Click on Salesforce on the header
        Click on Update Salesforce

        Expected Result:

        """
        self.ps.test_updates['name'] = 't1.57.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.57', 't1.57.002', '8312']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C8313 - 003 - Admin | Exclude assesments from all courses
    @pytest.mark.skipif(str(8313) not in TESTS, reason='Excluded')
    def test_admin_exclude_assesments_from_all_courses_8313(self):
        """Exclude assesments from all courses.

        Steps:

        Expected Result:
        """
        self.ps.test_updates['name'] = 't1.57.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.57', 't1.57.003', '8313']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        raise NotImplementedError(inspect.currentframe().f_code.co_name)

        self.ps.test_updates['passed'] = True

    # Case C8314 - 004 - Admin | Add a system notification
    @pytest.mark.skipif(str(8314) not in TESTS, reason='Excluded')
    def test_admin_add_a_system_notification_8314(self):
        """Add a system notification.

        Steps:
        Click on the user menu
        Click on the Admin option
        Click on System Setting on the header
        Click on the Notifications option
        Enter a notification into the New Notification text box
        Click on the Add button

        Expected Result:
        A system notification is added
        """
        self.ps.test_updates['name'] = 't1.57.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.57', 't1.57.004', '8314']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'System Setting')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Notifications')
            )
        ).click()
        self.admin.sleep(5)

        self.admin.find(By.XPATH, "//input[@id='new_message']").send_keys(
            'automated test')

        self.admin.find(By.XPATH, "//input[@class='btn btn-default']").click()

        self.admin.sleep(5)

        notif = self.admin.driver.find_elements_by_xpath(
            "//div[@class='col-xs-12']")

        for index, n in enumerate(notif):
            if n.text.find('automated test') >= 0:
                self.admin.driver.find_elements_by_xpath(
                    "//a[@class='btn btn-warning']")[index].click()
                self.admin.driver.switch_to_alert().accept()
                self.ps.test_updates['passed'] = True
                break

    # Case C8315 - 005 - Admin | Delete a system notification
    @pytest.mark.skipif(str(8315) not in TESTS, reason='Excluded')
    def test_admin_delete_a_system_notification_8315(self):
        """Delete a system notification.

        Steps:
        Click on the user menu
        Click on the Admin option
        Click on System Setting on the header
        Click on the Notifications option
        Click on the Remove button next to a notification
        Click OK on the dialouge box

        Expected Result:
        A system notification is deleted
        """
        self.ps.test_updates['name'] = 't1.57.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.57', 't1.57.005', '8315']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'System Setting')
            )
        ).click()
        self.admin.wait.until(
            expect.visibility_of_element_located(
                (By.PARTIAL_LINK_TEXT, 'Notifications')
            )
        ).click()
        self.admin.sleep(5)

        self.admin.find(By.XPATH, "//input[@id='new_message']").send_keys(
            'automated test')

        self.admin.find(By.XPATH, "//input[@class='btn btn-default']").click()

        self.admin.sleep(5)

        notif = self.admin.driver.find_elements_by_xpath(
            "//div[@class='col-xs-12']")

        for index, n in enumerate(notif):
            if n.text.find('automated test') >= 0:
                self.admin.driver.find_elements_by_xpath(
                    "//a[@class='btn btn-warning']")[index].click()
                self.admin.driver.switch_to_alert().accept()
                break

        deleted = True

        notif = self.admin.driver.find_elements_by_xpath(
            "//div[@class='col-xs-12']")

        for n in notif:
            if n.text.find('automated test') >= 0:
                deleted = False
                break

        if deleted:
            self.ps.test_updates['passed'] = True
class TestEditCourseSettingsAndRoster(unittest.TestCase):
    """T1.42 - Edit Course Settings and Roster."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher.login()
        self.teacher.select_course(appearance='physics')
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Course Settings and Roster')
            )
        ).click()
        self.teacher.page.wait_for_page_load()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C8258 - 001 - Teacher | Edit the course name
    @pytest.mark.skipif(str(8258) not in TESTS, reason='Excluded')
    def test_teacher_edit_the_course_name_8258(self):
        """Edit the course name.

        Steps:
        Click the "Rename Course" button that is next to the course name
        Enter a new course name
        Click the "Rename" button
        Click the X that is on the upper right corner of the dialogue box

        Expected Result:
        The course name is edited.
        (then put it back at the end)
        """
        self.ps.test_updates['name'] = 't1.42.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.001', '8258']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        course_name = self.teacher.driver.find_element(
            By.XPATH,
            '//div[@class="course-settings-title"]/span'
        ).text
        self.teacher.find(
            By.XPATH, '//button[contains(@class,"edit-course")]' +
            '//span[contains(text(),"Rename Course")]'
        ).click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys('_EDIT')
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-course-confirm")]'
        ).click()
        # check that it was edited
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="course-settings-title"]' +
                 '/span[contains(text(),"%s_EDIT")]' % course_name)
            )
        )
        # set it back
        self.teacher.sleep(1)
        self.teacher.driver.find_element(
            By.XPATH,
            '//button[contains(@class,"edit-course")]' +
            '//span[contains(text(),"Rename Course")]'
        ).click()
        for _ in range(len('_EDIT')):
            self.teacher.wait.until(
                expect.element_to_be_clickable(
                    (By.XPATH, '//input[contains(@class,"form-control")]')
                )
            ).send_keys(Keys.BACK_SPACE)
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-course-confirm")]'
        ).click()
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//div[@class="course-settings-title"]' +
                 '/span[text()="%s"]' % course_name)
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C8259 - 002 - Teacher | Remove an instructor from the course
    @pytest.mark.skipif(str(8259) not in TESTS, reason='Excluded')
    def test_teacher_remove_an_instructor_from_a_course_8259(self):
        """Remove an instructor from the course.

        Steps:
        Click "Remove" for an instructor under the Instructors section
        Click "Remove" on the box that pops up

        Expected Result:
        The instructor is removed from the Instructors list.
        """
        self.ps.test_updates['name'] = 't1.42.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.002', '8259']
        self.ps.test_updates['passed'] = False

        self.teacher.logout()
        # add extra instructor through admin first
        admin = Admin(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        admin.login()
        admin.get('https://tutor-qa.openstax.org/admin/courses/1/edit')
        admin.page.wait_for_page_load()
        teacher_name = 'Trent'
        admin.find(
            By.XPATH, '//a[contains(text(),"Teachers")]').click()
        admin.find(
            By.ID, 'course_teacher').send_keys(teacher_name)
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name)
            )
        ).click()
        admin.sleep(1)
        admin.find(
            By.LINK_TEXT, 'Main Dashboard').click()
        admin.page.wait_for_page_load()
        admin.logout()
        # redo set-up, but make sure to go to course 1
        self.teacher.login()
        self.teacher.get('https://tutor-qa.openstax.org/courses/1')
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Course Settings and Roster')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        # delete teacher
        teachers_list = self.teacher.find_all(
            By.XPATH, '//div[@class="teachers-table"]//tbody//tr')
        for x in range(len(teachers_list)):
            temp_first = self.teacher.find(
                By.XPATH,
                '//div[@class="teachers-table"]//tbody//tr[' +
                str(x + 1) + ']/td'
            ).text
            if temp_first == teacher_name:
                self.teacher.find(
                    By.XPATH,
                    '//div[@class="teachers-table"]//tbody//tr[' +
                    str(x + 1) + ']//td//span[contains(text(),"Remove")]'
                ).click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH, '//div[@class="popover-content"]//button'
                ).click()
                break
            if x == len(teachers_list) - 1:
                print('added teacher was not found, and not deleted')
                raise Exception
        deleted_teacher = self.teacher.driver.find_elements(
            By.XPATH, '//td[contains(text(),"%s")]' % teacher_name)
        assert(len(deleted_teacher) == 0), 'teacher not deleted'

        self.ps.test_updates['passed'] = True

    # Case C8260 - 003 - Teacher | Remove the last instructor from the course
    @pytest.mark.skipif(str(8260) not in TESTS, reason='Excluded')
    def test_teacher_remove_the_last_instructor_from_the_course_8260(self):
        """Remove the last instructor from the course.

        Steps:
        Click on the user menu in the upper right corner of the page
        Click "Course Roster"
        Click "Remove" for an instructor under the Instructors section
        Click "Remove" on the box that pops up

        Expected Result:
        The instructor is removed from the Instructors list.
        """
        self.ps.test_updates['name'] = 't1.42.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.003', '8260']
        self.ps.test_updates['passed'] = False

        raise NotImplementedError(inspect.currentframe().f_code.co_name)
        self.teacher.logout()
        # add extra instructor through admin first
        admin = Admin(
            use_env_vars=True,
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        admin.login()
        admin.get('https://tutor-qa.openstax.org/admin/courses/1/edit')
        admin.page.wait_for_page_load()
        teacher_name = 'Trent'
        admin.find(
            By.XPATH, '//a[contains(text(),"Teachers")]').click()
        admin.find(
            By.ID, 'course_teacher').send_keys(teacher_name)
        admin.wait.until(
            expect.visibility_of_element_located(
                (By.XPATH, '//li[contains(text(),"%s")]' % teacher_name)
            )
        ).click()
        admin.sleep(1)
        admin.find(
            By.LINK_TEXT, 'Main Dashboard').click()
        admin.page.wait_for_page_load()
        admin.logout()
        # redo set-up, but make sure to go to course 1
        self.teacher.login()
        self.teacher.get('https://tutor-qa.openstax.org/courses/1')
        self.teacher.open_user_menu()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.LINK_TEXT, 'Course Settings and Roster')
            )
        ).click()
        self.teacher.page.wait_for_page_load()
        # delete teacher
        teachers_list = self.teacher.find_all(
            By.XPATH, '//div[@class="teachers-table"]//tbody//tr')
        for x in range(len(teachers_list)):
            temp_first = self.teacher.find(
                By.XPATH,
                '//div[@class="teachers-table"]//tbody//tr[' +
                str(x + 1) + ']/td'
            ).text
            if temp_first == teacher_name:
                self.teacher.find(
                    By.XPATH,
                    '//div[@class="teachers-table"]//tbody//tr[' +
                    str(x + 1) + ']//td//span[contains(text(),"Remove")]'
                ).click()
                self.teacher.sleep(1)
                self.teacher.find(
                    By.XPATH, '//div[@class="popover-content"]//button'
                ).click()
                break
            if x == len(teachers_list) - 1:
                print('added teacher was not found, and not deleted')
                raise Exception
        deleted_teacher = self.teacher.driver.find_elements(
            By.XPATH, '//td[contains(text(),"%s")]' % teacher_name)
        assert(len(deleted_teacher) == 0), 'teacher not deleted'

        self.ps.test_updates['passed'] = True

    # Case C8261 - 004 - Teacher | Add a period
    @pytest.mark.skipif(str(8261) not in TESTS, reason='Excluded')
    def test_teacher_add_a_period_8261(self):
        """Add a period.

        Steps:
        Click "+ Add Period"
        Enter a period name into the Period Name text box
        Click "Add"

        Expected Result:
        A new period is added.
        """
        self.ps.test_updates['name'] = 't1.42.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.004', '8261']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        period_name = 'automated_' + str(randint(0, 999))
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"add-period")]//button').click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys(period_name)
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-period-confirm")]'
        ).click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, '//a[contains(text(),"'+period_name+'")]')

        self.ps.test_updates['passed'] = True

    # Case C8262 - 005 - Teacher | Rename a period
    @pytest.mark.skipif(str(8262) not in TESTS, reason='Excluded')
    def test_teacher_rename_a_period_8262(self):
        """Rename a period.

        Steps:
        Click "Rename Period"
        Enter a new period name into the Period Name text box
        Click "Rename"

        Expected Result:
        A period is renamed.
        """
        self.ps.test_updates['name'] = 't1.42.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.005', '8262']
        self.ps.test_updates['passed'] = False

        # create a period
        period_name = 'automated_' + str(randint(0, 999))
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"add-period")]//button').click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys(period_name)
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-period-confirm")]'
        ).click()
        self.teacher.sleep(1)
        # edit the period
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"'+period_name+'")]')
            )
        ).click()
        self.teacher.find(
            By.XPATH, '//span[contains(@class,"rename-period")]/button'
        ).click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys('_EDIT')
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-period-confirm")]'
        ).click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, '//a[contains(text(),"'+period_name+'_EDIT")]')

        self.ps.test_updates['passed'] = True

    # Case C8263 - 006 - Teacher | Archive an empty period
    @pytest.mark.skipif(str(8263) not in TESTS, reason='Excluded')
    def test_teacher_archive_an_empt_period_8263(self):
        """Archive an empty period.

        Steps:
        Click on an empty period
        Click "Archive Period"
        Click "Archive" on the dialogue box

        Expected Result:
        An empty period is archived.
        """
        self.ps.test_updates['name'] = 't1.42.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.006', '8263']
        self.ps.test_updates['passed'] = False

        # create a period
        period_name = 'automated_' + str(randint(0, 999))
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"add-period")]//button').click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys(period_name)
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-period-confirm")]'
        ).click()
        self.teacher.sleep(1)
        # edit the period
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"'+period_name+'")]')
            )
        ).click()
        self.teacher.find(
            By.XPATH, '//a[contains(@class,"archive-period")]').click()
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"popover-content")]' +
            '//button[contains(@class,"archive")]').click()
        self.teacher.sleep(2)
        archived_period = self.teacher.find_all(
            By.XPATH, '//a[contains(text(),"'+period_name+'")]')
        assert(len(archived_period) == 0), 'period not archived'

        self.ps.test_updates['passed'] = True

    # Case C8264 - 007 - Teacher | Archive a non-empty period
    @pytest.mark.skipif(str(8264) not in TESTS, reason='Excluded')
    def test_teacher_archive_a_non_empty_period_8264(self):
        """Archive a non-empty period.

        Steps:
        Click on a non-empty period
        Click "Archive Period"
        Click Archive

        Expected Result:
        Period is archived
        """
        self.ps.test_updates['name'] = 't1.42.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.007', '8264']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        period_name = self.teacher.find(
            By.XPATH, '//ul[@role="tablist"]//a[@role="tab"]').text
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"'+period_name+'")]')
            )
        ).click()
        self.teacher.find(
            By.XPATH, '//a[contains(@class,"archive-period")]').click()
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"popover-content")]' +
            '//button[contains(@class,"archive")]').click()
        self.teacher.find(
            By.XPATH, '//span[contains(text(),"View Archived")]').click()
        self.teacher.find(
            By.XPATH, '//div[@class="modal-body"]//td[contains(text(),"' +
            period_name + '")]')
        # add the section back
        periods = self.teacher.find_all(
            By.XPATH, '//div[@class="modal-body"]//table//tbody//tr')
        for x in range(len(periods)):
            temp_period = self.teacher.find(
                By.XPATH, '//div[@class="modal-body"]//table//tbody' +
                '//tr['+str(x+1)+']/td').text
            if temp_period == period_name:
                self.teacher.find(
                    By.XPATH,
                    '//div[@class="modal-body"]//table//tbody//tr[' +
                    str(x+1) + ']//button//span[contains(text(),"Unarchive")]'
                ).click()
                break

        self.ps.test_updates['passed'] = True

    # Case C8265 - 008 - Teacher | Move a student to another period
    @pytest.mark.skipif(str(8265) not in TESTS, reason='Excluded')
    def test_teacher_mover_a_student_to_another_period_8265(self):
        """Move a student to another period.

        Steps:
        Click on the user menu in the upper right corner of the page
        Click "Course Roster"
        Click "Change Period" for a student under the Roster section
        Click the desired period to move a student

        Expected Result:
        A student is moved to another period
        """
        self.ps.test_updates['name'] = 't1.42.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.008', '8265']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.teacher.find(
            By.XPATH, '//a[@aria-describedby="change-period"]').click()
        student_name = self.teacher.find(
            By.XPATH, '//div[@class="roster"]//td').text
        element = self.teacher.find(
            By.XPATH, '//div[@class="popover-content"]//a')
        period_name = element.text
        element.click()
        self.teacher.sleep(1)
        self.teacher.find(
            By.XPATH, '//li/a[contains(text(),"'+period_name+'")]').click()
        self.teacher.driver.find_element(
            By.XPATH, '//td[contains(text(),"%s")]' % student_name)

        self.ps.test_updates['passed'] = True

    # Case C8266 - 009 - Teacher | Drop a student
    @pytest.mark.skipif(str(8266) not in TESTS, reason='Excluded')
    def test_teacher_drop_a_student_8266(self):
        """Drop a student.

        Steps:
        Click on the user menu in the upper right corner of the page
        Click "Course Roster"
        Click "Drop" for a student under the Roster section
        Click "Drop" in the box that pops up

        Expected Result:
        A student is dropped from the course and
        is put under the Dropped Students section
        """
        self.ps.test_updates['name'] = 't1.42.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.009', '8266']
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        student_name = self.teacher.find(
            By.XPATH, '//div[@class="roster"]//td').text
        self.teacher.find(
            By.XPATH, '//a[@aria-describedby="drop-student"]').click()
        self.teacher.find(
            By.XPATH, '//div[@class="popover-content"]//button').click()
        self.teacher.sleep(1)
        # check that student was droped
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"dropped-students")]' +
            '//td[contains(text(),"%s")]' % student_name
        )

        self.ps.test_updates['passed'] = True

    # Case C8267 - 010 - Teacher | Readd a dropped student
    @pytest.mark.skipif(str(8267) not in TESTS, reason='Excluded')
    def test_teacher_readd_a_dropped_student_8267(self):
        """Readd a dropped student.

        Steps:
        Click "Add Back to Active Roster" for a student under
            the Dropped Students section
        Click "Add" on the box that pops up

        Expected Result:
        A student is added back to the course
        """
        self.ps.test_updates['name'] = 't1.42.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.010', '8267']
        self.ps.test_updates['passed'] = False

        # drop a student (to make sure there is someone to add back)
        student_name = self.teacher.find(
            By.XPATH, '//div[@class="roster"]//td').text
        self.teacher.find(
            By.XPATH, '//a[@aria-describedby="drop-student"]').click()
        self.teacher.find(
            By.XPATH, '//div[@class="popover-content"]//button').click()
        self.teacher.sleep(1)
        # add a student back (not necessarily the same student)
        element = self.teacher.find(
            By.XPATH, '//div[contains(@class,"dropped-students")]' +
            '//span[contains(text(),"Add Back to Active Roster")]')
        self.teacher.driver.execute_script(
            'return arguments[0].scrollIntoView();', element)
        self.teacher.driver.execute_script('window.scrollBy(0, -80);')
        element.click()
        self.teacher.find(
            By.XPATH, '//div[@class="popover-content"]//button').click()
        # check that student was added back
        self.teacher.find(
            By.XPATH,
            '//div[@class="roster"]//td[contains(text(),"%s")]' % student_name)

        self.ps.test_updates['passed'] = True

    # Case C58356 - 011 - Teacher | Unarchive an empty period
    @pytest.mark.skipif(str(58356) not in TESTS, reason='Excluded')
    def test_teacher_unarchive_an_empty_period_58356(self):
        """Unarchive an empty period.

        Steps:
        Go to Tutor
        Click on the 'Login' button
        Enter the teacher user account [ teacher001 ] and password in the boxes
        Click on the 'Sign in' button
        If the user has more than one course, click on a Tutor course name
        Click on the user menu in the upper right corner of the page
        Click "Course Settings and Roster"
        Click "View Archived Period(s)"
        Click Unarchived period next to selected course

        Expected Result:
        Period is made active.
        """
        self.ps.test_updates['name'] = 't1.42.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.42', 't1.42.011', '58356']
        self.ps.test_updates['passed'] = False

        # create a period
        period_name = 'automated_011_' + str(randint(0, 999))
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"add-period")]//button').click()
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//input[contains(@class,"form-control")]')
            )
        ).send_keys(period_name)
        self.teacher.find(
            By.XPATH,
            '//button[contains(@class,"edit-period-confirm")]'
        ).click()
        self.teacher.sleep(1)
        # archive the period
        self.teacher.wait.until(
            expect.element_to_be_clickable(
                (By.XPATH, '//a[contains(text(),"'+period_name+'")]')
            )
        ).click()
        self.teacher.find(
            By.XPATH, '//a[contains(@class,"archive-period")]').click()
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"popover-content")]' +
            '//button[contains(@class,"archive")]').click()
        self.teacher.sleep(2)
        archived_period = self.teacher.find_all(
            By.XPATH, '//a[contains(text(),"'+period_name+'")]')
        assert(len(archived_period) == 0), 'period not archived'
        # unarchive the period
        self.teacher.find(
            By.XPATH, '//div[contains(@class,"view-archived-periods")]//button'
        ).click()
        self.teacher.sleep(1)
        rows = self.teacher.find_all(
            By.XPATH, '//div[@class="modal-content"]//tbody/tr')
        for row in rows:
            temp_name = row.find_element(By.XPATH, "./td[1]").text
            if temp_name == period_name:
                row.find_element(
                    By.XPATH,
                    "./td[3]//button[contains(@class,'unarchive-section')]"
                ).click()
                self.teacher.find(
                    By.XPATH,
                    '//div[@class="modal-content"]//button[@class="close"]'
                ).click()
                break
        # check that period is no longer archived
        self.teacher.find(
            By.XPATH, '//a[contains(text(),"'+period_name+'")]')

        self.ps.test_updates['passed'] = True
Esempio n. 32
0
class TestTutorStudent(unittest.TestCase):
    ''''''
    def setUp(self):
        self.ps = PastaSauce()
        self.helper = StaxHelper()
        self.desired_capabilities['name'] = self.id()
        student = self.helper.student.name
        student_password = self.helper.student.password
        self.driver = StaxHelper.run_on(
            StaxHelper.LOCAL, self.ps, self.desired_capabilities
        )
        self.driver.implicitly_wait(15)
        self.wait = WebDriverWait(self.driver, 15)
        self.driver.set_window_size(*standard_window)
        self.helper.user.login(self.driver, student, student_password,
                               self.helper.user.url)
        self.helper.user.select_course(self.driver, category='Physics')

        # # # TODO: setup test assignments # # #

    def tearDown(self):
        ''''''
        self.driver.quit()
        status = (sys.exc_info() == (None, None, None))
        self.ps.update_job(self.driver.session_id, passed=status)

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_all_past_work(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_reference_book(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_a_standard_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_an_intro_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_a_homework(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_weakest_topics_from_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_specific_topic_from_dashboard(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_views_complete_performance_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_all_topics_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_one_chapter_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_practices_specific_topic_from_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_works_an_external_assignment(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_reviews_a_finished_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_student_reviews_a_finished_homework(self):
        ''''''
class TestWorkAnExternalAssignment(unittest.TestCase):
    """T1.48 - Work an external assignment."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.student = Student(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher = Teacher(
            use_env_vars=True,
            existing_driver=self.student.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher.login()

        # Create an external assignment for the student to work
        self.teacher.select_course(appearance='physics')
        self.teacher.wait.until(
            expect.visibility_of_element_located(
                (By.ID, 'add-assignment')
            )
        ).click()
        self.teacher.find(
            By.PARTIAL_LINK_TEXT, 'Add External Assignment').click()
        assert('externals/new' in self.teacher.current_url()), \
            'Not on the add an external assignment page'

        self.teacher.find(
            By.XPATH, "//input[@id = 'reading-title']").send_keys('Epic 48')
        self.teacher.find(
            By.XPATH, "//textarea[@class='form-control empty']").send_keys(
            "instructions go here")
        self.teacher.find(
            By.XPATH, "//input[@id = 'hide-periods-radio']").click()

        # Choose the first date calendar[0], second is calendar[1]
        # and set the open date to today
        self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__input-container']")[0].click()
        self.teacher.driver.find_element_by_xpath(
            "//div[@class = 'datepicker__day datepicker__day--today']").click()

        # Choose the second date calendar[1], first is calendar[0]
        self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__input-container']")[1].click()
        while(self.teacher.find(
            By.XPATH,
            "//span[@class = 'datepicker__current-month']"
        ).text != 'December 2016'):
            self.teacher.find(
                By.XPATH,
                "//a[@class = 'datepicker__navigation datepicker__" +
                "navigation--next']").click()

        # Choose the due date of December 31, 2016
        weekends = self.teacher.driver.find_elements_by_xpath(
            "//div[@class = 'datepicker__day datepicker__day--weekend']")
        for day in weekends:
            if day.text == '31':
                due = day
                due.click()
                break

        self.teacher.find(By.XPATH, "//input[@id='external-url']").send_keys(
            "google.com")
        self.teacher.sleep(5)

        # Publish the assignment
        self.teacher.find(
            By.XPATH,
            "//button[@class='async-button -publish btn btn-primary']").click()
        self.teacher.sleep(60)
        self.student.login()

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.student.driver.session_id),
            **self.ps.test_updates
        )
        try:

            # Delete the assignment
            assert('calendar' in self.teacher.current_url()), \
                'Not viewing the calendar dashboard'

            spans = self.teacher.driver.find_elements_by_tag_name('span')
            for element in spans:
                if element.text.endswith('2016'):
                    month = element

            # Change the calendar date if necessary
            while (month.text != 'December 2016'):
                self.teacher.find(
                    By.XPATH,
                    "//a[@class = 'calendar-header-control next']").click()

            # Select the newly created assignment and delete it
            assignments = self.teacher.driver.find_elements_by_tag_name(
                'label')
            for assignment in assignments:
                if assignment.text == 'Epic 48':
                    assignment.click()
                    self.teacher.find(
                        By.XPATH,
                        "//a[@class='btn btn-default -edit-assignment']"
                    ).click()
                    self.teacher.find(
                        By.XPATH,
                        "//button[@class='async-button delete-link " +
                        "pull-right btn btn-default']").click()
                    self.teacher.find(
                        By.XPATH, "//button[@class='btn btn-primary']").click()
                    self.teacher.sleep(5)
                    break
        except:
            pass
        try:
            self.teacher.driver.refresh()
            self.teacher.sleep(5)

            self.teacher = None
            self.student.delete()
        except:
            pass

    # Case C8281 - 001 - Student | Click on an external assignment
    @pytest.mark.skipif(str(8281) not in TESTS, reason='Excluded')
    def test_student_click_on_a_external_assignment_8281(self):
        """Click on an external assignment.

        Steps:
        Click on an external assignment under the tab "This Week"
        on the dashboard

        Expected Result:
        The user is presented with the assignment link and instructions
        """
        self.ps.test_updates['name'] = 't1.48.001' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.001',
            '8281'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        self.student.sleep(5)

        self.ps.test_updates['passed'] = True

    # Case C8282 - 002 - Student | Read the directions below the assignment
    # link or hover over the info icon in the footer
    @pytest.mark.skipif(str(8282) not in TESTS, reason='Excluded')
    def test_student_read_directions_below_or_hover_over_info_icon_8282(self):
        """Read directions below assignment link or hover over the info icon.

        Steps:
        Click on an external assignment under the tab "This Week"
            on the dashboard
        Hover the cursor over the info icon in the footer

        Expected Result:
        The user is presented with the directions for the assignment
        """
        self.ps.test_updates['name'] = 't1.48.002' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.002',
            '8282'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        instructions = self.student.driver.find_elements_by_tag_name("p")
        flag = False
        for instruction in instructions:
            if (instruction.text == 'instructions go here'):
                flag = True
                break

        assert(flag), \
            'Did not read instructions'

        self.ps.test_updates['passed'] = True

    # Case C8283 - 003 - Student | Click the assignment link
    @pytest.mark.skipif(str(8283) not in TESTS, reason='Excluded')
    def test_student_click_the_assignment_link_8283(self):
        """Click the assignment link.

        Steps:
        Click on an external assignment under the tab "This Week"
            on the dashboard
        Click on the link to the external assignment

        Expected Result:
        The user is presented with the external assignment
        """
        self.ps.test_updates['name'] = 't1.48.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.003',
            '8283'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        link = self.student.driver.find_element_by_link_text(
            'Epic 48')
        original = self.student.current_url()
        self.student.driver.get(link.get_attribute("href"))

        assert('google' in self.student.current_url()), \
            'Not viewing assignment link'

        self.student.sleep(5)
        self.student.driver.get(original)

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        self.ps.test_updates['passed'] = True

    # Case C8284 - 004 - Student | Close the assignment tab or window
    @pytest.mark.skipif(str(8284) not in TESTS, reason='Excluded')
    def test_student_close_the_assignment_8284(self):
        """Close the assignment tab or window.

        Steps:
        Click on an external assignment under the tab "This Week"
            on the dashboard
        Click on the link to the external assignment
        Close the assignment tab

        Expected Result:
        The assignment tab is closed and the user is presented with the
        external assignment link and instructions on Tutor
        """
        self.ps.test_updates['name'] = 't1.48.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.004',
            '8284'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        link = self.student.driver.find_element_by_link_text(
            'Epic 48')
        original = self.student.current_url()
        self.student.driver.get(link.get_attribute("href"))

        assert('google' in self.student.current_url()), \
            'Not viewing assignment link'

        self.student.sleep(5)
        self.student.driver.get(original)

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        self.ps.test_updates['passed'] = True

    # Case C8285 - 005 - Student | Click the Back To Dashboard button to
    # finish the assignment
    @pytest.mark.skipif(str(8285) not in TESTS, reason='Excluded')
    def test_student_click_back_to_dashboard_button_8285(self):
        """Click the Back To Dashboard button to finish the assignment.

        Steps:
        Click on an external assignment under the tab "This Week"
            on the dashboard
        Click on the link to the external assignment
        Close the assignment tab
        Click "Back To Dashboard"

        Expected Result:
        The user is presented with the dashboard
        """
        self.ps.test_updates['name'] = 't1.48.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.005',
            '8285'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        link = self.student.driver.find_element_by_link_text(
            'Epic 48')
        original = self.student.current_url()
        self.student.driver.get(link.get_attribute("href"))

        assert('google' in self.student.current_url()), \
            'Not viewing assignment link'

        self.student.sleep(5)
        self.student.driver.get(original)

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        self.student.find(By.LINK_TEXT, 'Back To Dashboard').click()

        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True

    # Case C8286 - 006 - Student | Verify the assignment status as Clicked
    @pytest.mark.skipif(str(8286) not in TESTS, reason='Excluded')
    def test_student_verify_assignment_status_as_clicked_8286(self):
        """Verify the assignment status as Clicked.

        Steps:
        Click on an external assignment under the tab "This Week"
            on the dashboard
        Click on the link to the external assignment
        Close the assignment tab
        Click "Back To Dashboard"

        Expected Result:
        The external assignment is marked as "Clicked" in the Progress column
        on the dashboard
        """
        self.ps.test_updates['name'] = 't1.48.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = [
            't1',
            't1.48',
            't1.48.006',
            '8286'
        ]
        self.ps.test_updates['passed'] = False

        # Test steps and verification assertions
        self.student.select_course(appearance='physics')
        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        assignments = self.student.driver.find_elements_by_xpath(
            "//div[@class='task row external workable']")
        for assignment in assignments:
            if (assignment.text.find('Epic 48') >= 0):
                assignment.click()
                break

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        link = self.student.driver.find_element_by_link_text(
            'Epic 48')
        original = self.student.current_url()
        self.student.driver.get(link.get_attribute("href"))

        assert('google' in self.student.current_url()), \
            'Not viewing assignment link'

        self.student.sleep(5)
        self.student.driver.get(original)

        assert('tasks' in self.student.current_url()), \
            'Not viewing assignment page'

        assert('steps' in self.student.current_url()), \
            'Not viewing assignment page'

        self.student.find(By.LINK_TEXT, 'Back To Dashboard').click()

        assert('list' in self.student.current_url()), \
            'Not viewing the calendar dashboard'

        externals = self.student.driver.find_elements_by_xpath(
            "//div[@class = 'task row external workable']")

        for assignment in externals:
            if assignment.text.find("Clicked") >= 0 \
                    and assignment.text.find("Epic 48") >= 0:
                self.ps.test_updates['passed'] = True
                break
Esempio n. 34
0
class TestTutorAssignments(unittest.TestCase):
    ''''''
    def setUp(self):
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(use_env_vars=True)
        self.helper = StaxHelper(driver_type='chrome', pasta_user=self.ps,
                                 capabilities=self.desired_capabilities,
                                 initial_user=self.teacher)
        self.driver = self.helper.driver
        self.wait = WebDriverWait(self.driver, StaxHelper.DEFAULT_WAIT_TIME)
        self.driver.set_window_size(*standard_window)
        self.teacher.login(self.driver)
        self.teacher.select_course(self.driver, category='physics')
        self.rword = Assignment.rword
        self.screenshot_path = '/tmp/errors/'

    def tearDown(self):
        # Returns the info of exception being handled
        has_errors = self._test_has_failed()
        if has_errors:
            print(self.driver.current_url, '\n')
            date_and_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f')
            filename = 'testerr_%s.png' % date_and_time
            self.driver.save_screenshot('%s%s' % (self.screenshot_path,
                                        filename))
        self.driver.quit()
        self.ps.update_job(self.driver.session_id, passed=has_errors)

    def _test_has_failed(self):
        # for 3.4. In 3.3, can just use self._outcomeForDoCleanups.success:
        for method, error in self._outcome.errors:
            if error:
                return True
        return False

    # @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_draft_to_all_cancel_to_period_delete(self):
        '''
        '''
        # 1st / 0 / 1 / 1S / Draft
        # 2nd / 0 / 1 / 1S
        # all / 0 / 1 / 1S / Cancel
        # 1st / 0 / 1 / 1S / Delete
        # 2nd / 0 / 1 / 1S
        name = 'Automated 2'
        description = 'by period draft to all cancel to period delete'
        open_p1 = StaxHelper.date_string()
        close_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        close_p2 = StaxHelper.date_string(2)
        open_all = StaxHelper.date_string()
        close_all = StaxHelper.date_string(1)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={
                    '1st': (open_p1, close_p1),
                    '2nd': (open_p2, close_p2), },
                readings=['1.1'],
                status=self.assign.DRAFT, )
        except Exception as ex:
            self.fail('1: Add :: %s :: %s' % (ex.__class__.__name__, ex))
        try:
            self.assign.change_reading(
                driver=self.driver,
                title=name,
                periods={
                    'all': (open_all, close_all), },
                status=self.assign.CANCEL)
        except Exception as ex:
            self.fail('2: Edit :: %s :: %s' % (ex.__class__.__name__, ex))
        try:
            self.assign.remove_reading(
                driver=self.driver,
                title=name)
        except Exception as ex:
            self.fail('3: Remove :: %s :: %s' % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_draft_to_all_draft_to_delete(self):
        '''
        '''
        # 1st / 0 / 1 / 1S / Draft
        # 2nd / 1 / 2 / 1S
        # all / 0 / 2 / 1S / Draft
        # all / 0 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_publish_to_all_publish_fail(self):
        '''
        '''
        # 1st / 0 / 1 / 1S / Publish
        # 2nd / 0 / 1 / 1S
        # all / 0 / 1 / 1S / Publish **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_publish_to_delete_fail(self):
        '''
        '''
        # 1st / 0 / 1 / 1S / Publish
        # 2nd / 1 / 2 / 1S
        # 1st / 0 / 1 / 1S / Delete **
        # 2nd / 1 / 2 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_publish_to_all_publish_to_delete_fail(self):
        '''
        '''
        # 1st / 0 / 1 / 1S / Publish
        # 2nd / 1 / 2 / 1S
        # all / 0 / 2 / 1S / Publish
        # all / 0 / 2 / 1S / Delete **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_publish_to_all_cancel_to_period_delete(self):
        '''
        '''
        # 1st / 1 / 2 / 1S / Publish
        # 2nd / 1 / 2 / 1S
        # all / 1 / 2 / 1S / Cancel
        # 1st / 1 / 2 / 1S / Delete
        # 2nd / 1 / 2 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_status_by_period_publish_to_all_publish_to_delete(
            self):
        '''
        '''
        # 1st / 1 / 2 / 1S / Publish
        # 2nd / 1 / 2 / 1S
        # all / 1 / 2 / 1S / Publish
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_by_period_publish_to_delete(self):
        '''
        '''
        # 1st / 1 / 2 / 1S / Publish
        # 2nd / 2 / 3 / 1S
        # 1st / 1 / 2 / 1S / Delete
        # 2nd / 2 / 3 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_dates_by_period_publish_to_all_publish_to_delete(self):
        '''
        '''
        # 1st / 1 / 2 / 1S / Publish
        # 2nd / 2 / 3 / 1S
        # all / 1 / 3 / 1S / Publish
        # all / 1 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_cancel(self):
        '''
        '''
        # all / 0 / 1 / 1S / Cancel

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_period_cancel_to_all_delete(self):
        '''
        '''
        # all / 0 / 1 / 1S / Draft
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 0 / 1 / 1S
        # all / 0 / 1 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_period_draft_to_delete(self):
        '''
        '''
        # all / 0 / 1 / 1S / Draft
        # 1st / 0 / 1 / 1S / Draft
        # 2nd / 1 / 2 / 1S
        # 1st / 0 / 1 / 1S / Delete
        # 2nd / 1 / 2 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_all_draft_to_delete(self):
        '''
        '''
        # all / 0 / 1 / 1S / Draft
        # all / 0 / 1 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_all_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1C / Draft
        # all / 1 / 2 / 1C / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_period_publish_to_period_delete_fail(
            self):
        '''
        '''
        # all / 0 / 1 / 1S / Publish
        # 1st / 0 / 1 / 1S / Publish
        # 2nd / 0 / 1 / 1S
        # 1st / 0 / 1 / 1S / Delete **
        # 2nd / 0 / 1 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_period_publish_fail(self):
        '''
        '''
        # all / 0 / 1 / 1S / Publish
        # 1st / 0 / 1 / 1S / Publish **
        # 2nd / 0 / 1 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_delete_fail(self):
        '''
        '''
        # all / 0 / 1 / 1S / Publish
        # all / 0 / 1 / 1S / Delete **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_due_dates_all_draft_to_cancel_to_delete(self):
        '''
        '''
        # all / 0 / 2 / 1S / Draft
        # all / 0 / 1 / 1S / Cancel
        # all / 0 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_open_dates_all_draft_to_cancel_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Draft
        # all / 0 / 2 / 1S / Cancel
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_dates_all_draft_to_cancel_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Draft
        # all / 2 / 3 / 1S / Cancel
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_due_dates_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 0 / 2 / 1S / Draft
        # all / 0 / 1 / 1S / Draft
        # all / 0 / 1 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_due_earlier_all_publish_to_publish_to_delete_fail(
            self):
        '''
        '''
        # all / 0 / 2 / 1S / Publish
        # all / 0 / 1 / 1S / Publish
        # all / 0 / 1 / 1S / Delete **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_due_later_all_publish_to_publish_to_delete_fail(self):
        '''
        '''
        # all / 0 / 2 / 1S / Publish
        # all / 0 / 3 / 1S / Publish
        # all / 0 / 3 / 1S / Delete **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_sections_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1C  / Draft
        # all / 1 / 2 / 1C - 1S / Draft
        # all / 1 / 2 / 1C - 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_draft_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Draft
        # all / 1 / 2 / 1C - 1S / Draft
        # all / 1 / 2 / 1C - 1S / Publish
        # all / 1 / 2 / 1C - 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_plus_sections_all_draft_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Draft
        # all / 1 / 2 / 1C + 1S / Draft
        # all / 1 / 2 / 1C + 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_plus_sections_all_draft_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1S  / Draft
        # all / 1 / 2 / 1S + 1S / Draft
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_plus_sections_all_draft_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Draft
        # all / 1 / 2 / 1C + 1S / Publish
        # all / 1 / 2 / 1C + 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_plus_sections_all_draft_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1S  / Draft
        # all / 1 / 2 / 1S + 1S / Publish
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_minus_sections_all_publish_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Publish
        # all / 1 / 2 / 1C - 1S / Draft
        # all / 1 / 2 / 1C - 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_open_dates_all_publish_to_draft_to_delete(self):
        '''
        '''
        # all / 2 / 3 / 1S / Publish
        # all / 1 / 3 / 1S / Draft
        # all / 1 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_minus_sections_all_publish_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 2S  / Publish
        # all / 1 / 2 / 2S - 1S / Draft
        # all / 1 / 2 / 1S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_ch_minus_sections_all_publish_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Publish
        # all / 1 / 2 / 1C - 1S / Publish
        # all / 1 / 2 / 1C - 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_dates_all_publish_to_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Publish
        # all / 2 / 3 / 1S / Publish
        # all / 2 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_sec_minus_sections_all_publish_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 2S  / Publish
        # all / 1 / 2 / 2S - 1S / Publish
        # all / 1 / 2 / 1S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_plus_sections_all_publish_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Publish
        # all / 1 / 2 / 1C + 1S / Draft
        # all / 1 / 2 / 1C + 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_plus_sections_all_publish_to_draft_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1S  / Publish
        # all / 1 / 2 / 1S + 1S / Draft
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_plus_sections_all_publish_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1C  / Publish
        # all / 1 / 2 / 1C + 1S / Publish
        # all / 1 / 2 / 1C + 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_all_draft_to_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1C / Draft
        # all / 1 / 2 / 1C / Publish
        # all / 1 / 2 / 1C / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_all_publish_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1C / Publish
        # all / 1 / 2 / 1C / Draft
        # all / 1 / 2 / 1C / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_chapter_all_publish_to_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1C / Publish
        # all / 1 / 2 / 1C / Publish
        # all / 1 / 2 / 1C / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_section_plus_sections_all_publish_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 1S  / Publish
        # all / 1 / 2 / 1S + 1S / Publish
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_open_dates_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Draft
        # all / 0 / 2 / 1S / Draft
        # all / 0 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_minus_sections_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 2S  / Draft
        # all / 1 / 2 / 2S - 1S / Draft
        # all / 1 / 2 / 1S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_dates_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Draft
        # all / 2 / 3 / 1S / Draft
        # all / 2 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Draft
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_period_cancel_to_all_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Publish
        # 1st / 1 / 2 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_period_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Publish
        # 1st / 1 / 2 / 1S / Publish
        # 2nd / 1 / 2 / 1S
        # 1st / 1 / 2 / 1S / Delete
        # 2nd / 1 / 2 / 1S

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_publish_to_delete_fail(self):
        '''
        '''
        # all / 1 / 2 / 1S / Publish
        # all / 0 / 2 / 1S / Publish
        # all / 0 / 2 / 1S / Delete **

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 1S / Publish
        # all / 1 / 2 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_minus_section_all_draft_to_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 2S  / Draft
        # all / 1 / 2 / 2S - 1S / Publish
        # all / 1 / 2 / 1S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_dates_all_draft_to_publish_to_delete(self):
        '''
        '''
        # all / 2 / 3 / 1S / Draft
        # all / 1 / 3 / 1S / Publish
        # all / 1 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 2S  / Draft
        # all / 1 / 2 / 2S + 1S / Draft
        # all / 1 / 2 / 3S - 1S / Draft
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_publish_to_draft_to_publish_to_delete(
            self):
        '''
        '''
        # all / 1 / 2 / 2S  / Draft
        # all / 1 / 2 / 2S + 1S / Publish
        # all / 1 / 2 / 3S - 1S / Draft
        # all / 1 / 2 / 2S  / Publish
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 2S  / Publish
        # all / 1 / 2 / 2S + 1S / Draft
        # all / 1 / 2 / 3S - 1S / Draft
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_publish_to_publish_to_delete(self):
        '''
        '''
        # all / 1 / 2 / 2S  / Publish
        # all / 1 / 2 / 2S + 1S / Publish
        # all / 1 / 2 / 3S - 1S / Publish
        # all / 1 / 2 / 2S  / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_draft_to_draft_to_delete(self):
        '''
        '''
        # all / 2 / 3 / 1S / Draft
        # all / 1 / 3 / 1S / Draft
        # all / 1 / 3 / 1S / Delete

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_all_publish_to_publish_to_delete(self):
        '''
class TestTutorBasicAssignments(unittest.TestCase):
    """"""

    def setUp(self):
        self.ps = PastaSauce()
        self.desired_capabilities["name"] = self.id()
        self.teacher = Teacher(use_env_vars=True)
        self.helper = StaxHelper(
            driver_type="chrome", pasta_user=self.ps, capabilities=self.desired_capabilities, initial_user=self.teacher
        )
        self.driver = self.helper.driver
        self.wait = WebDriverWait(self.driver, StaxHelper.DEFAULT_WAIT_TIME)
        self.driver.set_window_size(*standard_window)
        self.teacher.login(self.driver)
        self.teacher.select_course(self.driver, title="physics")
        self.rword = Assignment.rword
        self.screenshot_path = "/tmp/errors/"

    def tearDown(self):
        # Returns the info of exception being handled
        has_errors = self._test_has_failed()
        if has_errors:
            print(self.driver.current_url, "\n")
            date_and_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f")
            filename = "testerr_%s.png" % date_and_time
            self.driver.save_screenshot("%s%s" % (self.screenshot_path, filename))
        self.driver = None
        self.helper.quit()
        self.ps.update_job(self.driver.session_id, passed=has_errors)

    def _test_has_failed(self):
        # for 3.4. In 3.3, can just use self._outcomeForDoCleanups.success:
        for method, error in self._outcome.errors:
            if error:
                return True
        return False

    # @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_assignment_today_all_cancel(self):
        """
        """
        # all / 0 / 1 / 1S / Cancel
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 1"
        description = "by period cancel"
        open_all = StaxHelper.date_string()
        due_all = StaxHelper.date_string(1)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"all": (open_all, due_all)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_today_all_draft_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 2"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_today_all_publish(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 3"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_today_by_period_cancel(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 4"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_today_by_period_draft_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 5"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_today_by_period_publish(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 6"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_all_cancel(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 7"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_all_draft_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 8"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_all_publish_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 9"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_by_period_cancel(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 10"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_by_period_draft_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 11"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))

    @pytest.mark.skipif(NOT_STARTED, reason="Not started")
    def test_assignment_future_by_period_publish_and_delete(self):
        """
        """
        # 1st / 0 / 1 / 1S / Cancel
        # 2nd / 1 / 2 / 1S
        print(inspect.currentframe().f_code.co_name)
        print(self.__class__.__name__)
        name = "Automated 12"
        description = "by period cancel"
        open_p1 = StaxHelper.date_string()
        due_p1 = StaxHelper.date_string(1)
        open_p2 = StaxHelper.date_string(1)
        due_p2 = StaxHelper.date_string(2)
        try:
            self.assign.add_new_reading(
                driver=self.driver,
                title=name,
                description=description,
                periods={"1st": (open_p1, due_p1), "2nd": (open_p2, due_p2)},
                readings=["1.1"],
                status=self.assign.CANCEL,
            )
        except Exception as ex:
            self.fail("1: Add :: %s :: %s" % (ex.__class__.__name__, ex))
class TestViewTheCalendarDashboard(unittest.TestCase):
    """T1.13 - View the calendar."""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(
            use_env_vars=True,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities
        )
        self.teacher.login()
        self.teacher.select_course(title='HS Physics')

    def tearDown(self):
        """Test destructor."""
        self.ps.update_job(
            job_id=str(self.teacher.driver.session_id),
            **self.ps.test_updates
        )
        try:
            self.teacher.delete()
        except:
            pass

    # Case C7978 - 001 - Teacher | View the calendar dashboard
    @pytest.mark.skipif(str(7978) not in TESTS, reason='Excluded')
    def test_teacher_view_the_calendar_dashboard_7978(self):
        """View the calendar dashboard.

        Steps:
        If the user has more than one course, click on a Tutor course name

        Expected Result:
        The teacher is presented their calendar dashboard.
        """
        self.ps.test_updates['name'] = 't1.13.001' + \
            inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.001', '7978']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True

    # Case C7979 - 002 - Teacher | View student scores using dashboard button
    @pytest.mark.skipif(str(7979) not in TESTS, reason='Excluded')
    def test_teacher_view_student_scores_using_the_dashboard_button_7979(self):
        """View student scores using the dashboard button.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the 'Student Scores' button

        Expected Result:
        The teacher is presented with the student scores
        """
        self.ps.test_updates['name'] = 't1.13.002' + \
            inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.002', '7979']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        self.teacher.find(By.LINK_TEXT, 'Student Scores').click()
        assert('scores' in self.teacher.current_url()), \
            'Not viewing student scores'

        self.ps.test_updates['passed'] = True

    # Case C7980 - 003 - Teacher | View student scores using the user menu link
    @pytest.mark.skipif(str(7980) not in TESTS, reason='Excluded')
    def test_teacher_view_student_scores_using_the_user_menu_link_7980(self):
        """View student scores using the user menu link.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the user menu
        Click on the 'Student Scores' link

        Expected Result:
        The teacher is presented with the student scores
        """
        self.ps.test_updates['name'] = 't1.13.003' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.003', '7980']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.CLASS_NAME, 'viewScores'). \
            find_element_by_tag_name('a'). \
            click()
        assert('scores' in self.teacher.current_url()), \
            'Not viewing the student scores'

        self.ps.test_updates['passed'] = True

    # Case C7981 - 004 - Teacher | View performance forecast using the
    # dashboard button
    @pytest.mark.skipif(str(7981) not in TESTS, reason='Excluded')
    def test_teacher_view_performance_forecast_using_dash_button_7981(self):
        """View performance forecast using the dashboard button.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the 'Performance Forecast' button on the dashboard

        Expected Result:
        The teacher is presented with the performance forecast
        """
        self.ps.test_updates['name'] = 't1.13.004' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.004', '7981']
        self.ps.test_updates['passed'] = False

        self.teacher.find(By.LINK_TEXT, 'Performance Forecast').click()
        self.teacher.page.wait_for_page_load()
        assert('guide' in self.teacher.current_url()), \
            'Not viewing the performance forecast'

        self.ps.test_updates['passed'] = True

    # Case C7982 - 005 - Teacher | View performace forecast using
    # the user menu link
    @pytest.mark.skipif(str(7982) not in TESTS, reason='Excluded')
    def test_teacher_view_performance_forecast_using_user_menu_link_7982(self):
        """View performance forecast using the user menu link.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the user menu
        Click on the 'Performance Forecast' link

        Expected Result:
        The teacher is presented with the performance forecast
        """
        self.ps.test_updates['name'] = 't1.13.005' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.005', '7982']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        self.teacher.open_user_menu()
        self.teacher.find(By.CLASS_NAME, 'viewTeacherPerformanceForecast'). \
            find_element_by_tag_name('a'). \
            click()
        self.teacher.page.wait_for_page_load()
        assert('guide' in self.teacher.current_url()), \
            'Not viewing the performance forecast'

        self.ps.test_updates['passed'] = True

    # Case C7983 - 006 - Teacher | View a reading assignment summary
    @pytest.mark.skipif(str(7983) not in TESTS, reason='Excluded')
    def test_teacher_view_a_reading_assignment_summary_7983(self):
        """View a reading assignment summary.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Create a reading assignment
        Click on the reading assignment on the calendar

        Expected Result:
        The teacher is presented with the reading assignment summary
        """
        self.ps.test_updates['name'] = 't1.13.006' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.006', '7983']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(appearance='physics')
        # create an assignment
        assignment_name = 'reading-%s' % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=2)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=5)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='reading',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'reading_list': ['1.1'],
                'status': 'publish',
            }
        )
        # click on assignment
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//label[contains(text(), "%s")]' % assignment_name)
            )
        ).click()
        # check that it opened
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH,
                 '//*[@class="modal-title" and ' +
                 'contains(text(), "%s")]' % assignment_name)
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7984 - 007 - Teacher | View a homework assignment summary
    @pytest.mark.skipif(str(7984) not in TESTS, reason='Excluded')
    def test_teacher_view_a_homework_assignment_summary_7984(self):
        """View a homework assignment summary.

        Steps:
        create a homework assignment
        If the user has more than one course, click on a Tutor course name
        Click on a homework assignment on the calendar

        Expected Result:
        The teacher is presented with the homework assignment summary
        """
        self.ps.test_updates['name'] = 't1.13.007' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.007', '7984']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(appearance='physics')
        # create an assignment
        assignment_name = "homework-%s" % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=2)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=5)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='homework',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'problems': {'1.1': (2, 3), },
                'status': 'publish',
                'feedback': 'immediate'
            }
        )
        # click on assignment
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//label[contains(text(), "%s")]' % assignment_name)
            )
        ).click()
        # check that it opened
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH,
                 '//*[@class="modal-title" and ' +
                 'contains(text(), "%s")]' % assignment_name)
            )
        )
        self.ps.test_updates['passed'] = True

    # NOT DONE
    # Case C7985 - 008 - Teacher | View an external assignment summary
    @pytest.mark.skipif(str(7985) not in TESTS, reason='Excluded')
    def test_teacher_view_an_external_assignment_summary_7985(self):
        """View an external assignment summary.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on an external assignment on the calendar

        Expected Result:
        The teacher is presented with the external assignment summary
        """
        self.ps.test_updates['name'] = 't1.13.008' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.008', '7985']
        self.ps.test_updates['passed'] = False

        # create an assignment
        assignment_name = 'external-%s' % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=0)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=5)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='external',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'url': 'google.com',
                'status': 'publish'
            }
        )
        # click on assignment
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//label[contains(text(), "%s")]' % assignment_name)
            )
        ).click()
        # check that it opened
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH,
                 '//*[@class="modal-title" and ' +
                 'contains(text(), "%s")]' % assignment_name)
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7986 - 009 - Teacher | View an event summary
    @pytest.mark.skipif(str(7986) not in TESTS, reason='Excluded')
    def test_teacher_view_an_event_summary_7986(self):
        """View an event summary.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on an event on the calendar

        Expected Result:
        The teacher is presented with the event summary
        """
        self.ps.test_updates['name'] = 't1.13.009' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.009', '7986']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(appearance='physics')
        # create an assignment
        assignment_name = "homework-%s" % randint(100, 999)
        today = datetime.date.today()
        begin = (today + datetime.timedelta(days=2)).strftime('%m/%d/%Y')
        end = (today + datetime.timedelta(days=5)).strftime('%m/%d/%Y')
        self.teacher.add_assignment(
            assignment='event',
            args={
                'title': assignment_name,
                'description': 'description',
                'periods': {'all': (begin, end)},
                'status': 'publish'
            }
        )
        # click on assignment
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH, '//label[contains(text(), "%s")]' % assignment_name)
            )
        ).click()
        # check that it opened
        self.teacher.wait.until(
            expect.presence_of_element_located(
                (By.XPATH,
                 '//*[@class="modal-title" and ' +
                 'contains(text(), "%s")]' % assignment_name)
            )
        )

        self.ps.test_updates['passed'] = True

    # Case C7987 - 010 - Teacher | Open the refrenece book using the dashboard
    # button
    @pytest.mark.skipif(str(7987) not in TESTS, reason='Excluded')
    def test_teacher_open_the_reference_book_using_dashboard_button_7987(self):
        """Open the refrenece book using the dashboard button.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the 'Browse The Book'button

        Expected Result:
        The teacher is preseneted with the book in a new tab
        """
        self.ps.test_updates['name'] = 't1.13.010' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.010', '7987']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        self.teacher.driver.find_element(
            By.LINK_TEXT,
            'Browse The Book'
        ).click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        assert('book' in self.teacher.current_url()), \
            'Not viewing the textbook PDF'

        self.ps.test_updates['passed'] = True

    # Case C7988 - 011 - Teacher | Open the refrenece book using user menu link
    @pytest.mark.skipif(str(7988) not in TESTS, reason='Excluded')
    def test_teacher_open_the_reference_book_using_user_menu_link_7988(self):
        """Open the refrenece book using the user menu link.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the user menu
        Click on the 'Browse the Book' link

        Expected Result:
        The teacher is presented with the book in a new tab
        """
        self.ps.test_updates['name'] = 't1.13.011' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.011', '7988']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(title='HS Physics')
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.LINK_TEXT,
            'Browse the Book'
        ).click()
        window_with_book = self.teacher.driver.window_handles[1]
        self.teacher.driver.switch_to_window(window_with_book)
        assert('book' in self.teacher.current_url()), \
            'Not viewing the textbook PDF'

        self.ps.test_updates['passed'] = True

    # Case C7989 - 012 - Teacher | Click on the course name to return to
    # the dashboard
    @pytest.mark.skipif(str(7989) not in TESTS, reason='Excluded')
    def test_teacher_click_course_name_to_return_to_the_dashboard_7989(self):
        """Click on the course name to return to the dashboard.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click on the 'Performance Forecast' button
        Click on the course name in the header

        Expected Result:
        The teacher is presented with their calendar dashboard
        """
        self.ps.test_updates['name'] = 't1.13.012' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.012', '7989']
        self.ps.test_updates['passed'] = False

        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.CLASS_NAME,
            'viewTeacherPerformanceForecast'
        ).click()
        self.teacher.driver.find_element(
            By.CLASS_NAME,
            'course-name'
        ).click()
        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True

    # Case C7990 - 013 - Teacher | Cick on the OpenStax logo to return to
    # the course picker
    @pytest.mark.skipif(str(7990) not in TESTS, reason='Excluded')
    def test_teacher_click_openstax_logo_to_return_to_course_picker_7990(self):
        """Cick on the OpenStax logo to return to the course picker.

        Steps:
        If the user has more than one course, click on a Tutor course name
        Click in the OpenStax logo in the header

        Expected Result:
        The teacher is presented with the course picker
        """
        self.ps.test_updates['name'] = 't1.13.013' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.013', '7990']
        self.ps.test_updates['passed'] = False

        # self.teacher.select_course(appearance='physics')
        self.teacher.driver.find_element(
            By.CLASS_NAME,
            'ui-brand-logo'
        ).click()
        assert('dashboard' in self.teacher.current_url()), \
            'Not viewing the course picker'

        self.ps.test_updates['passed'] = True

    # Case C7991 - 014 - Teacher | CLick in the OpenStax logo to return to the
    # dashboard
    @pytest.mark.skipif(str(7991) not in TESTS, reason='Excluded')
    def test_teacher_clicks_openstax_logo_to_return_to_dashboard_7991(self):
        """CLick in the OpenStax logo to return to the dashboard.

        Steps:
        Click on the 'Performance Forecast' button
        Click on the OpenStax logo in the header

        Expected Result:
        The teacher is presented with their calendar dashboard
        """
        self.ps.test_updates['name'] = 't1.13.014' \
            + inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = ['t1', 't1.13', 't1.13.014', '7991']
        self.ps.test_updates['passed'] = False

        self.teacher.logout()
        teacher2 = Teacher(
            username=os.getenv('TEACHER_USER_ONE_COURSE'),
            password=os.getenv('TEACHER_PASSWORD'),
            site='https://tutor-qa.openstax.org',
            existing_driver=self.teacher.driver,
            pasta_user=self.ps,
            capabilities=self.desired_capabilities,
        )
        print(teacher2.username)
        print(teacher2.password)
        teacher2.login()
        self.teacher.open_user_menu()
        self.teacher.driver.find_element(
            By.CLASS_NAME,
            'viewTeacherPerformanceForecast'
        ).click()
        self.teacher.driver.find_element(
            By.CLASS_NAME,
            'ui-brand-logo'
        ).click()
        assert('calendar' in self.teacher.current_url()), \
            'Not viewing the calendar dashboard'

        self.ps.test_updates['passed'] = True
Esempio n. 37
0
class TestTutorTeacher(unittest.TestCase):
    ''''''
    def setUp(self):
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        self.teacher = Teacher(use_env_vars=True)
        self.helper = StaxHelper(driver_type='chrome', pasta_user=self.ps,
                                 capabilities=self.desired_capabilities,
                                 initial_user=self.teacher)
        self.driver = self.helper.driver
        self.wait = WebDriverWait(self.driver, StaxHelper.DEFAULT_WAIT_TIME)
        self.driver.set_window_size(*standard_window)
        self.teacher.login(self.driver)
        self.teacher.select_course(self.driver, category='physics')
        self.rword = Assignment.rword
        self.screenshot_path = '/tmp/errors/'

    def tearDown(self):
        # Returns the info of exception being handled
        has_errors = self._test_has_failed()
        if has_errors:
            print(self.driver.current_url, '\n')
            date_and_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f')
            filename = 'testerr_%s.png' % date_and_time
            self.driver.save_screenshot('%s%s' % (self.screenshot_path,
                                        filename))
        try:
            self.driver = None
            self.helper.driver.quit()
        except AttributeError:
            pass
        self.ps.update_job(self.driver.session_id, passed=has_errors)

    def _test_has_failed(self):
        # for 3.4. In 3.3, can just use self._outcomeForDoCleanups.success:
        for method, error in self._outcome.errors:
            if error:
                return True
        return False

    def test_teacher_views_calendar(self):
        ''''''
        today = date.today()
        today = today.strftime('%B %Y')
        cal_date = self.wait.until(
            expect.presence_of_element_located(
                (By.XPATH,
                 '//div[contains(@class,"calendar-header-label")]' +
                 '/span')
            )
        ).text
        assert(cal_date == today), 'Calendar date is not %s' % today

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_student_scores(self):
        ''''''
        # click on student scores
        self.helper.user.goto_student_scores(self.driver)

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_reference_book(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_class_roster(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_removes_a_student_from_class(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_moves_a_student_between_periods(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_reading_analytics_aggregate(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_performance_forecast_aggregate(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_single_student_performance_forecast(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_external_summary(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_homework_summary(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_reading_summary(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_event_summary(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_review_summary(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_single_student_homework(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_class_homework_details(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_single_student_reading(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_class_reading_details(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_single_student_review(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_views_class_review_details(self):
        ''''''

    @pytest.mark.skipif(NOT_STARTED, reason='Not started')
    def test_teacher_export_matches_student_scores(self):
        ''''''
Esempio n. 38
0
class TestTutorAdmin(unittest.TestCase):
    """Tutor | Teacher"""

    def setUp(self):
        """Pretest settings."""
        self.ps = PastaSauce()
        self.desired_capabilities['name'] = self.id()
        if not LOCAL_RUN:
            self.admin = Admin(
                use_env_vars=True,
                pasta_user=self.ps,
                capabilities=self.desired_capabilities
            )
        else:
            self.admin = Admin(
                use_env_vars=True
            )

    def tearDown(self):
        """Test destructor."""
        if not LOCAL_RUN:
            self.ps.update_job(
                job_id=str(self.teacher.driver.session_id),
                **self.ps.test_updates
            )
        try:
            self.admin.delete()
        except:
            pass

    @pytest.mark.skipif(str(162255) not in TESTS, reason='Excluded')
    def test_admin_change_course_start_end_dates_162255(self):
        """
        Log in as an Admin
        Go to the course management page
        Edit a course
        Change the term and course year
        Click Save
        ***Start and end dates should reflect the new term's timeframe***

        Edit a course
        Change the Starts at date and Ends at date
        Click Save

        Expected Result:

        ***Start and end dates are changed***

        https://trello.com/c/YuvX7DN0/25-admin-change-course-start-end-dates
        """

        self.ps.test_updates['name'] = 'tutor_course_settings_admin_162255' + \
            inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = \
            ['tutor', 'course_settings', 'admin', '162255']
        self.ps.test_updates['passed'] = False

        # go to courses admin page directly and log in
        URL = str(os.getenv('SERVER_URL')) + '/admin/courses'
        self.admin.login(url=URL)
        # search 'preview' in the search bar
        self.admin.find(By.CSS_SELECTOR, "#search-courses") \
            .send_keys('preview\n')
        self.admin.page.wait_for_page_load()
        pages = self.admin.find_all(By.CSS_SELECTOR, ".pagination>a")
        # go to very last page
        self.admin.scroll_to(pages[-2])
        self.admin.sleep(1)
        pages[-2].click()

        # click on Edit button for very last course
        edit = self.admin.find_all(By.XPATH, ".//*[contains(text(),'Edit')]")
        self.admin.scroll_to(edit[-1])
        edit[-1].click()
        # change year field by adding 1
        yearfield = self.admin.find(By.CSS_SELECTOR, "#course_year")
        year = yearfield.get_attribute('value')
        newyear = str(int(year) + 1)
        yearfield.send_keys(len(year) * Keys.DELETE)
        yearfield.send_keys(newyear)

        # change start date and end date
        oldstartdatefield = self.admin.find(
            By.CSS_SELECTOR,
            "#course_starts_at"
        )
        oldenddatefield = self.admin.find(By.CSS_SELECTOR, "#course_ends_at")
        # get start date and end date values
        oldstartdate = oldstartdatefield.get_attribute('value')
        oldenddate = oldenddatefield.get_attribute('value')
        change = datetime.timedelta(days=400)
        # converts start date and end date values into datetime objects and
        # adds the change
        newstartdate = datetime.datetime.strptime(
            oldstartdate,
            '%Y-%m-%d %X %Z') + change
        # converts into a string format accepted by the form
        oldstartdatefield.send_keys(
            datetime.datetime.strftime(
                newstartdate, '%Y/%m/%d %X'
                )[:-3]
            )
        # converts start date and end date values into datetime objects and
        # adds change ( 400 days)
        newenddate = datetime.datetime.strptime(
            oldenddate,
            '%Y-%m-%d %X %Z') + change
        # converts into a string format accepted by teh form
        # newenddate = datetime.datetime.strftime(newenddate1, '%Y/%m/%d %X')
        # [:-3]
        oldenddatefield.send_keys(
            datetime.datetime.strftime(
                newenddate, '%Y/%m/%d %X')[:-3]
        )

        # saves changes
        self.admin.sleep(1)
        self.admin.find(By.CSS_SELECTOR, "#edit-save").click()
        self.admin.sleep(1)
        # updated start date and end date fields, get their values
        updatedstartdate = self.admin.find(
            By.CSS_SELECTOR, "#course_starts_at").get_attribute('value')
        updatedstartdatetime = datetime.datetime.strptime(
            updatedstartdate,
            '%Y-%m-%d %X %Z'
        )
        updatedenddate = self.admin.find(
            By.CSS_SELECTOR,
            "#course_ends_at").get_attribute('value')
        updatedenddatetime = datetime.datetime.strptime(
            updatedenddate,
            '%Y-%m-%d %X %Z'
        )

        # assert that the datetime objects I put into it are the ones in the
        # updated field
        assert(newstartdate.isocalendar() ==
               updatedstartdatetime.isocalendar())
        assert(newenddate.isocalendar() == updatedenddatetime.isocalendar())

        # change start date and end date to what it was
        yearfield = self.admin.find(By.CSS_SELECTOR, "#course_year")
        yearfield.send_keys(len(year) * Keys.DELETE)
        yearfield.send_keys(year)
        startdatefield = self.admin.find(By.CSS_SELECTOR, "#course_starts_at")
        startdatefield.send_keys(datetime.datetime.strftime(
            datetime.datetime.strptime(oldstartdate, '%Y-%m-%d %X %Z'),
            '%Y/%m/%d %X')[:-3]
        )
        enddatefield = self.admin.find(By.CSS_SELECTOR, "#course_ends_at")
        enddatefield.send_keys(datetime.datetime.strftime(
            datetime.datetime.strptime(oldenddate, '%Y-%m-%d %X %Z'),
            '%Y/%m/%d %X')[:-3]
        )
        self.admin.find(By.CSS_SELECTOR, "#edit-save").click()

        self.ps.test_updates['passed'] = True

    @pytest.mark.skipif(str(162256) not in TESTS, reason='Excluded')
    def test_notification_and_faulty_url_162256(self):
        """
        Go to tutor qa
        Log in as admin
        Click "Admin" from the user menu
        Click "System Setting"
        Click "Notifications"
        Enter a new notification into the text box
        Click "Add"

        Log out of admin account
        Log in as a teacher
        ***An orange header with the notification pops up when you sign in***

        Go to a fake url page to test if styled error page is displayed

        Expected result:

        ***a styled error page is displayed***

        Corresponding test case: T2.18 001, 030
        """

        self.ps.test_updates['name'] = 'tutor_system_settings_admin_162256' + \
            inspect.currentframe().f_code.co_name[4:]
        self.ps.test_updates['tags'] = \
            ['tutor', 'system_settings', 'admin', '162256']
        self.ps.test_updates['passed'] = False

        # go to admin instance
        self.admin.login(url=os.getenv('SERVER_URL') + '/admin')
        # go to system settings, then notifications, then set a notification
        self.admin.find(By.XPATH, ".//*[contains(text(),'System Setting')]") \
            .click()
        self.admin.find(By.CSS_SELECTOR, "a[href*='notification']").click()
        self.admin.find(By.CSS_SELECTOR, "#message") \
            .send_keys('test_notification')
        self.admin.find(By.CSS_SELECTOR, ".btn.btn-default").click()

        # logout of admin
        self.admin.find(By.XPATH, ".//*[contains(text(),'admin')]").click()
        self.admin.find(By.CSS_SELECTOR, 'a[href*="logout"]').click()
        # log into teacher account
        self.admin.login(
            username=os.getenv('TEACHER_USER'),
            password=os.getenv('TEACHER_PASSWORD')
        )
        self.admin.find(By.CSS_SELECTOR, '.my-courses-item-title>a').click()
        # if popup asking how you will be using Tutor shows up
        try:
            self.admin.find(
                By.XPATH,
                './/*[contains(text(),"I don’t know yet")]'
            )
        except:
            pass
        # checks if notification is there
        self.admin.wait.until(
            expect.visibility_of_element_located((
                By.XPATH,
                '//div[contains(@class,"notifications-bar")]' +
                '//span[text()="test_notification"]'
            ))
        )
        self.admin.find(
            By.XPATH,
            '//div[contains(@class,"notifications-bar")]' +
            '//span[text()="test_notification"]'
        )

        # log out of teacher
        self.admin.logout()

        # log into admin
        self.admin.login(url=os.getenv('SERVER_URL') + '/admin')
        self.admin.find(By.XPATH, '//a[text()="System Setting"]').click()
        self.admin.find(By.XPATH, '//a[text()="Notifications"]').click()
        # remove general notification
        self.admin.find(By.XPATH, '//a[text()="Remove"]').click()
        self.admin.driver.switch_to_alert().accept()
        # go to invalid website
        self.admin.get(os.getenv('SERVER_URL') + '/not_a_Real_page')
        # confirm styling of webpage
        self.admin.find(By.CSS_SELECTOR, '.invalid-page')

        self.ps.test_updates['passed'] = True