Commit ccd692dd by Christina Roberts

Merge pull request #1133 from edx/jkarni/fix/customtag-error

Jkarni/fix/customtag error 
parents 52a47588 d9ba4103
import os
from lettuce import world
from django.conf import settings
def import_file(filename):
world.browser.execute_script("$('input.file-input').css('display', 'block')")
path = os.path.join(settings.COMMON_TEST_DATA_ROOT, "imports", filename)
world.browser.attach_file('course-data', os.path.abspath(path))
world.css_click('input.submit-button')
# Go to course outline
world.click_course_content()
outline_css = 'li.nav-course-courseware-outline a'
world.css_click(outline_css)
def go_to_import():
menu_css = 'li.nav-course-tools'
import_css = 'li.nav-course-tools-import a'
world.css_click(menu_css)
world.css_click(import_css)
...@@ -89,3 +89,13 @@ Feature: CMS.Problem Editor ...@@ -89,3 +89,13 @@ Feature: CMS.Problem Editor
When I edit and compile the High Level Source When I edit and compile the High Level Source
Then my change to the High Level Source is persisted Then my change to the High Level Source is persisted
And when I view the High Level Source I see my changes And when I view the High Level Source I see my changes
Scenario: Exceptions don't cause problem to be uneditable (bug STUD-786)
Given I have an empty course
And I go to the import page
And I import the file "get_html_exception_test.tar.gz"
When I go to the unit "Probability and BMI"
And I click on "edit a draft"
Then I see a message that says "We're having trouble rendering your component"
And I can edit the problem
# disable missing docstring # disable missing docstring
#pylint: disable=C0111 #pylint: disable=C0111
import os
import json
from lettuce import world, step from lettuce import world, step
from nose.tools import assert_equal, assert_true # pylint: disable=E0611 from nose.tools import assert_equal, assert_true # pylint: disable=E0611
from common import type_in_codemirror from common import type_in_codemirror, open_new_course
from course_import import import_file, go_to_import
DISPLAY_NAME = "Display Name" DISPLAY_NAME = "Display Name"
MAXIMUM_ATTEMPTS = "Maximum Attempts" MAXIMUM_ATTEMPTS = "Maximum Attempts"
...@@ -24,7 +28,7 @@ def i_created_blank_common_problem(step): ...@@ -24,7 +28,7 @@ def i_created_blank_common_problem(step):
@step('I edit and select Settings$') @step('I edit and select Settings$')
def i_edit_and_select_settings(step): def i_edit_and_select_settings(_step):
world.edit_component_and_select_settings() world.edit_component_and_select_settings()
...@@ -41,7 +45,7 @@ def i_see_advanced_settings_with_values(step): ...@@ -41,7 +45,7 @@ def i_see_advanced_settings_with_values(step):
@step('I can modify the display name') @step('I can modify the display name')
def i_can_modify_the_display_name(step): def i_can_modify_the_display_name(_step):
# Verifying that the display name can be a string containing a floating point value # Verifying that the display name can be a string containing a floating point value
# (to confirm that we don't throw an error because it is of the wrong type). # (to confirm that we don't throw an error because it is of the wrong type).
index = world.get_setting_entry_index(DISPLAY_NAME) index = world.get_setting_entry_index(DISPLAY_NAME)
...@@ -58,7 +62,7 @@ def my_display_name_change_is_persisted_on_save(step): ...@@ -58,7 +62,7 @@ def my_display_name_change_is_persisted_on_save(step):
@step('I can specify special characters in the display name') @step('I can specify special characters in the display name')
def i_can_modify_the_display_name_with_special_chars(step): def i_can_modify_the_display_name_with_special_chars(_step):
index = world.get_setting_entry_index(DISPLAY_NAME) index = world.get_setting_entry_index(DISPLAY_NAME)
world.css_fill('.wrapper-comp-setting .setting-input', "updated ' \" &", index=index) world.css_fill('.wrapper-comp-setting .setting-input', "updated ' \" &", index=index)
if world.is_firefox(): if world.is_firefox():
...@@ -73,7 +77,7 @@ def special_chars_persisted_on_save(step): ...@@ -73,7 +77,7 @@ def special_chars_persisted_on_save(step):
@step('I can revert the display name to unset') @step('I can revert the display name to unset')
def can_revert_display_name_to_unset(step): def can_revert_display_name_to_unset(_step):
world.revert_setting_entry(DISPLAY_NAME) world.revert_setting_entry(DISPLAY_NAME)
verify_unset_display_name() verify_unset_display_name()
...@@ -85,7 +89,7 @@ def my_display_name_is_persisted_on_save(step): ...@@ -85,7 +89,7 @@ def my_display_name_is_persisted_on_save(step):
@step('I can select Per Student for Randomization') @step('I can select Per Student for Randomization')
def i_can_select_per_student_for_randomization(step): def i_can_select_per_student_for_randomization(_step):
world.browser.select(RANDOMIZATION, "Per Student") world.browser.select(RANDOMIZATION, "Per Student")
verify_modified_randomization() verify_modified_randomization()
...@@ -104,7 +108,7 @@ def i_can_revert_to_default_for_randomization(step): ...@@ -104,7 +108,7 @@ def i_can_revert_to_default_for_randomization(step):
@step('I can set the weight to "(.*)"?') @step('I can set the weight to "(.*)"?')
def i_can_set_weight(step, weight): def i_can_set_weight(_step, weight):
set_weight(weight) set_weight(weight)
verify_modified_weight() verify_modified_weight()
...@@ -175,14 +179,14 @@ def create_latex_problem(step): ...@@ -175,14 +179,14 @@ def create_latex_problem(step):
@step('I edit and compile the High Level Source') @step('I edit and compile the High Level Source')
def edit_latex_source(step): def edit_latex_source(_step):
open_high_level_source() open_high_level_source()
type_in_codemirror(1, "hi") type_in_codemirror(1, "hi")
world.css_click('.hls-compile') world.css_click('.hls-compile')
@step('my change to the High Level Source is persisted') @step('my change to the High Level Source is persisted')
def high_level_source_persisted(step): def high_level_source_persisted(_step):
def verify_text(driver): def verify_text(driver):
css_sel = '.problem div>span' css_sel = '.problem div>span'
return world.css_text(css_sel) == 'hi' return world.css_text(css_sel) == 'hi'
...@@ -191,11 +195,53 @@ def high_level_source_persisted(step): ...@@ -191,11 +195,53 @@ def high_level_source_persisted(step):
@step('I view the High Level Source I see my changes') @step('I view the High Level Source I see my changes')
def high_level_source_in_editor(step): def high_level_source_in_editor(_step):
open_high_level_source() open_high_level_source()
assert_equal('hi', world.css_value('.source-edit-box')) assert_equal('hi', world.css_value('.source-edit-box'))
@step(u'I have an empty course')
def i_have_empty_course(step):
open_new_course()
@step(u'I go to the import page')
def i_go_to_import(_step):
go_to_import()
@step(u'I import the file "([^"]*)"$')
def i_import_the_file(_step, filename):
import_file(filename)
@step(u'I click on "edit a draft"$')
def i_edit_a_draft(_step):
world.css_click("a.create-draft")
@step(u'I go to the vertical "([^"]*)"$')
def i_go_to_vertical(_step, vertical):
world.css_click("span:contains('{0}')".format(vertical))
@step(u'I go to the unit "([^"]*)"$')
def i_go_to_unit(_step, unit):
loc = "window.location = $(\"span:contains('{0}')\").closest('a').attr('href')".format(unit)
world.browser.execute_script(loc)
@step(u'I see a message that says "([^"]*)"$')
def i_can_see_message(_step, msg):
msg = json.dumps(msg) # escape quotes
world.css_has_text("h2.title", msg)
@step(u'I can edit the problem$')
def i_can_edit_problem(_step):
world.edit_component()
def verify_high_level_source_links(step, visible): def verify_high_level_source_links(step, visible):
if visible: if visible:
assert_true(world.is_css_present('.launch-latex-compiler'), assert_true(world.is_css_present('.launch-latex-compiler'),
......
...@@ -193,6 +193,7 @@ def import_course(request, org, course, name): ...@@ -193,6 +193,7 @@ def import_course(request, org, course, name):
if not dirpath: if not dirpath:
return JsonResponse( return JsonResponse(
{ {
'ErrMsg': _('Could not find the course.xml file in the package.'), 'ErrMsg': _('Could not find the course.xml file in the package.'),
'Stage': 2 'Stage': 2
}, },
......
...@@ -6,7 +6,7 @@ from django.conf import settings ...@@ -6,7 +6,7 @@ from django.conf import settings
from django.http import HttpResponse, Http404, HttpResponseBadRequest, HttpResponseForbidden from django.http import HttpResponse, Http404, HttpResponseBadRequest, HttpResponseForbidden
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response, render_to_string
from xmodule_modifiers import replace_static_urls, wrap_xmodule from xmodule_modifiers import replace_static_urls, wrap_xmodule
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
...@@ -79,9 +79,17 @@ def preview_component(request, location): ...@@ -79,9 +79,17 @@ def preview_component(request, location):
# can bind to it correctly # can bind to it correctly
component.runtime.wrappers.append(partial(wrap_xmodule, 'xmodule_edit.html')) component.runtime.wrappers.append(partial(wrap_xmodule, 'xmodule_edit.html'))
try:
content = component.render('studio_view').content
# catch exceptions indiscriminately, since after this point they escape the
# dungeon and surface as uneditable, unsaveable, and undeletable
# component-goblins.
except Exception as exc: # pylint: disable=W0703
content = render_to_string('html_error.html', {'message': str(exc)})
return render_to_response('component.html', { return render_to_response('component.html', {
'preview': get_preview_html(request, component, 0), 'preview': get_preview_html(request, component, 0),
'editor': component.render('studio_view').content, 'editor': content
}) })
...@@ -157,4 +165,8 @@ def get_preview_html(request, descriptor, idx): ...@@ -157,4 +165,8 @@ def get_preview_html(request, descriptor, idx):
specified by the descriptor and idx. specified by the descriptor and idx.
""" """
module = load_preview_module(request, str(idx), descriptor) module = load_preview_module(request, str(idx), descriptor)
return module.render("student_view").content try:
content = module.render("student_view").content
except Exception as exc: # pylint: disable=W0703
content = render_to_string('html_error.html', {'message': str(exc)})
return content
...@@ -355,6 +355,20 @@ body.course.unit,.view-unit { ...@@ -355,6 +355,20 @@ body.course.unit,.view-unit {
} }
} }
.wrapper-alert-error {
margin-top: ($baseline*1.25);
box-shadow: none;
border-top: 5px solid $red-l1;
.copy,
.title {
color: $white;
}
}
} }
} }
......
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%block name="content">
<div class="wrapper wrapper-alert wrapper-alert-error is-shown">
<div class="error">
<div class="copy">
<h2 class="title">
<i class="icon-warning-sign"></i>
${_("We're having trouble rendering your component")}
</h2>
<p>${_("Students will not be able to access this component. Re-edit your component to fix the error.")}</p>
% if message:
<p class="description">
${_("Error:")}
${message | h}
</p>
% endif
</div>
</div>
</%block>
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