Files
edx-platform/cms/djangoapps/contentstore/views/tests/test_gating.py
Zia Fazal 53cf5638b6 added radio input fields to pre-requisite selection
Initial changes to gate section based on completion percentage

code refactoring and added evaluation of completion milestone

Fixed broken unit tests and added new tests

Fixed broken tests and quality violations

Fixed Pep8 violation

Fixed eslint quality violations

Test changes as suggested by reviewer

changes after feedbacy from reviewer

Update the docstring with suggested changes

excluding chapter from the blocks

Disallow empty values for min score and min completion

Changes afte feedback from UX/Accessibility

removed blank line
2018-05-30 11:25:59 +05:00

157 lines
5.6 KiB
Python

"""
Unit tests for the gating feature in Studio
"""
import ddt
import json
from mock import patch
from contentstore.tests.utils import CourseTestCase
from contentstore.utils import reverse_usage_url
from contentstore.views.item import VisibilityState
from openedx.core.lib.gating.api import GATING_NAMESPACE_QUALIFIER
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE
from xmodule.modulestore.tests.factories import ItemFactory
@ddt.ddt
class TestSubsectionGating(CourseTestCase):
"""
Tests for the subsection gating feature
"""
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
ENABLED_SIGNALS = ['item_deleted']
def setUp(self):
"""
Initial data setup
"""
super(TestSubsectionGating, self).setUp()
# Enable subsection gating for the test course
self.course.enable_subsection_gating = True
self.save_course()
# create a chapter
self.chapter = ItemFactory.create(
parent_location=self.course.location,
category='chapter',
display_name='untitled chapter'
)
# create 2 sequentials
self.seq1 = ItemFactory.create(
parent_location=self.chapter.location,
category='sequential',
display_name='untitled sequential 1'
)
self.seq1_url = reverse_usage_url('xblock_handler', self.seq1.location)
self.seq2 = ItemFactory.create(
parent_location=self.chapter.location,
category='sequential',
display_name='untitled sequential 2'
)
self.seq2_url = reverse_usage_url('xblock_handler', self.seq2.location)
@patch('contentstore.views.item.gating_api.add_prerequisite')
def test_add_prerequisite(self, mock_add_prereq):
"""
Test adding a subsection as a prerequisite
"""
self.client.ajax_post(
self.seq1_url,
data={'isPrereq': True}
)
mock_add_prereq.assert_called_with(self.course.id, self.seq1.location)
@patch('contentstore.views.item.gating_api.remove_prerequisite')
def test_remove_prerequisite(self, mock_remove_prereq):
"""
Test removing a subsection as a prerequisite
"""
self.client.ajax_post(
self.seq1_url,
data={'isPrereq': False}
)
mock_remove_prereq.assert_called_with(self.seq1.location)
@patch('contentstore.views.item.gating_api.set_required_content')
def test_add_gate(self, mock_set_required_content):
"""
Test adding a gated subsection
"""
self.client.ajax_post(
self.seq2_url,
data={'prereqUsageKey': unicode(self.seq1.location), 'prereqMinScore': '100', 'prereqMinCompletion': '100'}
)
mock_set_required_content.assert_called_with(
self.course.id,
self.seq2.location,
unicode(self.seq1.location),
'100',
'100'
)
@patch('contentstore.views.item.gating_api.set_required_content')
def test_remove_gate(self, mock_set_required_content):
"""
Test removing a gated subsection
"""
self.client.ajax_post(
self.seq2_url,
data={'prereqUsageKey': '', 'prereqMinScore': '', 'prereqMinCompletion': ''}
)
mock_set_required_content.assert_called_with(
self.course.id,
self.seq2.location,
'',
'',
''
)
@patch('contentstore.views.item.gating_api.get_prerequisites')
@patch('contentstore.views.item.gating_api.get_required_content')
@patch('contentstore.views.item.gating_api.is_prerequisite')
@ddt.data(
(90, None),
(None, 90),
(100, 100),
)
@ddt.unpack
def test_get_prerequisite(
self, min_score, min_completion,
mock_is_prereq, mock_get_required_content, mock_get_prereqs
):
mock_is_prereq.return_value = True
mock_get_required_content.return_value = unicode(self.seq1.location), min_score, min_completion
mock_get_prereqs.return_value = [
{'namespace': '{}{}'.format(unicode(self.seq1.location), GATING_NAMESPACE_QUALIFIER)},
{'namespace': '{}{}'.format(unicode(self.seq2.location), GATING_NAMESPACE_QUALIFIER)}
]
resp = json.loads(self.client.get_json(self.seq2_url).content)
mock_is_prereq.assert_called_with(self.course.id, self.seq2.location)
mock_get_required_content.assert_called_with(self.course.id, self.seq2.location)
mock_get_prereqs.assert_called_with(self.course.id)
self.assertTrue(resp['is_prereq'])
self.assertEqual(resp['prereq'], unicode(self.seq1.location))
self.assertEqual(resp['prereq_min_score'], min_score)
self.assertEqual(resp['prereq_min_completion'], min_completion)
self.assertEqual(resp['visibility_state'], VisibilityState.gated)
@patch('contentstore.signals.handlers.gating_api.set_required_content')
@patch('contentstore.signals.handlers.gating_api.remove_prerequisite')
def test_delete_item_signal_handler_called(self, mock_remove_prereq, mock_set_required):
seq3 = ItemFactory.create(
parent_location=self.chapter.location,
category='sequential',
display_name='untitled sequential 3'
)
self.client.delete(reverse_usage_url('xblock_handler', seq3.location))
mock_remove_prereq.assert_called_with(seq3.location)
mock_set_required.assert_called_with(seq3.location.course_key, seq3.location, None, None, None)