def test_modal_for_unsaved_notes_appears_on_clicking_another_highlight( selenium, base_url, book_slug, page_slug ): """Discard modal appears when unsaved notes are present & clicking another highlight.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # AND: Highlight 2 paragraphs paragraphs = random.sample(book.content.paragraphs, 2) book.content.highlight(target=paragraphs[0], offset=Highlight.ENTIRE) id_1 = list(set(book.content.highlight_ids))[0] book.content.highlight(target=paragraphs[1], offset=Highlight.ENTIRE, close_box=False) _ids = book.content.highlight_ids id_2 = _ids[0] if _ids[0] != id_1 else _ids[1] # AND: Add note to the 2nd highlight and do not save note = Utilities.random_string() book.content.highlight_box.note = note # WHEN: click the first highlight highlight = book.content.get_highlight(by_id=id_1) Utilities.click_option(driver=selenium, element=highlight[0], scroll_to=-150) # THEN: Discard modal is displayed assert book.discard_changes_modal_displayed assert book.discard_modal.content == "You have an unsaved note on this page." assert book.discard_modal.title == "Discard unsaved changes?" # AND: Clicking Cancel closes the modal and the unsaved note is retained in the page book.discard_modal.click_cancel_changes() assert book.content.highlight_box.is_open, "Highlight box not open" assert book.content.highlight_box.is_edit_box highlight = book.content.get_highlight(by_id=id_2)[0] assert "focus" in highlight.get_attribute("class"), "highlight is not in focus" assert book.content.highlight_box.note == note # WHEN: click the 1st highlight again highlight = book.content.get_highlight(by_id=id_1) Utilities.click_option(driver=selenium, element=highlight[0], scroll_to=-150) # AND: click Discard changes in the modal book.discard_modal.click_discard_changes() # THEN: Unsaved note is abandoned and the highlight box is opened for the 1st highlight assert book.content.highlight_box.is_open, "Highlight box not open" highlight = book.content.get_highlight(by_id=id_1)[0] assert "focus" in highlight.get_attribute("class"), "highlight is not in focus" assert book.content.highlight_box.note == ""
def test_cookie_notice_accepted_in_osweb_not_displayed_in_rex( selenium, base_url, book_slug, page_slug ): # GIVEN: Open osweb book details page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() book.navbar.click_login() Signup(selenium).register() osweb = WebBase(selenium, base_url, book_slug=book_slug).open() osweb.wait_for_load() # AND: Accept the cookie notice assert osweb.notification_dialog_displayed osweb.click_notification_got_it() # WHEN: Click the view online link in osweb book detail page osweb.fix_view_online_url(base_url) osweb.click_view_online() # THEN: The book page is opened in REX # AND: Discard any non-cookie notice from the page # AND: Cookie notice is not displayed rex = Content(selenium) try: assert(not rex.notification_present) except AssertionError: assert(rex.notification.title != "Privacy and cookies"), ( "cookie notice displayed" ) rex.notification.got_it() assert(not rex.notification_present), ( f"Additional {rex.notification.title} message present" )
def test_able_to_close_my_highlights_with_keyboard_navigation( selenium, base_url, book_slug, page_slug): """My Highlights and Notes summary shows all types of page content.""" # GIVEN: a book section is displayed # AND: a user is logged in # AND: all content is visible # AND: the My Highlights and Notes modal is open book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email, password = Signup(selenium).register(True) book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() book.toolbar.my_highlights() # WHEN: they tab to the close 'x' and send the return key to it (ActionChains(selenium).send_keys(Keys.TAB).send_keys( Keys.RETURN).perform()) # THEN: the My Highlights and Notes modal is closed assert not book.my_highlights_open, "My Highlights and Notes modal is still open"
def test_cookie_notice_not_accepted_in_rex_displayed_in_osweb( selenium, base_url, book_slug, page_slug, email, password ): # GIVEN: Rex book page is open rex = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() rex_nav = rex.navbar book_banner = rex.bookbanner # AND: Discard any non-cookie notice from the page while rex.notification_present: assert(rex.notification.title != "Privacy and cookies") rex.notification.got_it() # WHEN: Login Rex with email & password rex_nav.click_login() accounts = Login(selenium) accounts.login(email, password) rex.wait_for_page_to_load() # AND: Cookie notice is displayed assert(rex.notification.title == "Privacy and cookies"), ( "cookie notice is not displayed" ) # WHEN: click on the book title to navigate to the osweb book page book_banner.book_title.click() # THEN: Cookie notice is displayed in the osweb page osweb = WebBase(selenium) osweb.wait_for_page_to_load() osweb.close_dialogs() assert osweb.notification_dialog_displayed
def test_change_color_from_MH_page(selenium, base_url, book_slug, page_slug): """Changing highlight color from MH page, updates the highlight in content page.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() # AND: Highlight 2 set of texts in the page paragraph = random.sample(book.content.paragraphs, 2) note = Utilities.random_string() content_highlight_ids = book.content.highlight_ids data = [(paragraph[0], Color.GREEN, note), (paragraph[1], Color.YELLOW, note == "")] for paragraphs, colors, note in data: book.content.highlight(target=paragraphs, offset=Highlight.RANDOM, color=colors, note=note) content_highlight_ids = content_highlight_ids + list( set(book.content.highlight_ids) - set(content_highlight_ids) ) # WHEN: Change highlight color of the 2nd highlight from MH page my_highlights = book.toolbar.my_highlights() highlight = my_highlights.highlights.edit_highlight highlight_id_0 = highlight[0].mh_highlight_id highlight_id_1 = highlight[1].mh_highlight_id new_highlight_color = Color.PINK highlight[1].toggle_menu() highlight[1].toggle_color(new_highlight_color) highlight[1].toggle_menu() my_highlights.close() # Determine the current color of the highlights in the content page highlight_classes_0 = book.content.get_highlight(by_id=highlight_id_0)[0].get_attribute("class") highlight_0_color_after_MH_color_change = Color.from_html_class(highlight_classes_0) highlight_classes_1 = book.content.get_highlight(by_id=highlight_id_1)[0].get_attribute("class") highlight_1_color_after_MH_color_change = Color.from_html_class(highlight_classes_1) # THEN: The highlight color in the content page is changed correctly assert ( highlight_1_color_after_MH_color_change == new_highlight_color ), "the current highlight color does not match the new color" assert ( highlight_0_color_after_MH_color_change == data[0][1] if content_highlight_ids[0] == highlight_id_0 else data[1][1] ), "highlight color changed for different highlight"
def test_change_highlight_color_from_MH_page_context_menu_using_keyboard( selenium, base_url, book_slug, page_slug): """Change highlight color using keyboard navigation in MH page.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() # AND: Highlight some text in the page paragraph = random.sample(book.content.paragraphs, 1) note = Utilities.random_string() book.content.highlight(target=paragraph[0], offset=Highlight.RANDOM, color=Color.GREEN, note=note) # AND: Open MH page my_highlights = book.toolbar.my_highlights() highlights = my_highlights.highlights.edit_highlight highlight_id = highlights[0].mh_highlight_id # WHEN: Tab to the context menu and hit Return (ActionChains(selenium).send_keys(Keys.TAB * 7).send_keys( Keys.RETURN).perform()) # AND: Tab 4 times to select Purple color and hit Spacebar (ActionChains(selenium).send_keys(Keys.TAB * 4).send_keys( Keys.RETURN).send_keys(Keys.SPACE).perform()) # THEN: The highlight color in MH page is changed to purple assert highlights[0].highlight_color == "purple" # AND: The focus stays on purple color assert selenium.switch_to.active_element == highlights[0].purple # WHEN: Hit Esc twice to close the MH modal (ActionChains(selenium).send_keys(Keys.ESCAPE * 2).perform()) highlight_classes = book.content.get_highlight( by_id=highlight_id)[0].get_attribute("class") highlight_color_in_content_page_after_MH_color_change = Color.from_html_class( highlight_classes) # THEN: The highlight color in the content page is changed to purple assert (highlight_color_in_content_page_after_MH_color_change == Color. PURPLE), "the current highlight color does not match the new color"
def test_toc_disables_interacting_with_content_on_mobile(selenium, base_url, book_slug, page_slug): # GIVEN: A page URL in the format of {base_url}/books/{book_slug}/pages/{page_slug} # AND: A mobile resolution content = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() toolbar = content.toolbar attribution = content.attribution sidebar = content.sidebar # WHEN: the toc is open toolbar.click_toc_toggle_button() # THEN: The links in the content should be disabled if content.next_link_is_displayed: assert content.element_is_not_interactable(content.next_link) if content.previous_link_is_displayed: assert content.element_is_not_interactable(content.previous_link) assert content.element_is_not_interactable(attribution.attribution_link) # AND scrolling over content overlay should do nothing with pytest.raises(Exception) as exc_info: content.scroll_over_content_overlay() exception_raised = exc_info.type assert "ElementClickInterceptedException" in str(exception_raised) # AND clicking anywhere in the content overlay should just close the TOC and content stays in the same page initial_url = selenium.current_url content.click_content_overlay() assert not sidebar.is_displayed assert selenium.current_url == initial_url
def test_keyboard_navigation_for_my_highlights_button_on_content_page( selenium, base_url, book_slug, page_slug): """Use keyboard navigation to open and close My Highlights and Notes.""" # GIVEN: a book page is displayed # AND: a user is logged in # AND: all content is visible book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: they select the search bar, tab twice and hit the return key (ActionChains(selenium).click(book.toolbar.search_textbox).send_keys( Keys.TAB * 2).send_keys(Keys.RETURN).perform()) # THEN: the My Highlights and Notes modal is displayed assert(book.my_highlights_open), \ "My Highlights modal not open" assert(book.my_highlights.root.is_displayed()), \ "My Highlights modal not displayed" # WHEN: they tab and hit the return key (ActionChains(selenium).send_keys(Keys.TAB).send_keys( Keys.RETURN).perform()) # THEN: the My Highlights and Notes modal is closed assert(not book.my_highlights_open), \ "My Highlights modal is still open" # WHEN: they select the search bar, tab twice and hit the enter key (ActionChains(selenium).click(book.toolbar.search_textbox).send_keys( Keys.TAB * 2).send_keys(Keys.ENTER).perform()) # THEN: the My Highlights and Notes modal is displayed assert(book.my_highlights_open), \ "My Highlights modal not open" assert(book.my_highlights.root.is_displayed()), \ "My Highlights modal not displayed" # WHEN: they hit the escape key (ActionChains(selenium).send_keys(Keys.ESCAPE).perform()) # THEN: the My Highlights and Notes modal is closed assert(not book.my_highlights_open), \ "My Highlights modal is still open"
def test_MH_empty_state_logged_in_user(selenium, base_url, book_slug, page_slug): """Logged in user empty state for MH page.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: Open MH page my_highlights = book.toolbar.my_highlights() filterbar = my_highlights.filter_bar # THEN: MH page Empty state message for logged in user is displayed assert (my_highlights.highlights.logged_in_user_empty_state_message == "You have no highlights in this book" ), "message not displayed or incorrect message" # AND: Empty state nudge is displayed in desktop if book.is_desktop: assert ( my_highlights.highlights.logged_in_user_empty_state_nudge == "Make a highlight and add a noteThen use this page to create your own study guide" ), "nudge not displayed or incorrect message" # AND: No empty state nudge is displayed in mobile else: assert my_highlights.highlights.logged_in_user_empty_state_nudge == "" # AND: All chapter dropdown options are disabled filterbar.toggle_chapter_dropdown_menu() for chapter in filterbar.chapter_filters.chapters: assert not chapter.has_highlights, ( f"Highlights present in chapter {chapter.number}," f"{chapter.title}") # AND: All color dropdown options are disabled filterbar.toggle_color_dropdown_menu() for color in filterbar.color_filters.colors: assert not color.is_checked, f"Highlights present for the color {color.color}," # AND: Print button is displayed assert filterbar.print.is_displayed
def test_signup_as_a_new_user_via_the_highlight_nudge_overlay( selenium, base_url, book_slug, page_slug): """Signup as a new user using the highlight nudge overlay.""" # GIVEN: the Astronomy book section 1.0 introduction is displayed # AND: some content is selected book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() paragraph = random.choice(book.content.paragraphs) book.content.highlight(target=paragraph, offset=Highlight.RANDOM, color=None) initial_page_url = selenium.current_url # WHEN: they click the "Log in" button on the highlight nudge book.content.highlight_box.log_in() # THEN: the Accounts screen is displayed assert("accounts" in selenium.current_url), "not viewing the Accounts page" assert("Log in to your OpenStax account" in selenium.page_source), \ "Accounts header not found" # WHEN: they sign up for an account Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # THEN: the same book page as the log in nudge is displayed # AND: the user is logged in assert(selenium.current_url == initial_page_url), \ "not returned to the correct book section page after account sign up" assert(book.navbar.user_is_logged_in), "user not logged in" # WHEN: they select some content paragraph = random.choice(book.content.paragraphs) book.content.highlight(target=paragraph, offset=Highlight.RANDOM, color=None) # THEN: the create note box is displayed try: book.content.highlight_box except NoSuchElementException: pytest.fail("the create note box is not open") assert(not book.content.highlight_box.login_overlay_present), \ "log in nudge overlay found"
def test_keyboard_navigation_MH_empty_state_logged_in_user( selenium, base_url, book_slug, page_slug): """Keyboard navigation for logged in user empty state MH page.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: Open MH page my_highlights = book.toolbar.my_highlights() filterbar = my_highlights.filter_bar # AND: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Close icon is focussed assert selenium.switch_to.active_element == my_highlights.close_icon # WHEN: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Chapter dropdown is focussed assert selenium.switch_to.active_element == filterbar.chapter_dropdown assert filterbar.chapter_dropdown.get_attribute( "aria-label") == "Filter highlights by Chapter" # WHEN: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Color dropdown is focussed assert selenium.switch_to.active_element == filterbar.color_dropdown assert filterbar.color_dropdown.get_attribute( "aria-label") == "Filter highlights by Color" # WHEN: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Print icon is focussed assert selenium.switch_to.active_element == filterbar.print
def test_scroll_position_when_search_yields_no_results(selenium, base_url, book_slug, page_slug): # GIVEN: Book page is loaded content = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() # WHEN: they scroll the page down # AND: trigger a search for a term that yields no results content.scroll_through_page() scroll_position_before_search = content.scroll_position # use a random search term not found in the content search_term = "".join(choice(digits + ascii_letters) for i in range(25)) if content.is_desktop: content.toolbar.search_for(search_term) else: content.mobile_search_toolbar.search_for(search_term) # For mobile resolution, click on the search icon to close the search # sidebar/navigate back to content page content.toolbar.click_search_icon() # THEN: Scroll position of content is not changed after search scroll_position_after_search = content.scroll_position within = scroll_position_before_search * 0.01 assert (isclose( scroll_position_before_search, scroll_position_after_search, rel_tol=within)), ( r"vertical position after search not within 1% of position " "before search ({low} <= {target} <= {high})".format( low=scroll_position_before_search - within, high=scroll_position_before_search + within, target=scroll_position_after_search)) if content.is_desktop: # WHEN: they close the search sidebar content.search_sidebar.close_search_sidebar() # THEN: the content scroll position is unchanged scroll_position_after_closing_search = content.scroll_position assert (isclose( scroll_position_before_search, scroll_position_after_closing_search, rel_tol=within)), ( r"vertical position after search not within 1% of position " "before search ({low} <= {target} <= {high})".format( low=scroll_position_before_search - within, high=scroll_position_before_search + within, target=scroll_position_after_closing_search))
def test_logout_in_osweb_logsout_rex( selenium, base_url, book_slug, page_slug, email, password ): # GIVEN: Rex page is open rex = Content( selenium, base_url, book_slug=book_slug, page_slug=page_slug ).open() rex_nav = rex.navbar # WHEN: Login Rex with email & password rex_nav.click_login() accounts = Login(selenium) accounts.login(email, password) # AND: Open osweb url in a new tab rex.open_new_tab() rex.switch_to_window(1) osweb = WebBase(selenium, base_url, book_slug=book_slug).open() osweb.wait_for_load() osweb.close_dialogs() # THEN: osweb is in logged-in state assert osweb.user_is_logged_in # WHEN: click logout in osweb osweb.click_logout() osweb.wait_for_load() # THEN: REX tab goes to logged-out state immediately rex.switch_to_window(0) assert rex_nav.user_is_not_logged_in
def test_keyboard_navigation_MH_empty_state_non_logged_in_user( selenium, base_url, book_slug, page_slug): """Keyboard navigation for non-logged in user empty state MH page.""" # GIVEN: Open book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: Open MH page my_highlights = book.toolbar.my_highlights() # AND: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Close icon is focussed assert selenium.switch_to.active_element == my_highlights.close_icon # WHEN: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: Log in link is focussed assert selenium.switch_to.active_element == my_highlights.log_in_link
def test_TEA_attribution_for_HS_books(selenium, base_url, book_slug, page_slug): """Verify TEA attribution for HS books.""" # GIVEN: Book page is loaded book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() attribution = book.attribution # Skip any notification/nudge popups while book.notification_present: book.notification.got_it() # WHEN: The attribution section is expanded attribution.click_attribution_link() # THEN: TEA is present in the attribution text attribution_text_expected = "you must attribute Texas Education Agency (TEA)" assert attribution_text_expected in attribution.attribution_text # AND: TEA website link is present in the attribution text if book_slug == "physics": tea_link_expected = "https://www.texasgateway.org/book/tea-physics" else: tea_link_expected = "https://www.texasgateway.org/book/tea-statistics" assert tea_link_expected in attribution.attribution_text # AND: Copyright name is TEA assert attribution.copyright_name == "Texas Education Agency (TEA)"
def test_TOC_closed_if_search_sidebar_is_displayed(selenium, base_url, book_slug, page_slug): # GIVEN: Book page is loaded content = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() toolbar = content.toolbar mobile = content.mobile_search_toolbar toc_sidebar = content.sidebar search_sidebar = content.search_sidebar # WHEN: Search is triggered for a string search_term = get_search_term(book_slug) if content.is_desktop: toolbar.search_for(search_term) if content.is_mobile: mobile.search_for(search_term) # THEN: TOC is not displayed assert not toc_sidebar.is_displayed # AND: Search sidebar is displayed assert search_sidebar.is_displayed
def test_open_my_highlights_for_non_logged_in_users_on_mobile( selenium, base_url, book_slug, page_slug): """Open the My Highlights and Notes modal for non-logged in users.""" # GIVEN: a book page is displayed # AND: all content is visible book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: they click on the My highlights navigation bar button my_highlights = book.toolbar.my_highlights() # THEN: the My Highlights and Notes modal is displayed # AND: the log in link is available assert(book.my_highlights_open), \ "My Highlights modal not open" assert(my_highlights.root.is_displayed()), \ "My Highlights modal not displayed" assert(my_highlights.log_in_available), \ "log in link not found" # WHEN: they click the 'x' button book = my_highlights.close() # THEN: the My Highlights and Notes modal is closed assert(not book.my_highlights_open), \ "My Highlights modal is still open"
def test_open_my_highlights_for_non_logged_in_users_on_desktop( selenium, base_url, book_slug, page_slug): """Open the My Highlights and Notes modal for non-logged in users.""" # GIVEN: a book page is displayed # AND: all content is visible book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.content.show_solutions() # WHEN: they click on the My highlights navigation bar button my_highlights = book.toolbar.my_highlights() # THEN: the My Highlights and Notes modal is displayed # AND: the log in nudge message is displayed assert(book.my_highlights_open), \ "My Highlights modal not open" assert(my_highlights.root.is_displayed()), \ "My Highlights modal not displayed" assert(my_highlights.log_in_available), \ "log in link not found" # WHEN: they click on the 'Log in' link accounts = my_highlights.log_in() # THEN: the Accounts log in page is displayed assert("accounts" in accounts.current_url), \ "not viewing an Accounts URL" assert("Log in to your OpenStax account" in accounts.source), \ "Accounts log in page not displayed"
def test_cookie_notice_not_accepted_in_osweb_displayed_in_rex( selenium, base_url, book_slug, page_slug, email, password ): # GIVEN: Open osweb book details page osweb = WebBase(selenium, base_url, book_slug=book_slug).open() osweb.wait_for_load() osweb.close_dialogs() osweb.click_login() # AND: Login as existing user accounts = Login(selenium) accounts.login(email, password) osweb.wait_for_load() osweb.close_dialogs() # WHEN: Click the view online link in osweb book detail page osweb.fix_view_online_url(base_url) osweb.click_view_online() # THEN: The book page is opened in REX # AND: Discard any non-cookie notice from the page # AND: Cookie notice is displayed rex = Content(selenium) assert rex.notification_present, "cookie notice not displayed" try: assert rex.notification.title == "Privacy and cookies" except AssertionError: rex.notification.got_it() try: assert ( rex.notification.title == "Privacy and cookies" ), f"Additional {rex.notification.title} message present" except NoSuchElementException: pytest.fail("cookie notice not displayed")
def test_highlight_is_not_created_until_a_color_is_selected( selenium, base_url, book_slug, page_slug): """A highlight is not created until the highlight color is selected.""" # GIVEN: the Astronomy book section 1.0 introduction is displayed # AND: a user is logged in # AND: all content is visible book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() total_highlight_count = book.content.highlight_count # WHEN: they select some text content paragraph = random.choice(book.content.paragraphs) book.content.highlight(target=paragraph, offset=Highlight.RANDOM, color=None) new_highlight_count = book.content.highlight_count # THEN: the create note box is displayed # AND: the selected text is not a saved highlight try: book.content.highlight_box except NoSuchElementException: pytest.fail("the create note box is not open") assert(new_highlight_count == total_highlight_count), \ "a new highlight was found" total_highlight_count = book.content.highlight_count # WHEN: they select a highlight color book.content.highlight_box.toggle_color(Highlight.random_color()) new_highlight_count = book.content.highlight_count # THEN: the highlight is created assert(new_highlight_count > total_highlight_count), \ "the new highlight was not found"
def test_keyboard_navigation_for_MH_filter_tags(selenium, base_url, book_slug, page_slug): """Keyboard navigation for the MH filter tags.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() # AND: Highlight 1 paragraph Highlight.force_highlight(book=book, by=random.choice, group=book.content.paragraphs, offset=Highlight.ENTIRE, color=Color.YELLOW) # AND: Open MH page my_highlights = book.toolbar.my_highlights() filterbar = my_highlights.filter_bar # WHEN: Hit tab to focus the first filter tag and hit the return key - remove chapter tag (ActionChains(selenium).send_keys(Keys.TAB * 5).send_keys( Keys.RETURN).perform()) # THEN: No results message is displayed assert ( my_highlights.highlights.no_results_message == "No results.Try selecting different chapter or color filters to see different results." ), "message not displayed or incorrect message when both tags are removed" # WHEN: Hit Tab (ActionChains(selenium).send_keys(Keys.TAB).perform()) # THEN: The 'x' button of color filter tag is focussed assert selenium.switch_to.active_element == filterbar.active_filter_tags[ 0].remove_tag_icon
def test_rex_login_state_when_redirected_from_osweb( selenium, base_url, book_slug, page_slug, email, password ): # GIVEN: Open osweb book details page osweb = WebBase(selenium, base_url, book_slug=book_slug).open() osweb.close_dialogs() osweb.click_login() # AND: Login as existing user accounts = Login(selenium) accounts.login(email, password) osweb.wait_for_load() # verify user is logged in and get the username assert osweb.user_is_logged_in osweb_username = osweb.osweb_username() # WHEN: Click the view online link in osweb book detail page osweb.fix_view_online_url(base_url) osweb.click_view_online() # THEN: The book page is opened in REX with the same user as openstax.org rex = Content(selenium) rex.wait_for_page_to_load() rex_nav = rex.navbar assert rex_nav.user_is_logged_in rex_username = rex.username(rex_nav.user_nav_toggle)[3:] assert rex_username == osweb_username # AND: The user stays logged-in while navigating to other pages in REX rex.click_next_link() assert rex_nav.user_is_logged_in
def test_color_auto_selected_if_a_note_is_added( selenium, base_url, book_slug, page_slug): """The first highlight color is auto-selected if a note is typed.""" # GIVEN: the Astronomy book section 1.0 introduction is displayed # AND: a user is logged in # AND: all content is visible # AND: some content is selected book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() paragraph = random.choice(book.content.paragraphs) book.content.highlight(target=paragraph, offset=Highlight.RANDOM, color=None) expected_color = Color.YELLOW # WHEN: they type a note in the create note box book.content.highlight_box.note = Utilities.random_string() highlight_ids = book.content.highlight_ids # THEN: the first hightlight color is automatically selected (yellow) # AND: the selected color in the color picker is checked assert(highlight_ids), "no highlights found" highlight_classes = (book.content .get_highlight(by_id=highlight_ids[0])[0] .get_attribute("class")) current_color = Color.from_html_class(highlight_classes) assert(current_color == expected_color), \ "the current highlight color does not match the default color" assert(book.content.highlight_box.is_checked(expected_color)), \ "highlight color yellow is not currently selected"
def test_login_and_logout( selenium, base_url, book_slug, page_slug, email, password ): """Test Accounts log in and log out from a content page.""" # GIVEN: a content page is loaded content = Content( selenium, base_url, book_slug=book_slug, page_slug=page_slug ).open() user_nav = content.navbar page_url_before_login = selenium.current_url # WHEN: they click on the login link user_nav.click_login() # THEN: The page navigates to accounts/login expected_page_url = ( f"{base_url}/accounts/i/login?r=%2Fbooks%2F" f"{book_slug}%2Fpages%2F{page_slug}" ) assert(expected_page_url in selenium.current_url), ( "not viewing the Accounts log in page" ) # WHEN: they log in as an existing user Login(selenium).login(email, password) # THEN: they are redirected back to the preface page after logging in assert page_url_before_login == selenium.current_url # WHEN: they click on their name in the nav bar user_nav.click_user_name() # THEN: the user menu in the nav displays Account Profile and Log out assert user_nav.account_profile_is_displayed assert user_nav.logout_is_displayed # WHEN: they reload the page selenium.refresh() # THEN: the system does not reset the state to logged out assert user_nav.user_is_logged_in # WHEN: they click the Log out link user_nav.click_user_name() user_nav.click_logout() # THEN: they are logged out assert user_nav.user_is_not_logged_in # WHEN: they reload the page selenium.refresh() # THEN: the system does not reset the state back to logged in assert user_nav.user_is_not_logged_in
def read_section(self) -> Page: """Click the read section link. :return: the referenced book section page :rtype: :py:class:`~pages.base.Page` """ base_url = Utilities.parent_page().base_url book = self.driver.current_url.split("/")[4] link = self.find_element(*self._link_to_section_locator) page = link.get_attribute("href") if "/" in page: page = page.split("/")[-1] Utilities.click_option(self.driver, element=link) from pages.content import Content new_page = Content(driver=self.driver, base_url=base_url, book_slug=book, page_slug=page) new_page.wait_for_page_to_load() return new_page
def test_note_indicator_added_when_highlight_without_a_note_has_a_note_added( selenium, base_url, book_slug, page_slug): """Adding a note to a highlight also adds the indicator to the highlight. """ # GIVEN: a book page is displayed # AND: a user is logged in # AND: all content is visible # AND: some content is highlighted without a note book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() book.content.show_solutions() width, height = book.get_window_size() paragraph = random.choice(book.content.paragraphs) book.content.highlight(paragraph, Highlight.ENTIRE, Color.YELLOW) highlight_id = book.content.highlight_ids[0] highlight = book.content.get_highlight(by_id=highlight_id)[0] # WHEN: they click the highlight # AND: add a note # AND: click the 'Save' button Utilities.click_option(selenium, element=highlight, scroll_to=-130) book.content.highlight_box.note = Utilities.random_string() book.content.highlight_box.save() # THEN: the note indicator is present on the highlight assert(selenium.execute_script(HAS_INDICATOR, highlight)), \ "indicator not found after adding a note"
def test_search_results(selenium, base_url, page_slug): """Search sidebar shows total number of matches throughout the book""" book_list = Library() book_slugs = book_list.book_slugs_list # Repeat the test for all books in the library for book_slug in list(book_slugs): # GIVEN: Book page is loaded book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() # Skip any notification/nudge popups while book.notification_present: book.notification.got_it() # WHEN: Search is performed search_sidebar = book.search_sidebar search_term = get_search_term(book_slug) chapter_search_results_expected_value = expected_chapter_search_results_total( book_slug) rkt_results_expected_value = expected_rkt_search_results_total( book_slug) # AND: Search sidebar is open book.toolbar.search_for(search_term) try: assert search_sidebar.search_results_present except TimeoutException: # wait and check if search sidebar appears sleep(0.5) assert search_sidebar.search_results_present # THEN: Search sidebar shows total number of matches throughout the book assert search_sidebar.rkt_search_result_total == rkt_results_expected_value try: assert (search_sidebar.chapter_search_result_total == chapter_search_results_expected_value) except AssertionError: # Total search results vary slightly between environment/search sessions which is being worked on by the developers. # Till then asserting with a threshold value print( f"Search results mismatch for '{book_slug}', expected = '{chapter_search_results_expected_value}', actual = '{search_sidebar.chapter_search_result_total}'" ) tc = unittest.TestCase() tc.assertAlmostEqual( search_sidebar.chapter_search_result_total, chapter_search_results_expected_value, delta=3, )
def test_x_in_search_sidebar(selenium, base_url, book_slug, page_slug): """X in search sidebar closes sidebar, text in search input still visible""" # GIVEN: Book page is loaded book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() # Skip any notification/nudge popups while book.notification_present: book.notification.got_it() toolbar = book.toolbar mobile = book.mobile_search_toolbar search_sidebar = book.search_sidebar search_term = get_search_term(book_slug) if book.is_desktop: # AND: Search results are displayed in search sidebar book.toolbar.search_for(search_term) assert search_sidebar.search_results_present search_result_scroll_position = book.scroll_position # WHEN: Close search sidebar book.search_sidebar.close_search_sidebar() # THEN: Search sidebar is closed assert search_sidebar.search_results_not_displayed # AND: Search string in the search textbox is still visible assert toolbar.search_term_displayed_in_search_textbox == search_term # AND: User stays in the same location in the book content as before closing the sidebar scroll_position_after_closing_search_sidebar = book.scroll_position assert scroll_position_after_closing_search_sidebar == search_result_scroll_position if book.is_mobile: # AND: Search results are displayed in search sidebar mobile.search_for(search_term) assert search_sidebar.search_results_present # WHEN: Close search sidebar mobile.click_close_search_results_link() # THEN: Search sidebar is closed assert search_sidebar.search_results_not_displayed # AND search string in the search input box is still visible book.toolbar.click_search_icon() assert mobile.search_term_displayed_in_search_textbox == search_term
def test_modal_for_unsaved_notes_appears_on_clicking_content_links( selenium, base_url, book_slug, page_slug ): """Discard modal appears when unsaved notes are present & clicking in-content link.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() # AND: Highlight a paragraph, add a note & do not save paragraphs = random.sample(book.content.paragraphs, 1) book.content.highlight(target=paragraphs[0], offset=Highlight.ENTIRE, close_box=False) note = Utilities.random_string() book.content.highlight_box.note = note id_1 = book.content.highlight_ids[0] # WHEN: Click on a in-content link link = random.sample(book.content.links, 1) Utilities.click_option(selenium, element=link[0]) # THEN: Discard modal is displayed assert book.discard_changes_modal_displayed assert book.discard_modal.content == "You have an unsaved note on this page." assert book.discard_modal.title == "Discard unsaved changes?" # WHEN: Click Cancel on the modal book.discard_modal.click_cancel_changes() # THEN: The modal is closed and the unsaved note is retained on the page assert book.content.highlight_box.is_open, "Highlight box not open" assert book.content.highlight_box.is_edit_box highlight = book.content.get_highlight(by_id=id_1)[0] assert "focus" in highlight.get_attribute("class"), "highlight is not in focus" assert book.content.highlight_box.note == note # WHEN: Click the same link again Utilities.click_option(selenium, element=link[0]) # AND: click Discard changes in the modal book.discard_modal.click_discard_changes() book.wait_for_page_to_load() # THEN: The page scrolls to the clicked link assert book.element_in_viewport(link[0]) # AND: The unsaved note is not saved assert not selenium.execute_script(HAS_INDICATOR, highlight), "note is saved for the highlight"
def test_no_context_menu_in_mobile_MH_page(selenium, base_url, book_slug, page_slug): """Mobile MH page does not have context menu.""" # GIVEN: Login book page book = Content(selenium, base_url, book_slug=book_slug, page_slug=page_slug).open() while book.notification_present: book.notification.got_it() book.navbar.click_login() name, email = Signup(selenium).register() book.wait_for_page_to_load() while book.notification_present: book.notification.got_it() # AND: Highlight some text in the page paragraph = random.sample(book.content.paragraphs, 1) book.content.highlight(target=paragraph[0], offset=Highlight.RANDOM) my_highlights = book.toolbar.my_highlights() highlight = my_highlights.highlights.edit_highlight assert not highlight[0].toggle_menu_visible()