Commit ea3797c3 by raeeschachar

Moving upgraded e2e page objects to platform

parent f62b6602
""" """
Utility methods common to Studio and the LMS. Utility methods common to Studio and the LMS.
""" """
from bok_choy.promise import EmptyPromise from bok_choy.promise import BrokenPromise
from common.test.acceptance.tests.helpers import disable_animations from common.test.acceptance.tests.helpers import disable_animations
from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.action_chains import ActionChains
def wait_for_notification(page): def sync_on_notification(page, style='default', wait_for_hide=False):
""" """
Waits for the "mini-notification" to appear and disappear on the given page (subclass of PageObject). Sync on notifications but do not raise errors.
A BrokenPromise in the wait_for probably means that we missed it.
We should just swallow this error and not raise it for reasons including:
* We are not specifically testing this functionality
* This functionality is covered by unit tests
* This verification method is prone to flakiness
and browser version dependencies
See classes in edx-platform:
lms/static/sass/elements/_system-feedback.scss
""" """
def _is_saving(): hiding_class = 'is-hiding'
"""Whether or not the notification is currently showing.""" shown_class = 'is-shown'
return page.q(css='.wrapper-notification-mini.is-shown').present
def notification_has_class(style, el_class):
def _is_saving_done(): """
"""Whether or not the notification is finished showing.""" Return a boolean representing whether
return page.q(css='.wrapper-notification-mini.is-hiding').present the notification has the class applied.
"""
EmptyPromise( if style == 'mini':
_is_saving, css_string = '.wrapper-notification-mini.{}'
'Notification should have been shown.', else:
try_interval=0.1, css_string = '.wrapper-notification-confirmation.{}'
timeout=60, return page.q(css=css_string.format(el_class)).present
).fulfill()
EmptyPromise( # Wait for the notification to show.
_is_saving_done, # This notification appears very quickly and maybe missed. Don't raise an error.
'Notification should have been hidden.', try:
try_interval=0.1, page.wait_for(
timeout=60, lambda: notification_has_class(style, shown_class),
).fulfill() 'Notification should have been shown.',
timeout=5
)
except BrokenPromise as _err:
pass
# Now wait for it to hide.
# This is not required for web page interaction, so not really needed.
if wait_for_hide:
page.wait_for(
lambda: notification_has_class(style, hiding_class),
'Notification should have hidden.'
)
def click_css(page, css, source_index=0, require_notification=True): def click_css(page, css, source_index=0, require_notification=True):
...@@ -53,7 +75,7 @@ def click_css(page, css, source_index=0, require_notification=True): ...@@ -53,7 +75,7 @@ def click_css(page, css, source_index=0, require_notification=True):
page.q(css=css).filter(_is_visible).nth(source_index).click() page.q(css=css).filter(_is_visible).nth(source_index).click()
if require_notification: if require_notification:
wait_for_notification(page) sync_on_notification(page)
# Some buttons trigger ajax posts # Some buttons trigger ajax posts
# (e.g. .add-missing-groups-button as configured in split_test_author_view.js) # (e.g. .add-missing-groups-button as configured in split_test_author_view.js)
......
...@@ -11,7 +11,7 @@ from common.test.acceptance.pages.studio.users import UsersPageMixin ...@@ -11,7 +11,7 @@ from common.test.acceptance.pages.studio.users import UsersPageMixin
from common.test.acceptance.pages.studio.pagination import PaginatedMixin from common.test.acceptance.pages.studio.pagination import PaginatedMixin
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from common.test.acceptance.pages.studio.utils import HelpMixin from common.test.acceptance.pages.studio.utils import HelpMixin
from common.test.acceptance.pages.common.utils import confirm_prompt, wait_for_notification from common.test.acceptance.pages.common.utils import confirm_prompt, sync_on_notification
from common.test.acceptance.pages.studio import BASE_URL from common.test.acceptance.pages.studio import BASE_URL
...@@ -92,7 +92,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin): ...@@ -92,7 +92,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin):
Click on the duplicate button for the given XBlock Click on the duplicate button for the given XBlock
""" """
self._action_btn_for_xblock_id(xblock_id, "duplicate").click() self._action_btn_for_xblock_id(xblock_id, "duplicate").click()
wait_for_notification(self) sync_on_notification(self)
self.wait_for_ajax() self.wait_for_ajax()
def click_delete_button(self, xblock_id, confirm=True): def click_delete_button(self, xblock_id, confirm=True):
...@@ -101,7 +101,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin): ...@@ -101,7 +101,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin):
""" """
self._action_btn_for_xblock_id(xblock_id, "delete").click() self._action_btn_for_xblock_id(xblock_id, "delete").click()
if confirm: if confirm:
confirm_prompt(self) # this will also wait_for_notification() confirm_prompt(self) # this will also sync_on_notification()
self.wait_for_ajax() self.wait_for_ajax()
def _get_xblocks(self): def _get_xblocks(self):
......
...@@ -285,6 +285,8 @@ class SettingsPage(CoursePage): ...@@ -285,6 +285,8 @@ class SettingsPage(CoursePage):
'#alert-confirmation-title', '#alert-confirmation-title',
'Save confirmation message is visible' 'Save confirmation message is visible'
) )
# After visibility an ajax call is in process, waiting for that to complete
self.wait_for_ajax()
def refresh_page(self, wait_for_confirmation=True): def refresh_page(self, wait_for_confirmation=True):
""" """
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
Course Grading Settings page. Course Grading Settings page.
""" """
from common.test.acceptance.pages.studio.course_page import CoursePage from common.test.acceptance.pages.studio.settings import SettingsPage
class GradingPage(CoursePage): class GradingPage(SettingsPage):
""" """
Course Grading Settings page. Course Grading Settings page.
""" """
...@@ -14,3 +14,91 @@ class GradingPage(CoursePage): ...@@ -14,3 +14,91 @@ class GradingPage(CoursePage):
def is_browser_on_page(self): def is_browser_on_page(self):
return self.q(css='body.grading').present return self.q(css='body.grading').present
def letter_grade(self, selector):
"""
Returns: first letter of grade range on grading page
Example: if there are no manually added grades it would
return Pass, if a grade is added it will return 'A'
"""
return self.q(css=selector)[0].text
def add_new_grade(self):
"""
Add new grade
"""
self.q(css='.new-grade-button').click()
self.save_changes()
def remove_grade(self):
"""
Remove an added grade
"""
# Button displays after hovering on it
btn_css = '.remove-button'
self.browser.execute_script("$('{}').focus().click()".format(btn_css))
self.wait_for_ajax()
self.save_changes()
def remove_all_grades(self):
"""
Removes all grades
"""
while len(self.q(css='.remove-button')) > 0:
self.remove_grade()
def add_new_assignment_type(self):
"""
Add New Assignment type
"""
self.q(css='.add-grading-data').click()
self.save_changes()
def fill_assignment_type_fields(
self,
name,
abbreviation,
total_grade,
total_number,
drop
):
"""
Fills text to Assignment Type fields according to assignment box
number and text provided
Arguments:
name: Assignment Type Name
abbreviation: Abbreviation
total_grade: Weight of Total Grade
total_number: Total Number
drop: Number of Droppable
"""
self.q(css='#course-grading-assignment-name').fill(name)
self.q(css='#course-grading-assignment-shortname').fill(abbreviation)
self.q(css='#course-grading-assignment-gradeweight').fill(total_grade)
self.q(
css='#course-grading-assignment-totalassignments'
).fill(total_number)
self.q(css='#course-grading-assignment-droppable').fill(drop)
self.save_changes()
def assignment_name_field_value(self):
"""
Returns: Assignment type field value
"""
return self.q(css='#course-grading-assignment-name').attrs('value')
def delete_assignment_type(self):
"""
Deletes Assignment type
"""
self.q(css='.remove-grading-data').first.click()
self.save_changes()
def delete_all_assignment_types(self):
"""
Deletes all assignment types
"""
while len(self.q(css='.remove-grading-data')) > 0:
self.delete_assignment_type()
...@@ -6,7 +6,7 @@ from selenium.webdriver.common.keys import Keys ...@@ -6,7 +6,7 @@ from selenium.webdriver.common.keys import Keys
from bok_choy.javascript import js_defined from bok_choy.javascript import js_defined
from bok_choy.promise import EmptyPromise from bok_choy.promise import EmptyPromise
from common.test.acceptance.pages.common.utils import click_css, wait_for_notification from common.test.acceptance.pages.common.utils import click_css, sync_on_notification
NAV_HELP_NOT_SIGNED_IN_CSS = '.nav-item.nav-not-signedin-help a' NAV_HELP_NOT_SIGNED_IN_CSS = '.nav-item.nav-not-signedin-help a'
...@@ -103,7 +103,7 @@ def add_component(page, item_type, specific_type, is_advanced_problem=False): ...@@ -103,7 +103,7 @@ def add_component(page, item_type, specific_type, is_advanced_problem=False):
all_options = page.q(css='.new-component-{} ul.new-component-template li button span'.format(item_type)) all_options = page.q(css='.new-component-{} ul.new-component-template li button span'.format(item_type))
chosen_option = all_options.filter(text=specific_type).first chosen_option = all_options.filter(text=specific_type).first
chosen_option.click() chosen_option.click()
wait_for_notification(page) sync_on_notification(page)
page.wait_for_ajax() page.wait_for_ajax()
...@@ -219,7 +219,7 @@ def drag(page, source_index, target_index, placeholder_height=0): ...@@ -219,7 +219,7 @@ def drag(page, source_index, target_index, placeholder_height=0):
action.release(target).perform() action.release(target).perform()
else: else:
action.release().perform() action.release().perform()
wait_for_notification(page) sync_on_notification(page)
def verify_ordering(test_class, page, expected_orderings): def verify_ordering(test_class, page, expected_orderings):
......
...@@ -8,7 +8,7 @@ from bok_choy.promise import EmptyPromise, Promise ...@@ -8,7 +8,7 @@ from bok_choy.promise import EmptyPromise, Promise
from bok_choy.javascript import wait_for_js, js_defined from bok_choy.javascript import wait_for_js, js_defined
from common.test.acceptance.tests.helpers import YouTubeStubConfig from common.test.acceptance.tests.helpers import YouTubeStubConfig
from common.test.acceptance.pages.lms.video.video import VideoPage from common.test.acceptance.pages.lms.video.video import VideoPage
from common.test.acceptance.pages.common.utils import wait_for_notification from common.test.acceptance.pages.common.utils import sync_on_notification
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.action_chains import ActionChains
...@@ -160,7 +160,7 @@ class VideoComponentPage(VideoPage): ...@@ -160,7 +160,7 @@ class VideoComponentPage(VideoPage):
""" """
self.q(css=BUTTON_SELECTORS[button_name]).nth(index).click() self.q(css=BUTTON_SELECTORS[button_name]).nth(index).click()
if require_notification: if require_notification:
wait_for_notification(self) sync_on_notification(self)
self.wait_for_ajax() self.wait_for_ajax()
@staticmethod @staticmethod
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment