From 620e990616391db0605959de59d6c05a32ea2d17 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Fri, 11 Jul 2014 11:04:55 -0400 Subject: [PATCH] Adds more comprehensive bokchoy testing for publishing changes --- .../pages/studio/component_editor.py | 4 +- .../test/acceptance/pages/studio/container.py | 21 +++++ .../pages/studio/html_component_editor.py | 21 +++++ .../acceptance/tests/test_studio_container.py | 81 ++++++++++++++++++- 4 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 common/test/acceptance/pages/studio/html_component_editor.py diff --git a/common/test/acceptance/pages/studio/component_editor.py b/common/test/acceptance/pages/studio/component_editor.py index ca2e50e4c1..f14a833a32 100644 --- a/common/test/acceptance/pages/studio/component_editor.py +++ b/common/test/acceptance/pages/studio/component_editor.py @@ -44,7 +44,9 @@ class ComponentEditorView(PageObject): """ Returns the index of the setting entry with given label (display name) within the Settings modal. """ - # TODO: will need to handle tabbed "Settings" in future (current usage is in vertical, only shows Settings. + settings_button = self.q(css='.edit-xblock-modal .editor-modes .settings-button') + if settings_button.is_present(): + settings_button.click() setting_labels = self.q(css=self._bounded_selector('.metadata_edit .wrapper-comp-setting .setting-label')) for index, setting in enumerate(setting_labels): if setting.text == label: diff --git a/common/test/acceptance/pages/studio/container.py b/common/test/acceptance/pages/studio/container.py index 9cee0ffbbe..311c59ea1a 100644 --- a/common/test/acceptance/pages/studio/container.py +++ b/common/test/acceptance/pages/studio/container.py @@ -96,6 +96,20 @@ class ContainerPage(PageObject): """ return self.q(css='.wrapper-release .copy').first.text[0] + @property + def last_saved_text(self): + """ + Returns the last saved message as displayed in the publishing sidebar component. + """ + return self.q(css='.wrapper-last-draft').first.text[0] + + @property + def last_published_text(self): + """ + Returns the last published message as displayed in the sidebar. + """ + return self.q(css='.wrapper-last-publish').first.text[0] + @property def currently_visible_to_students(self): """ @@ -271,6 +285,13 @@ class XBlockWrapper(PageObject): selector ) + @property + def student_content(self): + """ + Returns the text content of the xblock as displayed on the container page. + """ + return self.q(css=self._bounded_selector('.xblock-student_view'))[0].text + @property def name(self): titles = self.q(css=self._bounded_selector(self.NAME_SELECTOR)).text diff --git a/common/test/acceptance/pages/studio/html_component_editor.py b/common/test/acceptance/pages/studio/html_component_editor.py new file mode 100644 index 0000000000..93048642ab --- /dev/null +++ b/common/test/acceptance/pages/studio/html_component_editor.py @@ -0,0 +1,21 @@ +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.action_chains import ActionChains +from utils import click_css +from component_editor import ComponentEditorView + + +class HtmlComponentEditorView(ComponentEditorView): + """ + Represents the rendered view of an HTML component editor. + """ + + def set_content_and_save(self, content): + """ + Types content into the html component. + """ + self.q(css='.edit-xblock-modal .editor-modes .editor-button').click() + editor = self.q(css=self._bounded_selector('.html-editor .mce-edit-area'))[0] + ActionChains(self.browser).click(editor).\ + send_keys([Keys.CONTROL, 'a']).key_up(Keys.CONTROL).send_keys(content).perform() + click_css(self, 'a.action-save') + diff --git a/common/test/acceptance/tests/test_studio_container.py b/common/test/acceptance/tests/test_studio_container.py index 398fd90e11..f785d858a4 100644 --- a/common/test/acceptance/tests/test_studio_container.py +++ b/common/test/acceptance/tests/test_studio_container.py @@ -9,6 +9,7 @@ from ..pages.studio.overview import CourseOutlinePage from ..fixtures.course import XBlockFixtureDesc from ..pages.studio.component_editor import ComponentEditorView +from ..pages.studio.html_component_editor import HtmlComponentEditorView from ..pages.studio.utils import add_discussion from ..pages.lms.courseware import CoursewarePage from ..pages.lms.staff_view import StaffPage @@ -16,7 +17,7 @@ from ..pages.lms.staff_view import StaffPage from unittest import skip from acceptance.tests.base_studio_test import StudioCourseTest import datetime -from bok_choy.promise import Promise +from bok_choy.promise import Promise, EmptyPromise @attr('shard_1') @@ -385,6 +386,9 @@ class UnitPublishingTest(ContainerBase): LOCKED_STATUS = "Publishing Status\nUnpublished (Staff only)" RELEASE_TITLE_RELEASED = "RELEASED:" + LAST_PUBLISHED = 'Last published' + LAST_SAVED = 'Draft saved on' + def setup_fixtures(self): """ Sets up a course structure with a unit and a single HTML child. @@ -434,11 +438,16 @@ class UnitPublishingTest(ContainerBase): When I go to the unit page in Studio Then the title in the Publish information box is "Published" And the Publish button is disabled + And the last published text contains "Last published" + And the last saved text contains "Last published" And when I add a component to the unit Then the title in the Publish information box is "Draft (Unpublished changes)" + And the last saved text contains "Draft saved on" And the Publish button is enabled And when I click the Publish button Then the title in the Publish information box is "Published" + And the last published text contains "Last published" + And the last saved text contains "Last published" """ unit = self.go_to_unit_page() self._verify_publish_title(unit, self.PUBLISHED_STATUS) @@ -446,15 +455,18 @@ class UnitPublishingTest(ContainerBase): self._verify_release_date_info( unit, self.RELEASE_TITLE_RELEASED, 'Jan 01, 1970 at 00:00 UTC with Section "Test Section"' ) + self._verify_last_published_and_saved(unit, self.LAST_PUBLISHED, self.LAST_PUBLISHED) # Should not be able to click on Publish action -- but I don't know how to test that it is not clickable. # TODO: continue discussion with Muhammad and Jay about this. # Add a component to the page so it will have unpublished changes. add_discussion(unit) self._verify_publish_title(unit, self.DRAFT_STATUS) + self._verify_last_published_and_saved(unit, self.LAST_PUBLISHED, self.LAST_SAVED) unit.publish_action.click() unit.wait_for_ajax() self._verify_publish_title(unit, self.PUBLISHED_STATUS) + self._verify_last_published_and_saved(unit, self.LAST_PUBLISHED, self.LAST_PUBLISHED) def test_discard_changes(self): """ @@ -606,18 +618,74 @@ class UnitPublishingTest(ContainerBase): # Switch to student view and verify visible. self._verify_student_view_visible(['discussion']) + def test_published_unit_with_draft_child(self): + """ + Scenario: A published unit with a draft child can be published + Given I have a published unit with no unpublished changes + When I go to the unit page in Studio + And edit the content of the only component + Then the content changes + And the title in the Publish information box is "Draft (Unpublished changes)" + And when I click the Publish button + Then the title in the Publish information box is "Published" + And when I click the View Live button + Then I see the changed content in LMS + """ + modified_content = 'modified content' + + unit = self.go_to_unit_page() + component = unit.xblocks[1] + component.edit() + HtmlComponentEditorView(self.browser, component.locator).set_content_and_save(modified_content) + self.assertEqual(component.student_content, modified_content) + self._verify_publish_title(unit, self.DRAFT_STATUS) + unit.publish_action.click() + unit.wait_for_ajax() + self._verify_publish_title(unit, self.PUBLISHED_STATUS) + unit.view_published_version() + self.assertTrue(modified_content in self.courseware.xblock_component_html_content(0)) + + def test_delete_child_in_published_unit(self): + """ + Scenario: A published unit can be published again after deleting a child + Given I have a published unit with no unpublished changes + When I go to the unit page in Studio + And delete the only component + Then the title in the Publish information box is "Draft (Unpublished changes)" + And when I click the Publish button + Then the title in the Publish information box is "Published" + And when I click the View Live button + Then I see an empty unit in LMS + """ + unit = self.go_to_unit_page() + unit.delete(0) + self._verify_publish_title(unit, self.DRAFT_STATUS) + unit.publish_action.click() + unit.wait_for_ajax() + self._verify_publish_title(unit, self.PUBLISHED_STATUS) + unit.view_published_version() + self.assertEqual(0, self.courseware.num_xblock_components) + + def _verify_and_return_staff_page(self): + """ + Verifies that the browser is on the staff page and returns a StaffPage. + """ + page = StaffPage(self.browser) + EmptyPromise(page.is_browser_on_page, 'Browser is on staff page in LMS').fulfill() + return page + def _verify_student_view_locked(self): """ Verifies no component is visible when viewing as a student. """ - StaffPage(self.browser).toggle_staff_view() + self._verify_and_return_staff_page().toggle_staff_view() self.assertEqual(0, self.courseware.num_xblock_components) def _verify_student_view_visible(self, expected_components): """ Verifies expected components are visible when viewing as a student. """ - StaffPage(self.browser).toggle_staff_view() + self._verify_and_return_staff_page().toggle_staff_view() self._verify_components_visible(expected_components) def _verify_components_visible(self, expected_components): @@ -644,6 +712,13 @@ class UnitPublishingTest(ContainerBase): Promise(wait_for_title_change, "Publish title incorrect. Found '" + unit.publish_title + "'").fulfill() + def _verify_last_published_and_saved(self, unit, expected_published_prefix, expected_saved_prefix): + """ + Verifies that last published and last saved messages respectively contain the given strings. + """ + self.assertTrue(expected_published_prefix in unit.last_published_text) + self.assertTrue(expected_saved_prefix in unit.last_saved_text) + # TODO: need to work with Jay/Christine to get testing of "Preview" working. # def test_preview(self): # unit = self.go_to_unit_page()