Commit 3257a7ba by Will Daly

Refactored navigation feature

Fixed grading tests
parent 4bb9dcf1
......@@ -2,7 +2,7 @@
# pylint: disable=W0621
from lettuce import world, step
from nose.tools import assert_true, assert_in, assert_false # pylint: disable=E0611
from nose.tools import assert_true, assert_equal, assert_in, assert_false # pylint: disable=E0611
from auth.authz import get_user_by_email, get_course_groupname_for_role
from django.conf import settings
......@@ -64,32 +64,16 @@ def select_new_course(_step, whom):
@step(u'I press the "([^"]*)" notification button$')
def press_the_notification_button(_step, name):
# TODO: fix up this code. Selenium is not dealing well with css transforms,
# as it thinks that the notification and the buttons are always visible
# First wait for the notification to pop up
notification_css = 'div#page-notification div.wrapper-notification'
world.wait_for_visible(notification_css)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world.wait(.5)
# Now make sure the button is there
# Because the notification uses a CSS transition,
# Selenium will always report it as being visible.
# This makes it very difficult to successfully click
# the "Save" button at the UI level.
# Instead, we use JavaScript to reliably click
# the button.
btn_css = 'div#page-notification a.action-%s' % name.lower()
world.wait_for_visible(btn_css)
# You would think that the above would have worked, but it doesn't.
# Brute force wait for now.
world.wait(.5)
if world.is_firefox():
# This is done to explicitly make the changes save on firefox.
# It will remove focus from the previously focused element
world.trigger_event(btn_css, event='focus')
world.browser.execute_script("$('{}').click()".format(btn_css))
else:
world.css_click(btn_css)
world.trigger_event(btn_css, event='focus')
world.browser.execute_script("$('{}').click()".format(btn_css))
world.wait_for_ajax_complete()
......
......@@ -2,7 +2,7 @@
#pylint: disable=C0111
from lettuce import world
from nose.tools import assert_equal # pylint: disable=E0611
from nose.tools import assert_equal, assert_true # pylint: disable=E0611
from terrain.steps import reload_the_page
......@@ -12,9 +12,13 @@ def create_component_instance(step, component_button_css, category,
has_multiple_templates=True):
click_new_component_button(step, component_button_css)
if category in ('problem', 'html'):
def animation_done(_driver):
return world.browser.evaluate_script("$('div.new-component').css('display')") == 'none'
script = "$('div.new-component').css('display')"
return world.browser.evaluate_script(script) == 'none'
world.wait_for(animation_done)
if has_multiple_templates:
......@@ -23,10 +27,7 @@ def create_component_instance(step, component_button_css, category,
if category in ('video',):
world.wait_for_xmodule()
assert_equal(
1,
len(world.css_find(expected_css)),
"Component instance with css {css} was not created successfully".format(css=expected_css))
assert_true(world.is_css_present(expected_css))
@world.absorb
......@@ -34,7 +35,8 @@ def click_new_component_button(step, component_button_css):
step.given('I have clicked the new unit button')
world.wait_for_requirejs(
["jquery", "js/models/course", "coffee/src/models/module",
"coffee/src/views/unit", "jquery.ui"])
"coffee/src/views/unit", "jquery.ui"]
)
world.css_click(component_button_css)
......
......@@ -6,7 +6,7 @@ from common import *
from terrain.steps import reload_the_page
from selenium.common.exceptions import (
InvalidElementStateException, WebDriverException)
from nose.tools import assert_in, assert_not_in # pylint: disable=E0611
from nose.tools import assert_in, assert_not_in, assert_equal, assert_not_equal # pylint: disable=E0611
@step(u'I am viewing the grading settings')
......@@ -36,7 +36,7 @@ def delete_grade(step):
def view_grade_slider(step, how_many):
grade_slider_css = '.grade-specific-bar'
all_grades = world.css_find(grade_slider_css)
assert len(all_grades) == int(how_many)
assert_equal(len(all_grades), int(how_many))
@step(u'I move a grading section')
......@@ -51,7 +51,7 @@ def confirm_change(step):
range_css = '.range'
all_ranges = world.css_find(range_css)
for i in range(len(all_ranges)):
assert world.css_html(range_css, index=i) != '0-50'
assert_not_equal(world.css_html(range_css, index=i), '0-50')
@step(u'I change assignment type "([^"]*)" to "([^"]*)"$')
......@@ -59,7 +59,7 @@ def change_assignment_name(step, old_name, new_name):
name_id = '#course-grading-assignment-name'
index = get_type_index(old_name)
f = world.css_find(name_id)[index]
assert index != -1
assert_not_equal(index, -1)
for count in range(len(old_name)):
f._element.send_keys(Keys.END, Keys.BACK_SPACE)
f._element.send_keys(new_name)
......@@ -78,7 +78,10 @@ def main_course_page(step):
def see_assignment_name(step, do_not, name):
assignment_menu_css = 'ul.menu > li > a'
# First assert that it is there, make take a bit to redraw
assert world.css_find(assignment_menu_css)
assert_true(
world.css_find(assignment_menu_css),
msg="Could not find assignment menu"
)
assignment_menu = world.css_find(assignment_menu_css)
allnames = [item.html for item in assignment_menu]
......@@ -113,7 +116,7 @@ def populate_course(step):
def changes_not_persisted(step):
reload_the_page(step)
name_id = '#course-grading-assignment-name'
assert(world.css_value(name_id) == 'Homework')
assert_equal(world.css_value(name_id), 'Homework')
@step(u'I see the assignment type "(.*)"$')
......@@ -121,7 +124,7 @@ def i_see_the_assignment_type(_step, name):
assignment_css = '#course-grading-assignment-name'
assignments = world.css_find(assignment_css)
types = [ele['value'] for ele in assignments]
assert name in types
assert_in(name, types)
@step(u'I change the highest grade range to "(.*)"$')
......@@ -135,15 +138,15 @@ def change_grade_range(_step, range_name):
def i_see_highest_grade_range(_step, range_name):
range_css = 'span.letter-grade'
grade = world.css_find(range_css).first
assert grade.value == range_name, "{0} != {1}".format(grade.value, range_name)
assert_equal(grade.value, range_name)
@step(u'I cannot edit the "Fail" grade range$')
def cannot_edit_fail(_step):
range_css = 'span.letter-grade'
ranges = world.css_find(range_css)
assert len(ranges) == 2
assert ranges.last.value != 'Failure'
assert_equal(len(ranges), 2)
assert_not_equal(ranges.last.value, 'Failure')
# try to change the grade range -- this should throw an exception
try:
......@@ -153,14 +156,23 @@ def cannot_edit_fail(_step):
# check to be sure that nothing has changed
ranges = world.css_find(range_css)
assert len(ranges) == 2
assert ranges.last.value != 'Failure'
assert_equal(len(ranges), 2)
assert_not_equal(ranges.last.value, 'Failure')
@step(u'I change the grace period to "(.*)"$')
def i_change_grace_period(_step, grace_period):
grace_period_css = '#course-grading-graceperiod'
ele = world.css_find(grace_period_css).first
# Sometimes it takes a moment for the JavaScript
# to populate the field. If we don't wait for
# this to happen, then we can end up with
# an invalid value (e.g. "00:0048:00")
# which prevents us from saving.
assert_true(world.css_has_value(grace_period_css, "00:00", allow_blank=False))
# Set the new grace period
ele.value = grace_period
......@@ -168,7 +180,7 @@ def i_change_grace_period(_step, grace_period):
def the_grace_period_is(_step, grace_period):
grace_period_css = '#course-grading-graceperiod'
ele = world.css_find(grace_period_css).first
assert ele.value == grace_period
assert_equal(ele.value, grace_period)
def get_type_index(name):
......
......@@ -32,18 +32,21 @@ def shows_captions(_step, show_captions):
@step('I see the correct video settings and default values$')
def correct_video_settings(_step):
world.verify_all_setting_entries([['Display Name', 'Video', False],
['Download Track', '', False],
['Download Video', '', False],
['End Time', '0', False],
['HTML5 Timed Transcript', '', False],
['Show Captions', 'True', False],
['Start Time', '0', False],
['Video Sources', '', False],
['Youtube ID', 'OEoXaMPEzfM', False],
['Youtube ID for .75x speed', '', False],
['Youtube ID for 1.25x speed', '', False],
['Youtube ID for 1.5x speed', '', False]])
expected_entries = [
['Display Name', 'Video', False],
['Download Track', '', False],
['Download Video', '', False],
['End Time', '0', False],
['HTML5 Timed Transcript', '', False],
['Show Captions', 'True', False],
['Start Time', '0', False],
['Video Sources', '', False],
['Youtube ID', 'OEoXaMPEzfM', False],
['Youtube ID for .75x speed', '', False],
['Youtube ID for 1.25x speed', '', False],
['Youtube ID for 1.5x speed', '', False]
]
world.verify_all_setting_entries(expected_entries)
@step('my video display name change is persisted on save$')
......@@ -52,4 +55,8 @@ def video_name_persisted(step):
reload_the_page(step)
world.wait_for_xmodule()
world.edit_component()
world.verify_setting_entry(world.get_setting_entry('Display Name'), 'Display Name', '3.4', True)
world.verify_setting_entry(
world.get_setting_entry('Display Name'),
'Display Name', '3.4', True
)
......@@ -41,13 +41,13 @@ def log_in(username='robot', password='test', email='robot@edx.org', name='Robot
@world.absorb
def register_by_course_id(course_id, is_staff=False):
create_user('robot', 'password')
u = User.objects.get(username='robot')
def register_by_course_id(course_id, username='robot', password='test', is_staff=False):
create_user(username, password)
user = User.objects.get(username=username)
if is_staff:
u.is_staff = True
u.save()
CourseEnrollment.enroll(u, course_id)
user.is_staff = True
user.save()
CourseEnrollment.enroll(user, course_id)
@world.absorb
......
......@@ -34,7 +34,7 @@ def wait(seconds):
def wait_for_js_variable_truthy(variable):
"""
Using Selenium's `execute_async_script` function, poll the Javascript
enviornment until the given variable is defined and truthy. This process
environment until the given variable is defined and truthy. This process
guards against page reloads, and seamlessly retries on the next page.
"""
js = """
......@@ -194,8 +194,51 @@ def is_css_not_present(css_selector, wait_time=5):
@world.absorb
def css_has_text(css_selector, text, index=0):
return world.css_text(css_selector, index=index) == text
def css_has_text(css_selector, text, index=0,
strip=False, allow_blank=True):
"""
Return a boolean indicating whether the element with `css_selector`
has `text`.
If `strip` is True, strip whitespace at beginning/end of both
strings before comparing.
If `allow_blank` is False, wait for the element to have non-empty
text before making the assertion. This is useful for elements
that are populated by JavaScript after the page loads.
If there are multiple elements matching the css selector,
use `index` to indicate which one.
"""
if not allow_blank:
world.wait_for(lambda _: world.css_text(css_selector, index=index))
actual_text = world.css_text(css_selector, index=index)
if strip:
actual_text = actual_text.strip()
text = text.strip()
return actual_text == text
@world.absorb
def css_has_value(css_selector, value, index=0, allow_blank=False):
"""
Return a boolean indicating whether the element with
`css_selector` has the specified `value`.
If `allow_blank` is False, wait for the element to have
a value that is a non-empty string.
If there are multiple elements matching the css selector,
use `index` to indicate which one.
"""
if not allow_blank:
world.wait_for(lambda _: world.css_value(css_selector, index=index))
return world.css_value(css_selector, index=index) == value
@world.absorb
......
@shard_1
Feature: LMS.Navigate Course
As a student in an edX course
In order to view the course properly
In order to access courseware
I want to be able to navigate through the content
Scenario: I can navigate to a section
Given I am viewing a course with multiple sections
When I click on section "2"
Then I should see the content of section "2"
When I navigate to a section
Then I see the content of the section
Scenario: I can navigate to subsections
Given I am viewing a section with multiple subsections
When I click on subsection "2"
Then I should see the content of subsection "2"
When I navigate to a subsection
Then I see the content of the subsection
Scenario: I can navigate to sequences
Given I am viewing a section with multiple sequences
When I click on sequence "2"
Then I should see the content of sequence "2"
When I navigate to an item in a sequence
Then I see the content of the sequence item
Scenario: I can go back to where I was after I log out and back in
Scenario: I can return to the last section I visited
Given I am viewing a course with multiple sections
When I click on section "2"
And I return later
Then I should see that I was most recently in section "2"
When I navigate to a section
And I see the content of the section
And I return to the courseware
Then I see that I was most recently in the subsection
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment