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: ...@@ -518,6 +518,12 @@ following command:
$ DJANGO_SETTINGS_MODULE="workbench.settings_mentoring" nosetests --with-django $ 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, 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. 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). (`/path/to/xblock` is the path to the xblock-sdk, where the workbench resides).
......
...@@ -99,6 +99,8 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin): ...@@ -99,6 +99,8 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin):
@classmethod @classmethod
def add_node_as_child(cls, block, xml_child, child_id): def add_node_as_child(cls, block, xml_child, child_id):
if xml_child.tag is etree.Comment:
return
# Instantiate child # Instantiate child
child_class = cls.get_class_by_element(xml_child.tag) child_class = cls.get_class_by_element(xml_child.tag)
child = child_class(block) child = child_class(block)
......
...@@ -69,7 +69,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -69,7 +69,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
url_name = String(help="Name of the current step, used for URL building", url_name = String(help="Name of the current step, used for URL building",
default='mentoring-default', scope=Scope.content) default='mentoring-default', scope=Scope.content)
enforce_dependency = Boolean(help="Should the next step be the current block to complete?", 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) display_submit = Boolean(help="Allow to submit current block?", default=True, scope=Scope.content)
xml_content = String(help="XML content", default='', scope=Scope.content) xml_content = String(help="XML content", default='', scope=Scope.content)
weight = Float(help="Defines the maximum total grade of the block.", weight = Float(help="Defines the maximum total grade of the block.",
......
...@@ -22,7 +22,6 @@ class Migration(SchemaMigration): ...@@ -22,7 +22,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['student_id', 'name'] # Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name']) db.create_unique('mentoring_answer', ['student_id', 'name'])
def backwards(self, orm): def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['student_id', 'name'] # Removing unique constraint on 'Answer', fields ['student_id', 'name']
db.delete_unique('mentoring_answer', ['student_id', 'name']) db.delete_unique('mentoring_answer', ['student_id', 'name'])
...@@ -30,7 +29,6 @@ class Migration(SchemaMigration): ...@@ -30,7 +29,6 @@ class Migration(SchemaMigration):
# Deleting model 'Answer' # Deleting model 'Answer'
db.delete_table('mentoring_answer') db.delete_table('mentoring_answer')
models = { models = {
'mentoring.answer': { 'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'name'),)", 'object_name': 'Answer'}, 'Meta': {'unique_together': "(('student_id', 'name'),)", 'object_name': 'Answer'},
......
...@@ -13,7 +13,6 @@ class Migration(SchemaMigration): ...@@ -13,7 +13,6 @@ class Migration(SchemaMigration):
self.gf('django.db.models.fields.CharField')(default='default', max_length=50, db_index=True), self.gf('django.db.models.fields.CharField')(default='default', max_length=50, db_index=True),
keep_default=False) keep_default=False)
# Changing field 'Answer.student_id' # Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=32)) db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=32))
...@@ -21,7 +20,6 @@ class Migration(SchemaMigration): ...@@ -21,7 +20,6 @@ class Migration(SchemaMigration):
# Deleting field 'Answer.course_id' # Deleting field 'Answer.course_id'
db.delete_column('mentoring_answer', 'course_id') db.delete_column('mentoring_answer', 'course_id')
# Changing field 'Answer.student_id' # Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=20)) db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=20))
...@@ -38,4 +36,4 @@ class Migration(SchemaMigration): ...@@ -38,4 +36,4 @@ class Migration(SchemaMigration):
} }
} }
complete_apps = ['mentoring'] complete_apps = ['mentoring']
\ No newline at end of file
...@@ -14,7 +14,6 @@ class Migration(SchemaMigration): ...@@ -14,7 +14,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['course_id', 'student_id', 'name'] # Adding unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.create_unique('mentoring_answer', ['course_id', 'student_id', 'name']) db.create_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
def backwards(self, orm): def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['course_id', 'student_id', 'name'] # Removing unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.delete_unique('mentoring_answer', ['course_id', 'student_id', 'name']) db.delete_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
...@@ -22,7 +21,6 @@ class Migration(SchemaMigration): ...@@ -22,7 +21,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'Answer', fields ['student_id', 'name'] # Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name']) db.create_unique('mentoring_answer', ['student_id', 'name'])
models = { models = {
'mentoring.answer': { 'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'}, 'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
...@@ -36,4 +34,4 @@ class Migration(SchemaMigration): ...@@ -36,4 +34,4 @@ class Migration(SchemaMigration):
} }
} }
complete_apps = ['mentoring'] complete_apps = ['mentoring']
\ No newline at end of file
...@@ -23,7 +23,6 @@ class Migration(SchemaMigration): ...@@ -23,7 +23,6 @@ class Migration(SchemaMigration):
# Adding unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name'] # Adding unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.create_unique('mentoring_lightchild', ['student_id', 'course_id', 'name']) db.create_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
def backwards(self, orm): def backwards(self, orm):
# Removing unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name'] # Removing unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.delete_unique('mentoring_lightchild', ['student_id', 'course_id', 'name']) db.delete_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
...@@ -31,7 +30,6 @@ class Migration(SchemaMigration): ...@@ -31,7 +30,6 @@ class Migration(SchemaMigration):
# Deleting model 'LightChild' # Deleting model 'LightChild'
db.delete_table('mentoring_lightchild') db.delete_table('mentoring_lightchild')
models = { models = {
'mentoring.answer': { 'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'}, 'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
......
...@@ -40,4 +40,4 @@ class Migration(SchemaMigration): ...@@ -40,4 +40,4 @@ class Migration(SchemaMigration):
} }
} }
complete_apps = ['mentoring'] complete_apps = ['mentoring']
\ No newline at end of file
...@@ -78,7 +78,7 @@ class QuestionnaireAbstractBlock(LightChild, StepMixin): ...@@ -78,7 +78,7 @@ class QuestionnaireAbstractBlock(LightChild, StepMixin):
as_template = context.get('as_template', True) as_template = context.get('as_template', True)
if str(self.type) not in self.valid_types: 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) template_path = 'templates/html/{}_{}.html'.format(name.lower(), self.type)
......
...@@ -29,7 +29,7 @@ import logging ...@@ -29,7 +29,7 @@ import logging
from xblock.fields import Scope from xblock.fields import Scope
from .light_children import LightChild, String from .light_children import LightChild, String
from .utils import load_resource, render_js_template from .utils import load_resource, render_template
# Globals ########################################################### # Globals ###########################################################
...@@ -50,8 +50,7 @@ class MentoringTableBlock(LightChild): ...@@ -50,8 +50,7 @@ class MentoringTableBlock(LightChild):
has_children = True has_children = True
def student_view(self, context): def student_view(self, context):
fragment, columns_frags = self.get_children_fragment(context, fragment, columns_frags = self.get_children_fragment(context, view_name='mentoring_table_view')
view_name='mentoring_table_view')
f, header_frags = self.get_children_fragment(context, view_name='mentoring_table_header_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, bg_image_url = self.runtime.local_resource_url(self.xblock_container,
...@@ -66,7 +65,7 @@ class MentoringTableBlock(LightChild): ...@@ -66,7 +65,7 @@ class MentoringTableBlock(LightChild):
else: else:
raise raise
fragment.add_content(render_js_template('templates/html/mentoring-table.html', { fragment.add_content(render_template('templates/html/mentoring-table.html', {
'self': self, 'self': self,
'columns_frags': columns_frags, 'columns_frags': columns_frags,
'header_frags': header_frags, 'header_frags': header_frags,
...@@ -99,10 +98,10 @@ class MentoringTableColumnBlock(LightChild): ...@@ -99,10 +98,10 @@ class MentoringTableColumnBlock(LightChild):
""" """
The content of the column The content of the column
""" """
fragment, named_children = self.get_children_fragment(context, fragment, named_children = self.get_children_fragment(
view_name='mentoring_table_view', context, view_name='mentoring_table_view',
not_instance_of=MentoringTableColumnHeaderBlock) not_instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_js_template('templates/html/mentoring-table-column.html', { fragment.add_content(render_template('templates/html/mentoring-table-column.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
...@@ -112,10 +111,10 @@ class MentoringTableColumnBlock(LightChild): ...@@ -112,10 +111,10 @@ class MentoringTableColumnBlock(LightChild):
""" """
The content of the column's header The content of the column's header
""" """
fragment, named_children = self.get_children_fragment(context, fragment, named_children = self.get_children_fragment(
view_name='mentoring_table_header_view', context, view_name='mentoring_table_header_view',
instance_of=MentoringTableColumnHeaderBlock) instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_js_template('templates/html/mentoring-table-header.html', { fragment.add_content(render_template('templates/html/mentoring-table-header.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
...@@ -127,9 +126,8 @@ class MentoringTableColumnHeaderBlock(LightChild): ...@@ -127,9 +126,8 @@ class MentoringTableColumnHeaderBlock(LightChild):
Header content for a given column Header content for a given column
""" """
content = String(help="Body of the header", scope=Scope.content, default='') content = String(help="Body of the header", scope=Scope.content, default='')
def mentoring_table_header_view(self, context): def mentoring_table_header_view(self, context):
fragment = super(MentoringTableColumnHeaderBlock, self).children_view(context) fragment = super(MentoringTableColumnHeaderBlock, self).children_view(context)
fragment.add_content(unicode(self.content)) fragment.add_content(unicode(self.content))
return fragment return fragment
...@@ -23,24 +23,28 @@ ...@@ -23,24 +23,28 @@
# Imports ########################################################### # Imports ###########################################################
import time
from selenium.webdriver.support.ui import WebDriverWait
from workbench import scenarios from workbench import scenarios
from workbench.test.selenium_test import SeleniumTest from workbench.test.selenium_test import SeleniumTest
from .utils import load_scenarios_from_path from .utils import load_scenarios_from_path
# Classes ########################################################### # Classes ###########################################################
class MentoringBaseTest(SeleniumTest): class MentoringBaseTest(SeleniumTest):
def setUp(self): def setUp(self):
super(MentoringBaseTest, self).setUp() super(MentoringBaseTest, self).setUp()
# Use test scenarios # 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.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: for identifier, title, xml in scenarios_list:
scenarios.add_xml_scenario(identifier, title, xml)
self.addCleanup(scenarios.remove_scenario, identifier) self.addCleanup(scenarios.remove_scenario, identifier)
# Suzy opens the browser to visit the workbench # Suzy opens the browser to visit the workbench
...@@ -50,6 +54,18 @@ class MentoringBaseTest(SeleniumTest): ...@@ -50,6 +54,18 @@ class MentoringBaseTest(SeleniumTest):
header1 = self.browser.find_element_by_css_selector('h1') header1 = self.browser.find_element_by_css_selector('h1')
self.assertEqual(header1.text, 'XBlock scenarios') 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'): def go_to_page(self, page_name, css_selector='div.mentoring'):
""" """
Navigate to the page `page_name`, as listed on the workbench home Navigate to the page `page_name`, as listed on the workbench home
...@@ -57,6 +73,6 @@ class MentoringBaseTest(SeleniumTest): ...@@ -57,6 +73,6 @@ class MentoringBaseTest(SeleniumTest):
""" """
self.browser.get(self.live_server_url) self.browser.get(self.live_server_url)
self.browser.find_element_by_link_text(page_name).click() self.browser.find_element_by_link_text(page_name).click()
time.sleep(1)
mentoring = self.browser.find_element_by_css_selector(css_selector) mentoring = self.browser.find_element_by_css_selector(css_selector)
return mentoring return mentoring
...@@ -45,10 +45,9 @@ def commas_to_set(commas_str): ...@@ -45,10 +45,9 @@ def commas_to_set(commas_str):
else: else:
return set(commas_str.split(',')) return set(commas_str.split(','))
# Classes ########################################################### # Classes ###########################################################
class TipBlock(LightChild): class TipBlock(LightChild):
""" """
Each choice can define a tip depending on selection Each choice can define a tip depending on selection
......
...@@ -33,6 +33,7 @@ log = logging.getLogger(__name__) ...@@ -33,6 +33,7 @@ log = logging.getLogger(__name__)
# Classes ########################################################### # Classes ###########################################################
class TitleBlock(LightChild): class TitleBlock(LightChild):
""" """
A simple html representation of a title, with the mentoring weight. 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 ...@@ -29,11 +29,11 @@ from mentoring.test_base import MentoringBaseTest
# Classes ########################################################### # Classes ###########################################################
class AnswerBlockTest(MentoringBaseTest): class AnswerBlockTest(MentoringBaseTest):
def test_answer_edit(self): def test_answer_edit(self):
""" """
Answers of same name should share value accross blocks Answers of same name should share value accross blocks
""" """
# Answer should initially be blank on all instances with the same answer name # Answer should initially be blank on all instances with the same answer name
mentoring = self.go_to_page('Answer Edit 2') mentoring = self.go_to_page('Answer Edit 2')
answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea') answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea')
...@@ -47,37 +47,40 @@ class AnswerBlockTest(MentoringBaseTest): ...@@ -47,37 +47,40 @@ class AnswerBlockTest(MentoringBaseTest):
self.assertEqual(header1.text, 'XBlock: Answer Edit 1') self.assertEqual(header1.text, 'XBlock: Answer Edit 1')
# Check <html> child # 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') self.assertEqual(p.text, 'This should be displayed in the answer_edit scenario')
# Initial unsubmitted text # Initial unsubmitted text
answer1 = mentoring.find_element_by_css_selector('textarea') answer1 = mentoring.find_element_by_css_selector('textarea')
self.assertEqual(answer1.text, '') 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 is disabled for empty 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(submit.is_enabled())
self.assertEqual(answer1.get_attribute('value'), '')
self.assertEqual(progress.text, '')
self.assertFalse(progress.find_elements_by_xpath('./*'))
# Submit an answer # Filling in the answer enables the submit button
answer1.send_keys('This is the answer') answer1.send_keys('This is the answer')
self.assertTrue(submit.is_enabled())
submit.click() submit.click()
self.wait_until_disabled(submit)
self.assertEqual(answer1.get_attribute('value'), 'This is the answer') 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 # Answer content should show on a different instance with the same name
mentoring = self.go_to_page('Answer Edit 2') mentoring = self.go_to_page('Answer Edit 2')
answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea') answer1_bis = mentoring.find_element_by_css_selector('.xblock textarea')
answer1_readonly = mentoring.find_element_by_css_selector('blockquote.answer.read_only') 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_bis.get_attribute('value'), 'This is the answer. It has a second statement.')
self.assertEqual(answer1_readonly.text, 'This is the answer') self.assertEqual(answer1_readonly.text, 'This is the answer. It has a second statement.')
def test_answer_blank_read_only(self): def test_answer_blank_read_only(self):
""" """
...@@ -87,12 +90,11 @@ class AnswerBlockTest(MentoringBaseTest): ...@@ -87,12 +90,11 @@ class AnswerBlockTest(MentoringBaseTest):
mentoring = self.go_to_page('Answer Blank Read Only') mentoring = self.go_to_page('Answer Blank Read Only')
answer = mentoring.find_element_by_css_selector('blockquote.answer.read_only') answer = mentoring.find_element_by_css_selector('blockquote.answer.read_only')
self.assertEqual(answer.text, '') self.assertEqual(answer.text, '')
progress = mentoring.find_element_by_css_selector('.progress > .indicator')
self.assertEqual(progress.text, '')
# Submit should allow to complete # 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() 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 @@ ...@@ -23,8 +23,6 @@
# Imports ########################################################### # Imports ###########################################################
import time
from mentoring.test_base import MentoringBaseTest from mentoring.test_base import MentoringBaseTest
...@@ -33,29 +31,43 @@ from mentoring.test_base import MentoringBaseTest ...@@ -33,29 +31,43 @@ from mentoring.test_base import MentoringBaseTest
class MCQBlockTest(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): def test_mcq_choices_rating(self):
""" """
Mentoring MCQ should display tips according to user choice Mentoring MCQ should display tips according to user choice
""" """
# Initial MCQ status # 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') mcq1 = mentoring.find_element_by_css_selector('fieldset.choices')
mcq2 = mentoring.find_element_by_css_selector('fieldset.rating') mcq2 = mentoring.find_element_by_css_selector('fieldset.rating')
messages = mentoring.find_element_by_css_selector('.messages') 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.assertEqual(messages.text, '')
self.assertFalse(messages.find_elements_by_xpath('./*')) self.assertFalse(messages.find_elements_by_xpath('./*'))
self.assertEqual(progress.text, '') self.assertFalse(submit.is_enabled())
self.assertFalse(progress.find_elements_by_xpath('./*'))
mcq1_legend = mcq1.find_element_by_css_selector('legend') mcq1_legend = mcq1.find_element_by_css_selector('legend')
mcq2_legend = mcq2.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(mcq1_legend.text, 'QUESTION 1\nDo you like this MCQ?')
self.assertEqual(mcq2_legend.text, 'How much do you rate 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') 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(mcq1_choices), 3)
self.assertEqual(len(mcq2_choices), 6) self.assertEqual(len(mcq2_choices), 6)
...@@ -69,19 +81,9 @@ class MCQBlockTest(MentoringBaseTest): ...@@ -69,19 +81,9 @@ class MCQBlockTest(MentoringBaseTest):
self.assertEqual(mcq2_choices[4].text, '5') self.assertEqual(mcq2_choices[4].text, '5')
self.assertEqual(mcq2_choices[5].text, "I don't want to rate it") self.assertEqual(mcq2_choices[5].text, "I don't want to rate it")
mcq1_choices_input = [ mcq1_choices_input = self._get_inputs(mcq1_choices)
mcq1_choices[0].find_element_by_css_selector('input'), mcq2_choices_input = self._get_inputs(mcq2_choices)
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'),
]
self.assertEqual(mcq1_choices_input[0].get_attribute('value'), 'yes') 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[1].get_attribute('value'), 'maybenot')
self.assertEqual(mcq1_choices_input[2].get_attribute('value'), 'understand') self.assertEqual(mcq1_choices_input[2].get_attribute('value'), 'understand')
...@@ -92,83 +94,62 @@ class MCQBlockTest(MentoringBaseTest): ...@@ -92,83 +94,62 @@ class MCQBlockTest(MentoringBaseTest):
self.assertEqual(mcq2_choices_input[4].get_attribute('value'), '5') self.assertEqual(mcq2_choices_input[4].get_attribute('value'), '5')
self.assertEqual(mcq2_choices_input[5].get_attribute('value'), 'notwant') self.assertEqual(mcq2_choices_input[5].get_attribute('value'), 'notwant')
# Submit without selecting anything # Submit button disabled without selecting anything
submit = mentoring.find_element_by_css_selector('input.submit') self.assertFalse(submit.is_enabled())
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('./*'))
# 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() mcq1_choices_input[1].click()
submit.click() self.assertFalse(submit.is_enabled())
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('./*'))
# 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() mcq1_choices_input[0].click()
mcq2_choices_input[2].click() mcq2_choices_input[2].click()
self.assertTrue(submit.is_enabled())
submit.click() submit.click()
self.wait_until_disabled(submit)
time.sleep(1) self.assertEqual(mcq1.find_element_by_css_selector(".feedback").text, 'Great!')
tips = messages.find_elements_by_xpath('./*') self.assertEqual(mcq2.find_element_by_css_selector(".feedback").text, 'Will do better next time...')
self.assertEqual(len(tips), 2) self.assertEqual(messages.text, '')
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you answered "Yes".\nGreat!') self.assertFalse(messages.is_displayed())
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('./*'))
# 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() mcq1_choices_input[0].click()
mcq2_choices_input[3].click() mcq2_choices_input[3].click()
self.assertTrue(submit.is_enabled())
submit.click() submit.click()
self.wait_until_disabled(submit)
time.sleep(1) self.assertEqual(mcq1.find_element_by_css_selector(".feedback").text, 'Great!')
tips = messages.find_elements_by_xpath('./*') self.assertEqual(mcq2.find_element_by_css_selector(".feedback").text, 'I love good grades.')
self.assertEqual(len(tips), 3) self.assertIn('All is good now...\nCongratulations!', messages.text)
self.assertEqual(tips[0].text, 'To the question "Do you like this MCQ?", you answered "Yes".\nGreat!') self.assertTrue(messages.is_displayed())
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'))
def test_mcq_with_comments(self): 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') mcq = mentoring.find_element_by_css_selector('fieldset.choices')
messages = mentoring.find_element_by_css_selector('.messages') 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.assertEqual(messages.text, '')
self.assertFalse(messages.find_elements_by_xpath('./*')) self.assertFalse(messages.find_elements_by_xpath('./*'))
self.assertEqual(progress.text, '') self.assertFalse(submit.is_enabled())
self.assertFalse(progress.find_elements_by_xpath('./*'))
mcq_legend = mcq.find_element_by_css_selector('legend') 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') 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[0].text, 'Its elegance')
self.assertEqual(mcq_choices[1].text, 'Its beauty') self.assertEqual(mcq_choices[1].text, 'Its beauty')
self.assertEqual(mcq_choices[2].text, "Its gracefulness") self.assertEqual(mcq_choices[2].text, "Its gracefulness")
self.assertEqual(mcq_choices[3].text, "Its bugs") self.assertEqual(mcq_choices[3].text, "Its bugs")
mcq_choices_input = [ mcq_choices_input = self._get_inputs(mcq_choices)
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'),
]
self.assertEqual(mcq_choices_input[0].get_attribute('value'), 'elegance') 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[1].get_attribute('value'), 'beauty')
self.assertEqual(mcq_choices_input[2].get_attribute('value'), 'gracefulness') self.assertEqual(mcq_choices_input[2].get_attribute('value'), 'gracefulness')
......
...@@ -35,55 +35,50 @@ class MentoringProgressionTest(MentoringBaseTest): ...@@ -35,55 +35,50 @@ class MentoringProgressionTest(MentoringBaseTest):
Check that the provided DOM element is a progression warning, and includes a link with a href Check that the provided DOM element is a progression warning, and includes a link with a href
pointing to `link_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('./*') warning_link = warning_dom.find_element_by_xpath('./*')
link_href = 'http://localhost:8081{}'.format(link_href) link_href = 'http://localhost:8081{}'.format(link_href)
self.assertEqual(warning_link.get_attribute('href'), 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): def test_progression(self):
""" """
Mentoring blocks after the current step in the workflow should redirect user to current step 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 # Initial - Step 1 ok, steps 2&3 redirect to step 1
mentoring = self.go_to_page('Progression 1') mentoring = self.go_to_page('Progression 1')
self.assertFalse(mentoring.find_elements_by_css_selector('.warning')) self.assert_warning_is_hidden(mentoring)
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
mentoring = self.go_to_page('Progression 2') self.assertFalse(submit.is_enabled())
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('./*'))
mentoring = self.go_to_page('Progression 2') mentoring = self.go_to_page('Progression 2')
warning = mentoring.find_element_by_css_selector('.warning') warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first') 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') mentoring = self.go_to_page('Progression 3')
warning = mentoring.find_element_by_css_selector('.warning') warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/mentoring_first') 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 # Should be impossible to complete step 2
mentoring = self.go_to_page('Progression 2') mentoring = self.go_to_page('Progression 2')
answer = mentoring.find_element_by_css_selector('textarea') answer = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer') 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() submit.click()
self.wait_until_disabled(submit)
progress = mentoring.find_element_by_css_selector('.progress > .indicator') messages = mentoring.find_element_by_css_selector('.messages')
self.assertEqual(progress.text, '') self.assertTrue(messages.is_displayed())
self.assertFalse(progress.find_elements_by_xpath('./*')) 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') mentoring = self.go_to_page('Progression 2')
warning = mentoring.find_element_by_css_selector('.warning') warning = mentoring.find_element_by_css_selector('.warning')
...@@ -97,47 +92,44 @@ class MentoringProgressionTest(MentoringBaseTest): ...@@ -97,47 +92,44 @@ class MentoringProgressionTest(MentoringBaseTest):
mentoring = self.go_to_page('Progression 1') mentoring = self.go_to_page('Progression 1')
answer = mentoring.find_element_by_css_selector('textarea') answer = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer') 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() 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') messages = mentoring.find_element_by_css_selector('.messages')
self.assertEqual(progress.text, '') self.assertFalse(messages.is_displayed())
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'))
mentoring = self.go_to_page('Progression 3') mentoring = self.go_to_page('Progression 3')
warning = mentoring.find_element_by_css_selector('.warning') warning = mentoring.find_element_by_css_selector('.warning')
self.assert_warning(warning, '/jump_to_id/progression_2') self.assert_warning(warning, '/jump_to_id/progression_2')
# Complete step 2 - no more warnings anywhere
mentoring = self.go_to_page('Progression 2') mentoring = self.go_to_page('Progression 2')
submit = mentoring.find_element_by_css_selector('input.submit') self.assert_warning_is_hidden(mentoring)
submit.click() # Already filled the textarea in previous step
# 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') messages = mentoring.find_element_by_css_selector('.messages')
self.assertEqual(progress.text, '') self.assertFalse(messages.is_displayed())
self.assertTrue(progress.find_elements_by_css_selector('img'))
mentoring = self.go_to_page('Progression 1') 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') 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') 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 # 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 = mentoring.find_element_by_css_selector('textarea')
answer.send_keys('This is the answer') 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() submit.click()
self.wait_until_disabled(submit)
progress = mentoring.find_element_by_css_selector('.progress > .indicator') messages = mentoring.find_element_by_css_selector('.messages')
self.assertEqual(progress.text, '') self.assertFalse(messages.is_displayed())
self.assertTrue(progress.find_elements_by_css_selector('img'))
...@@ -48,12 +48,12 @@ class MentoringTableBlockTest(MentoringBaseTest): ...@@ -48,12 +48,12 @@ class MentoringTableBlockTest(MentoringBaseTest):
answers = mentoring.find_elements_by_css_selector('textarea') answers = mentoring.find_elements_by_css_selector('textarea')
answers[0].send_keys('This is the answer #1') answers[0].send_keys('This is the answer #1')
answers[1].send_keys('This is the answer #2') 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() submit.click()
self.wait_until_disabled(submit)
table = self.go_to_page('Table 2', css_selector='.mentoring-table') table = self.go_to_page('Table 2', css_selector='.mentoring-table')
rows = table.find_elements_by_css_selector('td') rows = table.find_elements_by_css_selector('td')
self.assertEqual(len(rows), 2) self.assertEqual(len(rows), 2)
self.assertEqual(rows[0].text, 'This is the answer #1') self.assertEqual(rows[0].text, 'This is the answer #1')
self.assertEqual(rows[1].text, 'This is the answer #2') self.assertEqual(rows[1].text, 'This is the answer #2')
<vertical> <vertical_demo>
<mentoring url_name="answer_blank_read_only" enforce_dependency="false"> <mentoring url_name="answer_blank_read_only" enforce_dependency="false">
<answer name="answer_blank" read_only="true" /> <answer name="answer_blank" read_only="true" />
</mentoring> </mentoring>
</vertical> </vertical_demo>
<vertical> <vertical_demo>
<mentoring url_name="answer_edit_1" enforce_dependency="false"> <mentoring url_name="answer_edit_1" enforce_dependency="false">
<html> <html>
<p>This should be displayed in the answer_edit scenario</p> <p>This should be displayed in the answer_edit scenario</p>
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
<answer name="answer_1" /> <answer name="answer_1" />
</mentoring> </mentoring>
</vertical> </vertical_demo>
<vertical> <vertical_demo>
<mentoring url_name="answer_edit_2" enforce_dependency="false"> <mentoring url_name="answer_edit_2" enforce_dependency="false">
<answer name="answer_1" read_only="true" /> <answer name="answer_1" read_only="true" />
<answer name="answer_1" /> <answer name="answer_1" />
</mentoring> </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"> <mentoring url_name="mcq_1" enforce_dependency="false">
<mcq name="mcq_1_1" type="choices"> <mcq name="mcq_1_1" type="choices">
<question>Do you like this MCQ?</question> <question>Do you like this MCQ?</question>
...@@ -25,4 +25,4 @@ ...@@ -25,4 +25,4 @@
<html><p>Congratulations!</p></html> <html><p>Congratulations!</p></html>
</message> </message>
</mentoring> </mentoring>
</vertical> </vertical_demo>
<vertical> <vertical_demo>
<mentoring url_name="mentoring-87043a1f-f14a-4813-b89f-3e051939a7ee" display_name="MRQ Exercise 7" weight="1"> <mentoring url_name="mcq_with_comments" display_name="MRQ Exercise 7" weight="1" enforce_dependency="false">
<title>MRQ With Resizable popups</title> <title>MRQ With Resizable popups</title>
<mrq name="mrq_1_1_7" type="choices"> <mrq name="mrq_1_1_7" type="choices">
<question>What do you like in this MRQ?</question> <question>What do you like in this MRQ?</question>
...@@ -23,4 +23,4 @@ ...@@ -23,4 +23,4 @@
<html><p>Still some work to do...</p></html> <html><p>Still some work to do...</p></html>
</message> </message>
</mentoring> </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"> <mentoring url_name="table_1" enforce_dependency="false">
<answer name="table_1_answer_1" /> <answer name="table_1_answer_1" />
<answer name="table_1_answer_2" /> <answer name="table_1_answer_2" />
</mentoring> </mentoring>
</vertical> </vertical_demo>
<vertical> <vertical_demo>
<mentoring display_submit="false" enforce_dependency="false"> <mentoring display_submit="false" enforce_dependency="false">
<mentoring-table type="table_test" url_name="table_2"> <mentoring-table type="table_test" url_name="table_2">
<column> <column>
...@@ -12,4 +12,4 @@ ...@@ -12,4 +12,4 @@
</column> </column>
</mentoring-table> </mentoring-table>
</mentoring> </mentoring>
</vertical> </vertical_demo>
...@@ -6,6 +6,7 @@ from mentoring import MentoringBlock ...@@ -6,6 +6,7 @@ from mentoring import MentoringBlock
import mentoring import mentoring
from mentoring.step import StepMixin, StepParentMixin from mentoring.step import StepMixin, StepParentMixin
class Parent(StepParentMixin): class Parent(StepParentMixin):
def get_children_objects(self): def get_children_objects(self):
return list(self._children) return list(self._children)
...@@ -18,10 +19,15 @@ class Parent(StepParentMixin): ...@@ -18,10 +19,15 @@ class Parent(StepParentMixin):
except AttributeError: except AttributeError:
pass pass
class Step(StepMixin): class Step(StepMixin):
def __init__(self): pass def __init__(self):
pass
class NotAStep(object):
pass
class NotAStep(object): pass
class TestStepMixin(unittest.TestCase): class TestStepMixin(unittest.TestCase):
def test_single_step_is_returned_correctly(self): def test_single_step_is_returned_correctly(self):
...@@ -39,7 +45,6 @@ class TestStepMixin(unittest.TestCase): ...@@ -39,7 +45,6 @@ class TestStepMixin(unittest.TestCase):
self.assertSequenceEqual(block.steps, [step1, step2]) self.assertSequenceEqual(block.steps, [step1, step2])
def test_proper_number_is_returned_for_step(self): def test_proper_number_is_returned_for_step(self):
block = Parent() block = Parent()
step1 = Step() step1 = Step()
...@@ -73,4 +78,3 @@ class TestStepMixin(unittest.TestCase): ...@@ -73,4 +78,3 @@ class TestStepMixin(unittest.TestCase):
self.assertFalse(step1.lonely_step) self.assertFalse(step1.lonely_step)
self.assertFalse(step2.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