This will remove imports from __future__ that are no longer needed. https://docs.python.org/3.5/library/2to3.html#2to3fixer-future
269 lines
9.9 KiB
Python
269 lines
9.9 KiB
Python
"""
|
|
Acceptance tests for Studio.
|
|
"""
|
|
|
|
|
|
import uuid
|
|
|
|
from selenium.webdriver.common.keys import Keys
|
|
|
|
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
|
|
from common.test.acceptance.pages.common.auto_auth import AutoAuthPage
|
|
from common.test.acceptance.pages.studio import LMS_URL
|
|
from common.test.acceptance.pages.studio.asset_index import AssetIndexPageStudioFrontend
|
|
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 AccessibilityPage, DashboardPage, HomePage, IndexPage
|
|
from common.test.acceptance.pages.studio.login import CourseOutlineSignInRedirectPage, LoginPage
|
|
from common.test.acceptance.pages.studio.overview import CourseOutlinePage
|
|
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 AcceptanceTest, UniqueCourseTest
|
|
|
|
from .base_studio_test import StudioCourseTest
|
|
|
|
|
|
class LoggedOutTest(AcceptanceTest):
|
|
"""
|
|
Smoke test for pages in Studio that are visible when logged out.
|
|
"""
|
|
shard = 21
|
|
|
|
def setUp(self):
|
|
super(LoggedOutTest, self).setUp()
|
|
self.pages = [LoginPage(self.browser), IndexPage(self.browser), SignupPage(self.browser),
|
|
AccessibilityPage(self.browser)]
|
|
|
|
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(AcceptanceTest):
|
|
"""
|
|
Verify the pages in Studio that you can get to when logged in and do not have a course yet.
|
|
"""
|
|
shard = 21
|
|
|
|
def setUp(self):
|
|
super(LoggedInPagesTest, self).setUp()
|
|
self.auth_page = AutoAuthPage(self.browser, staff=True)
|
|
self.dashboard_page = DashboardPage(self.browser)
|
|
self.home_page = HomePage(self.browser)
|
|
|
|
def test_logged_in_no_courses(self):
|
|
"""
|
|
Make sure that you can get to the dashboard and home pages without a course.
|
|
"""
|
|
self.auth_page.visit()
|
|
self.dashboard_page.visit()
|
|
self.home_page.visit()
|
|
|
|
|
|
class SignUpAndSignInTest(UniqueCourseTest):
|
|
"""
|
|
Test studio sign-up and sign-in
|
|
"""
|
|
shard = 21
|
|
|
|
def setUp(self):
|
|
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()
|
|
|
|
# Register the user.
|
|
unique_number = uuid.uuid4().hex[:4]
|
|
self.sign_up_page.sign_up_user(
|
|
'{}-email@host.com'.format(unique_number),
|
|
'{}-name'.format(unique_number),
|
|
'{}-username'.format(unique_number),
|
|
'{}-password'.format(unique_number),
|
|
)
|
|
home = HomePage(self.browser)
|
|
home.wait_for_page()
|
|
|
|
def test_sign_up_with_bad_password(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
|
|
When I enter an insufficient password and focus out
|
|
I should see an error message
|
|
"""
|
|
index_page = IndexPage(self.browser)
|
|
index_page.visit()
|
|
index_page.click_sign_up()
|
|
|
|
password_input = self.sign_up_page.input_password('a') # Arbitrary short password that will fail
|
|
password_input.send_keys(Keys.TAB) # Focus out of the element
|
|
index_page.wait_for_element_visibility('#register-password-validation-error', 'Password Error Message')
|
|
self.assertIsNotNone(index_page.q(css='#register-password-validation-error-msg')) # Error message should exist
|
|
|
|
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 the path is "/signin_redirect_to_lms?next=/course/slashes%3AMITx%2B999%2BRobot_Super_Course"
|
|
When I fill in and submit the LMS login 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)
|
|
|
|
|
|
class CoursePagesTest(StudioCourseTest):
|
|
"""
|
|
Tests that verify the pages in Studio that you can get to when logged
|
|
in and have a course.
|
|
"""
|
|
shard = 21
|
|
COURSE_ID_SEPARATOR = "."
|
|
|
|
def setUp(self):
|
|
"""
|
|
Install a course with no content using a fixture.
|
|
"""
|
|
super(CoursePagesTest, self).setUp()
|
|
|
|
self.pages = [
|
|
clz(self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'])
|
|
for clz in [
|
|
AssetIndexPageStudioFrontend,
|
|
CourseUpdatesPage,
|
|
PagesPage, ExportCoursePage, ImportCoursePage, CourseTeamPage, CourseOutlinePage, SettingsPage,
|
|
AdvancedSettingsPage, GradingPage, TextbookUploadPage
|
|
]
|
|
]
|
|
|
|
def test_page_redirect(self):
|
|
"""
|
|
/course/ is the base URL for all courses, but by itself, it should
|
|
redirect to /home/.
|
|
"""
|
|
self.dashboard_page = DashboardPage(self.browser) # pylint: disable=attribute-defined-outside-init
|
|
self.dashboard_page.visit()
|
|
self.assertEqual(self.browser.current_url.strip('/').rsplit('/')[-1], 'home')
|
|
|
|
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.
|
|
"""
|
|
|
|
# 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()
|
|
|
|
# Verify that each page is available
|
|
for page in self.pages:
|
|
page.visit()
|
|
|
|
|
|
class DiscussionPreviewTest(StudioCourseTest):
|
|
"""
|
|
Tests that Inline Discussions are rendered with a custom preview in Studio
|
|
"""
|
|
shard = 21
|
|
|
|
def setUp(self):
|
|
super(DiscussionPreviewTest, self).setUp()
|
|
cop = CourseOutlinePage(
|
|
self.browser,
|
|
self.course_info['org'],
|
|
self.course_info['number'],
|
|
self.course_info['run']
|
|
)
|
|
cop.visit()
|
|
self.unit = cop.section('Test Section').subsection('Test Subsection').expand_subsection().unit('Test Unit')
|
|
self.unit.go_to()
|
|
|
|
def populate_course_fixture(self, course_fixture):
|
|
"""
|
|
Return a test course fixture containing a discussion component.
|
|
"""
|
|
course_fixture.add_children(
|
|
XBlockFixtureDesc("chapter", "Test Section").add_children(
|
|
XBlockFixtureDesc("sequential", "Test Subsection").add_children(
|
|
XBlockFixtureDesc("vertical", "Test Unit").add_children(
|
|
XBlockFixtureDesc(
|
|
"discussion",
|
|
"Test Discussion",
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
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)
|