""" Tests for tab functions (just primitive). """ import json from cms.djangoapps.contentstore.tests.utils import CourseTestCase from cms.djangoapps.contentstore.utils import reverse_course_url from cms.djangoapps.contentstore.views import tabs from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.tabs import CourseTabList from xmodule.x_module import STUDENT_VIEW class TabsPageTests(CourseTestCase): """Test cases for Tabs (a.k.a Pages) page""" def setUp(self): """Common setup for tests""" # call super class to setup course, etc. super().setUp() # Set the URL for tests self.url = reverse_course_url('tabs_handler', self.course.id) # add a static tab to the course, for code coverage self.test_tab = ItemFactory.create( parent_location=self.course.location, category="static_tab", display_name="Static_1" ) self.reload_course() def check_invalid_tab_id_response(self, resp): """Verify response is an error listing the invalid_tab_id""" self.assertEqual(resp.status_code, 400) resp_content = json.loads(resp.content.decode('utf-8')) self.assertIn("error", resp_content) self.assertIn("invalid_tab_id", resp_content['error']) def test_not_implemented(self): """Verify not implemented errors""" # JSON GET request not supported with self.assertRaises(NotImplementedError): self.client.get(self.url) # JSON POST request not supported with self.assertRaises(NotImplementedError): self.client.ajax_post( self.url, data=json.dumps({ 'tab_id_locator': {'tab_id': 'courseware'}, 'unsupported_request': None, }), ) # invalid JSON POST request with self.assertRaises(NotImplementedError): self.client.ajax_post( self.url, data={'invalid_request': None}, ) def test_view_index(self): """Basic check that the Pages page responds correctly""" resp = self.client.get_html(self.url) self.assertContains(resp, 'course-nav-list') def test_reorder_tabs(self): """Test re-ordering of tabs""" # get the original tab ids orig_tab_ids = [tab.tab_id for tab in self.course.tabs] tab_ids = list(orig_tab_ids) num_orig_tabs = len(orig_tab_ids) # make sure we have enough tabs to play around with self.assertGreaterEqual(num_orig_tabs, 5) # reorder the last two tabs tab_ids[num_orig_tabs - 1], tab_ids[num_orig_tabs - 2] = tab_ids[num_orig_tabs - 2], tab_ids[num_orig_tabs - 1] # remove the middle tab # (the code needs to handle the case where tabs requested for re-ordering is a subset of the tabs in the course) removed_tab = tab_ids.pop(num_orig_tabs // 2) self.assertEqual(len(tab_ids), num_orig_tabs - 1) # post the request resp = self.client.ajax_post( self.url, data={'tabs': [{'tab_id': tab_id} for tab_id in tab_ids]}, ) self.assertEqual(resp.status_code, 204) # reload the course and verify the new tab order self.reload_course() new_tab_ids = [tab.tab_id for tab in self.course.tabs] self.assertEqual(new_tab_ids, tab_ids + [removed_tab]) self.assertNotEqual(new_tab_ids, orig_tab_ids) def test_reorder_tabs_invalid_list(self): """Test re-ordering of tabs with invalid tab list""" orig_tab_ids = [tab.tab_id for tab in self.course.tabs] tab_ids = list(orig_tab_ids) # reorder the first two tabs tab_ids[0], tab_ids[1] = tab_ids[1], tab_ids[0] # post the request resp = self.client.ajax_post( self.url, data={'tabs': [{'tab_id': tab_id} for tab_id in tab_ids]}, ) self.assertEqual(resp.status_code, 400) resp_content = json.loads(resp.content.decode('utf-8')) self.assertIn("error", resp_content) def test_reorder_tabs_invalid_tab(self): """Test re-ordering of tabs with invalid tab""" invalid_tab_ids = ['courseware', 'info', 'invalid_tab_id'] # post the request resp = self.client.ajax_post( self.url, data={'tabs': [{'tab_id': tab_id} for tab_id in invalid_tab_ids]}, ) self.check_invalid_tab_id_response(resp) def check_toggle_tab_visiblity(self, tab_type, new_is_hidden_setting): """Helper method to check changes in tab visibility""" # find the tab old_tab = CourseTabList.get_tab_by_type(self.course.tabs, tab_type) # visibility should be different from new setting self.assertNotEqual(old_tab.is_hidden, new_is_hidden_setting) # post the request resp = self.client.ajax_post( self.url, data=json.dumps({ 'tab_id_locator': {'tab_id': old_tab.tab_id}, 'is_hidden': new_is_hidden_setting, }), ) self.assertEqual(resp.status_code, 204) # reload the course and verify the new visibility setting self.reload_course() new_tab = CourseTabList.get_tab_by_type(self.course.tabs, tab_type) self.assertEqual(new_tab.is_hidden, new_is_hidden_setting) def test_toggle_tab_visibility(self): """Test toggling of tab visibility""" self.check_toggle_tab_visiblity('wiki', True) self.check_toggle_tab_visiblity('wiki', False) def test_toggle_invalid_tab_visibility(self): """Test toggling visibility of an invalid tab""" # post the request resp = self.client.ajax_post( self.url, data=json.dumps({ 'tab_id_locator': {'tab_id': 'invalid_tab_id'} }), ) self.check_invalid_tab_id_response(resp) def test_tab_preview_html(self): """ Verify that the static tab renders itself with the correct HTML """ preview_url = f'/xblock/{self.test_tab.location}/{STUDENT_VIEW}' resp = self.client.get(preview_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) resp_content = json.loads(resp.content.decode('utf-8')) html = resp_content['html'] # Verify that the HTML contains the expected elements self.assertIn('Edit', html) self.assertIn('Duplicate this component', html) self.assertIn('Delete this component', html) self.assertIn('', html) class PrimitiveTabEdit(ModuleStoreTestCase): """Tests for the primitive tab edit data manipulations""" def test_delete(self): """Test primitive tab deletion.""" course = CourseFactory.create() with self.assertRaises(ValueError): tabs.primitive_delete(course, 0) with self.assertRaises(ValueError): tabs.primitive_delete(course, 1) with self.assertRaises(IndexError): tabs.primitive_delete(course, 7) tabs.primitive_delete(course, 2) self.assertNotIn({'type': 'textbooks'}, course.tabs) # Check that discussion has shifted up self.assertEqual(course.tabs[2], {'type': 'discussion', 'name': 'Discussion'}) def test_insert(self): """Test primitive tab insertion.""" course = CourseFactory.create() tabs.primitive_insert(course, 2, 'pdf_textbooks', 'aname') self.assertEqual(course.tabs[2], {'type': 'pdf_textbooks', 'name': 'aname'}) with self.assertRaises(ValueError): tabs.primitive_insert(course, 0, 'pdf_textbooks', 'aname') with self.assertRaises(ValueError): tabs.primitive_insert(course, 3, 'static_tab', 'aname') def test_save(self): """Test course saving.""" course = CourseFactory.create() tabs.primitive_insert(course, 3, 'pdf_textbooks', 'aname') course2 = modulestore().get_course(course.id) self.assertEqual(course2.tabs[3], {'type': 'pdf_textbooks', 'name': 'aname'})