diff --git a/cms/djangoapps/contentstore/features/advanced-settings.feature b/cms/djangoapps/contentstore/features/advanced-settings.feature index db7294c14c..558294e890 100644 --- a/cms/djangoapps/contentstore/features/advanced-settings.feature +++ b/cms/djangoapps/contentstore/features/advanced-settings.feature @@ -21,8 +21,7 @@ Feature: Advanced (manual) course policy Scenario: Test editing key value Given I am on the Advanced Course Settings page in Studio - When I edit the value of a policy key - And I press the "Save" notification button + When I edit the value of a policy key and save Then the policy key value is changed And I reload the page Then the policy key value is changed diff --git a/cms/djangoapps/contentstore/features/advanced-settings.py b/cms/djangoapps/contentstore/features/advanced-settings.py index 16562b6b15..6fb102faea 100644 --- a/cms/djangoapps/contentstore/features/advanced-settings.py +++ b/cms/djangoapps/contentstore/features/advanced-settings.py @@ -51,6 +51,11 @@ def edit_the_value_of_a_policy_key(step): e._element.send_keys(Keys.TAB, Keys.END, Keys.ARROW_LEFT, ' ', 'X') +@step(u'I edit the value of a policy key and save$') +def edit_the_value_of_a_policy_key(step): + change_display_name_value(step, '"foo"') + + @step('I create a JSON object as a value$') def create_JSON_object(step): change_display_name_value(step, '{"key": "value", "key_2": "value_2"}') @@ -96,7 +101,7 @@ def the_policy_key_value_is_unchanged(step): @step(u'the policy key value is changed$') def the_policy_key_value_is_changed(step): - assert_equal(get_display_name_value(), '"Robot Super Course X"') + assert_equal(get_display_name_value(), '"foo"') ############# HELPERS ############### diff --git a/cms/djangoapps/contentstore/features/course-settings.py b/cms/djangoapps/contentstore/features/course-settings.py index 9eb5b0951d..d69266b7de 100644 --- a/cms/djangoapps/contentstore/features/course-settings.py +++ b/cms/djangoapps/contentstore/features/course-settings.py @@ -18,8 +18,8 @@ COURSE_END_TIME_CSS = "#course-end-time" ENROLLMENT_START_TIME_CSS = "#course-enrollment-start-time" ENROLLMENT_END_TIME_CSS = "#course-enrollment-end-time" -DUMMY_TIME = "3:30pm" -DEFAULT_TIME = "12:00am" +DUMMY_TIME = "15:30" +DEFAULT_TIME = "00:00" ############### ACTIONS #################### diff --git a/cms/djangoapps/contentstore/features/section.py b/cms/djangoapps/contentstore/features/section.py index fca14e21f0..59c5a37b33 100644 --- a/cms/djangoapps/contentstore/features/section.py +++ b/cms/djangoapps/contentstore/features/section.py @@ -38,7 +38,7 @@ def i_click_the_edit_link_for_the_release_date(step): @step('I save a new section release date$') def i_save_a_new_section_release_date(step): set_date_and_time('input.start-date.date.hasDatepicker', '12/25/2013', - 'input.start-time.time.ui-timepicker-input', '12:00am') + 'input.start-time.time.ui-timepicker-input', '00:00') world.browser.click_link_by_text('Save') @@ -105,7 +105,7 @@ def the_section_release_date_picker_not_visible(step): def the_section_release_date_is_updated(step): css = 'span.published-status' status_text = world.css_text(css) - assert_equal(status_text, 'Will Release: 12/25/2013 at 12:00am') + assert_equal(status_text, 'Will Release: 12/25/2013 at 00:00 UTC') ############ HELPER METHODS ################### diff --git a/cms/djangoapps/contentstore/features/subsection.py b/cms/djangoapps/contentstore/features/subsection.py index 1ec43e6971..f9e5b52bb2 100644 --- a/cms/djangoapps/contentstore/features/subsection.py +++ b/cms/djangoapps/contentstore/features/subsection.py @@ -57,18 +57,18 @@ def i_see_complete_subsection_name_with_quote_in_editor(step): @step('I have set a release date and due date in different years$') def test_have_set_dates_in_different_years(step): - set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '3:00am') + set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '03:00') world.css_click('.set-date') # Use a year in the past so that current year will always be different. - set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '4:00am') + set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '04:00') @step('I see the correct dates$') def i_see_the_correct_dates(step): assert_equal('12/25/2011', world.css_find('input#start_date').first.value) - assert_equal('3:00am', world.css_find('input#start_time').first.value) + assert_equal('03:00', world.css_find('input#start_time').first.value) assert_equal('01/02/2012', world.css_find('input#due_date').first.value) - assert_equal('4:00am', world.css_find('input#due_time').first.value) + assert_equal('04:00', world.css_find('input#due_time').first.value) @step('I mark it as Homework$') diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 685867a1cb..ef6ab71b88 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -93,6 +93,69 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): return cnt + def test_draft_metadata(self): + ''' + This verifies a bug we had where inherited metadata was getting written to the + module as 'own-metadata' when publishing. Also verifies the metadata inheritance is + properly computed + ''' + store = modulestore() + draft_store = modulestore('draft') + import_from_xml(store, 'common/test/data/', ['simple']) + + course = draft_store.get_item(Location(['i4x', 'edX', 'simple', + 'course', '2012_Fall', None]), depth=None) + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod) + self.assertNotIn('graceperiod', own_metadata(html_module)) + + draft_store.clone_item(html_module.location, html_module.location) + + # refetch to check metadata + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod) + self.assertNotIn('graceperiod', own_metadata(html_module)) + + # publish module + draft_store.publish(html_module.location, 0) + + # refetch to check metadata + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + self.assertEqual(html_module.lms.graceperiod, course.lms.graceperiod) + self.assertNotIn('graceperiod', own_metadata(html_module)) + + # put back in draft and change metadata and see if it's now marked as 'own_metadata' + draft_store.clone_item(html_module.location, html_module.location) + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + new_graceperiod = timedelta(**{'hours': 1}) + + self.assertNotIn('graceperiod', own_metadata(html_module)) + html_module.lms.graceperiod = new_graceperiod + self.assertIn('graceperiod', own_metadata(html_module)) + self.assertEqual(html_module.lms.graceperiod, new_graceperiod) + + draft_store.update_metadata(html_module.location, own_metadata(html_module)) + + # read back to make sure it reads as 'own-metadata' + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + self.assertIn('graceperiod', own_metadata(html_module)) + self.assertEqual(html_module.lms.graceperiod, new_graceperiod) + + # republish + draft_store.publish(html_module.location, 0) + + # and re-read and verify 'own-metadata' + draft_store.clone_item(html_module.location, html_module.location) + html_module = draft_store.get_item(['i4x', 'edX', 'simple', 'html', 'test_html', None]) + + self.assertIn('graceperiod', own_metadata(html_module)) + self.assertEqual(html_module.lms.graceperiod, new_graceperiod) + def test_get_depth_with_drafts(self): import_from_xml(modulestore(), 'common/test/data/', ['simple']) @@ -609,6 +672,113 @@ class ContentStoreTest(ModuleStoreTestCase): self.assertIn('markdown', context, "markdown is missing from context") self.assertNotIn('markdown', problem.editable_metadata_fields, "Markdown slipped into the editable metadata fields") + def test_cms_imported_course_walkthrough(self): + """ + Import and walk through some common URL endpoints. This just verifies non-500 and no other + correct behavior, so it is not a deep test + """ + import_from_xml(modulestore(), 'common/test/data/', ['simple']) + loc = Location(['i4x', 'edX', 'simple', 'course', '2012_Fall', None]) + resp = self.client.get(reverse('course_index', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + + self.assertEqual(200, resp.status_code) + self.assertContains(resp, 'Chapter 2') + + # go to various pages + + # import page + resp = self.client.get(reverse('import_course', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # export page + resp = self.client.get(reverse('export_course', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # manage users + resp = self.client.get(reverse('manage_users', + kwargs={'location': loc.url()})) + self.assertEqual(200, resp.status_code) + + # course info + resp = self.client.get(reverse('course_info', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # settings_details + resp = self.client.get(reverse('settings_details', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # settings_details + resp = self.client.get(reverse('settings_grading', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # static_pages + resp = self.client.get(reverse('static_pages', + kwargs={'org': loc.org, + 'course': loc.course, + 'coursename': loc.name})) + self.assertEqual(200, resp.status_code) + + # static_pages + resp = self.client.get(reverse('asset_index', + kwargs={'org': loc.org, + 'course': loc.course, + 'name': loc.name})) + self.assertEqual(200, resp.status_code) + + # go look at a subsection page + subsection_location = loc._replace(category='sequential', name='test_sequence') + resp = self.client.get(reverse('edit_subsection', + kwargs={'location': subsection_location.url()})) + self.assertEqual(200, resp.status_code) + + # go look at the Edit page + unit_location = loc._replace(category='vertical', name='test_vertical') + resp = self.client.get(reverse('edit_unit', + kwargs={'location': unit_location.url()})) + self.assertEqual(200, resp.status_code) + + # delete a component + del_loc = loc._replace(category='html', name='test_html') + resp = self.client.post(reverse('delete_item'), + json.dumps({'id': del_loc.url()}), "application/json") + self.assertEqual(200, resp.status_code) + + # delete a unit + del_loc = loc._replace(category='vertical', name='test_vertical') + resp = self.client.post(reverse('delete_item'), + json.dumps({'id': del_loc.url()}), "application/json") + self.assertEqual(200, resp.status_code) + + # delete a unit + del_loc = loc._replace(category='sequential', name='test_sequence') + resp = self.client.post(reverse('delete_item'), + json.dumps({'id': del_loc.url()}), "application/json") + self.assertEqual(200, resp.status_code) + + # delete a chapter + del_loc = loc._replace(category='chapter', name='chapter_2') + resp = self.client.post(reverse('delete_item'), + json.dumps({'id': del_loc.url()}), "application/json") + self.assertEqual(200, resp.status_code) + def test_import_metadata_with_attempts_empty_string(self): import_from_xml(modulestore(), 'common/test/data/', ['simple']) module_store = modulestore('direct') diff --git a/cms/static/client_templates/checklist.html b/cms/static/client_templates/checklist.html index ec6ff4e892..6884b0e9c9 100644 --- a/cms/static/client_templates/checklist.html +++ b/cms/static/client_templates/checklist.html @@ -44,7 +44,7 @@ <% if (item['action_text'] !== '' && item['action_url'] !== '') { %>