Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
cdadcba9
Commit
cdadcba9
authored
Jun 03, 2013
by
Jonah Stanley
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10 from edx/jonahstanley/add-more-tests
Jonahstanley/add more tests
parents
8d7a2f31
6af54ead
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
473 additions
and
365 deletions
+473
-365
AUTHORS
+1
-0
cms/djangoapps/contentstore/features/courses.py
+0
-6
cms/djangoapps/contentstore/features/studio-overview-togglesection.py
+1
-1
common/djangoapps/terrain/steps.py
+6
-3
common/djangoapps/terrain/ui_helpers.py
+12
-4
lms/djangoapps/courseware/features/courseware_common.py
+0
-6
lms/djangoapps/courseware/features/high-level-tabs.feature
+1
-4
lms/djangoapps/courseware/features/high-level-tabs.py
+11
-0
lms/djangoapps/courseware/features/homepage.feature
+2
-6
lms/djangoapps/courseware/features/homepage.py
+15
-4
lms/djangoapps/courseware/features/problems.feature
+35
-0
lms/djangoapps/courseware/features/problems.py
+53
-323
lms/djangoapps/courseware/features/problems_setup.py
+325
-0
lms/djangoapps/courseware/features/registration.feature
+1
-1
lms/djangoapps/courseware/features/registration.py
+10
-7
No files found.
AUTHORS
View file @
cdadcba9
...
...
@@ -72,4 +72,5 @@ Giulio Gratta <giulio@giuliogratta.com>
David Baumgold <david@davidbaumgold.com>
Jason Bau <jbau@stanford.edu>
Frances Botsford <frances@edx.org>
Jonah Stanley <Jonah_Stanley@brown.edu>
Slater Victoroff <slater.r.victoroff@gmail.com>
cms/djangoapps/contentstore/features/courses.py
View file @
cdadcba9
...
...
@@ -47,12 +47,6 @@ def i_see_the_course_in_my_courses(step):
assert
world
.
css_has_text
(
course_css
,
'Robot Super Course'
)
@step
(
'the course is loaded$'
)
def
course_is_loaded
(
step
):
class_css
=
'a.class-name'
assert
world
.
css_has_text
(
course_css
,
'Robot Super Cousre'
)
@step
(
'I am on the "([^"]*)" tab$'
)
def
i_am_on_tab
(
step
,
tab_name
):
header_css
=
'div.inner-wrapper h1'
...
...
cms/djangoapps/contentstore/features/studio-overview-togglesection.py
View file @
cdadcba9
...
...
@@ -112,7 +112,7 @@ def all_sections_are_expanded(step):
@step
(
u'all sections are collapsed$'
)
def
all_sections_are_
expand
ed
(
step
):
def
all_sections_are_
collaps
ed
(
step
):
subsection_locator
=
'div.subsection-list'
subsections
=
world
.
css_find
(
subsection_locator
)
for
s
in
subsections
:
...
...
common/djangoapps/terrain/steps.py
View file @
cdadcba9
...
...
@@ -129,9 +129,12 @@ def should_have_link_with_id_and_text(step, link_id, text):
assert_equals
(
link
.
text
,
text
)
@step
(
r'should see "(.*)" (?:somewhere|anywhere) in (?:the|this) page'
)
def
should_see_in_the_page
(
step
,
text
):
assert_in
(
text
,
world
.
css_text
(
'body'
))
@step
(
r'should( not)? see "(.*)" (?:somewhere|anywhere) (?:in|on) (?:the|this) page'
)
def
should_see_in_the_page
(
step
,
doesnt_appear
,
text
):
if
doesnt_appear
:
assert
world
.
browser
.
is_text_not_present
(
text
,
wait_time
=
5
)
else
:
assert
world
.
browser
.
is_text_present
(
text
,
wait_time
=
5
)
@step
(
'I am logged in$'
)
...
...
common/djangoapps/terrain/ui_helpers.py
View file @
cdadcba9
...
...
@@ -32,8 +32,13 @@ def url_equals(url):
@world.absorb
def
is_css_present
(
css_selector
):
return
world
.
browser
.
is_element_present_by_css
(
css_selector
,
wait_time
=
4
)
def
is_css_present
(
css_selector
,
wait_time
=
5
):
return
world
.
browser
.
is_element_present_by_css
(
css_selector
,
wait_time
=
wait_time
)
@world.absorb
def
is_css_not_present
(
css_selector
,
wait_time
=
5
):
return
world
.
browser
.
is_element_not_present_by_css
(
css_selector
,
wait_time
=
wait_time
)
@world.absorb
...
...
@@ -42,11 +47,11 @@ def css_has_text(css_selector, text):
@world.absorb
def
css_find
(
css
):
def
css_find
(
css
,
wait_time
=
5
):
def
is_visible
(
driver
):
return
EC
.
visibility_of_element_located
((
By
.
CSS_SELECTOR
,
css
,))
world
.
browser
.
is_element_present_by_css
(
css
,
5
)
world
.
browser
.
is_element_present_by_css
(
css
,
wait_time
=
wait_time
)
wait_for
(
is_visible
)
return
world
.
browser
.
find_by_css
(
css
)
...
...
@@ -56,6 +61,7 @@ def css_click(css_selector):
"""
Perform a click on a CSS selector, retrying if it initially fails
"""
assert
is_css_present
(
css_selector
)
try
:
world
.
browser
.
find_by_css
(
css_selector
)
.
click
()
...
...
@@ -89,6 +95,7 @@ def id_click(elem_id):
@world.absorb
def
css_fill
(
css_selector
,
text
):
assert
is_css_present
(
css_selector
)
world
.
browser
.
find_by_css
(
css_selector
)
.
first
.
fill
(
text
)
...
...
@@ -114,6 +121,7 @@ def css_text(css_selector):
@world.absorb
def
css_visible
(
css_selector
):
assert
is_css_present
(
css_selector
)
return
world
.
browser
.
find_by_css
(
css_selector
)
.
visible
...
...
lms/djangoapps/courseware/features/courseware_common.py
View file @
cdadcba9
...
...
@@ -12,7 +12,6 @@ def i_click_on_view_courseware(step):
@step
(
'I click on the "([^"]*)" tab$'
)
def
i_click_on_the_tab
(
step
,
tab_text
):
world
.
click_link
(
tab_text
)
world
.
save_the_html
()
@step
(
'I visit the courseware URL$'
)
...
...
@@ -20,11 +19,6 @@ def i_visit_the_course_info_url(step):
world
.
visit
(
'/courses/MITx/6.002x/2012_Fall/courseware'
)
@step
(
u'I do not see "([^"]*)" anywhere on the page'
)
def
i_do_not_see_text_anywhere_on_the_page
(
step
,
text
):
assert
world
.
browser
.
is_text_not_present
(
text
)
@step
(
u'I am on the dashboard page$'
)
def
i_am_on_the_dashboard_page
(
step
):
assert
world
.
is_css_present
(
'section.courses'
)
...
...
lms/djangoapps/courseware/features/high-level-tabs.feature
View file @
cdadcba9
...
...
@@ -8,10 +8,7 @@ Scenario: I can navigate to all high - level tabs in a course
And
The course
"6.002x"
has extra tab
"Custom Tab"
And
I am logged in
And
I click on View Courseware
When
I click on the
"<TabName>"
tab
Then
the page title should contain
"<PageTitle>"
Examples
:
When I click on the tabs then the page title should contain the following titles
:
|
TabName
|
PageTitle
|
|
Courseware
|
6.002x
Courseware
|
|
Course
Info
|
6.002x
Course
Info
|
...
...
lms/djangoapps/courseware/features/high-level-tabs.py
0 → 100644
View file @
cdadcba9
from
lettuce
import
world
,
step
from
nose.tools
import
assert_equals
@step
(
u'I click on the tabs then the page title should contain the following titles:'
)
def
i_click_on_the_tab_and_check
(
step
):
for
tab_title
in
step
.
hashes
:
tab_text
=
tab_title
[
'TabName'
]
title
=
tab_title
[
'PageTitle'
]
world
.
click_link
(
tab_text
)
assert
(
title
in
world
.
browser
.
title
)
lms/djangoapps/courseware/features/homepage.feature
View file @
cdadcba9
...
...
@@ -13,9 +13,7 @@ Feature: Homepage for web users
Scenario Outline
:
User can see main parts of the page
Given
I visit the homepage
Then
I should see a link with the id
"<id>"
called
"<Link>"
Examples
:
Then
I should see the following links and ids
|
id
|
Link
|
|
about
|
About
|
|
jobs
|
Jobs
|
...
...
@@ -27,9 +25,7 @@ Feature: Homepage for web users
# TODO: test according to domain or policy
Scenario
:
User can see the partner institutions
Given
I visit the homepage
Then
I should see
"<Partner>"
in the Partners section
Examples
:
Then
I should see the following Partners in the Partners section
|
Partner
|
|
MITx
|
|
HarvardX
|
...
...
lms/djangoapps/courseware/features/homepage.py
View file @
cdadcba9
...
...
@@ -2,11 +2,22 @@
#pylint: disable=W0621
from
lettuce
import
world
,
step
from
nose.tools
import
assert_in
from
nose.tools
import
assert_in
,
assert_equals
@step
(
'I should see "([^"]*)" in the Partners section$
'
)
def
i_should_see_partner
(
step
,
partner
):
@step
(
u'I should see the following Partners in the Partners section
'
)
def
i_should_see_partner
(
step
):
partners
=
world
.
browser
.
find_by_css
(
".partner .name span"
)
names
=
set
(
span
.
text
for
span
in
partners
)
assert_in
(
partner
,
names
)
for
partner
in
step
.
hashes
:
assert_in
(
partner
[
'Partner'
],
names
)
@step
(
u'I should see the following links and ids'
)
def
should_see_a_link_called
(
step
):
for
link_id_pair
in
step
.
hashes
:
link_id
=
link_id_pair
[
'id'
]
text
=
link_id_pair
[
'Link'
]
link
=
world
.
browser
.
find_by_id
(
link_id
)
assert
len
(
link
)
>
0
assert_equals
(
link
.
text
,
text
)
lms/djangoapps/courseware/features/problems.feature
View file @
cdadcba9
...
...
@@ -84,3 +84,38 @@ Feature: Answer problems
|
formula
|
incorrect
|
|
script
|
correct
|
|
script
|
incorrect
|
Scenario
:
I
can answer a problem with one attempt correctly and not reset
Given
I am viewing a
"multiple choice"
problem with
"1"
attempt
When
I answer a
"multiple choice"
problem
"correctly"
Then
The
"Reset"
button does not appear
Scenario
:
I
can answer a problem with multiple attempts correctly and still reset the problem
Given
I am viewing a
"multiple choice"
problem with
"3"
attempts
Then
I should see
"You have used 0 of 3 submissions"
somewhere in the page
When
I answer a
"multiple choice"
problem
"correctly"
Then
The
"Reset"
button does appear
Scenario
:
I
can view how many attempts I have left on a problem
Given
I am viewing a
"multiple choice"
problem with
"3"
attempts
Then
I should see
"You have used 0 of 3 submissions"
somewhere in the page
When
I answer a
"multiple choice"
problem
"incorrectly"
And
I reset the problem
Then
I should see
"You have used 1 of 3 submissions"
somewhere in the page
When
I answer a
"multiple choice"
problem
"incorrectly"
And
I reset the problem
Then
I should see
"You have used 2 of 3 submissions"
somewhere in the page
And
The
"Final Check"
button does appear
When
I answer a
"multiple choice"
problem
"correctly"
Then
The
"Reset"
button does not appear
Scenario
:
I can view and hide the answer if the problem has it
:
Given
I am viewing a
"numerical"
that shows the answer
"always"
When
I press the
"Show Answer"
button
Then
The
"Hide Answer"
button does appear
And
The
"Show Answer"
button does not appear
And
I should see
"4.14159"
somewhere in the page
When
I press the
"Hide Answer"
button
Then
The
"Show Answer"
button does appear
And
I should not see
"4.14159"
anywhere on the page
lms/djangoapps/courseware/features/problems.py
View file @
cdadcba9
...
...
@@ -7,119 +7,42 @@ Steps for problem.feature lettuce tests
from
lettuce
import
world
,
step
from
lettuce.django
import
django_url
import
random
import
textwrap
from
common
import
i_am_registered_for_the_course
,
\
TEST_SECTION_NAME
,
section_location
from
capa.tests.response_xml_factory
import
OptionResponseXMLFactory
,
\
ChoiceResponseXMLFactory
,
MultipleChoiceResponseXMLFactory
,
\
StringResponseXMLFactory
,
NumericalResponseXMLFactory
,
\
FormulaResponseXMLFactory
,
CustomResponseXMLFactory
,
\
CodeResponseXMLFactory
# Factories from capa.tests.response_xml_factory that we will use
# to generate the problem XML, with the keyword args used to configure
# the output.
PROBLEM_FACTORY_DICT
=
{
'drop down'
:
{
'factory'
:
OptionResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Option 2'
,
'options'
:
[
'Option 1'
,
'Option 2'
,
'Option 3'
,
'Option 4'
],
'correct_option'
:
'Option 2'
}},
'multiple choice'
:
{
'factory'
:
MultipleChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choice 3'
,
'choices'
:
[
False
,
False
,
True
,
False
],
'choice_names'
:
[
'choice_0'
,
'choice_1'
,
'choice_2'
,
'choice_3'
]}},
'checkbox'
:
{
'factory'
:
ChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choices 1 and 3'
,
'choice_type'
:
'checkbox'
,
'choices'
:
[
True
,
False
,
True
,
False
,
False
],
'choice_names'
:
[
'Choice 1'
,
'Choice 2'
,
'Choice 3'
,
'Choice 4'
]}},
'radio'
:
{
'factory'
:
ChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choice 3'
,
'choice_type'
:
'radio'
,
'choices'
:
[
False
,
False
,
True
,
False
],
'choice_names'
:
[
'Choice 1'
,
'Choice 2'
,
'Choice 3'
,
'Choice 4'
]}},
'string'
:
{
'factory'
:
StringResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The answer is "correct string"'
,
'case_sensitive'
:
False
,
'answer'
:
'correct string'
}},
'numerical'
:
{
'factory'
:
NumericalResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The answer is pi + 1'
,
'answer'
:
'4.14159'
,
'tolerance'
:
'0.00001'
,
'math_display'
:
True
}},
'formula'
:
{
'factory'
:
FormulaResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The solution is [mathjax]x^2+2x+y[/mathjax]'
,
'sample_dict'
:
{
'x'
:
(
-
100
,
100
),
'y'
:
(
-
100
,
100
)},
'num_samples'
:
10
,
'tolerance'
:
0.00001
,
'math_display'
:
True
,
'answer'
:
'x^2+2*x+y'
}},
'script'
:
{
'factory'
:
CustomResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'Enter two integers that sum to 10.'
,
'cfn'
:
'test_add_to_ten'
,
'expect'
:
'10'
,
'num_inputs'
:
2
,
'script'
:
textwrap
.
dedent
(
"""
def test_add_to_ten(expect,ans):
try:
a1=int(ans[0])
a2=int(ans[1])
except ValueError:
a1=0
a2=0
return (a1+a2)==int(expect)
"""
)}},
'code'
:
{
'factory'
:
CodeResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'Submit code to an external grader'
,
'initial_display'
:
'print "Hello world!"'
,
'grader_payload'
:
'{"grader": "ps1/Spring2013/test_grader.py"}'
,
}},
}
def
add_problem_to_course
(
course
,
problem_type
):
'''
Add a problem to the course we have created using factories.
'''
from
common
import
i_am_registered_for_the_course
,
TEST_SECTION_NAME
from
problems_setup
import
PROBLEM_DICT
,
answer_problem
,
problem_has_answer
,
add_problem_to_course
@step
(
u'I am viewing a "([^"]*)" problem with "([^"]*)" attempt'
)
def
view_problem_with_attempts
(
step
,
problem_type
,
attempts
):
i_am_registered_for_the_course
(
step
,
'model_course'
)
# Ensure that the course has this problem type
add_problem_to_course
(
'model_course'
,
problem_type
,
{
'attempts'
:
attempts
})
# Go to the one section in the factory-created course
# which should be loaded with the correct problem
chapter_name
=
TEST_SECTION_NAME
.
replace
(
" "
,
"_"
)
section_name
=
chapter_name
url
=
django_url
(
'/courses/edx/model_course/Test_Course/courseware/
%
s/
%
s'
%
(
chapter_name
,
section_name
))
assert
(
problem_type
in
PROBLEM_FACTORY_DICT
)
world
.
browser
.
visit
(
url
)
# Generate the problem XML using capa.tests.response_xml_factory
factory_dict
=
PROBLEM_FACTORY_DICT
[
problem_type
]
problem_xml
=
factory_dict
[
'factory'
]
.
build_xml
(
**
factory_dict
[
'kwargs'
])
# Create a problem item using our generated XML
# We set rerandomize=always in the metadata so that the "Reset" button
# will appear.
template_name
=
"i4x://edx/templates/problem/Blank_Common_Problem"
world
.
ItemFactory
.
create
(
parent_location
=
section_location
(
course
),
template
=
template_name
,
display_name
=
str
(
problem_type
),
data
=
problem_xml
,
metadata
=
{
'rerandomize'
:
'always'
})
@step
(
u'I am viewing a "([^"]*)" that shows the answer "([^"]*)"'
)
def
view_problem_with_show_answer
(
step
,
problem_type
,
answer
):
i_am_registered_for_the_course
(
step
,
'model_course'
)
# Ensure that the course has this problem type
add_problem_to_course
(
'model_course'
,
problem_type
,
{
'showanswer'
:
answer
})
# Go to the one section in the factory-created course
# which should be loaded with the correct problem
chapter_name
=
TEST_SECTION_NAME
.
replace
(
" "
,
"_"
)
section_name
=
chapter_name
url
=
django_url
(
'/courses/edx/model_course/Test_Course/courseware/
%
s/
%
s'
%
(
chapter_name
,
section_name
))
world
.
browser
.
visit
(
url
)
@step
(
u'I am viewing a "([^"]*)" problem'
)
...
...
@@ -153,7 +76,7 @@ def set_external_grader_response(step, correctness):
@step
(
u'I answer a "([^"]*)" problem "([^"]*)ly"'
)
def
answer_problem
(
step
,
problem_type
,
correctness
):
def
answer_problem
_step
(
step
,
problem_type
,
correctness
):
""" Mark a given problem type correct or incorrect, then submit it.
*problem_type* is a string representing the type of problem (e.g. 'drop down')
...
...
@@ -161,73 +84,18 @@ def answer_problem(step, problem_type, correctness):
"""
assert
(
correctness
in
[
'correct'
,
'incorrect'
])
if
problem_type
==
"drop down"
:
select_name
=
"input_i4x-edx-model_course-problem-drop_down_2_1"
option_text
=
'Option 2'
if
correctness
==
'correct'
else
'Option 3'
world
.
browser
.
select
(
select_name
,
option_text
)
elif
problem_type
==
"multiple choice"
:
if
correctness
==
'correct'
:
inputfield
(
'multiple choice'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'multiple choice'
,
choice
=
'choice_1'
)
.
check
()
elif
problem_type
==
"checkbox"
:
if
correctness
==
'correct'
:
inputfield
(
'checkbox'
,
choice
=
'choice_0'
)
.
check
()
inputfield
(
'checkbox'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'checkbox'
,
choice
=
'choice_3'
)
.
check
()
elif
problem_type
==
'radio'
:
if
correctness
==
'correct'
:
inputfield
(
'radio'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'radio'
,
choice
=
'choice_1'
)
.
check
()
elif
problem_type
==
'string'
:
textvalue
=
'correct string'
if
correctness
==
'correct'
\
else
'incorrect'
inputfield
(
'string'
)
.
fill
(
textvalue
)
elif
problem_type
==
'numerical'
:
textvalue
=
"pi + 1"
if
correctness
==
'correct'
\
else
str
(
random
.
randint
(
-
2
,
2
))
inputfield
(
'numerical'
)
.
fill
(
textvalue
)
elif
problem_type
==
'formula'
:
textvalue
=
"x^2+2*x+y"
if
correctness
==
'correct'
else
'x^2'
inputfield
(
'formula'
)
.
fill
(
textvalue
)
elif
problem_type
==
'script'
:
# Correct answer is any two integers that sum to 10
first_addend
=
random
.
randint
(
-
100
,
100
)
second_addend
=
10
-
first_addend
# If we want an incorrect answer, then change
# the second addend so they no longer sum to 10
if
correctness
==
'incorrect'
:
second_addend
+=
random
.
randint
(
1
,
10
)
inputfield
(
'script'
,
input_num
=
1
)
.
fill
(
str
(
first_addend
))
inputfield
(
'script'
,
input_num
=
2
)
.
fill
(
str
(
second_addend
))
elif
problem_type
==
'code'
:
# The fake xqueue server is configured to respond
# correct / incorrect no matter what we submit.
# Furthermore, since the inline code response uses
# JavaScript to make the code display nicely, it's difficult
# to programatically input text
# (there's not <textarea> we can just fill text into)
# For this reason, we submit the initial code in the response
# (configured in the problem XML above)
pass
assert
(
problem_type
in
PROBLEM_DICT
)
answer_problem
(
problem_type
,
correctness
)
# Submit the problem
check_problem
(
step
)
@step
(
u'I check a problem'
)
def
check_problem
(
step
):
world
.
css_click
(
"input.check"
)
@step
(
u'The "([^"]*)" problem displays a "([^"]*)" answer'
)
def
assert_problem_has_answer
(
step
,
problem_type
,
answer_class
):
'''
...
...
@@ -239,67 +107,8 @@ def assert_problem_has_answer(step, problem_type, answer_class):
by setting answer_class='blank'
'''
assert
answer_class
in
[
'correct'
,
'incorrect'
,
'blank'
]
if
problem_type
==
"drop down"
:
if
answer_class
==
'blank'
:
assert
world
.
browser
.
is_element_not_present_by_css
(
'option[selected="true"]'
)
else
:
actual
=
world
.
browser
.
find_by_css
(
'option[selected="true"]'
)
.
value
expected
=
'Option 2'
if
answer_class
==
'correct'
else
'Option 3'
assert
actual
==
expected
elif
problem_type
==
"multiple choice"
:
if
answer_class
==
'correct'
:
assert_checked
(
'multiple choice'
,
[
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'multiple choice'
,
[
'choice_1'
])
else
:
assert_checked
(
'multiple choice'
,
[])
elif
problem_type
==
"checkbox"
:
if
answer_class
==
'correct'
:
assert_checked
(
'checkbox'
,
[
'choice_0'
,
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'checkbox'
,
[
'choice_3'
])
else
:
assert_checked
(
'checkbox'
,
[])
elif
problem_type
==
"radio"
:
if
answer_class
==
'correct'
:
assert_checked
(
'radio'
,
[
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'radio'
,
[
'choice_1'
])
else
:
assert_checked
(
'radio'
,
[])
elif
problem_type
==
'string'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
'correct string'
if
answer_class
==
'correct'
\
else
'incorrect'
assert_textfield
(
'string'
,
expected
)
elif
problem_type
==
'formula'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
"x^2+2*x+y"
if
answer_class
==
'correct'
else
'x^2'
assert_textfield
(
'formula'
,
expected
)
else
:
# The other response types use random data,
# which would be difficult to check
# We trade input value coverage in the other tests for
# input type coverage in this test.
pass
@step
(
u'I check a problem'
)
def
check_problem
(
step
):
world
.
css_click
(
"input.check"
)
assert
problem_type
in
PROBLEM_DICT
problem_has_answer
(
problem_type
,
answer_class
)
@step
(
u'I reset the problem'
)
...
...
@@ -307,45 +116,13 @@ def reset_problem(step):
world
.
css_click
(
'input.reset'
)
# Dictionaries that map problem types to the css selectors
# for correct/incorrect/unanswered marks.
# The elements are lists of selectors because a particular problem type
# might be marked in multiple ways.
# For example, multiple choice is marked incorrect differently
# depending on whether the user selects an incorrect
# item or submits without selecting any item)
CORRECTNESS_SELECTORS
=
{
'correct'
:
{
'drop down'
:
[
'span.correct'
],
'multiple choice'
:
[
'label.choicegroup_correct'
],
'checkbox'
:
[
'span.correct'
],
'radio'
:
[
'label.choicegroup_correct'
],
'string'
:
[
'div.correct'
],
'numerical'
:
[
'div.correct'
],
'formula'
:
[
'div.correct'
],
'script'
:
[
'div.correct'
],
'code'
:
[
'span.correct'
]},
'incorrect'
:
{
'drop down'
:
[
'span.incorrect'
],
'multiple choice'
:
[
'label.choicegroup_incorrect'
,
'span.incorrect'
],
'checkbox'
:
[
'span.incorrect'
],
'radio'
:
[
'label.choicegroup_incorrect'
,
'span.incorrect'
],
'string'
:
[
'div.incorrect'
],
'numerical'
:
[
'div.incorrect'
],
'formula'
:
[
'div.incorrect'
],
'script'
:
[
'div.incorrect'
],
'code'
:
[
'span.incorrect'
]},
'unanswered'
:
{
'drop down'
:
[
'span.unanswered'
],
'multiple choice'
:
[
'span.unanswered'
],
'checkbox'
:
[
'span.unanswered'
],
'radio'
:
[
'span.unanswered'
],
'string'
:
[
'div.unanswered'
],
'numerical'
:
[
'div.unanswered'
],
'formula'
:
[
'div.unanswered'
],
'script'
:
[
'div.unanswered'
],
'code'
:
[
'span.unanswered'
]}}
@step
(
u'The "([^"]*)" button does( not)? appear'
)
def
action_button_present
(
step
,
buttonname
,
doesnt_appear
):
button_css
=
'section.action input[value*="
%
s"]'
%
buttonname
if
doesnt_appear
:
assert
world
.
is_css_not_present
(
button_css
)
else
:
assert
world
.
is_css_present
(
button_css
)
@step
(
u'My "([^"]*)" answer is marked "([^"]*)"'
)
...
...
@@ -359,12 +136,11 @@ def assert_answer_mark(step, problem_type, correctness):
"""
# Determine which selector(s) to look for based on correctness
assert
(
correctness
in
CORRECTNESS_SELECTORS
)
selector_dict
=
CORRECTNESS_SELECTORS
[
correctness
]
assert
(
problem_type
in
selector_dict
)
assert
(
correctness
in
[
'correct'
,
'incorrect'
,
'unanswered'
])
assert
(
problem_type
in
PROBLEM_DICT
)
# At least one of the correct selectors should be present
for
sel
in
selector_dict
[
problem_type
]:
for
sel
in
PROBLEM_DICT
[
problem_type
][
correctness
]:
has_expected
=
world
.
is_css_present
(
sel
)
# As soon as we find the selector, break out of the loop
...
...
@@ -373,49 +149,3 @@ def assert_answer_mark(step, problem_type, correctness):
# Expect that we found the expected selector
assert
(
has_expected
)
def
inputfield
(
problem_type
,
choice
=
None
,
input_num
=
1
):
""" Return the <input> element for *problem_type*.
For example, if problem_type is 'string', return
the text field for the string problem in the test course.
*choice* is the name of the checkbox input in a group
of checkboxes. """
sel
=
(
"input#input_i4x-edx-model_course-problem-
%
s_2_
%
s"
%
(
problem_type
.
replace
(
" "
,
"_"
),
str
(
input_num
)))
if
choice
is
not
None
:
base
=
"_choice_"
if
problem_type
==
"multiple choice"
else
"_"
sel
=
sel
+
base
+
str
(
choice
)
# If the input element doesn't exist, fail immediately
assert
world
.
is_css_present
(
sel
)
# Retrieve the input element
return
world
.
browser
.
find_by_css
(
sel
)
def
assert_checked
(
problem_type
,
choices
):
'''
Assert that choice names given in *choices* are the only
ones checked.
Works for both radio and checkbox problems
'''
all_choices
=
[
'choice_0'
,
'choice_1'
,
'choice_2'
,
'choice_3'
]
for
this_choice
in
all_choices
:
element
=
inputfield
(
problem_type
,
choice
=
this_choice
)
if
this_choice
in
choices
:
assert
element
.
checked
else
:
assert
not
element
.
checked
def
assert_textfield
(
problem_type
,
expected_text
,
input_num
=
1
):
element
=
inputfield
(
problem_type
,
input_num
=
input_num
)
assert
element
.
value
==
expected_text
lms/djangoapps/courseware/features/problems_setup.py
0 → 100644
View file @
cdadcba9
#pylint: disable=C0111
#pylint: disable=W0621
#EVERY PROBLEM TYPE MUST HAVE THE FOLLOWING:
# -Section in Dictionary containing:
# -factory
# -kwargs
# -(optional metadata)
# -Correct, Incorrect and Unanswered CSS selectors
# -A way to answer the problem correctly and incorrectly
# -A way to check the problem was answered correctly, incorrectly and blank
from
lettuce
import
world
import
random
import
textwrap
from
common
import
section_location
from
capa.tests.response_xml_factory
import
OptionResponseXMLFactory
,
\
ChoiceResponseXMLFactory
,
MultipleChoiceResponseXMLFactory
,
\
StringResponseXMLFactory
,
NumericalResponseXMLFactory
,
\
FormulaResponseXMLFactory
,
CustomResponseXMLFactory
,
\
CodeResponseXMLFactory
# Factories from capa.tests.response_xml_factory that we will use
# to generate the problem XML, with the keyword args used to configure
# the output.
PROBLEM_DICT
=
{
'drop down'
:
{
'factory'
:
OptionResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Option 2'
,
'options'
:
[
'Option 1'
,
'Option 2'
,
'Option 3'
,
'Option 4'
],
'correct_option'
:
'Option 2'
},
'correct'
:
[
'span.correct'
],
'incorrect'
:
[
'span.incorrect'
],
'unanswered'
:
[
'span.unanswered'
]},
'multiple choice'
:
{
'factory'
:
MultipleChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choice 3'
,
'choices'
:
[
False
,
False
,
True
,
False
],
'choice_names'
:
[
'choice_0'
,
'choice_1'
,
'choice_2'
,
'choice_3'
]},
'correct'
:
[
'label.choicegroup_correct'
,
'span.correct'
],
'incorrect'
:
[
'label.choicegroup_incorrect'
,
'span.incorrect'
],
'unanswered'
:
[
'span.unanswered'
]},
'checkbox'
:
{
'factory'
:
ChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choices 1 and 3'
,
'choice_type'
:
'checkbox'
,
'choices'
:
[
True
,
False
,
True
,
False
,
False
],
'choice_names'
:
[
'Choice 1'
,
'Choice 2'
,
'Choice 3'
,
'Choice 4'
]},
'correct'
:
[
'span.correct'
],
'incorrect'
:
[
'span.incorrect'
],
'unanswered'
:
[
'span.unanswered'
]},
'radio'
:
{
'factory'
:
ChoiceResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The correct answer is Choice 3'
,
'choice_type'
:
'radio'
,
'choices'
:
[
False
,
False
,
True
,
False
],
'choice_names'
:
[
'Choice 1'
,
'Choice 2'
,
'Choice 3'
,
'Choice 4'
]},
'correct'
:
[
'label.choicegroup_correct'
,
'span.correct'
],
'incorrect'
:
[
'label.choicegroup_incorrect'
,
'span.incorrect'
],
'unanswered'
:
[
'span.unanswered'
]},
'string'
:
{
'factory'
:
StringResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The answer is "correct string"'
,
'case_sensitive'
:
False
,
'answer'
:
'correct string'
},
'correct'
:
[
'div.correct'
],
'incorrect'
:
[
'div.incorrect'
],
'unanswered'
:
[
'div.unanswered'
]},
'numerical'
:
{
'factory'
:
NumericalResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The answer is pi + 1'
,
'answer'
:
'4.14159'
,
'tolerance'
:
'0.00001'
,
'math_display'
:
True
},
'correct'
:
[
'div.correct'
],
'incorrect'
:
[
'div.incorrect'
],
'unanswered'
:
[
'div.unanswered'
]},
'formula'
:
{
'factory'
:
FormulaResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'The solution is [mathjax]x^2+2x+y[/mathjax]'
,
'sample_dict'
:
{
'x'
:
(
-
100
,
100
),
'y'
:
(
-
100
,
100
)},
'num_samples'
:
10
,
'tolerance'
:
0.00001
,
'math_display'
:
True
,
'answer'
:
'x^2+2*x+y'
},
'correct'
:
[
'div.correct'
],
'incorrect'
:
[
'div.incorrect'
],
'unanswered'
:
[
'div.unanswered'
]},
'script'
:
{
'factory'
:
CustomResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'Enter two integers that sum to 10.'
,
'cfn'
:
'test_add_to_ten'
,
'expect'
:
'10'
,
'num_inputs'
:
2
,
'script'
:
textwrap
.
dedent
(
"""
def test_add_to_ten(expect,ans):
try:
a1=int(ans[0])
a2=int(ans[1])
except ValueError:
a1=0
a2=0
return (a1+a2)==int(expect)
"""
)},
'correct'
:
[
'div.correct'
],
'incorrect'
:
[
'div.incorrect'
],
'unanswered'
:
[
'div.unanswered'
]},
'code'
:
{
'factory'
:
CodeResponseXMLFactory
(),
'kwargs'
:
{
'question_text'
:
'Submit code to an external grader'
,
'initial_display'
:
'print "Hello world!"'
,
'grader_payload'
:
'{"grader": "ps1/Spring2013/test_grader.py"}'
,
},
'correct'
:
[
'span.correct'
],
'incorrect'
:
[
'span.incorrect'
],
'unanswered'
:
[
'span.unanswered'
]}
}
def
answer_problem
(
problem_type
,
correctness
):
if
problem_type
==
"drop down"
:
select_name
=
"input_i4x-edx-model_course-problem-drop_down_2_1"
option_text
=
'Option 2'
if
correctness
==
'correct'
else
'Option 3'
world
.
browser
.
select
(
select_name
,
option_text
)
elif
problem_type
==
"multiple choice"
:
if
correctness
==
'correct'
:
inputfield
(
'multiple choice'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'multiple choice'
,
choice
=
'choice_1'
)
.
check
()
elif
problem_type
==
"checkbox"
:
if
correctness
==
'correct'
:
inputfield
(
'checkbox'
,
choice
=
'choice_0'
)
.
check
()
inputfield
(
'checkbox'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'checkbox'
,
choice
=
'choice_3'
)
.
check
()
elif
problem_type
==
'radio'
:
if
correctness
==
'correct'
:
inputfield
(
'radio'
,
choice
=
'choice_2'
)
.
check
()
else
:
inputfield
(
'radio'
,
choice
=
'choice_1'
)
.
check
()
elif
problem_type
==
'string'
:
textvalue
=
'correct string'
if
correctness
==
'correct'
else
'incorrect'
inputfield
(
'string'
)
.
fill
(
textvalue
)
elif
problem_type
==
'numerical'
:
textvalue
=
"pi + 1"
if
correctness
==
'correct'
else
str
(
random
.
randint
(
-
2
,
2
))
inputfield
(
'numerical'
)
.
fill
(
textvalue
)
elif
problem_type
==
'formula'
:
textvalue
=
"x^2+2*x+y"
if
correctness
==
'correct'
else
'x^2'
inputfield
(
'formula'
)
.
fill
(
textvalue
)
elif
problem_type
==
'script'
:
# Correct answer is any two integers that sum to 10
first_addend
=
random
.
randint
(
-
100
,
100
)
second_addend
=
10
-
first_addend
# If we want an incorrect answer, then change
# the second addend so they no longer sum to 10
if
correctness
==
'incorrect'
:
second_addend
+=
random
.
randint
(
1
,
10
)
inputfield
(
'script'
,
input_num
=
1
)
.
fill
(
str
(
first_addend
))
inputfield
(
'script'
,
input_num
=
2
)
.
fill
(
str
(
second_addend
))
elif
problem_type
==
'code'
:
# The fake xqueue server is configured to respond
# correct / incorrect no matter what we submit.
# Furthermore, since the inline code response uses
# JavaScript to make the code display nicely, it's difficult
# to programatically input text
# (there's not <textarea> we can just fill text into)
# For this reason, we submit the initial code in the response
# (configured in the problem XML above)
pass
def
problem_has_answer
(
problem_type
,
answer_class
):
if
problem_type
==
"drop down"
:
if
answer_class
==
'blank'
:
assert
world
.
browser
.
is_element_not_present_by_css
(
'option[selected="true"]'
)
else
:
actual
=
world
.
browser
.
find_by_css
(
'option[selected="true"]'
)
.
value
expected
=
'Option 2'
if
answer_class
==
'correct'
else
'Option 3'
assert
actual
==
expected
elif
problem_type
==
"multiple choice"
:
if
answer_class
==
'correct'
:
assert_checked
(
'multiple choice'
,
[
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'multiple choice'
,
[
'choice_1'
])
else
:
assert_checked
(
'multiple choice'
,
[])
elif
problem_type
==
"checkbox"
:
if
answer_class
==
'correct'
:
assert_checked
(
'checkbox'
,
[
'choice_0'
,
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'checkbox'
,
[
'choice_3'
])
else
:
assert_checked
(
'checkbox'
,
[])
elif
problem_type
==
"radio"
:
if
answer_class
==
'correct'
:
assert_checked
(
'radio'
,
[
'choice_2'
])
elif
answer_class
==
'incorrect'
:
assert_checked
(
'radio'
,
[
'choice_1'
])
else
:
assert_checked
(
'radio'
,
[])
elif
problem_type
==
'string'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
'correct string'
if
answer_class
==
'correct'
else
'incorrect'
assert_textfield
(
'string'
,
expected
)
elif
problem_type
==
'formula'
:
if
answer_class
==
'blank'
:
expected
=
''
else
:
expected
=
"x^2+2*x+y"
if
answer_class
==
'correct'
else
'x^2'
assert_textfield
(
'formula'
,
expected
)
else
:
# The other response types use random data,
# which would be difficult to check
# We trade input value coverage in the other tests for
# input type coverage in this test.
pass
##############################
# HELPER METHODS
##############################
def
add_problem_to_course
(
course
,
problem_type
,
extraMeta
=
None
):
'''
Add a problem to the course we have created using factories.
'''
assert
(
problem_type
in
PROBLEM_DICT
)
# Generate the problem XML using capa.tests.response_xml_factory
factory_dict
=
PROBLEM_DICT
[
problem_type
]
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.
template_name
=
"i4x://edx/templates/problem/Blank_Common_Problem"
world
.
ItemFactory
.
create
(
parent_location
=
section_location
(
course
),
template
=
template_name
,
display_name
=
str
(
problem_type
),
data
=
problem_xml
,
metadata
=
metadata
)
def
inputfield
(
problem_type
,
choice
=
None
,
input_num
=
1
):
""" Return the <input> element for *problem_type*.
For example, if problem_type is 'string', return
the text field for the string problem in the test course.
*choice* is the name of the checkbox input in a group
of checkboxes. """
sel
=
(
"input#input_i4x-edx-model_course-problem-
%
s_2_
%
s"
%
(
problem_type
.
replace
(
" "
,
"_"
),
str
(
input_num
)))
if
choice
is
not
None
:
base
=
"_choice_"
if
problem_type
==
"multiple choice"
else
"_"
sel
=
sel
+
base
+
str
(
choice
)
# If the input element doesn't exist, fail immediately
assert
world
.
is_css_present
(
sel
)
# Retrieve the input element
return
world
.
browser
.
find_by_css
(
sel
)
def
assert_checked
(
problem_type
,
choices
):
'''
Assert that choice names given in *choices* are the only
ones checked.
Works for both radio and checkbox problems
'''
all_choices
=
[
'choice_0'
,
'choice_1'
,
'choice_2'
,
'choice_3'
]
for
this_choice
in
all_choices
:
element
=
inputfield
(
problem_type
,
choice
=
this_choice
)
if
this_choice
in
choices
:
assert
element
.
checked
else
:
assert
not
element
.
checked
def
assert_textfield
(
problem_type
,
expected_text
,
input_num
=
1
):
element
=
inputfield
(
problem_type
,
input_num
=
input_num
)
assert
element
.
value
==
expected_text
lms/djangoapps/courseware/features/registration.feature
View file @
cdadcba9
...
...
@@ -16,5 +16,5 @@ Feature: Register for a course
Then
I should see the course numbered
"6.002x"
in my dashboard
When
I unregister for the course numbered
"6.002x"
Then
I should be on the dashboard page
And
I should see
"Looks like you haven't registered for any courses yet."
somewhere in the p
age
And
I should see
an empty dashboard mess
age
And
I should NOT see the course numbered
"6.002x"
in my dashboard
lms/djangoapps/courseware/features/registration.py
View file @
cdadcba9
...
...
@@ -19,16 +19,19 @@ def i_register_for_the_course(step, course):
assert
world
.
is_css_present
(
'section.container.dashboard'
)
@step
(
u'I should see
the course numbered "([^"]*)" in my dashboard$
'
)
def
i_should_see_
that_course_in_my_dashboard
(
step
,
course
):
course_link_css
=
'section.my-courses a[href*="
%
s"]'
%
course
assert
world
.
is_css_present
(
course_link
_css
)
@step
(
u'I should see
an empty dashboard message
'
)
def
i_should_see_
empty_dashboard
(
step
):
empty_dash_css
=
'section.empty-dashboard-message'
assert
world
.
is_css_present
(
empty_dash
_css
)
@step
(
u'I should
NOT
see the course numbered "([^"]*)" in my dashboard$'
)
def
i_should_
not_see_that_course_in_my_dashboard
(
step
,
course
):
@step
(
u'I should
( NOT)?
see the course numbered "([^"]*)" in my dashboard$'
)
def
i_should_
see_that_course_in_my_dashboard
(
step
,
doesnt_appear
,
course
):
course_link_css
=
'section.my-courses a[href*="
%
s"]'
%
course
assert
not
world
.
is_css_present
(
course_link_css
)
if
doesnt_appear
:
assert
world
.
is_css_not_present
(
course_link_css
)
else
:
assert
world
.
is_css_present
(
course_link_css
)
@step
(
u'I unregister for the course numbered "([^"]*)"'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment