diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index 590be213bd..e669046ecb 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -92,9 +92,13 @@ class ConditionalModule(ConditionalFields, XModule): if xml_value and self.required_modules: for module in self.required_modules: if not hasattr(module, attr_name): - raise Exception('Error in conditional module: \ - required module {module} has no {module_attr}'.format( - module=module, module_attr=attr_name)) + # We don't throw an exception here because it is possible for + # the descriptor of a required module to have a property but + # for the resulting module to be a (flavor of) ErrorModule. + # So just log and return false. + log.warn('Error in conditional module: \ + required module {module} has no {module_attr}'.format(module=module, module_attr=attr_name)) + return False attr = getattr(module, attr_name) if callable(attr): @@ -137,16 +141,15 @@ class ConditionalModule(ConditionalFields, XModule): def get_icon_class(self): new_class = 'other' - if self.is_condition_satisfied(): - # HACK: This shouldn't be hard-coded to two types - # OBSOLETE: This obsoletes 'type' - class_priority = ['video', 'problem'] + # HACK: This shouldn't be hard-coded to two types + # OBSOLETE: This obsoletes 'type' + class_priority = ['video', 'problem'] - child_classes = [self.system.get_module(child_descriptor).get_icon_class() - for child_descriptor in self.descriptor.get_children()] - for c in class_priority: - if c in child_classes: - new_class = c + child_classes = [self.system.get_module(child_descriptor).get_icon_class() + for child_descriptor in self.descriptor.get_children()] + for c in class_priority: + if c in child_classes: + new_class = c return new_class diff --git a/common/lib/xmodule/xmodule/tests/test_conditional.py b/common/lib/xmodule/xmodule/tests/test_conditional.py index 1b2da0b74a..320b94efb7 100644 --- a/common/lib/xmodule/xmodule/tests/test_conditional.py +++ b/common/lib/xmodule/xmodule/tests/test_conditional.py @@ -1,23 +1,19 @@ + import json -from path import path import unittest from fs.memoryfs import MemoryFS - -from lxml import etree +from ast import literal_eval from mock import Mock, patch -from collections import defaultdict -from xmodule.x_module import XMLParsingSystem, XModuleDescriptor -from xmodule.xml_module import is_pointer_tag -from xmodule.errortracker import make_error_tracker +from xmodule.error_module import NonStaffErrorDescriptor from xmodule.modulestore import Location from xmodule.modulestore.xml import ImportSystem, XMLModuleStore -from xmodule.modulestore.exceptions import ItemNotFoundError +from xmodule.conditional_module import ConditionalModule -from .test_export import DATA_DIR +from xmodule.tests.test_export import DATA_DIR ORG = 'test_org' -COURSE = 'conditional' # name of directory with course data +COURSE = 'conditional' # name of directory with course data from . import test_system @@ -47,10 +43,118 @@ class DummySystem(ImportSystem): def render_template(self, template, context): raise Exception("Shouldn't be called") +class ConditionalFactory(object): + """ + A helper class to create a conditional module and associated source and child modules + to allow for testing. + """ + @staticmethod + def create(system, source_is_error_module=False): + """ + return a dict of modules: the conditional with a single source and a single child. + Keys are 'cond_module', 'source_module', and 'child_module'. + + if the source_is_error_module flag is set, create a real ErrorModule for the source. + """ + # construct source descriptor and module: + source_location = Location(["i4x", "edX", "conditional_test", "problem", "SampleProblem"]) + if source_is_error_module: + # Make an error descriptor and module + source_descriptor = NonStaffErrorDescriptor.from_xml('some random xml data', + system, + org=source_location.org, + course=source_location.course, + error_msg='random error message') + source_module = source_descriptor.xmodule(system) + else: + source_descriptor = Mock() + source_descriptor.location = source_location + source_module = Mock() + + # construct other descriptors: + child_descriptor = Mock() + cond_descriptor = Mock() + cond_descriptor.get_required_module_descriptors = lambda: [source_descriptor, ] + cond_descriptor.get_children = lambda: [child_descriptor, ] + cond_descriptor.xml_attributes = {"attempted": "true"} + + # create child module: + child_module = Mock() + child_module.get_html = lambda: '
This is a secret
' + child_module.displayable_items = lambda: [child_module] + module_map = {source_descriptor: source_module, child_descriptor: child_module} + system.get_module = lambda descriptor: module_map[descriptor] + + # construct conditional module: + cond_location = Location(["i4x", "edX", "conditional_test", "conditional", "SampleConditional"]) + model_data = {'data': '