def test_partial_completion_status_migration(self): """ Changed `completed` to `status` in `self.student_results` to accomodate partial responses """ # Instantiate a mentoring block with the old format student_results = [ [u'goal', {u'completed': True, u'score': 1, u'student_input': u'test', u'weight': 1}], [u'mcq_1_1', {u'completed': False, u'score': 0, u'submission': u'maybenot', u'weight': 1}], ] mentoring = MentoringBlock(MagicMock(), DictFieldData({'student_results': student_results}), Mock()) self.assertEqual(copy.deepcopy(student_results), mentoring.student_results) migrated_student_results = copy.deepcopy(student_results) migrated_student_results[0][1]['status'] = 'correct' migrated_student_results[1][1]['status'] = 'incorrect' del migrated_student_results[0][1]['completed'] del migrated_student_results[1][1]['completed'] mentoring.migrate_fields() self.assertEqual(migrated_student_results, mentoring.student_results)
class TestMentoringBlockOptions(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) def test_get_options_returns_default_if_settings_service_is_not_available(self): self.runtime_mock.service = Mock(return_value=None) self.assertEqual(self.block.get_options(), _default_options_config) def test_get_options_returns_default_if_xblock_settings_not_customized(self): self.block.get_xblock_settings = Mock(return_value=None) self.assertEqual(self.block.get_options(), _default_options_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {}, {'mass': 123}, {'spin': {}}, {'parity': "1"} ) def test_get_options_returns_default_if_options_not_customized(self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) self.assertEqual(self.block.get_options(), _default_options_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {MentoringBlock.options_key: 123}, {MentoringBlock.options_key: [1, 2, 3]}, {MentoringBlock.options_key: {'pb_mcq_hide_previous_answer': False}}, ) def test_get_options_correctly_returns_customized_options(self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) self.assertEqual(self.block.get_options(), xblock_settings[MentoringBlock.options_key]) self.block.get_xblock_settings.assert_called_once_with(default={}) def test_get_option(self): random_key, random_value = random(), random() with patch.object(self.block, 'get_options') as patched_get_options: # Happy path: Customizations contain expected key patched_get_options.return_value = {random_key: random_value} option = self.block.get_option(random_key) patched_get_options.assert_called_once_with() self.assertEqual(option, random_value) with patch.object(self.block, 'get_options') as patched_get_options: # Sad path: Customizations do not contain expected key patched_get_options.return_value = {} option = self.block.get_option(random_key) patched_get_options.assert_called_once_with() self.assertEqual(option, None) def test_student_view_calls_get_option(self): self.block.get_xblock_settings = Mock(return_value={}) with patch.object(self.block, 'get_option') as patched_get_option: self.block.student_view({}) patched_get_option.assert_any_call('pb_mcq_hide_previous_answer') patched_get_option.assert_any_call('pb_hide_feedback_if_attempts_remain') def test_get_standard_results_calls_get_option(self): with patch.object(self.block, 'get_option') as patched_get_option: self.block._get_standard_results() patched_get_option.assert_called_with('pb_hide_feedback_if_attempts_remain')
def test_does_not_send_progress_event_when_rendered_student_view_with_display_submit_true(self): block = MentoringBlock(MagicMock(), DictFieldData({ 'display_submit': True }), Mock()) with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() block.student_view(context={}) self.assertFalse(patched_runtime.publish.called)
def test_sends_progress_event_when_rendered_student_view_with_display_submit_false(self): block = MentoringBlock(MagicMock(), DictFieldData({ 'display_submit': False }), Mock()) with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() block.student_view(context={}) patched_runtime.publish.assert_called_once_with(block, 'progress', {})
def test_sends_progress_event_when_rendered_student_view_with_display_submit_false( self): block = MentoringBlock(MagicMock(), DictFieldData({'display_submit': False}), Mock()) with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() block.student_view(context={}) patched_runtime.publish.assert_called_once_with( block, 'progress', {})
def test_get_content_titles(self, has_title_set): """ Test that we don't send a title to the LMS for the sequential's tooltips when no title is set """ if has_title_set: data = {'display_name': 'Custom Title'} expected = ['Custom Title'] else: data = {} expected = [] block = MentoringBlock(MagicMock(), DictFieldData(data), Mock()) self.assertEqual(block.get_content_titles(), expected)
def test_correctly_decides_to_show_or_hide_feedback_message( self, pb_hide_feedback_if_attempts_remain, max_attempts_reached, expected_show_message ): block = MentoringBlock(Mock(), DictFieldData({ 'student_results': ['must', 'be', 'non-empty'], }), Mock()) block.get_option = Mock(return_value=pb_hide_feedback_if_attempts_remain) with patch( 'problem_builder.mentoring.MentoringBlock.max_attempts_reached', new_callable=PropertyMock ) as patched_max_attempts_reached: patched_max_attempts_reached.return_value = max_attempts_reached _, _, show_message = block._get_standard_results() self.assertEqual(show_message, expected_show_message)
def test_does_not_crash_when_get_child_is_broken(self): block = MentoringBlock(MagicMock(), DictFieldData({ 'children': ['invalid_id'], }), Mock()) with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() patched_runtime.service().ugettext = lambda str: str patched_runtime.get_block = lambda block_id: None patched_runtime.load_block_type = lambda block_id: Mock fragment = block.student_view(context={}) self.assertIn('Unable to load child component', fragment.content)
def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) self.block.children = ['dummy_id'] self.message_block = MentoringMessageBlock( self.runtime_mock, DictFieldData({ 'type': 'bogus', 'content': 'test' }), Mock()) self.block.runtime.replace_jump_to_id_urls = lambda x: x.replace( 'test', 'replaced-url')
def test_correctly_decides_to_show_or_hide_feedback_message( self, pb_hide_feedback_if_attempts_remain, max_attempts_reached, expected_show_message): block = MentoringBlock( Mock(), DictFieldData({ 'student_results': ['must', 'be', 'non-empty'], }), Mock()) block.get_option = Mock( return_value=pb_hide_feedback_if_attempts_remain) with patch( 'problem_builder.mentoring.MentoringBlock.max_attempts_reached', new_callable=PropertyMock) as patched_max_attempts_reached: patched_max_attempts_reached.return_value = max_attempts_reached _, _, show_message = block._get_standard_results() self.assertEqual(show_message, expected_show_message)
def test_allowed_nested_blocks(self): block = MentoringBlock(Mock(), DictFieldData({}), Mock()) self.assert_allowed_nested_blocks(block, message_blocks=[ 'pb-message', # Message type: "completed" 'pb-message', # Message type: "incomplete" 'pb-message', # Message type: "max_attempts_reached" ] )
def test_allowed_nested_blocks(self): block = MentoringBlock(Mock(), DictFieldData({}), Mock()) self.assert_allowed_nested_blocks(block, message_blocks=[ 'pb-message', # Message type: "completed" 'pb-message', # Message type: "incomplete" 'pb-message', # Message type: "max_attempts_reached" ] + (['pb-message'] if block.is_assessment else []) # Message type: "on-assessment-review" )
def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({'mode': 'assessment'}), Mock()) self.block.children = ['dummy_id'] self.message_block = MentoringMessageBlock( self.runtime_mock, DictFieldData({'type': 'bogus', 'content': 'test'}), Mock() ) self.block.runtime.replace_jump_to_id_urls = lambda x: x.replace('test', 'replaced-url')
class TestMentoringBlockJumpToIds(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({'mode': 'assessment'}), Mock()) self.block.children = ['dummy_id'] self.message_block = MentoringMessageBlock( self.runtime_mock, DictFieldData({ 'type': 'bogus', 'content': 'test' }), Mock()) self.block.runtime.replace_jump_to_id_urls = lambda x: x.replace( 'test', 'replaced-url') def test_get_message_content(self): with patch('problem_builder.mixins.child_isinstance' ) as mock_child_isinstance: mock_child_isinstance.return_value = True self.runtime_mock.get_block = Mock() self.runtime_mock.get_block.return_value = self.message_block self.assertEqual(self.block.get_message_content('bogus'), 'replaced-url') def test_get_tip_content(self): self.mcq_block = MCQBlock(self.runtime_mock, DictFieldData({'name': 'test_mcq'}), Mock()) self.mcq_block.get_review_tip = Mock() self.mcq_block.get_review_tip.return_value = self.message_block.content self.block.step_ids = [] self.block.steps = [self.mcq_block] self.block.student_results = {'test_mcq': {'status': 'incorrect'}} self.assertEqual(self.block.review_tips, ['replaced-url']) def test_get_tip_content_no_tips(self): self.mcq_block = MCQBlock(self.runtime_mock, DictFieldData({'name': 'test_mcq'}), Mock()) self.mcq_block.get_review_tip = Mock() # If there are no review tips, get_review_tip will return None; # simulate this situation here: self.mcq_block.get_review_tip.return_value = None self.block.step_ids = [] self.block.steps = [self.mcq_block] self.block.student_results = {'test_mcq': {'status': 'incorrect'}} try: review_tips = self.block.review_tips except TypeError: self.fail( 'Trying to replace jump_to_id URLs in non-existent review tips.' ) else: self.assertEqual(review_tips, [])
def test_student_view_data(self): def get_mock_components(): child_a = Mock(spec=['student_view_data']) child_a.block_id = 'child_a' child_a.category = 'text' child_a.student_view_data.return_value = 'child_a_json' child_b = Mock(spec=[]) child_b.block_id = 'child_b' child_b.category = 'html' return [child_a, child_b] shared_data = { 'max_attempts': 3, 'extended_feedback': True, 'feedback_label': 'Feedback label', } children = get_mock_components() children_by_id = {child.block_id: child for child in children} display_name = "I'm problem builder" block_data = {'display_name': display_name, 'children': children} block_data.update(shared_data) block = MentoringBlock(Mock(usage_id=1), DictFieldData(block_data), Mock(usage_id=1)) block.runtime = Mock( get_block=lambda block: children_by_id[block.block_id], load_block_type=lambda block: Mock, id_reader=Mock(get_definition_id=lambda block: block, get_block_type=lambda block: block), ) expected = { 'block_id': '1', 'display_name': display_name, 'components': ['child_a_json'], 'messages': { 'completed': None, 'incomplete': None, 'max_attempts_reached': None, } } expected.update(shared_data) self.assertEqual(block.student_view_data(), expected)
def test_partial_completion_status_migration(self): """ Changed `completed` to `status` in `self.student_results` to accomodate partial responses """ # Instantiate a mentoring block with the old format student_results = [ [ u'goal', { u'completed': True, u'score': 1, u'student_input': u'test', u'weight': 1 } ], [ u'mcq_1_1', { u'completed': False, u'score': 0, u'submission': u'maybenot', u'weight': 1 } ], ] mentoring = MentoringBlock( MagicMock(), DictFieldData({'student_results': student_results}), Mock()) self.assertEqual(copy.deepcopy(student_results), mentoring.student_results) migrated_student_results = copy.deepcopy(student_results) migrated_student_results[0][1]['status'] = 'correct' migrated_student_results[1][1]['status'] = 'incorrect' del migrated_student_results[0][1]['completed'] del migrated_student_results[1][1]['completed'] mentoring.migrate_fields() self.assertEqual(migrated_student_results, mentoring.student_results)
class TestMentoringBlockJumpToIds(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({'mode': 'assessment'}), Mock()) self.block.children = ['dummy_id'] self.message_block = MentoringMessageBlock( self.runtime_mock, DictFieldData({'type': 'bogus', 'content': 'test'}), Mock() ) self.block.runtime.replace_jump_to_id_urls = lambda x: x.replace('test', 'replaced-url') def test_get_message_content(self): with patch('problem_builder.mixins.child_isinstance') as mock_child_isinstance: mock_child_isinstance.return_value = True self.runtime_mock.get_block = Mock() self.runtime_mock.get_block.return_value = self.message_block self.assertEqual(self.block.get_message_content('bogus'), 'replaced-url') def test_get_tip_content(self): self.mcq_block = MCQBlock(self.runtime_mock, DictFieldData({'name': 'test_mcq'}), Mock()) self.mcq_block.get_review_tip = Mock() self.mcq_block.get_review_tip.return_value = self.message_block.content self.block.step_ids = [] self.block.steps = [self.mcq_block] self.block.student_results = {'test_mcq': {'status': 'incorrect'}} self.assertEqual(self.block.review_tips, ['replaced-url']) def test_get_tip_content_no_tips(self): self.mcq_block = MCQBlock(self.runtime_mock, DictFieldData({'name': 'test_mcq'}), Mock()) self.mcq_block.get_review_tip = Mock() # If there are no review tips, get_review_tip will return None; # simulate this situation here: self.mcq_block.get_review_tip.return_value = None self.block.step_ids = [] self.block.steps = [self.mcq_block] self.block.student_results = {'test_mcq': {'status': 'incorrect'}} try: review_tips = self.block.review_tips except TypeError: self.fail('Trying to replace jump_to_id URLs in non-existent review tips.') else: self.assertEqual(review_tips, [])
class TestMentoringBlockTheming(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) def test_get_theme_returns_default_if_settings_service_is_not_available(self): self.runtime_mock.service = Mock(return_value=None) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) def test_get_theme_returns_default_if_xblock_settings_not_customized(self): self.block.get_xblock_settings = Mock(return_value=None) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {}, {'mass': 123}, {'spin': {}}, {'parity': "1"} ) def test_get_theme_returns_default_if_theme_not_customized(self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {MentoringBlock.theme_key: 123}, {MentoringBlock.theme_key: [1, 2, 3]}, {MentoringBlock.theme_key: {'package': 'qwerty', 'locations': ['something_else.css']}}, ) def test_get_theme_correctly_returns_customized_theme(self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, xblock_settings[MentoringBlock.theme_key]) self.block.get_xblock_settings.assert_called_once_with(default={}) def test_theme_files_are_loaded_from_correct_package(self): fragment = MagicMock() package_name = 'some_package' xblock_settings = {MentoringBlock.theme_key: {'package': package_name, 'locations': ['lms.css']}} self.block.get_xblock_settings = Mock(return_value=xblock_settings) with patch("xblockutils.settings.ResourceLoader") as patched_resource_loader: self.block.include_theme_files(fragment) patched_resource_loader.assert_called_with(package_name) @ddt.data( ('problem_builder', ['public/themes/lms.css']), ('problem_builder', ['public/themes/lms.css', 'public/themes/lms.part2.css']), ('my_app.my_rules', ['typography.css', 'icons.css']), ) @ddt.unpack def test_theme_files_are_added_to_fragment(self, package_name, locations): fragment = MagicMock() xblock_settings = {MentoringBlock.theme_key: {'package': package_name, 'locations': locations}} self.block.get_xblock_settings = Mock(return_value=xblock_settings) with patch("xblockutils.settings.ResourceLoader.load_unicode") as patched_load_unicode: self.block.include_theme_files(fragment) for location in locations: patched_load_unicode.assert_any_call(location) self.assertEqual(patched_load_unicode.call_count, len(locations)) def test_student_view_calls_include_theme_files(self): self.block.get_xblock_settings = Mock(return_value={}) with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.student_view({}) patched_include_theme_files.assert_called_with(fragment) def test_author_preview_view_calls_include_theme_files(self): self.block.get_xblock_settings = Mock(return_value={}) with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.author_preview_view({}) patched_include_theme_files.assert_called_with(fragment)
def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())
class TestMentoringBlockOptions(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) def test_get_options_returns_default_if_settings_service_is_not_available( self): self.runtime_mock.service = Mock(return_value=None) self.assertEqual(self.block.get_options(), _default_options_config) def test_get_options_returns_default_if_xblock_settings_not_customized( self): self.block.get_xblock_settings = Mock(return_value=None) self.assertEqual(self.block.get_options(), _default_options_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data({}, {'mass': 123}, {'spin': {}}, {'parity': "1"}) def test_get_options_returns_default_if_options_not_customized( self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) self.assertEqual(self.block.get_options(), _default_options_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {MentoringBlock.options_key: 123}, {MentoringBlock.options_key: [1, 2, 3]}, {MentoringBlock.options_key: { 'pb_mcq_hide_previous_answer': False }}, ) def test_get_options_correctly_returns_customized_options( self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) self.assertEqual(self.block.get_options(), xblock_settings[MentoringBlock.options_key]) self.block.get_xblock_settings.assert_called_once_with(default={}) def test_get_option(self): random_key, random_value = random(), random() with patch.object(self.block, 'get_options') as patched_get_options: # Happy path: Customizations contain expected key patched_get_options.return_value = {random_key: random_value} option = self.block.get_option(random_key) patched_get_options.assert_called_once_with() self.assertEqual(option, random_value) with patch.object(self.block, 'get_options') as patched_get_options: # Sad path: Customizations do not contain expected key patched_get_options.return_value = {} option = self.block.get_option(random_key) patched_get_options.assert_called_once_with() self.assertEqual(option, None) def test_student_view_calls_get_option(self): random_key, random_value = random(), random() self.block.get_xblock_settings = Mock(return_value={}) with patch.object(self.block, 'get_option') as patched_get_option: self.runtime_mock.service.return_value = { random_key: random_value, } self.block.student_view({}) patched_get_option.assert_any_call('pb_mcq_hide_previous_answer') patched_get_option.assert_any_call( 'pb_hide_feedback_if_attempts_remain') def test_get_standard_results_calls_get_option(self): with patch.object(self.block, 'get_option') as patched_get_option: self.block._get_standard_results() patched_get_option.assert_called_with( 'pb_hide_feedback_if_attempts_remain')
class TestMentoringBlockTheming(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) def test_theme_uses_default_theme_if_settings_service_is_not_available(self): self.runtime_mock.service = Mock(return_value=None) self.assertEqual(self.block.get_theme(), _default_theme_config) def test_theme_uses_default_theme_if_no_theme_is_set(self): self.service_mock.get_settings_bucket = Mock(return_value=None) self.assertEqual(self.block.get_theme(), _default_theme_config) self.service_mock.get_settings_bucket.assert_called_once_with(self.block) @ddt.data(123, object()) def test_theme_raises_if_theme_object_is_not_iterable(self, theme_config): self.service_mock.get_settings_bucket = Mock(return_value=theme_config) with self.assertRaises(TypeError): self.block.get_theme() self.service_mock.get_settings_bucket.assert_called_once_with(self.block) @ddt.data( {}, {'mass': 123}, {'spin': {}}, {'parity': "1"} ) def test_theme_uses_default_theme_if_no_mentoring_theme_is_set_up(self, theme_config): self.service_mock.get_settings_bucket = Mock(return_value=theme_config) self.assertEqual(self.block.get_theme(), _default_theme_config) self.service_mock.get_settings_bucket.assert_called_once_with(self.block) @ddt.data( {MentoringBlock.theme_key: 123}, {MentoringBlock.theme_key: [1, 2, 3]}, {MentoringBlock.theme_key: {'package': 'qwerty', 'locations': ['something_else.css']}}, ) def test_theme_correctly_returns_configured_theme(self, theme_config): self.service_mock.get_settings_bucket = Mock(return_value=theme_config) self.assertEqual(self.block.get_theme(), theme_config[MentoringBlock.theme_key]) def test_theme_files_are_loaded_from_correct_package(self): fragment = MagicMock() package_name = 'some_package' theme_config = {MentoringBlock.theme_key: {'package': package_name, 'locations': ['lms.css']}} self.service_mock.get_settings_bucket = Mock(return_value=theme_config) with patch("problem_builder.mentoring.ResourceLoader") as patched_resource_loader: self.block.include_theme_files(fragment) patched_resource_loader.assert_called_with(package_name) @ddt.data( ('problem_builder', ['public/themes/lms.css']), ('problem_builder', ['public/themes/lms.css', 'public/themes/lms.part2.css']), ('my_app.my_rules', ['typography.css', 'icons.css']), ) @ddt.unpack def test_theme_files_are_added_to_fragment(self, package_name, locations): fragment = MagicMock() theme_config = {MentoringBlock.theme_key: {'package': package_name, 'locations': locations}} self.service_mock.get_settings_bucket = Mock(return_value=theme_config) with patch("problem_builder.mentoring.ResourceLoader.load_unicode") as patched_load_unicode: self.block.include_theme_files(fragment) for location in locations: patched_load_unicode.assert_any_call(location) self.assertEqual(patched_load_unicode.call_count, len(locations)) def test_student_view_calls_include_theme_files(self): with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.student_view({}) patched_include_theme_files.assert_called_with(fragment) def test_author_preview_view_calls_include_theme_files(self): with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.author_preview_view({}) patched_include_theme_files.assert_called_with(fragment)
class TestMentoringBlockTheming(unittest.TestCase): def setUp(self): self.service_mock = Mock() self.runtime_mock = Mock() self.runtime_mock.service = Mock(return_value=self.service_mock) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) def test_get_theme_returns_default_if_settings_service_is_not_available( self): self.runtime_mock.service = Mock(return_value=None) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) def test_get_theme_returns_default_if_xblock_settings_not_customized(self): self.block.get_xblock_settings = Mock(return_value=None) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data({}, {'mass': 123}, {'spin': {}}, {'parity': "1"}) def test_get_theme_returns_default_if_theme_not_customized( self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, MentoringBlock.default_theme_config) self.block.get_xblock_settings.assert_called_once_with(default={}) @ddt.data( {MentoringBlock.theme_key: 123}, {MentoringBlock.theme_key: [1, 2, 3]}, { MentoringBlock.theme_key: { 'package': 'qwerty', 'locations': ['something_else.css'] } }, ) def test_get_theme_correctly_returns_customized_theme( self, xblock_settings): self.block.get_xblock_settings = Mock(return_value=xblock_settings) theme = self.block.get_theme() # Ensure MentoringBlock overrides "default_theme_config" from ThemableXBlockMixin with meaningful value: self.assertIsNotNone(theme) self.assertEqual(theme, xblock_settings[MentoringBlock.theme_key]) self.block.get_xblock_settings.assert_called_once_with(default={}) def test_theme_files_are_loaded_from_correct_package(self): fragment = MagicMock() package_name = 'some_package' xblock_settings = { MentoringBlock.theme_key: { 'package': package_name, 'locations': ['lms.css'] } } self.block.get_xblock_settings = Mock(return_value=xblock_settings) with patch("xblockutils.settings.ResourceLoader" ) as patched_resource_loader: self.block.include_theme_files(fragment) patched_resource_loader.assert_called_with(package_name) @ddt.data( ('problem_builder', ['public/themes/lms.css']), ('problem_builder', ['public/themes/lms.css', 'public/themes/lms.part2.css']), ('my_app.my_rules', ['typography.css', 'icons.css']), ) @ddt.unpack def test_theme_files_are_added_to_fragment(self, package_name, locations): fragment = MagicMock() xblock_settings = { MentoringBlock.theme_key: { 'package': package_name, 'locations': locations } } self.block.get_xblock_settings = Mock(return_value=xblock_settings) with patch("xblockutils.settings.ResourceLoader.load_unicode" ) as patched_load_unicode: self.block.include_theme_files(fragment) for location in locations: patched_load_unicode.assert_any_call(location) self.assertEqual(patched_load_unicode.call_count, len(locations)) def test_student_view_calls_include_theme_files(self): self.block.get_xblock_settings = Mock(return_value={}) with patch.object( self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.student_view({}) patched_include_theme_files.assert_called_with(fragment) def test_author_preview_view_calls_include_theme_files(self): self.block.get_xblock_settings = Mock(return_value={}) with patch.object( self.block, 'include_theme_files') as patched_include_theme_files: fragment = self.block.author_preview_view({}) patched_include_theme_files.assert_called_with(fragment)