Merge pull request #17860 from edx/yro/EDUCATOR-2333
Delete visual_progress_enabled waffle flag.
This commit is contained in:
@@ -720,8 +720,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
|
||||
submit_completions_for_testing(self.user, course_key, block_keys)
|
||||
|
||||
with patch('completion.utilities.visual_progress_enabled', return_value=True):
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
|
||||
course_key_string = str(course_key)
|
||||
resume_block_key_string = str(block_keys[-1])
|
||||
@@ -808,8 +807,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin,
|
||||
)
|
||||
)
|
||||
|
||||
with patch('completion.utilities.visual_progress_enabled', return_value=True):
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
|
||||
html_for_view_buttons = [
|
||||
self._remove_whitespace_from_html_string(button)
|
||||
|
||||
@@ -210,8 +210,6 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
|
||||
|
||||
if dispatch == 'get_completion':
|
||||
completion_service = self.runtime.service(self, 'completion')
|
||||
if not completion_service.visual_progress_enabled():
|
||||
return None
|
||||
|
||||
usage_key = data.get('usage_key', None)
|
||||
item = self.get_child(UsageKey.from_string(usage_key))
|
||||
@@ -472,8 +470,9 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
|
||||
'path': " > ".join(display_names + [item.display_name_with_default]),
|
||||
}
|
||||
|
||||
if is_user_authenticated and completion_service.visual_progress_enabled():
|
||||
iteminfo['complete'] = completion_service.vertical_is_complete(item)
|
||||
if is_user_authenticated:
|
||||
if item.location.block_type == 'vertical':
|
||||
iteminfo['complete'] = completion_service.vertical_is_complete(item)
|
||||
|
||||
contents.append(iteminfo)
|
||||
|
||||
|
||||
@@ -280,22 +280,6 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
# assert content shown as normal
|
||||
self._assert_ungated(html, self.sequence_1_2)
|
||||
|
||||
def test_handle_ajax_get_completion_disabled(self):
|
||||
"""
|
||||
Test when completion service is turned off by waffle, the ajax call returns correct
|
||||
None value
|
||||
"""
|
||||
completion_waffle_mock = Mock()
|
||||
completion_waffle_mock.return_value.visual_progress_enabled.return_value = False
|
||||
self.sequence_3_1.xmodule_runtime._services['completion'] = completion_waffle_mock # pylint: disable=protected-access
|
||||
for child in self.sequence_3_1.get_children():
|
||||
usage_key = unicode(child.location)
|
||||
completion_return = self.sequence_3_1.handle_ajax(
|
||||
'get_completion',
|
||||
{'usage_key': usage_key}
|
||||
)
|
||||
self.assertIs(completion_return, None)
|
||||
|
||||
def test_handle_ajax_get_completion_success(self):
|
||||
"""
|
||||
Test that the completion data is returned successfully on
|
||||
|
||||
@@ -124,16 +124,6 @@ class CourseHomeTest(CourseHomeBaseTest):
|
||||
bookmarks_page = BookmarksPage(self.browser, self.course_id)
|
||||
self.assertTrue(bookmarks_page.is_browser_on_page())
|
||||
|
||||
# Test "Resume Course" button from header
|
||||
self.course_home_page.visit()
|
||||
self.course_home_page.resume_course_from_header()
|
||||
self.assertTrue(self.courseware_page.nav.is_on_section('Test Section 2', 'Test Subsection 3'))
|
||||
|
||||
# Test "Resume Course" button from within outline
|
||||
self.course_home_page.visit()
|
||||
self.course_home_page.outline.resume_course_from_outline()
|
||||
self.assertTrue(self.courseware_page.nav.is_on_section('Test Section 2', 'Test Subsection 3'))
|
||||
|
||||
|
||||
@attr('a11y')
|
||||
class CourseHomeA11yTest(CourseHomeBaseTest):
|
||||
|
||||
@@ -113,9 +113,8 @@ class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMix
|
||||
)
|
||||
|
||||
@override_settings(LMS_ROOT_URL='test_url:9999')
|
||||
@patch('completion.waffle.get_current_site')
|
||||
@ddt.data(True, False)
|
||||
def test_retrieve_last_sitewide_block_completed(self, use_username, get_patched_current_site): # pylint: disable=unused-argument
|
||||
def test_retrieve_last_sitewide_block_completed(self, use_username):
|
||||
"""
|
||||
Test that the method returns a URL for the "last completed" block
|
||||
when sending a user object
|
||||
|
||||
@@ -37,7 +37,7 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
id="${ section['id'] }">
|
||||
<span class="fa fa-chevron-right ${ 'fa-rotate-90' if section_is_auto_opened else '' }" aria-hidden="true"></span>
|
||||
<h3 class="section-title">${ section['display_name'] }</h3>
|
||||
% if show_visual_progress and section.get('complete'):
|
||||
% if section.get('complete'):
|
||||
<span class="complete-checkmark fa fa-check"></span>
|
||||
% endif
|
||||
</button>
|
||||
@@ -83,7 +83,7 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
<span class="subsection-title">
|
||||
${ subsection['display_name'] }
|
||||
</span>
|
||||
% if subsection.get('complete') and show_visual_progress:
|
||||
% if subsection.get('complete'):
|
||||
<span class="complete-checkmark fa fa-check"></span>
|
||||
% endif
|
||||
% endif
|
||||
@@ -168,7 +168,7 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
${ vertical['display_name'] }
|
||||
</span>
|
||||
</div>
|
||||
% if vertical.get('complete') and show_visual_progress:
|
||||
% if vertical.get('complete'):
|
||||
<span class="complete-checkmark fa fa-check"></span>
|
||||
% endif
|
||||
</a>
|
||||
|
||||
@@ -307,11 +307,6 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
cls.user = UserFactory(password=TEST_PASSWORD)
|
||||
CourseEnrollment.enroll(cls.user, cls.course.id)
|
||||
cls.site = Site.objects.get_current()
|
||||
SiteConfiguration.objects.get_or_create(
|
||||
site=cls.site,
|
||||
enabled=True,
|
||||
values={waffle.ENABLE_SITE_VISUAL_PROGRESS: True}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def create_test_course(cls):
|
||||
@@ -354,6 +349,27 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
)
|
||||
self.assertEqual(200, self.client.get(last_accessed_url).status_code)
|
||||
|
||||
@override_switch(
|
||||
'{}.{}'.format(
|
||||
waffle.WAFFLE_NAMESPACE, waffle.ENABLE_COMPLETION_TRACKING
|
||||
),
|
||||
active=True
|
||||
)
|
||||
def complete_sequential(self, course, sequential):
|
||||
"""
|
||||
Completes provided sequential.
|
||||
"""
|
||||
course_key = CourseKey.from_string(str(course.id))
|
||||
# Fake a visit to sequence2/vertical2
|
||||
block_key = UsageKey.from_string(unicode(sequential.location))
|
||||
completion = 1.0
|
||||
BlockCompletion.objects.submit_completion(
|
||||
user=self.user,
|
||||
course_key=course_key,
|
||||
block_key=block_key,
|
||||
completion=completion
|
||||
)
|
||||
|
||||
def visit_course_home(self, course, start_count=0, resume_count=0):
|
||||
"""
|
||||
Helper function to navigates to course home page, test for resume buttons
|
||||
@@ -384,37 +400,12 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
|
||||
self.assertTrue(content('.action-resume-course').attr('href').endswith('/course/' + course.url_name))
|
||||
|
||||
def test_resume_course(self):
|
||||
"""
|
||||
Tests that two resume course buttons appear when the course has been accessed.
|
||||
"""
|
||||
course = self.course
|
||||
|
||||
# first navigate to a sequential to make it the last accessed
|
||||
chapter = course.children[0]
|
||||
sequential = chapter.children[0]
|
||||
vertical = sequential.children[0]
|
||||
self.visit_sequential(course, chapter, sequential)
|
||||
|
||||
# check resume course buttons
|
||||
response = self.visit_course_home(course, resume_count=2)
|
||||
content = pq(response.content)
|
||||
self.assertTrue(content('.action-resume-course').attr('href').endswith('/vertical/' + vertical.url_name))
|
||||
|
||||
@override_switch(
|
||||
'{}.{}'.format(
|
||||
waffle.WAFFLE_NAMESPACE, waffle.ENABLE_VISUAL_PROGRESS
|
||||
),
|
||||
active=True
|
||||
)
|
||||
@override_settings(LMS_BASE='test_url:9999')
|
||||
@patch('completion.waffle.get_current_site')
|
||||
def test_resume_course_with_completion_api(self, get_patched_current_site):
|
||||
def test_resume_course_with_completion_api(self):
|
||||
"""
|
||||
Tests completion API resume button functionality
|
||||
"""
|
||||
self.override_waffle_switch(True)
|
||||
get_patched_current_site.return_value = self.site
|
||||
|
||||
# Course tree
|
||||
course = self.course
|
||||
@@ -422,16 +413,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
vertical1 = course.children[0].children[0].children[0]
|
||||
vertical2 = course.children[0].children[1].children[0]
|
||||
|
||||
# Fake a visit to sequence1/vertical1
|
||||
block_key = UsageKey.from_string(unicode(vertical1.location))
|
||||
completion = 1.0
|
||||
BlockCompletion.objects.submit_completion(
|
||||
user=self.user,
|
||||
course_key=course_key,
|
||||
block_key=block_key,
|
||||
completion=completion
|
||||
)
|
||||
|
||||
self.complete_sequential(self.course, vertical1)
|
||||
# Test for 'resume' link
|
||||
response = self.visit_course_home(course, resume_count=2)
|
||||
|
||||
@@ -439,15 +421,8 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
content = pq(response.content)
|
||||
self.assertTrue(content('.action-resume-course').attr('href').endswith('/vertical/' + vertical1.url_name))
|
||||
|
||||
# Fake a visit to sequence2/vertical2
|
||||
block_key = UsageKey.from_string(unicode(vertical2.location))
|
||||
completion = 1.0
|
||||
BlockCompletion.objects.submit_completion(
|
||||
user=self.user,
|
||||
course_key=course_key,
|
||||
block_key=block_key,
|
||||
completion=completion
|
||||
)
|
||||
self.complete_sequential(self.course, vertical2)
|
||||
# Test for 'resume' link
|
||||
response = self.visit_course_home(course, resume_count=2)
|
||||
|
||||
# Test for 'resume' link URL - should be vertical 2
|
||||
@@ -465,7 +440,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
|
||||
def test_resume_course_deleted_sequential(self):
|
||||
"""
|
||||
Tests resume course when the last accessed sequential is deleted and
|
||||
Tests resume course when the last completed sequential is deleted and
|
||||
there is another sequential in the vertical.
|
||||
|
||||
"""
|
||||
@@ -476,7 +451,8 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
self.assertGreaterEqual(len(chapter.children), 2)
|
||||
sequential = chapter.children[0]
|
||||
sequential2 = chapter.children[1]
|
||||
self.visit_sequential(course, chapter, sequential)
|
||||
self.complete_sequential(course, sequential)
|
||||
self.complete_sequential(course, sequential2)
|
||||
|
||||
# remove one of the sequentials from the chapter
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id):
|
||||
@@ -490,7 +466,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
|
||||
def test_resume_course_deleted_sequentials(self):
|
||||
"""
|
||||
Tests resume course when the last accessed sequential is deleted and
|
||||
Tests resume course when the last completed sequential is deleted and
|
||||
there are no sequentials left in the vertical.
|
||||
|
||||
"""
|
||||
@@ -500,7 +476,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
chapter = course.children[0]
|
||||
self.assertEqual(len(chapter.children), 2)
|
||||
sequential = chapter.children[0]
|
||||
self.visit_sequential(course, chapter, sequential)
|
||||
self.complete_sequential(course, sequential)
|
||||
|
||||
# remove all sequentials from chapter
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id):
|
||||
@@ -508,22 +484,14 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
self.store.delete_item(sequential.location, self.user.id)
|
||||
|
||||
# check resume course buttons
|
||||
self.visit_course_home(course, resume_count=1)
|
||||
self.visit_course_home(course, start_count=1, resume_count=0)
|
||||
|
||||
@override_switch(
|
||||
'{}.{}'.format(
|
||||
waffle.WAFFLE_NAMESPACE, waffle.ENABLE_VISUAL_PROGRESS
|
||||
),
|
||||
active=True
|
||||
)
|
||||
@patch('completion.waffle.get_current_site')
|
||||
def test_course_home_for_global_staff(self, get_patched_current_site):
|
||||
def test_course_home_for_global_staff(self):
|
||||
"""
|
||||
Tests that staff user can access the course home without being enrolled
|
||||
in the course.
|
||||
"""
|
||||
course = self.course
|
||||
get_patched_current_site.return_value = self.site
|
||||
self.user.is_staff = True
|
||||
self.user.save()
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Common utilities for the course experience, including course outline.
|
||||
"""
|
||||
from completion.models import BlockCompletion
|
||||
from completion.waffle import visual_progress_enabled
|
||||
|
||||
from lms.djangoapps.course_api.blocks.api import get_blocks
|
||||
from lms.djangoapps.course_blocks.utils import get_student_module_as_dict
|
||||
@@ -154,14 +153,11 @@ def get_course_outline_block_tree(request, course_id):
|
||||
populate_children(course_outline_root_block, all_blocks['blocks'])
|
||||
set_last_accessed_default(course_outline_root_block)
|
||||
|
||||
if visual_progress_enabled(course_key=course_key):
|
||||
mark_blocks_completed(
|
||||
block=course_outline_root_block,
|
||||
user=request.user,
|
||||
course_key=course_key
|
||||
)
|
||||
else:
|
||||
mark_last_accessed(request.user, course_key, course_outline_root_block)
|
||||
mark_blocks_completed(
|
||||
block=course_outline_root_block,
|
||||
user=request.user,
|
||||
course_key=course_key
|
||||
)
|
||||
return course_outline_root_block
|
||||
|
||||
|
||||
|
||||
@@ -43,18 +43,11 @@ class CourseOutlineFragmentView(EdxFragmentView):
|
||||
if not course_block_tree:
|
||||
return None
|
||||
|
||||
# TODO: EDUCATOR-2283 Remove 'show_visual_progress' from context
|
||||
# and remove the check for it in the HTML file
|
||||
show_visual_progress = (
|
||||
completion_waffle.visual_progress_enabled(course_key) and
|
||||
self.user_enrolled_after_completion_collection(request.user, course_key)
|
||||
)
|
||||
context = {
|
||||
'csrf': csrf(request)['csrf_token'],
|
||||
'course': course_overview,
|
||||
'blocks': course_block_tree,
|
||||
'show_visual_progress': show_visual_progress,
|
||||
'due_date_display_format': course.due_date_display_format,
|
||||
'blocks': course_block_tree
|
||||
}
|
||||
|
||||
# TODO: EDUCATOR-2283 Remove this check when the waffle flag is turned on in production
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
"""
|
||||
Tests waffle mechanics and feature-gating for block completion features.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from completion import waffle
|
||||
import ddt
|
||||
from django.test import TestCase
|
||||
import mock
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory, SiteConfigurationFactory
|
||||
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
|
||||
|
||||
@skip_unless_lms
|
||||
@ddt.ddt
|
||||
class FeatureGatingTests(TestCase):
|
||||
"""
|
||||
Tests the logic of the completion feature-gating functions in the LMS.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.site = SiteFactory.create()
|
||||
self.site_patcher = mock.patch('completion.waffle.get_current_site')
|
||||
mocked_current_site = self.site_patcher.start()
|
||||
mocked_current_site.return_value = self.site
|
||||
|
||||
self.course_key = CourseKey.from_string('course-v1:edX+DemoX+Demo_Course')
|
||||
|
||||
def tearDown(self):
|
||||
self.site_patcher.stop()
|
||||
|
||||
def _make_site_config(self, enable_feature):
|
||||
site_config = SiteConfigurationFactory.create(site=self.site)
|
||||
site_config.values[waffle.ENABLE_SITE_VISUAL_PROGRESS] = enable_feature
|
||||
site_config.save()
|
||||
|
||||
def test_site_disables_visual_progress_no_config(self):
|
||||
assert waffle.site_disables_visual_progress() is False
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_site_disables_visual_progress_with_config(self, config_value):
|
||||
self._make_site_config(config_value)
|
||||
assert (not config_value) == waffle.site_disables_visual_progress()
|
||||
|
||||
def test_visual_progress_gating_tracking_disabled(self):
|
||||
with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, False):
|
||||
assert waffle.visual_progress_enabled(self.course_key) is False
|
||||
|
||||
def test_visual_progress_gating_site_disabled(self):
|
||||
self._make_site_config(False)
|
||||
assert waffle.visual_progress_enabled(self.course_key) is False
|
||||
|
||||
def test_visual_progress_gating_course_disabled(self):
|
||||
self._make_site_config(True)
|
||||
with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True):
|
||||
with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, False):
|
||||
with override_waffle_flag(waffle.waffle_flag(), active=False):
|
||||
assert waffle.visual_progress_enabled(self.course_key) is False
|
||||
|
||||
def test_visual_progress_happy_path_no_site_config(self):
|
||||
with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True):
|
||||
with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, True):
|
||||
assert waffle.visual_progress_enabled(self.course_key) is True
|
||||
|
||||
def test_visual_progress_happy_path_with_site_config(self):
|
||||
self._make_site_config(True)
|
||||
with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True):
|
||||
with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, True):
|
||||
assert waffle.visual_progress_enabled(self.course_key) is True
|
||||
|
||||
def test_visual_progress_happy_path_visual_switch_disabled(self):
|
||||
self._make_site_config(True)
|
||||
with waffle.waffle().override(waffle.ENABLE_COMPLETION_TRACKING, True):
|
||||
with waffle.waffle().override(waffle.ENABLE_VISUAL_PROGRESS, False):
|
||||
with override_waffle_flag(waffle.waffle_flag(), active=True):
|
||||
assert waffle.visual_progress_enabled(self.course_key) is True
|
||||
@@ -54,7 +54,7 @@ edx-lint==0.5.4
|
||||
git+https://github.com/cpennington/pylint-django@fix-field-inference-during-monkey-patching#egg=pylint-django==0.0
|
||||
|
||||
enum34==1.1.6
|
||||
edx-completion==0.1.4
|
||||
edx-completion==0.1.5
|
||||
edx-django-oauth2-provider==1.2.5
|
||||
edx-django-sites-extensions==2.3.1
|
||||
edx-enterprise==0.67.3
|
||||
|
||||
Reference in New Issue
Block a user