212 lines
6.2 KiB
Python
212 lines
6.2 KiB
Python
from lettuce import world, step
|
|
from lettuce.django import django_url
|
|
from nose.tools import assert_true
|
|
from nose.tools import assert_equal
|
|
from selenium.webdriver.support.ui import WebDriverWait
|
|
from selenium.common.exceptions import WebDriverException, StaleElementReferenceException
|
|
from selenium.webdriver.support import expected_conditions as EC
|
|
from selenium.webdriver.common.by import By
|
|
|
|
from terrain.factories import UserFactory, RegistrationFactory, UserProfileFactory
|
|
from terrain.factories import CourseFactory, GroupFactory
|
|
from xmodule.modulestore.django import _MODULESTORES, modulestore
|
|
from xmodule.templates import update_templates
|
|
from auth.authz import get_user_by_email
|
|
|
|
from logging import getLogger
|
|
logger = getLogger(__name__)
|
|
|
|
########### STEP HELPERS ##############
|
|
@step('I (?:visit|access|open) the Studio homepage$')
|
|
def i_visit_the_studio_homepage(step):
|
|
# To make this go to port 8001, put
|
|
# LETTUCE_SERVER_PORT = 8001
|
|
# in your settings.py file.
|
|
world.browser.visit(django_url('/'))
|
|
signin_css = 'a.action-signin'
|
|
assert world.browser.is_element_present_by_css(signin_css, 10)
|
|
|
|
|
|
@step('I am logged into Studio$')
|
|
def i_am_logged_into_studio(step):
|
|
log_into_studio()
|
|
|
|
|
|
@step('I confirm the alert$')
|
|
def i_confirm_with_ok(step):
|
|
world.browser.get_alert().accept()
|
|
|
|
|
|
@step(u'I press the "([^"]*)" delete icon$')
|
|
def i_press_the_category_delete_icon(step, category):
|
|
if category == 'section':
|
|
css = 'a.delete-button.delete-section-button span.delete-icon'
|
|
elif category == 'subsection':
|
|
css = 'a.delete-button.delete-subsection-button span.delete-icon'
|
|
else:
|
|
assert False, 'Invalid category: %s' % category
|
|
css_click(css)
|
|
|
|
|
|
@step('I have opened a new course in Studio$')
|
|
def i_have_opened_a_new_course(step):
|
|
clear_courses()
|
|
log_into_studio()
|
|
create_a_course()
|
|
|
|
|
|
####### HELPER FUNCTIONS ##############
|
|
def create_studio_user(
|
|
uname='robot',
|
|
email='robot+studio@edx.org',
|
|
password='test',
|
|
is_staff=False):
|
|
studio_user = UserFactory.build(
|
|
username=uname,
|
|
email=email,
|
|
password=password,
|
|
is_staff=is_staff)
|
|
studio_user.set_password(password)
|
|
studio_user.save()
|
|
|
|
registration = RegistrationFactory(user=studio_user)
|
|
registration.register(studio_user)
|
|
registration.activate()
|
|
|
|
user_profile = UserProfileFactory(user=studio_user)
|
|
|
|
|
|
def flush_xmodule_store():
|
|
# Flush and initialize the module store
|
|
# It needs the templates because it creates new records
|
|
# by cloning from the template.
|
|
# Note that if your test module gets in some weird state
|
|
# (though it shouldn't), do this manually
|
|
# from the bash shell to drop it:
|
|
# $ mongo test_xmodule --eval "db.dropDatabase()"
|
|
_MODULESTORES = {}
|
|
modulestore().collection.drop()
|
|
update_templates()
|
|
|
|
|
|
def assert_css_with_text(css, text):
|
|
assert_true(world.browser.is_element_present_by_css(css, 5))
|
|
assert_equal(world.browser.find_by_css(css).text, text)
|
|
|
|
|
|
def css_click(css):
|
|
'''
|
|
First try to use the regular click method,
|
|
but if clicking in the middle of an element
|
|
doesn't work it might be that it thinks some other
|
|
element is on top of it there so click in the upper left
|
|
'''
|
|
try:
|
|
css_find(css).first.click()
|
|
except WebDriverException, e:
|
|
css_click_at(css)
|
|
|
|
|
|
def css_click_at(css, x=10, y=10):
|
|
'''
|
|
A method to click at x,y coordinates of the element
|
|
rather than in the center of the element
|
|
'''
|
|
e = css_find(css).first
|
|
e.action_chains.move_to_element_with_offset(e._element, x, y)
|
|
e.action_chains.click()
|
|
e.action_chains.perform()
|
|
|
|
|
|
def css_fill(css, value):
|
|
world.browser.find_by_css(css).first.fill(value)
|
|
|
|
|
|
def css_find(css):
|
|
def is_visible(driver):
|
|
return EC.visibility_of_element_located((By.CSS_SELECTOR,css,))
|
|
|
|
world.browser.is_element_present_by_css(css, 5)
|
|
wait_for(is_visible)
|
|
return world.browser.find_by_css(css)
|
|
|
|
|
|
def wait_for(func):
|
|
WebDriverWait(world.browser.driver, 5).until(func)
|
|
|
|
|
|
def id_find(id):
|
|
return world.browser.find_by_id(id)
|
|
|
|
|
|
def clear_courses():
|
|
flush_xmodule_store()
|
|
|
|
|
|
def fill_in_course_info(
|
|
name='Robot Super Course',
|
|
org='MITx',
|
|
num='101'):
|
|
css_fill('.new-course-name', name)
|
|
css_fill('.new-course-org', org)
|
|
css_fill('.new-course-number', num)
|
|
|
|
|
|
def log_into_studio(
|
|
uname='robot',
|
|
email='robot+studio@edx.org',
|
|
password='test',
|
|
is_staff=False):
|
|
create_studio_user(uname=uname, email=email, is_staff=is_staff)
|
|
world.browser.cookies.delete()
|
|
world.browser.visit(django_url('/'))
|
|
signin_css = 'a.action-signin'
|
|
world.browser.is_element_present_by_css(signin_css, 10)
|
|
|
|
# click the signin button
|
|
css_click(signin_css)
|
|
|
|
login_form = world.browser.find_by_css('form#login_form')
|
|
login_form.find_by_name('email').fill(email)
|
|
login_form.find_by_name('password').fill(password)
|
|
login_form.find_by_name('submit').click()
|
|
|
|
assert_true(world.browser.is_element_present_by_css('.new-course-button', 5))
|
|
|
|
|
|
def create_a_course():
|
|
c = CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
|
|
|
|
# Add the user to the instructor group of the course
|
|
# so they will have the permissions to see it in studio
|
|
g = GroupFactory.create(name='instructor_MITx/999/Robot_Super_Course')
|
|
u = get_user_by_email('robot+studio@edx.org')
|
|
u.groups.add(g)
|
|
u.save()
|
|
world.browser.reload()
|
|
|
|
course_link_css = 'span.class-name'
|
|
css_click(course_link_css)
|
|
course_title_css = 'span.course-title'
|
|
assert_true(world.browser.is_element_present_by_css(course_title_css, 5))
|
|
|
|
|
|
def add_section(name='My Section'):
|
|
link_css = 'a.new-courseware-section-button'
|
|
css_click(link_css)
|
|
name_css = 'input.new-section-name'
|
|
save_css = 'input.new-section-name-save'
|
|
css_fill(name_css, name)
|
|
css_click(save_css)
|
|
span_css = 'span.section-name-span'
|
|
assert_true(world.browser.is_element_present_by_css(span_css, 5))
|
|
|
|
|
|
def add_subsection(name='Subsection One'):
|
|
css = 'a.new-subsection-item'
|
|
css_click(css)
|
|
name_css = 'input.new-subsection-name-input'
|
|
save_css = 'input.new-subsection-name-save'
|
|
css_fill(name_css, name)
|
|
css_click(save_css)
|