Commit 3a7b7822 by Xavier Antoviaque

Merge pull request #84 from open-craft/dragonfi-fix-integration-tests-edx-solutions

Fix integration tests for edx solutions
parents cc2026a4 7ed871e0
......@@ -518,6 +518,12 @@ following command:
$ DJANGO_SETTINGS_MODULE="workbench.settings_mentoring" nosetests --with-django
```
If you want to run only the integration or the unit tests, append the directory to the command. You can also run separate modules in this manner.
```bash
$ DJANGO_SETTINGS_MODULE="workbench.settings_mentoring" nosetests --with-django tests/unit
```
If you have not installed the xblock-sdk in the active virtualenv,
you might also have to prepend `PYTHONPATH=".:/path/to/xblock"` to the command above.
(`/path/to/xblock` is the path to the xblock-sdk, where the workbench resides).
......
......@@ -99,6 +99,8 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin):
@classmethod
def add_node_as_child(cls, block, xml_child, child_id):
if xml_child.tag is etree.Comment:
return
# Instantiate child
child_class = cls.get_class_by_element(xml_child.tag)
child = child_class(block)
......
......@@ -69,7 +69,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
url_name = String(help="Name of the current step, used for URL building",
default='mentoring-default', scope=Scope.content)
enforce_dependency = Boolean(help="Should the next step be the current block to complete?",
default=False, scope=Scope.content)
default=False, scope=Scope.content, enforce_type=True)
display_submit = Boolean(help="Allow to submit current block?", default=True, scope=Scope.content)
xml_content = String(help="XML content", default='', scope=Scope.content)
weight = Float(help="Defines the maximum total grade of the block.",
......
......@@ -22,7 +22,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['student_id', 'name']
db.delete_unique('mentoring_answer', ['student_id', 'name'])
......@@ -30,7 +29,6 @@ class Migration(SchemaMigration):
# Deleting model 'Answer'
db.delete_table('mentoring_answer')
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'name'),)", 'object_name': 'Answer'},
......
......@@ -13,7 +13,6 @@ class Migration(SchemaMigration):
self.gf('django.db.models.fields.CharField')(default='default', max_length=50, db_index=True),
keep_default=False)
# Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=32))
......@@ -21,7 +20,6 @@ class Migration(SchemaMigration):
# Deleting field 'Answer.course_id'
db.delete_column('mentoring_answer', 'course_id')
# Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=20))
......@@ -38,4 +36,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['mentoring']
\ No newline at end of file
complete_apps = ['mentoring']
......@@ -14,7 +14,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.create_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.delete_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
......@@ -22,7 +21,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name'])
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
......@@ -36,4 +34,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['mentoring']
\ No newline at end of file
complete_apps = ['mentoring']
......@@ -23,7 +23,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.create_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.delete_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
......@@ -31,7 +30,6 @@ class Migration(SchemaMigration):
# Deleting model 'LightChild'
db.delete_table('mentoring_lightchild')
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
......
......@@ -40,4 +40,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['mentoring']
\ No newline at end of file
complete_apps = ['mentoring']
......@@ -78,7 +78,7 @@ class QuestionnaireAbstractBlock(LightChild, StepMixin):
as_template = context.get('as_template', True)
if str(self.type) not in self.valid_types:
raise ValueError, u'Invalid value for {}.type: `{}`'.format(name, self.type)
raise ValueError(u'Invalid value for {}.type: `{}`'.format(name, self.type))
template_path = 'templates/html/{}_{}.html'.format(name.lower(), self.type)
......
......@@ -29,7 +29,7 @@ import logging
from xblock.fields import Scope
from .light_children import LightChild, String
from .utils import load_resource, render_js_template
from .utils import load_resource, render_template
# Globals ###########################################################
......@@ -50,8 +50,7 @@ class MentoringTableBlock(LightChild):
has_children = True
def student_view(self, context):
fragment, columns_frags = self.get_children_fragment(context,
view_name='mentoring_table_view')
fragment, columns_frags = self.get_children_fragment(context, view_name='mentoring_table_view')
f, header_frags = self.get_children_fragment(context, view_name='mentoring_table_header_view')
bg_image_url = self.runtime.local_resource_url(self.xblock_container,
......@@ -66,7 +65,7 @@ class MentoringTableBlock(LightChild):
else:
raise
fragment.add_content(render_js_template('templates/html/mentoring-table.html', {
fragment.add_content(render_template('templates/html/mentoring-table.html', {
'self': self,
'columns_frags': columns_frags,
'header_frags': header_frags,
......@@ -99,10 +98,10 @@ class MentoringTableColumnBlock(LightChild):
"""
The content of the column
"""
fragment, named_children = self.get_children_fragment(context,
view_name='mentoring_table_view',
not_instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_js_template('templates/html/mentoring-table-column.html', {
fragment, named_children = self.get_children_fragment(
context, view_name='mentoring_table_view',
not_instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_template('templates/html/mentoring-table-column.html', {
'self': self,
'named_children': named_children,
}))
......@@ -112,10 +111,10 @@ class MentoringTableColumnBlock(LightChild):
"""
The content of the column's header
"""
fragment, named_children = self.get_children_fragment(context,
view_name='mentoring_table_header_view',
instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_js_template('templates/html/mentoring-table-header.html', {
fragment, named_children = self.get_children_fragment(
context, view_name='mentoring_table_header_view',
instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_template('templates/html/mentoring-table-header.html', {
'self': self,
'named_children': named_children,
}))
......@@ -127,9 +126,8 @@ class MentoringTableColumnHeaderBlock(LightChild):
Header content for a given column
"""
content = String(help="Body of the header", scope=Scope.content, default='')
def mentoring_table_header_view(self, context):
fragment = super(MentoringTableColumnHeaderBlock, self).children_view(context)
fragment.add_content(unicode(self.content))
return fragment
......@@ -23,24 +23,28 @@
# Imports ###########################################################
import time
from selenium.webdriver.support.ui import WebDriverWait
from workbench import scenarios
from workbench.test.selenium_test import SeleniumTest
from .utils import load_scenarios_from_path
# Classes ###########################################################
class MentoringBaseTest(SeleniumTest):
def setUp(self):
super(MentoringBaseTest, self).setUp()
# Use test scenarios
self.browser.get(self.live_server_url) # Needed to load tests once
self.browser.get(self.live_server_url) # Needed to load tests once
scenarios.SCENARIOS.clear()
scenarios_list = load_scenarios_from_path('../tests/xml')
scenarios_list = load_scenarios_from_path('../tests/integration/xml')
for identifier, title, xml in scenarios_list:
scenarios.add_xml_scenario(identifier, title, xml)
self.addCleanup(scenarios.remove_scenario, identifier)
# Suzy opens the browser to visit the workbench
......@@ -50,6 +54,18 @@ class MentoringBaseTest(SeleniumTest):
header1 = self.browser.find_element_by_css_selector('h1')
self.assertEqual(header1.text, 'XBlock scenarios')
def wait_until_disabled(self, submit):
wait = WebDriverWait(submit, 10)
wait.until(lambda s: not s.is_enabled(), "{} should be disabled".format(submit.text))
def wait_until_clickable(self, submit):
wait = WebDriverWait(submit, 10)
wait.until(lambda s: s.is_displayed() and s.is_enabled(), "{} should be cliclable".format(submit.text))
def wait_until_text_in(self, text, elem):
wait = WebDriverWait(elem, 10)
wait.until(lambda elem: text in elem.text, "{} should be in {}".format(text, elem.text))
def go_to_page(self, page_name, css_selector='div.mentoring'):
"""
Navigate to the page `page_name`, as listed on the workbench home
......@@ -57,6 +73,6 @@ class MentoringBaseTest(SeleniumTest):
"""
self.browser.get(self.live_server_url)
self.browser.find_element_by_link_text(page_name).click()
time.sleep(1)
mentoring = self.browser.find_element_by_css_selector(css_selector)
return mentoring
......@@ -45,10 +45,9 @@ def commas_to_set(commas_str):
else:
return set(commas_str.split(','))
# Classes ###########################################################
class TipBlock(LightChild):
"""
Each choice can define a tip depending on selection
......
......@@ -33,6 +33,7 @@ log = logging.getLogger(__name__)
# Classes ###########################################################
class TitleBlock(LightChild):
"""
A simple html representation of a title, with the mentoring weight.
......
<vertical>
<mentoring url_name="mentoring_first" followed_by="progression_2">
<answer name="progression_1_answer" />
</mentoring>
</vertical>
<vertical>
<mentoring url_name="progression_2" followed_by="progression_3">
<answer name="progression_2_answer" />
</mentoring>
</vertical>
<vertical>
<mentoring url_name="progression_3">
<answer name="progression_3_answer" />
</mentoring>
</vertical>
......@@ -29,11 +29,11 @@ from mentoring.test_base import MentoringBaseTest
# Classes ###########################################################
class AnswerBlockTest(MentoringBaseTest):
def test_answer_edit(self):
"""
Answers of same name should share value accross blocks
"""
# Answer should initially be blank on all instances with the same answer name
mentoring = self.go_to_page('Answer Edit 2')
answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea')
......@@ -47,37 +47,40 @@ class AnswerBlockTest(MentoringBaseTest):
self.assertEqual(header1.text, 'XBlock: Answer Edit 1')
# Check <html> child
p = mentoring.find_element_by_css_selector('div.xblock > p')
p = mentoring.find_element_by_css_selector('div.xblock p')
self.assertEqual(p.text, 'This should be displayed in the answer_edit scenario')
# Initial unsubmitted text
answer1 = mentoring.find_element_by_css_selector('textarea')
self.assertEqual(answer1.text, '')
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
# Submit without answer
submit = mentoring.find_element_by_css_selector('input.submit')
submit.click()
self.assertEqual(answer1.get_attribute('value'), '')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
# Submit is disabled for empty answer
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertFalse(submit.is_enabled())
# Submit an answer
# Filling in the answer enables the submit button
answer1.send_keys('This is the answer')
self.assertTrue(submit.is_enabled())
submit.click()
self.wait_until_disabled(submit)
self.assertEqual(answer1.get_attribute('value'), 'This is the answer')
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
# Modifying the answer re-enables submission
answer1.send_keys('. It has a second statement.')
self.assertTrue(submit.is_enabled())
# Submitting a new answer overwrites the previous one
submit.click()
self.wait_until_disabled(submit)
self.assertEqual(answer1.get_attribute('value'), 'This is the answer. It has a second statement.')
# Answer content should show on a different instance with the same name
mentoring = self.go_to_page('Answer Edit 2')
answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea')
answer1_readonly = mentoring.find_element_by_css_selector('blockquote.answer.read_only')
self.assertEqual(answer1_bis.get_attribute('value'), 'This is the answer')
self.assertEqual(answer1_readonly.text, 'This is the answer')
self.assertEqual(answer1_bis.get_attribute('value'), 'This is the answer. It has a second statement.')
self.assertEqual(answer1_readonly.text, 'This is the answer. It has a second statement.')
def test_answer_blank_read_only(self):
"""
......@@ -87,12 +90,11 @@ class AnswerBlockTest(MentoringBaseTest):
mentoring = self.go_to_page('Answer Blank Read Only')
answer = mentoring.find_element_by_css_selector('blockquote.answer.read_only')
self.assertEqual(answer.text, '')
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
# Submit should allow to complete
submit = mentoring.find_element_by_css_selector('input.submit')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertTrue(submit.is_enabled())
submit.click()
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
# Submit is disabled after submission
self.wait_until_disabled(submit)
from mentoring.test_base import MentoringBaseTest
class MentoringAssessmentTest(MentoringBaseTest):
def _selenium_bug_workaround_scroll_to(self, mentoring):
"""Workaround for selenium bug:
Some version of Selenium has a bug that prevents scrolling
to radiobuttons before being clicked. The click not taking
place, when it's outside the view.
Since the bug does not affect other content, asking Selenium
to click on the legend first, will properly scroll it.
It also have it's fair share of issues with the workbench header.
For this reason we click on the bottom-most element, scrolling to it.
Then, click on the title of the question (also scrolling to it)
hopefully, this gives us enough room for the full step with the
control buttons to fit.
"""
controls = mentoring.find_element_by_css_selector("div.submit")
title = mentoring.find_element_by_css_selector("h3.question-title")
controls.click()
title.click()
def assert_hidden(self, elem):
self.assertFalse(elem.is_displayed())
def assert_disabled(self, elem):
self.assertTrue(elem.is_displayed())
self.assertFalse(elem.is_enabled())
def assert_clickable(self, elem):
self.assertTrue(elem.is_displayed())
self.assertTrue(elem.is_enabled())
def assert_persistent_elements_present(self, mentoring):
self.assertIn("A Simple Assessment", mentoring.text)
self.assertIn("This paragraph is shared between all questions.", mentoring.text)
def assert_disabled(self, elem):
self.assertTrue(elem.is_displayed())
self.assertFalse(elem.is_enabled())
class _GetChoices(object):
def __init__(self, mentoring, selector=".choices"):
self._mcq = mentoring.find_element_by_css_selector(selector)
@property
def text(self):
return self._mcq.text
@property
def state(self):
return {
choice.text: choice.find_element_by_css_selector("input").is_selected()
for choice in self._mcq.find_elements_by_css_selector(".choice")}
def select(self, text):
state = {}
for choice in self._mcq.find_elements_by_css_selector(".choice"):
if choice.text == text:
choice.find_element_by_css_selector("input").click()
return
raise AssertionError("Expected selectable item present: {}".format(text))
def test_assessment(self):
# step 1 -- freeform answer
mentoring = self.go_to_page('Assessment 1')
self.assert_persistent_elements_present(mentoring)
self._selenium_bug_workaround_scroll_to(mentoring)
submit = mentoring.find_element_by_css_selector("input.input-main")
next_question = mentoring.find_element_by_css_selector("input.input-next")
review = mentoring.find_element_by_css_selector("input.input-review")
try_again = mentoring.find_element_by_css_selector("input.input-try-again")
answer = mentoring.find_element_by_css_selector("textarea.answer.editable")
self.assertIn("Please answer the questions below.", mentoring.text)
self.assertIn("QUESTION 1", mentoring.text)
self.assertIn("What is your goal?", mentoring.text)
self.assertEquals("", answer.get_attribute("value"))
self.assert_disabled(submit)
self.assert_disabled(next_question)
answer.send_keys('This is the answer')
self.assertEquals('This is the answer', answer.get_attribute("value"))
self.assert_clickable(submit)
self.assert_disabled(next_question)
self.assert_hidden(review)
self.assert_hidden(try_again)
submit.click()
self.wait_until_clickable(next_question)
next_question.click()
# step 2 -- single choice question
self.wait_until_text_in("QUESTION 2", mentoring)
self.assert_persistent_elements_present(mentoring)
self._selenium_bug_workaround_scroll_to(mentoring)
self.assertIn("Do you like this MCQ?", mentoring.text)
self.assert_disabled(submit)
self.assert_disabled(next_question)
self.assert_hidden(review)
self.assert_hidden(try_again)
choices = self._GetChoices(mentoring)
self.assertEquals(choices.state, {"Yes": False, "Maybe not": False, "I don't understand": False})
choices.select("Yes")
self.assertEquals(choices.state, {"Yes": True, "Maybe not": False, "I don't understand": False})
self.assert_clickable(submit)
self.assert_disabled(next_question)
self.assert_hidden(review)
self.assert_hidden(try_again)
submit.click()
self.wait_until_clickable(next_question)
next_question.click()
# step 3 -- rating question
self.wait_until_text_in("QUESTION 3", mentoring)
self.assert_persistent_elements_present(mentoring)
self._selenium_bug_workaround_scroll_to(mentoring)
self.assertIn("How much do you rate this MCQ?", mentoring.text)
self.assert_disabled(submit)
self.assert_disabled(next_question)
self.assert_hidden(review)
self.assert_hidden(try_again)
choices = self._GetChoices(mentoring, ".rating")
self.assertEquals(choices.state, {
"1 - Not good at all": False,
"2": False, "3": False, "4": False,
"5 - Extremely good": False,
"I don't want to rate it": False,
})
choices.select("5 - Extremely good")
self.assertEquals(choices.state, {
"1 - Not good at all": False,
"2": False, "3": False, "4": False,
"5 - Extremely good": True,
"I don't want to rate it": False,
})
self.assert_clickable(submit)
self.assert_disabled(next_question)
self.assert_hidden(review)
self.assert_hidden(try_again)
submit.click()
self.wait_until_clickable(next_question)
next_question.click()
# step 4 -- multiple choice question
self.wait_until_text_in("QUESTION 4", mentoring)
self.assert_persistent_elements_present(mentoring)
self._selenium_bug_workaround_scroll_to(mentoring)
self.assertIn("What do you like in this MRQ?", mentoring.text)
self.assert_disabled(submit)
self.assert_hidden(next_question)
self.assert_disabled(review)
self.assert_hidden(try_again)
# see if assessment remembers the current step
self.browser.get(self.live_server_url)
# step 4 -- a second time
mentoring = self.go_to_page("Assessment 1")
self.wait_until_text_in("QUESTION 4", mentoring)
self.assert_persistent_elements_present(mentoring)
self._selenium_bug_workaround_scroll_to(mentoring)
self.assertIn("What do you like in this MRQ?", mentoring.text)
submit = mentoring.find_element_by_css_selector("input.input-main")
next_question = mentoring.find_element_by_css_selector("input.input-next")
review = mentoring.find_element_by_css_selector("input.input-review")
try_again = mentoring.find_element_by_css_selector("input.input-try-again")
self.assert_disabled(submit)
self.assert_hidden(next_question)
self.assert_disabled(review)
self.assert_hidden(try_again)
choices = self._GetChoices(mentoring)
self.assertEquals(choices.state, {
"Its elegance": False,
"Its beauty": False,
"Its gracefulness": False,
"Its bugs": False,
})
choices.select("Its elegance")
choices.select("Its beauty")
choices.select("Its gracefulness")
self.assertEquals(choices.state, {
"Its elegance": True,
"Its beauty": True,
"Its gracefulness": True,
"Its bugs": False,
})
self.assert_clickable(submit)
self.assert_hidden(next_question)
self.assert_disabled(review)
self.assert_hidden(try_again)
submit.click()
self.wait_until_clickable(review)
review.click()
# step 5 -- review
self.wait_until_text_in("You scored 100% on this assessment.", mentoring)
self.assert_persistent_elements_present(mentoring)
self.assertIn("Note: if you retake this assessment, only your final score counts.", mentoring.text)
self.assertIn("You answered 4 questions correctly.", mentoring.text)
self.assertIn("You answered 0 questions incorrectly.", mentoring.text)
self.assert_hidden(submit)
self.assert_hidden(next_question)
self.assert_hidden(review)
self.assert_disabled(try_again)
......@@ -23,8 +23,6 @@
# Imports ###########################################################
import time
from mentoring.test_base import MentoringBaseTest
......@@ -33,29 +31,43 @@ from mentoring.test_base import MentoringBaseTest
class MCQBlockTest(MentoringBaseTest):
def _selenium_bug_workaround_scroll_to(self, mcq_legend):
"""Workaround for selenium bug:
Some version of Selenium has a bug that prevents scrolling
to radiobuttons before being clicked. The click not taking
place, when it's outside the view.
Since the bug does not affect other content, asking Selenium
to click on the legend first, will properly scroll it.
"""
mcq_legend.click()
def _get_inputs(self, choices):
return [choice.find_element_by_css_selector('input') for choice in choices]
def test_mcq_choices_rating(self):
"""
Mentoring MCQ should display tips according to user choice
"""
# Initial MCQ status
mentoring = self.go_to_page('MCQ 1')
mentoring = self.go_to_page('Mcq 1')
mcq1 = mentoring.find_element_by_css_selector('fieldset.choices')
mcq2 = mentoring.find_element_by_css_selector('fieldset.rating')
messages = mentoring.find_element_by_css_selector('.messages')
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertEqual(messages.text, '')
self.assertFalse(messages.find_elements_by_xpath('./*'))
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
self.assertFalse(submit.is_enabled())
mcq1_legend = mcq1.find_element_by_css_selector('legend')
mcq2_legend = mcq2.find_element_by_css_selector('legend')
self.assertEqual(mcq1_legend.text, 'Do you like this MCQ?')
self.assertEqual(mcq2_legend.text, 'How much do you rate this MCQ?')
self.assertEqual(mcq1_legend.text, 'QUESTION 1\nDo you like this MCQ?')
self.assertEqual(mcq2_legend.text, 'QUESTION 2\nHow much do you rate this MCQ?')
mcq1_choices = mcq1.find_elements_by_css_selector('.choices .choice label')
mcq2_choices = mcq2.find_elements_by_css_selector('.choices .choice label')
mcq2_choices = mcq2.find_elements_by_css_selector('.rating .choice label')
self.assertEqual(len(mcq1_choices), 3)
self.assertEqual(len(mcq2_choices), 6)
......@@ -69,19 +81,9 @@ class MCQBlockTest(MentoringBaseTest):
self.assertEqual(mcq2_choices[4].text, '5')
self.assertEqual(mcq2_choices[5].text, "I don't want to rate it")
mcq1_choices_input = [
mcq1_choices[0].find_element_by_css_selector('input'),
mcq1_choices[1].find_element_by_css_selector('input'),
mcq1_choices[2].find_element_by_css_selector('input'),
]
mcq2_choices_input = [
mcq2_choices[0].find_element_by_css_selector('input'),
mcq2_choices[1].find_element_by_css_selector('input'),
mcq2_choices[2].find_element_by_css_selector('input'),
mcq2_choices[3].find_element_by_css_selector('input'),
mcq2_choices[4].find_element_by_css_selector('input'),
mcq2_choices[5].find_element_by_css_selector('input'),
]
mcq1_choices_input = self._get_inputs(mcq1_choices)
mcq2_choices_input = self._get_inputs(mcq2_choices)
self.assertEqual(mcq1_choices_input[0].get_attribute('value'), 'yes')
self.assertEqual(mcq1_choices_input[1].get_attribute('value'), 'maybenot')
self.assertEqual(mcq1_choices_input[2].get_attribute('value'), 'understand')
......@@ -92,83 +94,62 @@ class MCQBlockTest(MentoringBaseTest):
self.assertEqual(mcq2_choices_input[4].get_attribute('value'), '5')
self.assertEqual(mcq2_choices_input[5].get_attribute('value'), 'notwant')
# Submit without selecting anything
submit = mentoring.find_element_by_css_selector('input.submit')
submit.click()
tips = messages.find_elements_by_xpath('./*')
self.assertEqual(len(tips), 2)
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you have not provided an answer.')
self.assertEqual(tips[1].text, 'To the question "How much do you rate this MCQ?", you have not provided an answer.')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
# Submit button disabled without selecting anything
self.assertFalse(submit.is_enabled())
# Select only one option
# Submit button stays disabled when there are unfinished mcqs
self._selenium_bug_workaround_scroll_to(mcq1)
mcq1_choices_input[1].click()
submit.click()
time.sleep(1)
tips = messages.find_elements_by_xpath('./*')
self.assertEqual(len(tips), 2)
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you answered "Maybe not".\nAh, damn.')
self.assertEqual(tips[1].text, 'To the question "How much do you rate this MCQ?", you have not provided an answer.')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
self.assertFalse(submit.is_enabled())
# One with only display tip, one with reject tip - should not complete
# Should not show full completion message when wrong answers are selected
self._selenium_bug_workaround_scroll_to(mcq1)
mcq1_choices_input[0].click()
mcq2_choices_input[2].click()
self.assertTrue(submit.is_enabled())
submit.click()
self.wait_until_disabled(submit)
time.sleep(1)
tips = messages.find_elements_by_xpath('./*')
self.assertEqual(len(tips), 2)
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you answered "Yes".\nGreat!')
self.assertEqual(tips[1].text, 'To the question "How much do you rate this MCQ?", you answered "3".\nWill do better next time...')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
self.assertEqual(mcq1.find_element_by_css_selector(".feedback").text, 'Great!')
self.assertEqual(mcq2.find_element_by_css_selector(".feedback").text, 'Will do better next time...')
self.assertEqual(messages.text, '')
self.assertFalse(messages.is_displayed())
# Only display tips, to allow to complete
# Should show full completion when the right answers are selected
self._selenium_bug_workaround_scroll_to(mcq1)
mcq1_choices_input[0].click()
mcq2_choices_input[3].click()
self.assertTrue(submit.is_enabled())
submit.click()
self.wait_until_disabled(submit)
time.sleep(1)
tips = messages.find_elements_by_xpath('./*')
self.assertEqual(len(tips), 3)
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you answered "Yes".\nGreat!')
self.assertEqual(tips[1].text, 'To the question "How much do you rate this MCQ?", you answered "4".\nI love good grades.')
self.assertEqual(tips[2].text, 'Congratulations!\nAll is good now...') # Includes child <html>
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
self.assertEqual(mcq1.find_element_by_css_selector(".feedback").text, 'Great!')
self.assertEqual(mcq2.find_element_by_css_selector(".feedback").text, 'I love good grades.')
self.assertIn('All is good now...\nCongratulations!', messages.text)
self.assertTrue(messages.is_displayed())
def test_mcq_with_comments(self):
mentoring = self.go_to_page('MCQ With Comments 1')
mentoring = self.go_to_page('Mcq With Comments 1')
mcq = mentoring.find_element_by_css_selector('fieldset.choices')
messages = mentoring.find_element_by_css_selector('.messages')
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertEqual(messages.text, '')
self.assertFalse(messages.find_elements_by_xpath('./*'))
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
self.assertFalse(submit.is_enabled())
mcq_legend = mcq.find_element_by_css_selector('legend')
self.assertEqual(mcq_legend.text, 'Do you like this MCQ?')
self.assertEqual(mcq_legend.text, 'QUESTION\nWhat do you like in this MRQ?')
mcq_choices = mcq.find_elements_by_css_selector('.choices .choice label')
self.assertEqual(len(mcq_choices), 3)
self.assertEqual(len(mcq_choices), 4)
self.assertEqual(mcq_choices[0].text, 'Its elegance')
self.assertEqual(mcq_choices[1].text, 'Its beauty')
self.assertEqual(mcq_choices[2].text, "Its gracefulness")
self.assertEqual(mcq_choices[3].text, "Its bugs")
mcq_choices_input = [
mcq_choices[0].find_element_by_css_selector('input'),
mcq_choices[1].find_element_by_css_selector('input'),
mcq_choices[2].find_element_by_css_selector('input'),
]
mcq_choices_input = self._get_inputs(mcq_choices)
self.assertEqual(mcq_choices_input[0].get_attribute('value'), 'elegance')
self.assertEqual(mcq_choices_input[1].get_attribute('value'), 'beauty')
self.assertEqual(mcq_choices_input[2].get_attribute('value'), 'gracefulness')
......
......@@ -35,55 +35,50 @@ class MentoringProgressionTest(MentoringBaseTest):
Check that the provided DOM element is a progression warning, and includes a link with a href
pointing to `link_href`
"""
self.assertEqual(warning_dom.text, 'You need to complete the following step before attempting this step.')
self.assertEqual(warning_dom.text, 'You need to complete the previous step before attempting this step.')
warning_link = warning_dom.find_element_by_xpath('./*')
link_href = 'http://localhost:8081{}'.format(link_href)
self.assertEqual(warning_link.get_attribute('href'), link_href)
def assert_warning_is_hidden(self, mentoring):
for elem in mentoring.find_elements_by_css_selector('.warning'):
self.assertFalse(elem.is_displayed())
def test_progression(self):
"""
Mentoring blocks after the current step in the workflow should redirect user to current step
"""
# Initial - Step 1 ok, steps 2&3 redirect to step 1
mentoring = self.go_to_page('Progression 1')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
mentoring = self.go_to_page('Progression 2')
warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first')
mentoring = self.go_to_page('Progression 3')
warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first')
# Submit step 1 without completing it - no change should be registered
mentoring = self.go_to_page('Progression 1')
submit = mentoring.find_element_by_css_selector('input.submit')
submit.click()
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
self.assert_warning_is_hidden(mentoring)
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertFalse(submit.is_enabled())
mentoring = self.go_to_page('Progression 2')
warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertFalse(submit.is_enabled())
mentoring = self.go_to_page('Progression 3')
warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self.assertFalse(submit.is_enabled())
# Should be impossible to complete step 2
mentoring = self.go_to_page('Progression 2')
answer = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer')
submit = mentoring.find_element_by_css_selector('input.submit')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
submit.click()
self.wait_until_disabled(submit)
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
messages = mentoring.find_element_by_css_selector('.messages')
self.assertTrue(messages.is_displayed())
self.assertIn(
'You need to complete all previous steps before being able to complete the current one.',
messages.text)
mentoring = self.go_to_page('Progression 2')
warning = mentoring.find_element_by_css_selector('.warning')
......@@ -97,47 +92,44 @@ class MentoringProgressionTest(MentoringBaseTest):
mentoring = self.go_to_page('Progression 1')
answer = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer')
submit = mentoring.find_element_by_css_selector('input.submit')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
submit.click()
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
self.wait_until_disabled(submit)
self.assert_warning_is_hidden(mentoring)
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
mentoring = self.go_to_page('Progression 2')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
messages = mentoring.find_element_by_css_selector('.messages')
self.assertFalse(messages.is_displayed())
mentoring = self.go_to_page('Progression 3')
warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/progression_2')
# Complete step 2 - no more warnings anywhere
mentoring = self.go_to_page('Progression 2')
submit = mentoring.find_element_by_css_selector('input.submit')
submit.click() # Already filled the textarea in previous step
self.assert_warning_is_hidden(mentoring)
# Complete step 2 - no more warnings anywhere
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
submit.click() # Already filled the textarea in previous step
self.wait_until_disabled(submit)
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
messages = mentoring.find_element_by_css_selector('.messages')
self.assertFalse(messages.is_displayed())
mentoring = self.go_to_page('Progression 1')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
self.assert_warning_is_hidden(mentoring)
mentoring = self.go_to_page('Progression 2')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
self.assert_warning_is_hidden(mentoring)
mentoring = self.go_to_page('Progression 3')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning'))
self.assert_warning_is_hidden(mentoring)
# Should be able to complete step 3 too now
mentoring = self.go_to_page('Progression 3')
answer = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer')
submit = mentoring.find_element_by_css_selector('input.submit')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
submit.click()
self.wait_until_disabled(submit)
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
self.assertTrue(progress.find_elements_by_css_selector('img'))
messages = mentoring.find_element_by_css_selector('.messages')
self.assertFalse(messages.is_displayed())
......@@ -48,12 +48,12 @@ class MentoringTableBlockTest(MentoringBaseTest):
answers = mentoring.find_elements_by_css_selector('textarea')
answers[0].send_keys('This is the answer #1')
answers[1].send_keys('This is the answer #2')
submit = mentoring.find_element_by_css_selector('input.submit')
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
submit.click()
self.wait_until_disabled(submit)
table = self.go_to_page('Table 2', css_selector='.mentoring-table')
rows = table.find_elements_by_css_selector('td')
self.assertEqual(len(rows), 2)
self.assertEqual(rows[0].text, 'This is the answer #1')
self.assertEqual(rows[1].text, 'This is the answer #2')
<vertical>
<vertical_demo>
<mentoring url_name="answer_blank_read_only" enforce_dependency="false">
<answer name="answer_blank" read_only="true" />
</mentoring>
</vertical>
</vertical_demo>
<vertical>
<vertical_demo>
<mentoring url_name="answer_edit_1" enforce_dependency="false">
<html>
<p>This should be displayed in the answer_edit scenario</p>
......@@ -6,4 +6,4 @@
<answer name="answer_1" />
</mentoring>
</vertical>
</vertical_demo>
<vertical>
<vertical_demo>
<mentoring url_name="answer_edit_2" enforce_dependency="false">
<answer name="answer_1" read_only="true" />
<answer name="answer_1" />
</mentoring>
</vertical>
</vertical_demo>
<mentoring url_name="mentoring-assessment" display_name="Nav tooltip title" weight="1" mode="assessment">
<title>A Simple Assessment</title>
<shared-header>
<p>This paragraph is shared between <strong>all</strong> questions.</p>
</shared-header>
<html>
<p>Please answer the questions below.</p>
</html>
<answer name="goal">
<question>What is your goal?</question>
</answer>
<mcq name="mcq_1_1" type="choices">
<question>Do you like this MCQ?</question>
<choice value="yes">Yes</choice>
<choice value="maybenot">Maybe not</choice>
<choice value="understand">I don't understand</choice>
</mcq>
<mcq name="mcq_1_2" type="rating" low="Not good at all" high="Extremely good">
<question>How much do you rate this MCQ?</question>
<choice value="notwant">I don't want to rate it</choice>
</mcq>
<mrq name="mrq_1_1" type="choices">
<question>What do you like in this MRQ?</question>
<choice value="elegance">Its elegance</choice>
<choice value="beauty">Its beauty</choice>
<choice value="gracefulness">Its gracefulness</choice>
<choice value="bugs">Its bugs</choice>
</mrq>
</mentoring>
<vertical>
<vertical_demo>
<mentoring url_name="mcq_1" enforce_dependency="false">
<mcq name="mcq_1_1" type="choices">
<question>Do you like this MCQ?</question>
......@@ -25,4 +25,4 @@
<html><p>Congratulations!</p></html>
</message>
</mentoring>
</vertical>
</vertical_demo>
<vertical>
<mentoring url_name="mentoring-87043a1f-f14a-4813-b89f-3e051939a7ee" display_name="MRQ Exercise 7" weight="1">
<vertical_demo>
<mentoring url_name="mcq_with_comments" display_name="MRQ Exercise 7" weight="1" enforce_dependency="false">
<title>MRQ With Resizable popups</title>
<mrq name="mrq_1_1_7" type="choices">
<question>What do you like in this MRQ?</question>
......@@ -23,4 +23,4 @@
<html><p>Still some work to do...</p></html>
</message>
</mentoring>
</vertical>
</vertical_demo>
<vertical_demo>
<mentoring url_name="mentoring_first" followed_by="progression_2" enforce_dependency="true">
<answer name="progression_1_answer" />
</mentoring>
</vertical_demo>
<vertical_demo>
<mentoring url_name="progression_2" followed_by="progression_3" enforce_dependency="true">
<answer name="progression_2_answer" />
</mentoring>
</vertical_demo>
<vertical_demo>
<mentoring url_name="progression_3" enforce_dependency="true">
<answer name="progression_3_answer" />
</mentoring>
</vertical_demo>
<vertical>
<vertical_demo>
<mentoring url_name="table_1" enforce_dependency="false">
<answer name="table_1_answer_1" />
<answer name="table_1_answer_2" />
</mentoring>
</vertical>
</vertical_demo>
<vertical>
<vertical_demo>
<mentoring display_submit="false" enforce_dependency="false">
<mentoring-table type="table_test" url_name="table_2">
<column>
......@@ -12,4 +12,4 @@
</column>
</mentoring-table>
</mentoring>
</vertical>
</vertical_demo>
......@@ -6,6 +6,7 @@ from mentoring import MentoringBlock
import mentoring
from mentoring.step import StepMixin, StepParentMixin
class Parent(StepParentMixin):
def get_children_objects(self):
return list(self._children)
......@@ -18,10 +19,15 @@ class Parent(StepParentMixin):
except AttributeError:
pass
class Step(StepMixin):
def __init__(self): pass
def __init__(self):
pass
class NotAStep(object):
pass
class NotAStep(object): pass
class TestStepMixin(unittest.TestCase):
def test_single_step_is_returned_correctly(self):
......@@ -39,7 +45,6 @@ class TestStepMixin(unittest.TestCase):
self.assertSequenceEqual(block.steps, [step1, step2])
def test_proper_number_is_returned_for_step(self):
block = Parent()
step1 = Step()
......@@ -73,4 +78,3 @@ class TestStepMixin(unittest.TestCase):
self.assertFalse(step1.lonely_step)
self.assertFalse(step2.lonely_step)
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