test_studio_general.py 11.8 KB
Newer Older
1 2 3
"""
Acceptance tests for Studio.
"""
4
import uuid
5

6 7
from bok_choy.web_app_test import WebAppTest

8
from base_studio_test import StudioCourseTest
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
from common.test.acceptance.pages.studio.auto_auth import AutoAuthPage
from common.test.acceptance.pages.studio.course_info import CourseUpdatesPage
from common.test.acceptance.pages.studio.edit_tabs import PagesPage
from common.test.acceptance.pages.studio.import_export import ExportCoursePage, ImportCoursePage
from common.test.acceptance.pages.studio.index import DashboardPage, HomePage, IndexPage
from common.test.acceptance.pages.studio.login import LoginPage, CourseOutlineSignInRedirectPage
from common.test.acceptance.pages.studio.overview import CourseOutlinePage
from common.test.acceptance.pages.studio.asset_index import AssetIndexPage
from common.test.acceptance.pages.studio.settings import SettingsPage
from common.test.acceptance.pages.studio.settings_advanced import AdvancedSettingsPage
from common.test.acceptance.pages.studio.settings_graders import GradingPage
from common.test.acceptance.pages.studio.signup import SignupPage
from common.test.acceptance.pages.studio.textbook_upload import TextbookUploadPage
from common.test.acceptance.pages.studio.users import CourseTeamPage
from common.test.acceptance.tests.helpers import UniqueCourseTest
25 26 27 28 29 30 31 32


class LoggedOutTest(WebAppTest):
    """
    Smoke test for pages in Studio that are visible when logged out.
    """
    def setUp(self):
        super(LoggedOutTest, self).setUp()
33
        self.pages = [LoginPage(self.browser), IndexPage(self.browser), SignupPage(self.browser)]
34 35 36 37 38 39 40 41 42 43 44 45 46

    def test_page_existence(self):
        """
        Make sure that all the pages are accessible.
        Rather than fire up the browser just to check each url,
        do them all sequentially in this testcase.
        """
        for page in self.pages:
            page.visit()


class LoggedInPagesTest(WebAppTest):
    """
47
    Verify the pages in Studio that you can get to when logged in and do not have a course yet.
48 49 50 51 52
    """
    def setUp(self):
        super(LoggedInPagesTest, self).setUp()
        self.auth_page = AutoAuthPage(self.browser, staff=True)
        self.dashboard_page = DashboardPage(self.browser)
53
        self.home_page = HomePage(self.browser)
54

55
    def test_logged_in_no_courses(self):
56
        """
57
        Make sure that you can get to the dashboard and home pages without a course.
58 59 60
        """
        self.auth_page.visit()
        self.dashboard_page.visit()
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
        self.home_page.visit()


class SignUpAndSignInTest(UniqueCourseTest):
    """
    Test studio sign-up and sign-in
    """
    def setUp(self):  # pylint: disable=arguments-differ
        super(SignUpAndSignInTest, self).setUp()
        self.sign_up_page = SignupPage(self.browser)
        self.login_page = LoginPage(self.browser)

        self.course_outline_page = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        self.course_outline_sign_in_redirect_page = CourseOutlineSignInRedirectPage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )

        self.course_fixture = CourseFixture(
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run'],
            self.course_info['display_name'],
        )
        self.user = None

    def install_course_fixture(self):
        """
        Install a course fixture
        """
        self.course_fixture.install()
        self.user = self.course_fixture.user

    def test_sign_up_from_home(self):
        """
        Scenario: Sign up from the homepage
        Given I visit the Studio homepage
        When I click the link with the text "Sign Up"
        And I fill in the registration form
        And I press the Create My Account button on the registration form
        Then I should see an email verification prompt
        """
        index_page = IndexPage(self.browser)
        index_page.visit()
        index_page.click_sign_up()

        unique_number = uuid.uuid4().hex[:4]
        registration_dic = {
            '#email': '{}-email@host.com'.format(unique_number),
            '#name': '{}-name'.format(unique_number),
            '#username': '{}-username'.format(unique_number),
            '#password': '{}-password'.format(unique_number),
        }
        # Register the user.
        self.sign_up_page.sign_up_user(registration_dic)
        home = HomePage(self.browser)
        home.wait_for_page()

    def test_login_with_valid_redirect(self):
        """
        Scenario: Login with a valid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/course/slashes:MITx+999+Robot_Super_Course"
        And I should see that the path is "/signin?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
        When I fill in and submit the signin form
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        # Get the url, browser should land here after sign in.
        course_url = self.course_outline_sign_in_redirect_page.url
        self.course_outline_sign_in_redirect_page.visit()
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, course_url)

    def test_login_with_invalid_redirect(self):
        """
        Scenario: Login with an invalid redirect
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the url "/signin?next=http://www.google.com/"
        When I fill in and submit the signin form
        Then I should see that the path is "/home/"
        """
        self.install_course_fixture()
        # Visit course
        self.course_outline_sign_in_redirect_page.visit()
        # Change redirect url
        self.browser.get(self.browser.current_url.split('=')[0] + '=http://www.google.com')
        # Login
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        home = HomePage(self.browser)
        home.wait_for_page()
        self.assertEqual(self.browser.current_url, home.url)

    def test_login_with_mistyped_credentials(self):
        """
        Given I have opened a new course in Studio
        And I am not logged in
        And I visit the Studio homepage
        When I click the link with the text "Sign In"
        Then I should see that the path is "/signin"
        And I should not see a login error message
        And I fill in and submit the signin form incorrectly
        Then I should see a login error message
        And I edit the password field
        Then I should not see a login error message
        And I submit the signin form
        And I wait for "2" seconds
        Then I should see that the path is "/course/slashes:MITx+999+Robot_Super_Course"
        """
        self.install_course_fixture()
        self.course_outline_sign_in_redirect_page.visit()
        # Verify login_error is not present
        self.course_outline_sign_in_redirect_page.wait_for_element_absence(
            '#login_error',
            'Login error not be present'
        )
        # Login with wrong credentials
        self.course_outline_sign_in_redirect_page.login(
            self.user['email'],
            'wrong_password',
            expect_success=False
        )
        # Verify that login error is shown
        self.course_outline_sign_in_redirect_page.wait_for_element_visibility(
            '#login_error',
            'Login error is visible'
        )
        # Change the password
        self.course_outline_sign_in_redirect_page.fill_field('input#password', 'changed_password')
        # Login error should not be visible
        self.course_outline_sign_in_redirect_page.wait_for_element_invisibility(
            '#login_error',
            'Login error is not visible'
        )
        # Login with correct credentials
        self.course_outline_sign_in_redirect_page.login(self.user['email'], self.user['password'])
        self.course_outline_page.wait_for_page()
        # Verify that correct course is displayed after sign in.
        self.assertEqual(self.browser.current_url, self.course_outline_page.url)
212 213


214
class CoursePagesTest(StudioCourseTest):
215 216 217 218 219 220 221 222 223 224 225
    """
    Tests that verify the pages in Studio that you can get to when logged
    in and have a course.
    """

    COURSE_ID_SEPARATOR = "."

    def setUp(self):
        """
        Install a course with no content using a fixture.
        """
Muhammad Ammar committed
226
        super(CoursePagesTest, self).setUp()
227 228 229 230

        self.pages = [
            clz(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'])
            for clz in [
Diana Huang committed
231
                AssetIndexPage,
232
                CourseUpdatesPage,
233
                PagesPage, ExportCoursePage, ImportCoursePage, CourseTeamPage, CourseOutlinePage, SettingsPage,
234
                AdvancedSettingsPage, GradingPage, TextbookUploadPage
235 236 237
            ]
        ]

238 239 240 241 242
    def test_page_redirect(self):
        """
        /course/ is the base URL for all courses, but by itself, it should
        redirect to /home/.
        """
E. Kolpakov committed
243
        self.dashboard_page = DashboardPage(self.browser)  # pylint: disable=attribute-defined-outside-init
244 245 246
        self.dashboard_page.visit()
        self.assertEqual(self.browser.current_url.strip('/').rsplit('/')[-1], 'home')

247 248 249 250 251 252 253
    def test_page_existence(self):
        """
        Make sure that all these pages are accessible once you have a course.
        Rather than fire up the browser just to check each url,
        do them all sequentially in this testcase.
        """

Jay Zoldak committed
254 255 256 257 258 259 260 261
        # In the real workflow you will be at the dashboard page
        # after you log in. This test was intermittently failing on the
        # first (asset) page load with a 404.
        # Not exactly sure why, so adding in a visit
        # to the dashboard page here to replicate the usual flow.
        self.dashboard_page = DashboardPage(self.browser)
        self.dashboard_page.visit()

262 263 264 265 266
        # Verify that each page is available
        for page in self.pages:
            page.visit()


267
class DiscussionPreviewTest(StudioCourseTest):
268 269 270 271 272 273
    """
    Tests that Inline Discussions are rendered with a custom preview in Studio
    """

    def setUp(self):
        super(DiscussionPreviewTest, self).setUp()
274 275 276 277 278 279 280
        cop = CourseOutlinePage(
            self.browser,
            self.course_info['org'],
            self.course_info['number'],
            self.course_info['run']
        )
        cop.visit()
281
        self.unit = cop.section('Test Section').subsection('Test Subsection').expand_subsection().unit('Test Unit')
282
        self.unit.go_to()
283

284 285 286 287 288
    def populate_course_fixture(self, course_fixture):
        """
        Return a test course fixture containing a discussion component.
        """
        course_fixture.add_children(
289 290 291 292 293 294 295 296 297 298
            XBlockFixtureDesc("chapter", "Test Section").add_children(
                XBlockFixtureDesc("sequential", "Test Subsection").add_children(
                    XBlockFixtureDesc("vertical", "Test Unit").add_children(
                        XBlockFixtureDesc(
                            "discussion",
                            "Test Discussion",
                        )
                    )
                )
            )
299 300
        )

301 302 303 304 305 306
    def test_is_preview(self):
        """
        Ensure that the preview version of the discussion is rendered.
        """
        self.assertTrue(self.unit.q(css=".discussion-preview").present)
        self.assertFalse(self.unit.q(css=".discussion-show").present)