diff --git a/cms/djangoapps/contentstore/features/course-updates.feature b/cms/djangoapps/contentstore/features/course-updates.feature
index 79d6445194..f71d6c3d78 100644
--- a/cms/djangoapps/contentstore/features/course-updates.feature
+++ b/cms/djangoapps/contentstore/features/course-updates.feature
@@ -2,46 +2,6 @@
Feature: CMS.Course updates
As a course author, I want to be able to provide updates to my students
-# Commenting out as flaky TNL-5051 07/20/2016
- # Internet explorer can't select all so the update appears weirdly
-# @skip_internetexplorer
-# Scenario: Users can add updates
-# Given I have opened a new course in Studio
-# And I go to the course updates page
-# When I add a new update with the text "Hello"
-# Then I should see the update "Hello"
-# And I see a "saving" notification
-
-# Commenting out as flaky TNL-5051 07/20/2016
-# # Internet explorer can't select all so the update appears weirdly
-# @skip_internetexplorer
-# Scenario: Users can edit updates
-# Given I have opened a new course in Studio
-# And I go to the course updates page
-# When I add a new update with the text "Hello"
-# And I modify the text to "Goodbye"
-# Then I should see the update "Goodbye"
-# And I see a "saving" notification
-
-# Commenting out as flaky TNL-5051 07/20/2016
-# Scenario: Users can delete updates
-# Given I have opened a new course in Studio
-# And I go to the course updates page
-# And I add a new update with the text "Hello"
-# And I delete the update
-# And I confirm the prompt
-# Then I should not see the update "Hello"
-# And I see a "deleting" notification
-
-# Commenting out as flaky TNL-5051 07/20/2016
-# Scenario: Users can edit update dates
-# Given I have opened a new course in Studio
-# And I go to the course updates page
-# And I add a new update with the text "Hello"
-# When I edit the date to "06/01/13"
-# Then I should see the date "June 1, 2013"
-# And I see a "saving" notification
-
# Internet explorer can't select all so the update appears weirdly
@skip_internetexplorer
Scenario: Users can change handouts
@@ -51,26 +11,6 @@ Feature: CMS.Course updates
Then I see the handout "Test"
And I see a "saving" notification
- Scenario: Text outside of tags is preserved
- Given I have opened a new course in Studio
- And I go to the course updates page
- When I add a new update with the text "before middle after"
- Then I should see the update "before middle after"
- And when I reload the page
- Then I should see the update "before middle after"
-
-# Commenting out as flaky TNL-5051 07/22/2016
-# Scenario: Static links are rewritten when previewing a course update
-# Given I have opened a new course in Studio
-# And I go to the course updates page
-# When I add a new update with the text "
"
-# # Can only do partial text matches because of the quotes with in quotes (and regexp step matching).
-# Then I should see the asset update to "my_img.jpg"
-# And I change the update from "/static/my_img.jpg" to "
"
-# Then I should see the asset update to "modified.jpg"
-# And when I reload the page
-# Then I should see the asset update to "modified.jpg"
-
Scenario: Static links are rewritten when previewing handouts
Given I have opened a new course in Studio
And I go to the course updates page
diff --git a/cms/djangoapps/contentstore/features/course-updates.py b/cms/djangoapps/contentstore/features/course-updates.py
index 1b50910a65..3a9d0103c6 100644
--- a/cms/djangoapps/contentstore/features/course-updates.py
+++ b/cms/djangoapps/contentstore/features/course-updates.py
@@ -1,8 +1,7 @@
# pylint: disable=missing-docstring
+from cms.djangoapps.contentstore.features.common import type_in_codemirror, get_codemirror_value
from lettuce import world, step
-from selenium.webdriver.common.keys import Keys
-from common import type_in_codemirror, get_codemirror_value
from nose.tools import assert_in
@@ -15,77 +14,11 @@ def go_to_updates(_step):
world.wait_for_visible('#course-handouts-view')
-@step(u'I add a new update with the text "([^"]*)"$')
-def add_update(_step, text):
- update_css = '.new-update-button'
- world.css_click(update_css)
- world.wait_for_visible('.CodeMirror')
- change_text(text)
-
-
-@step(u'I should see the update "([^"]*)"$')
-def check_update(_step, text):
- update_css = 'div.update-contents'
- update_html = world.css_find(update_css).html
- assert_in(text, update_html)
-
-
-@step(u'I should see the asset update to "([^"]*)"$')
-def check_asset_update(_step, asset_file):
- update_css = 'div.update-contents'
- update_html = world.css_find(update_css).html
- asset_key = world.scenario_dict['COURSE'].id.make_asset_key(asset_type='asset', path=asset_file)
- assert_in(unicode(asset_key), update_html)
-
-
-@step(u'I should not see the update "([^"]*)"$')
-def check_no_update(_step, text):
- update_css = 'div.update-contents'
- assert world.is_css_not_present(update_css)
-
-
-@step(u'I modify the text to "([^"]*)"$')
-def modify_update(_step, text):
- button_css = 'div.post-preview .edit-button'
- world.css_click(button_css)
- change_text(text)
-
-
-@step(u'I change the update from "([^"]*)" to "([^"]*)"$')
-def change_existing_update(_step, before, after):
- verify_text_in_editor_and_update('div.post-preview .edit-button', before, after)
-
-
@step(u'I change the handout from "([^"]*)" to "([^"]*)"$')
def change_existing_handout(_step, before, after):
verify_text_in_editor_and_update('div.course-handouts .edit-button', before, after)
-@step(u'I delete the update$')
-def click_button(_step):
- button_css = 'div.post-preview .delete-button'
- world.css_click(button_css)
-
-
-@step(u'I edit the date to "([^"]*)"$')
-def change_date(_step, new_date):
- button_css = 'div.post-preview .edit-button'
- world.css_click(button_css)
- date_css = 'input.date'
- date = world.css_find(date_css)
- for __ in range(len(date.value)):
- date._element.send_keys(Keys.END, Keys.BACK_SPACE)
- date._element.send_keys(new_date)
- save_css = '.save-button'
- world.css_click(save_css)
-
-
-@step(u'I should see the date "([^"]*)"$')
-def check_date(_step, date):
- date_css = 'span.date-display'
- assert_in(date, world.css_html(date_css))
-
-
@step(u'I modify the handout to "([^"]*)"$')
def edit_handouts(_step, text):
edit_css = 'div.course-handouts > .edit-button'
diff --git a/common/test/acceptance/pages/studio/course_info.py b/common/test/acceptance/pages/studio/course_info.py
index 12b8780085..39f09b4851 100644
--- a/common/test/acceptance/pages/studio/course_info.py
+++ b/common/test/acceptance/pages/studio/course_info.py
@@ -1,16 +1,134 @@
"""
Course Updates page.
"""
-
+from common.test.acceptance.pages.common.utils import click_css, confirm_prompt
from common.test.acceptance.pages.studio.course_page import CoursePage
+from common.test.acceptance.pages.studio.utils import type_in_codemirror, set_input_value
class CourseUpdatesPage(CoursePage):
"""
Course Updates page.
"""
-
url_path = "course_info"
def is_browser_on_page(self):
- return self.q(css='body.view-updates').present
+ """
+ Returns whether or not the browser on the page and has loaded the required content
+ """
+ # Check for the presence of handouts-content, when it is present the render function has completed
+ # loading the updates and handout sections
+ return (self.q(css='.handouts-content').present and
+ self.q(css='article#course-update-view.course-updates').present)
+
+ def is_course_update_list_empty(self):
+ """
+ Checks whether or not the update contents list is empty
+ """
+ return len(self.q(css='.update-contents')) == 0
+
+ def is_new_update_button_present(self):
+ """
+ Checks for the presence of the new update post button.
+ """
+ return self.q(css='.new-update-button').present
+
+ def click_new_update_button(self):
+ """
+ Clicks the new-update button.
+ """
+ click_css(self, '.new-update-button', require_notification=False)
+
+ def submit_update(self, message):
+ """
+ Adds update text to the new update CodeMirror form and submits that text.
+
+ Arguments:
+ message (str): The message to be added and saved.
+ """
+ type_in_codemirror(self, 0, message)
+ self.click_new_update_save_button()
+
+ def set_date(self, date):
+ """
+ Sets the updates date input to the provided value.
+
+ Arguments:
+ date (str): Date string in the format DD/MM/YYYY
+ """
+ set_input_value(self, 'input.date', date)
+
+ def is_first_update_date(self, search_date):
+ """
+ Checks to see if the search date is present
+
+ Arguments:
+ search_date (str): e.g. 06/01/2013 would be found with June 1, 2013
+
+ Returns:
+ bool: True if the date is in the first update and False otherwise.
+ """
+ return search_date == self.q(css='.date-display').html[0]
+
+ def is_new_update_save_button_present(self):
+ """
+ Checks to see if the CodeMirror Update save button is present.
+ """
+ return self.q(css='.save-button').present
+
+ def click_new_update_save_button(self):
+ """
+ Clicks the CodeMirror Update save button.
+ """
+ click_css(self, '.save-button')
+
+ def is_edit_button_present(self):
+ """
+ Checks to see if the edit update post buttons if present.
+ """
+ return self.q(css='.post-preview .edit-button').present
+
+ def click_edit_update_button(self):
+ """
+ Clicks the edit update post button.
+ """
+ click_css(self, '.post-preview .edit-button', require_notification=False)
+ self.wait_for_element_visibility('.CodeMirror', 'Waiting for .CodeMirror')
+
+ def is_delete_update_button_present(self):
+ """
+ Checks to see if the delete update post button is present.
+ """
+ return self.q(css='.post-preview .delete-button').present
+
+ def click_delete_update_button(self):
+ """
+ Clicks the delete update post button and confirms the delete notification.
+ """
+ click_css(self, '.post-preview .delete-button', require_notification=False)
+ confirm_prompt(self)
+
+ def is_first_update_message(self, message):
+ """
+ Looks for the message in the first course update posted.
+
+ Arguments:
+ message (str): String containing the message that is to be searched for
+
+ Returns:
+ bool: True if the first update is the message, false otherwise.
+ """
+ return message == self.q(css='.update-contents').html[0]
+
+ def first_update_contains_html(self, value):
+ """
+ Looks to see if the html provided is contained in the first update
+
+ Arguments:
+ value (str): String value that will be looked for
+
+ Returns:
+ bool: True if the value is contained in the first update
+ """
+ update = self.q(css='.update-contents').html
+ return value in update[0]
diff --git a/common/test/acceptance/tests/studio/test_studio_course_info.py b/common/test/acceptance/tests/studio/test_studio_course_info.py
new file mode 100644
index 0000000000..78d5f901e8
--- /dev/null
+++ b/common/test/acceptance/tests/studio/test_studio_course_info.py
@@ -0,0 +1,146 @@
+"""
+Acceptance Tests for Course Information
+"""
+from common.test.acceptance.pages.studio.course_info import CourseUpdatesPage
+from common.test.acceptance.tests.studio.base_studio_test import StudioCourseTest
+
+from ...pages.studio.auto_auth import AutoAuthPage
+from ...pages.studio.index import DashboardPage
+
+
+class UsersCanAddUpdatesTest(StudioCourseTest):
+ """
+ Series of Bok Choy Tests to test the Course Updates page
+ """
+
+ def _create_and_verify_update(self, message):
+ """
+ Helper method to create and verify and update based on the message.
+
+ Arguments:
+ message (str): Message to add to the update.
+ """
+ self.course_updates_page.visit()
+ self.assertTrue(self.course_updates_page.is_new_update_button_present())
+ self.course_updates_page.click_new_update_button()
+ self.course_updates_page.submit_update(message)
+ self.assertTrue(self.course_updates_page.is_first_update_message(message))
+
+ def setUp(self, is_staff=False, test_xss=True):
+ super(UsersCanAddUpdatesTest, self).setUp()
+ self.auth_page = AutoAuthPage(self.browser, staff=True)
+ self.dashboard_page = DashboardPage(self.browser)
+ self.course_updates_page = CourseUpdatesPage(
+ self.browser,
+ self.course_info['org'],
+ self.course_info['number'],
+ self.course_info['run']
+ )
+
+ def test_course_updates_page_exists(self):
+ """
+ Scenario: User can access Course Updates Page
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ When I visit the page
+ Then I should see any course updates
+ And I should see the new update button
+ """
+ self.course_updates_page.visit()
+ self.course_updates_page.wait_for_page()
+ self.assertTrue(self.course_updates_page.is_new_update_button_present)
+
+ def test_new_course_update_is_present(self):
+ """
+ Scenario: Users can add updates
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ When I add a new update with the text "Hello"
+ Then I should see the update "Hello"
+ And I see a "saving" notification
+ """
+ self._create_and_verify_update('Hello')
+
+ def test_new_course_update_can_be_edited(self):
+ """
+ Scenario: Users can edit updates
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ When I add a new update with the text "Hello"
+ And I modify the text to "Goodbye"
+ Then I should see the update "Goodbye"
+ """
+ self._create_and_verify_update('Hello')
+ self.assertTrue(self.course_updates_page.is_edit_button_present())
+ self.course_updates_page.click_edit_update_button()
+ self.course_updates_page.submit_update('Goodbye')
+ self.assertFalse(self.course_updates_page.is_first_update_message('Hello'))
+ self.assertTrue(self.course_updates_page.is_first_update_message('Goodbye'))
+
+ def test_delete_course_update(self):
+ """
+ Scenario: Users can delete updates
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ And I add a new update with the text "Hello"
+ And I delete the update
+ And I confirm the prompt
+ Then I should not see the update "Hello"
+ """
+ self._create_and_verify_update('Hello')
+ self.course_updates_page.click_delete_update_button()
+ self.assertTrue(self.course_updates_page.is_course_update_list_empty())
+
+ def test_user_edit_date(self):
+ """
+ Scenario: Users can edit update dates
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ And I add a new update with the text "Hello"
+ When I edit the date to "06/01/13"
+ Then I should see the date "June 1, 2013"
+ """
+ self._create_and_verify_update('Hello')
+ self.course_updates_page.click_edit_update_button()
+ self.course_updates_page.set_date('06/01/2013')
+ self.course_updates_page.click_new_update_save_button()
+ self.assertTrue(self.course_updates_page.is_first_update_date('June 1, 2013'))
+
+ def test_outside_tag_preserved(self):
+ """
+ Scenario: Text outside of tags is preserved
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ When I add a new update with the text "before middle after"
+ Then I should see the update "before middle after"
+ And when I reload the page
+ Then I should see the update "before middle after"
+ """
+ self._create_and_verify_update('before middle after')
+ self.course_updates_page.visit()
+ self.assertTrue(self.course_updates_page.is_first_update_message('before middle after'))
+
+ def test_asset_change_in_updates(self):
+ """
+ Scenario: Static links are rewritten when previewing a course update
+ Given I have opened a new course in Studio
+ And I go to the course updates page
+ When I add a new update with the text "
"
+ # Can only do partial text matches because of the quotes with in quotes (and regexp step matching).
+ Then I should see the asset update to "my_img.jpg"
+ And I change the update from "/static/my_img.jpg" to "
"
+ Then I should see the asset update to "modified.jpg"
+ And when I reload the page
+ Then I should see the asset update to "modified.jpg"
+ """
+ self.course_updates_page.visit()
+ self.assertTrue(self.course_updates_page.is_new_update_button_present())
+ self.course_updates_page.click_new_update_button()
+ self.course_updates_page.submit_update("
")
+ self.assertTrue(self.course_updates_page.first_update_contains_html("my_img.jpg"))
+ self.course_updates_page.click_edit_update_button()
+ self.course_updates_page.submit_update("
")
+ self.assertFalse(self.course_updates_page.first_update_contains_html("my_img.jpg"))
+ self.assertTrue(self.course_updates_page.first_update_contains_html("modified.jpg"))
+ self.course_updates_page.visit()
+ self.assertTrue(self.course_updates_page.first_update_contains_html("modified.jpg"))