Refactored navigation feature
Fixed grading tests
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
@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
|
||||
|
||||
@@ -2,37 +2,39 @@
|
||||
#pylint: disable=W0621
|
||||
|
||||
from lettuce import world, step
|
||||
from django.contrib.auth.models import User
|
||||
from lettuce.django import django_url
|
||||
from student.models import CourseEnrollment
|
||||
from common import course_id, course_location
|
||||
from problems_setup import PROBLEM_DICT
|
||||
|
||||
TEST_SECTION_NAME = 'Test Section'
|
||||
TEST_SUBSECTION_NAME = 'Test Subsection'
|
||||
from nose.tools import assert_in
|
||||
|
||||
|
||||
@step(u'I am viewing a course with multiple sections')
|
||||
def view_course_multiple_sections(step):
|
||||
create_course()
|
||||
# Add a section to the course to contain problems
|
||||
section1 = world.ItemFactory.create(parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name=section_name(1))
|
||||
|
||||
# Add a section to the course to contain problems
|
||||
section2 = world.ItemFactory.create(parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name=section_name(2))
|
||||
section1 = world.ItemFactory.create(
|
||||
parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name="Test Section 1"
|
||||
)
|
||||
|
||||
place1 = world.ItemFactory.create(parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name=subsection_name(1))
|
||||
section2 = world.ItemFactory.create(
|
||||
parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name="Test Section 2"
|
||||
)
|
||||
|
||||
place2 = world.ItemFactory.create(parent_location=section2.location,
|
||||
category='sequential',
|
||||
display_name=subsection_name(2))
|
||||
place1 = world.ItemFactory.create(
|
||||
parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name="Test Subsection 1"
|
||||
)
|
||||
|
||||
add_problem_to_course_section('model_course', 'multiple choice', place1.location)
|
||||
add_problem_to_course_section('model_course', 'drop down', place2.location)
|
||||
place2 = world.ItemFactory.create(
|
||||
parent_location=section2.location,
|
||||
category='sequential',
|
||||
display_name="Test Subsection 2"
|
||||
)
|
||||
|
||||
add_problem_to_course_section(place1.location, "Problem 1")
|
||||
add_problem_to_course_section(place2.location, "Problem 2")
|
||||
|
||||
create_user_and_visit_course()
|
||||
|
||||
@@ -41,19 +43,24 @@ def view_course_multiple_sections(step):
|
||||
def view_course_multiple_subsections(step):
|
||||
create_course()
|
||||
|
||||
# Add a section to the course to contain problems
|
||||
section1 = world.ItemFactory.create(parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name=section_name(1))
|
||||
section1 = world.ItemFactory.create(
|
||||
parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name="Test Section 1"
|
||||
)
|
||||
|
||||
place1 = world.ItemFactory.create(parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name=subsection_name(1))
|
||||
place1 = world.ItemFactory.create(
|
||||
parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name="Test Subsection 1"
|
||||
)
|
||||
|
||||
place2 = world.ItemFactory.create(parent_location=section1.location,
|
||||
display_name=subsection_name(2))
|
||||
place2 = world.ItemFactory.create(
|
||||
parent_location=section1.location,
|
||||
display_name="Test Subsection 2"
|
||||
)
|
||||
|
||||
add_problem_to_course_section('model_course', 'multiple choice', place1.location)
|
||||
add_problem_to_course_section('model_course', 'drop down', place2.location)
|
||||
add_problem_to_course_section(place1.location, "Problem 3")
|
||||
add_problem_to_course_section(place2.location, "Problem 4")
|
||||
|
||||
create_user_and_visit_course()
|
||||
|
||||
@@ -61,121 +68,116 @@ def view_course_multiple_subsections(step):
|
||||
@step(u'I am viewing a section with multiple sequences')
|
||||
def view_course_multiple_sequences(step):
|
||||
create_course()
|
||||
# Add a section to the course to contain problems
|
||||
section1 = world.ItemFactory.create(parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name=section_name(1))
|
||||
|
||||
place1 = world.ItemFactory.create(parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name=subsection_name(1))
|
||||
section1 = world.ItemFactory.create(
|
||||
parent_location=course_location(world.scenario_dict['COURSE'].number),
|
||||
display_name="Test Section 1"
|
||||
)
|
||||
|
||||
add_problem_to_course_section('model_course', 'multiple choice', place1.location)
|
||||
add_problem_to_course_section('model_course', 'drop down', place1.location)
|
||||
place1 = world.ItemFactory.create(
|
||||
parent_location=section1.location,
|
||||
category='sequential',
|
||||
display_name="Test Subsection 1"
|
||||
)
|
||||
|
||||
add_problem_to_course_section(place1.location, "Problem 5")
|
||||
add_problem_to_course_section(place1.location, "Problem 6")
|
||||
|
||||
create_user_and_visit_course()
|
||||
|
||||
|
||||
@step(u'I click on section "([^"]*)"$')
|
||||
def click_on_section(step, section):
|
||||
@step(u'I navigate to a section')
|
||||
def when_i_navigate_to_a_section(step):
|
||||
section_css = 'h3[tabindex="-1"]'
|
||||
world.css_click(section_css)
|
||||
|
||||
subid = "ui-accordion-accordion-panel-{}".format(str(int(section) - 1))
|
||||
subid = "ui-accordion-accordion-panel-1"
|
||||
world.wait_for_visible("#" + subid)
|
||||
|
||||
subsection_css = "ul.ui-accordion-content-active[id='{}'] > li > a".format(subid)
|
||||
world.css_click(subsection_css)
|
||||
|
||||
|
||||
@step(u'I click on subsection "([^"]*)"$')
|
||||
def click_on_subsection(step, subsection):
|
||||
@step(u'I navigate to a subsection')
|
||||
def when_i_navigate_to_a_subsection(step):
|
||||
subsection_css = 'ul[id="ui-accordion-accordion-panel-0"]> li > a'
|
||||
world.css_click(subsection_css, index=(int(subsection) - 1))
|
||||
world.css_click(subsection_css, index=1)
|
||||
|
||||
|
||||
@step(u'I click on sequence "([^"]*)"$')
|
||||
def click_on_sequence(step, sequence):
|
||||
sequence_css = 'a[data-element="%s"]' % sequence
|
||||
@step(u'I navigate to an item in a sequence')
|
||||
def when_i_navigate_to_an_item_in_a_sequence(step):
|
||||
sequence_css = 'a[data-element="2"]'
|
||||
world.css_click(sequence_css)
|
||||
|
||||
|
||||
@step(u'I should see the content of (?:sub)?section "([^"]*)"$')
|
||||
def see_section_content(step, section):
|
||||
world.wait(0.5)
|
||||
if section == "2":
|
||||
text = 'The correct answer is Option 2'
|
||||
elif section == "1":
|
||||
text = 'The correct answer is Choice 3'
|
||||
step.given('I should see "' + text + '" somewhere on the page')
|
||||
@step(u'I see the content of the section')
|
||||
def then_i_see_the_content_of_the_section(step):
|
||||
wait_for_problem('PROBLEM 2')
|
||||
|
||||
|
||||
@step(u'I should see the content of sequence "([^"]*)"$')
|
||||
def see_sequence_content(step, sequence):
|
||||
step.given('I should see the content of section "2"')
|
||||
@step(u'I see the content of the subsection')
|
||||
def then_i_see_the_content_of_the_subsection(step):
|
||||
wait_for_problem('PROBLEM 4')
|
||||
|
||||
|
||||
@step(u'I return later')
|
||||
def return_to_course(step):
|
||||
step.given('I visit the homepage')
|
||||
@step(u'I see the content of the sequence item')
|
||||
def then_i_see_the_content_of_the_sequence_item(step):
|
||||
wait_for_problem('PROBLEM 6')
|
||||
|
||||
|
||||
@step(u'I return to the courseware')
|
||||
def and_i_return_to_the_courseware(step):
|
||||
world.visit('/')
|
||||
world.click_link("View Course")
|
||||
world.click_link("Courseware")
|
||||
|
||||
|
||||
@step(u'I should see that I was most recently in section "([^"]*)"$')
|
||||
def see_recent_section(step, section):
|
||||
step.given('I should see "You were most recently in %s" somewhere on the page' % subsection_name(int(section)))
|
||||
|
||||
#####################
|
||||
# HELPERS
|
||||
#####################
|
||||
|
||||
|
||||
def section_name(section):
|
||||
return TEST_SECTION_NAME + str(section)
|
||||
|
||||
|
||||
def subsection_name(section):
|
||||
return TEST_SUBSECTION_NAME + str(section)
|
||||
@step(u'I see that I was most recently in the subsection')
|
||||
def then_i_see_that_i_was_most_recently_in_the_subsection(step):
|
||||
message = world.css_text('section.course-content > p')
|
||||
assert_in("You were most recently in Test Subsection 2", message)
|
||||
|
||||
|
||||
def create_course():
|
||||
world.clear_courses()
|
||||
|
||||
world.scenario_dict['COURSE'] = world.CourseFactory.create(org='edx', number='model_course', display_name='Test Course')
|
||||
world.scenario_dict['COURSE'] = world.CourseFactory.create(
|
||||
org='edx', number='999', display_name='Test Course'
|
||||
)
|
||||
|
||||
|
||||
def create_user_and_visit_course():
|
||||
world.create_user('robot', 'test')
|
||||
u = User.objects.get(username='robot')
|
||||
|
||||
CourseEnrollment.enroll(u, course_id(world.scenario_dict['COURSE'].number))
|
||||
|
||||
world.log_in(username='robot', password='test')
|
||||
chapter_name = (TEST_SECTION_NAME + "1").replace(" ", "_")
|
||||
section_name = (TEST_SUBSECTION_NAME + "1").replace(" ", "_")
|
||||
url = django_url('/courses/edx/model_course/Test_Course/courseware/%s/%s' %
|
||||
(chapter_name, section_name))
|
||||
|
||||
world.browser.visit(url)
|
||||
world.register_by_course_id('edx/999/Test_Course')
|
||||
world.log_in()
|
||||
world.visit('/courses/edx/999/Test_Course/courseware/')
|
||||
|
||||
|
||||
def add_problem_to_course_section(course, problem_type, parent_location, extraMeta=None):
|
||||
'''
|
||||
Add a problem to the course we have created using factories.
|
||||
'''
|
||||
def add_problem_to_course_section(parent_location, display_name):
|
||||
"""
|
||||
Add a problem to the course at `parent_location` (a `Location` instance)
|
||||
|
||||
assert(problem_type in PROBLEM_DICT)
|
||||
`display_name` is the name of the problem to display, which
|
||||
is useful to identify which problem we're looking at.
|
||||
"""
|
||||
|
||||
# Generate the problem XML using capa.tests.response_xml_factory
|
||||
factory_dict = PROBLEM_DICT[problem_type]
|
||||
# Since this is just a placeholder, we always use multiple choice.
|
||||
factory_dict = PROBLEM_DICT['multiple choice']
|
||||
problem_xml = factory_dict['factory'].build_xml(**factory_dict['kwargs'])
|
||||
metadata = {'rerandomize': 'always'} if not 'metadata' in factory_dict else factory_dict['metadata']
|
||||
if extraMeta:
|
||||
metadata = dict(metadata, **extraMeta)
|
||||
|
||||
# Create a problem item using our generated XML
|
||||
# We set rerandomize=always in the metadata so that the "Reset" button
|
||||
# will appear.
|
||||
world.ItemFactory.create(parent_location=parent_location,
|
||||
category='problem',
|
||||
display_name=str(problem_type),
|
||||
data=problem_xml,
|
||||
metadata=metadata)
|
||||
# Add the problem
|
||||
world.ItemFactory.create(
|
||||
parent_location=parent_location,
|
||||
category='problem',
|
||||
display_name=display_name,
|
||||
data=problem_xml
|
||||
)
|
||||
|
||||
|
||||
def wait_for_problem(display_name):
|
||||
"""
|
||||
Wait for the problem with `display_name` to appear on the page.
|
||||
"""
|
||||
wait_func = lambda _: world.css_has_text(
|
||||
'h2.problem-header', display_name, strip=True
|
||||
)
|
||||
world.wait_for(wait_func)
|
||||
|
||||
Reference in New Issue
Block a user