-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Complete default blocks #16234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jcdyer
merged 1 commit into
openedx:master
from
open-craft:cliff/complete-default-blocks
Nov 28, 2017
Merged
Complete default blocks #16234
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,60 @@ | ||
| """ | ||
| Tests for vertical module. | ||
| """ | ||
|
|
||
| # pylint: disable=protected-access | ||
| from __future__ import absolute_import, division, print_function, unicode_literals | ||
|
|
||
| from collections import namedtuple | ||
| import json | ||
|
|
||
| import ddt | ||
| from mock import Mock | ||
| from fs.memoryfs import MemoryFS | ||
| from xmodule.tests import get_test_system | ||
| from xmodule.tests.helpers import StubUserService | ||
| from xmodule.tests.xml import XModuleXmlImportTest | ||
| from xmodule.tests.xml import factories as xml | ||
| from xmodule.x_module import STUDENT_VIEW, AUTHOR_VIEW | ||
| from mock import Mock, patch | ||
| import six | ||
|
|
||
| from . import get_test_system | ||
| from .helpers import StubUserService | ||
| from .xml import XModuleXmlImportTest | ||
| from .xml import factories as xml | ||
| from ..x_module import STUDENT_VIEW, AUTHOR_VIEW | ||
|
|
||
|
|
||
| JsonRequest = namedtuple('JsonRequest', ['method', 'body']) | ||
|
|
||
|
|
||
| def get_json_request(data): | ||
| """ | ||
| Given a data dictionary, return an appropriate JSON request. | ||
| """ | ||
| return JsonRequest( | ||
| method='POST', | ||
| body=json.dumps(data), | ||
| ) | ||
|
|
||
|
|
||
| class StubCompletionService(object): | ||
| """ | ||
| A stub implementation of the CompletionService for testing without access to django | ||
| """ | ||
|
|
||
| def __init__(self, enabled, completion_value): | ||
| self._enabled = enabled | ||
| self._completion_value = completion_value | ||
|
|
||
| def completion_tracking_enabled(self): | ||
| """ | ||
| Turn on or off completion tracking for clients of the | ||
| StubCompletionService. | ||
| """ | ||
| return self._enabled | ||
|
|
||
| def get_completions(self, candidates): | ||
| """ | ||
| Return the (dummy) completion values for each specified candidate | ||
| block. | ||
| """ | ||
| return {candidate: self._completion_value for candidate in candidates} | ||
|
|
||
|
|
||
| class BaseVerticalBlockTest(XModuleXmlImportTest): | ||
|
|
@@ -33,12 +79,15 @@ def setUp(self): | |
| course_seq = self.course.get_children()[0] | ||
| self.module_system = get_test_system() | ||
|
|
||
| self.module_system.descriptor_runtime = self.course._runtime # pylint: disable=protected-access | ||
| self.module_system.descriptor_runtime = self.course._runtime | ||
| self.course.runtime.export_fs = MemoryFS() | ||
|
|
||
| self.vertical = course_seq.get_children()[0] | ||
| self.vertical.xmodule_runtime = self.module_system | ||
|
|
||
| self.html1block = self.vertical.get_children()[0] | ||
| self.html2block = self.vertical.get_children()[1] | ||
|
|
||
| self.username = "bilbo" | ||
| self.default_context = {"bookmarked": False, "username": self.username} | ||
|
|
||
|
|
@@ -66,8 +115,8 @@ def test_render_student_view(self, context): | |
| """ | ||
| Test the rendering of the student view. | ||
| """ | ||
| self.module_system._services['bookmarks'] = Mock() # pylint: disable=protected-access | ||
| self.module_system._services['user'] = StubUserService() # pylint: disable=protected-access | ||
| self.module_system._services['bookmarks'] = Mock() | ||
| self.module_system._services['user'] = StubUserService() | ||
|
|
||
| html = self.module_system.render( | ||
| self.vertical, STUDENT_VIEW, self.default_context if context is None else context | ||
|
|
@@ -76,6 +125,38 @@ def test_render_student_view(self, context): | |
| self.assertIn(self.test_html_2, html) | ||
| self.assert_bookmark_info_in(html) | ||
|
|
||
| @staticmethod | ||
| def _render_completable_blocks(template, context): # pylint: disable=unused-argument | ||
| """ | ||
| A custom template rendering function that displays the | ||
| watched_completable_blocks of the template. | ||
|
|
||
| This is used because the default test renderer is haphazardly | ||
| formatted, and is difficult to make assertions about. | ||
| """ | ||
| return u'|'.join(context['watched_completable_blocks']) | ||
|
|
||
| @ddt.unpack | ||
| @ddt.data( | ||
| (True, 0.9, 'assertIn'), | ||
| (False, 0.9, 'assertNotIn'), | ||
| (True, 1.0, 'assertNotIn'), | ||
| ) | ||
| def test_completion_data_attrs(self, completion_enabled, completion_value, assertion_method): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this test could use a docstring - it's not immediately obvious exactly what it's doing. |
||
| """ | ||
| Test that data-completable-by-viewing attributes are included only when | ||
| the completion service is enabled, and only for blocks with a | ||
| completion value less than 1.0. | ||
| """ | ||
| with patch.object(self.module_system, 'render_template', new=self._render_completable_blocks): | ||
| self.module_system._services['completion'] = StubCompletionService( | ||
| enabled=completion_enabled, | ||
| completion_value=completion_value, | ||
| ) | ||
| response = self.module_system.render(self.vertical, STUDENT_VIEW, self.default_context) | ||
| getattr(self, assertion_method)(six.text_type(self.html1block.location), response.content) | ||
| getattr(self, assertion_method)(six.text_type(self.html2block.location), response.content) | ||
|
|
||
| def test_render_studio_view(self): | ||
| """ | ||
| Test the rendering of the Studio author view | ||
|
|
@@ -97,3 +178,14 @@ def test_render_studio_view(self): | |
| html = self.module_system.render(self.vertical, AUTHOR_VIEW, context).content | ||
| self.assertIn(self.test_html_1, html) | ||
| self.assertIn(self.test_html_2, html) | ||
|
|
||
| def test_publish_completion(self): | ||
| request = get_json_request({"block_key": six.text_type(self.html1block.location), "completion": 1.0}) | ||
| with patch.object(self.vertical.runtime, 'publish') as mock_publisher: | ||
| response = self.vertical.publish_completion(request) | ||
| self.assertEqual( | ||
| response.status_code, | ||
| 200, | ||
| "Expected 200, got {}: {}".format(response.status_code, response.body), | ||
| ) | ||
| mock_publisher.assert_called_with(self.html1block, "completion", {"completion": 1.0}) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I view a sequential like "Lesson 1 - Getting Started" in the demo course and click from the first vertical to another vertical and then back to the first, I see that it still POSTs a
publish_completionevent to the server - it has "forgotten" that it already marked the block as complete.I was going to suggest calling
delete block.dataset.completableByViewing;after the AJAX request completes successfully, but I think that each vertical gets rendered from an HTML string when switching verticals in a sequential, so that approach wouldn't work.If you think it's worth doing, maybe add a global variable to track already-submitted completion events? Or we can ignore the duplicates, as it's not a huge optimization.