Moving upgraded e2e page objects to platform
This commit is contained in:
@@ -1,35 +1,57 @@
|
||||
"""
|
||||
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,
|
||||
'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()
|
||||
# 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.',
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user