Commit ea3797c3 by raeeschachar

Moving upgraded e2e page objects to platform

parent f62b6602
"""
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 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():
"""Whether or not the notification is currently showing."""
return page.q(css='.wrapper-notification-mini.is-shown').present
hiding_class = 'is-hiding'
shown_class = 'is-shown'
def _is_saving_done():
"""Whether or not the notification is finished showing."""
return page.q(css='.wrapper-notification-mini.is-hiding').present
def notification_has_class(style, el_class):
"""
Return a boolean representing whether
the notification has the class applied.
"""
if style == 'mini':
css_string = '.wrapper-notification-mini.{}'
else:
css_string = '.wrapper-notification-confirmation.{}'
return page.q(css=css_string.format(el_class)).present
EmptyPromise(
_is_saving,
# Wait for the notification to show.
# This notification appears very quickly and maybe missed. Don't raise an error.
try:
page.wait_for(
lambda: notification_has_class(style, shown_class),
'Notification should have been shown.',
try_interval=0.1,
timeout=60,
).fulfill()
EmptyPromise(
_is_saving_done,
'Notification should have been hidden.',
try_interval=0.1,
timeout=60,
).fulfill()
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):
......@@ -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()
if require_notification:
wait_for_notification(page)
sync_on_notification(page)
# Some buttons trigger ajax posts
# (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
from common.test.acceptance.pages.studio.pagination import PaginatedMixin
from selenium.webdriver.common.keys import Keys
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
......@@ -92,7 +92,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin):
Click on the duplicate button for the given XBlock
"""
self._action_btn_for_xblock_id(xblock_id, "duplicate").click()
wait_for_notification(self)
sync_on_notification(self)
self.wait_for_ajax()
def click_delete_button(self, xblock_id, confirm=True):
......@@ -101,7 +101,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin):
"""
self._action_btn_for_xblock_id(xblock_id, "delete").click()
if confirm:
confirm_prompt(self) # this will also wait_for_notification()
confirm_prompt(self) # this will also sync_on_notification()
self.wait_for_ajax()
def _get_xblocks(self):
......
......@@ -285,6 +285,8 @@ class SettingsPage(CoursePage):
'#alert-confirmation-title',
'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):
"""
......
......@@ -2,10 +2,10 @@
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.
"""
......@@ -14,3 +14,91 @@ class GradingPage(CoursePage):
def is_browser_on_page(self):
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
from bok_choy.javascript import js_defined
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'
......@@ -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))
chosen_option = all_options.filter(text=specific_type).first
chosen_option.click()
wait_for_notification(page)
sync_on_notification(page)
page.wait_for_ajax()
......@@ -219,7 +219,7 @@ def drag(page, source_index, target_index, placeholder_height=0):
action.release(target).perform()
else:
action.release().perform()
wait_for_notification(page)
sync_on_notification(page)
def verify_ordering(test_class, page, expected_orderings):
......
......@@ -8,7 +8,7 @@ from bok_choy.promise import EmptyPromise, Promise
from bok_choy.javascript import wait_for_js, js_defined
from common.test.acceptance.tests.helpers import YouTubeStubConfig
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.action_chains import ActionChains
......@@ -160,7 +160,7 @@ class VideoComponentPage(VideoPage):
"""
self.q(css=BUTTON_SELECTORS[button_name]).nth(index).click()
if require_notification:
wait_for_notification(self)
sync_on_notification(self)
self.wait_for_ajax()
@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