""" Unit page in Studio """ from bok_choy.page_object import PageObject from bok_choy.promise import EmptyPromise, Promise from . import BASE_URL from .container import ContainerPage class UnitPage(PageObject): """ Unit page in Studio """ def __init__(self, browser, unit_locator): super(UnitPage, self).__init__(browser) self.unit_locator = unit_locator @property def url(self): """URL to the pages UI in a course.""" return "{}/unit/{}".format(BASE_URL, self.unit_locator) def is_browser_on_page(self): def _is_finished_loading(): # Wait until all components have been loaded number_of_leaf_xblocks = len(self.q(css='{} .xblock-student_view'.format(Component.BODY_SELECTOR)).results) is_done = len(self.q(css=Component.BODY_SELECTOR).results) == number_of_leaf_xblocks return (is_done, is_done) # First make sure that an element with the view-unit class is present on the page, # and then wait to make sure that the xblocks are all there return ( self.q(css='body.view-unit').present and Promise(_is_finished_loading, 'Finished rendering the xblocks in the unit.').fulfill() ) @property def components(self): """ Return a list of components loaded on the unit page. """ return self.q(css=Component.BODY_SELECTOR).map( lambda el: Component(self.browser, el.get_attribute('data-locator'))).results def edit_draft(self): """ Started editing a draft of this unit. """ EmptyPromise( lambda: self.q(css='.create-draft').present, 'Wait for edit draft link to be present' ).fulfill() self.q(css='.create-draft').first.click() EmptyPromise( lambda: self.q(css='.editing-draft-alert').present, 'Wait for draft mode to be activated' ).fulfill() class Component(PageObject): """ A PageObject representing an XBlock child on the Studio UnitPage (including the editing controls). """ url = None BODY_SELECTOR = '.component' NAME_SELECTOR = '.component-header' def __init__(self, browser, locator): super(Component, self).__init__(browser) self.locator = locator def is_browser_on_page(self): return self.q(css='{}[data-locator="{}"]'.format(self.BODY_SELECTOR, self.locator)).present def _bounded_selector(self, selector): """ Return `selector`, but limited to this particular `CourseOutlineChild` context """ return '{}[data-locator="{}"] {}'.format( self.BODY_SELECTOR, self.locator, selector ) @property def name(self): titles = self.q(css=self._bounded_selector(self.NAME_SELECTOR)).text if titles: return titles[0] else: return None @property def preview_selector(self): return self._bounded_selector('.xblock-student_view') def edit(self): self.q(css=self._bounded_selector('.edit-button')).first.click() EmptyPromise( lambda: self.q(css='.xblock-studio_view').present, 'Wait for the Studio editor to be present' ).fulfill() return self @property def editor_selector(self): return '.xblock-studio_view' def go_to_container(self): """ Open the container page linked to by this component, and return an initialized :class:`.ContainerPage` for that xblock. """ return ContainerPage(self.browser, self.locator).visit()