Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 60 additions & 35 deletions playwright/e2e/ui/pages/home.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import asyncio
import pytest

from playwright.async_api import expect

import re


class HomeRex:
def __init__(self, page):
Expand All @@ -22,7 +17,7 @@ async def main_menu_and_openstax_logo_is_visible(self):

@pytest.mark.asyncio
async def osweb_homepage_content_sections(self):
return await self.page.locator(f"main > section:nth-child(5)").is_visible()
return await self.page.locator("main > section:nth-child(5)").is_visible()

@pytest.mark.asyncio
async def upper_menu_options(self):
Expand Down Expand Up @@ -92,11 +87,11 @@ async def resources_tabs_are_visible(self):

@pytest.mark.asyncio
async def click_instructor_resources_tab(self):
await self.page.locator("id=Instructor resources-tab").click()
await self.page.locator(r"#Instructor\ resources-tab").click()

@pytest.mark.asyncio
async def click_student_resources_tab(self):
await self.page.locator("id=Student resources-tab").click()
await self.page.locator(r"#Student\ resources-tab").click()

@pytest.mark.asyncio
async def click_subjects_science_link(self):
Expand All @@ -120,7 +115,7 @@ async def subjects_title(self):

@pytest.mark.asyncio
async def highlights_option_is_visible(self):
return await self.page.locator("id=nudge-study-tools").is_visible()
return await self.page.locator("#nudge-study-tools").is_visible()

@pytest.mark.asyncio
async def click_highlights_option(self):
Expand Down Expand Up @@ -194,7 +189,7 @@ async def click_give_today_link(self):

@pytest.mark.asyncio
async def footer_section(self):
return await self.page.locator("id=footer").is_visible()
return await self.page.locator("#footer").is_visible()

@pytest.mark.asyncio
async def footer_section_help_is_visible(self):
Expand Down Expand Up @@ -310,11 +305,11 @@ async def click_login_other(self):

@pytest.mark.asyncio
async def fill_user_field(self, value):
await self.page.locator("id=login_form_email").fill(value)
await self.page.locator("#login_form_email").fill(value)

@pytest.mark.asyncio
async def fill_password_field(self, value):
await self.page.locator("id=login_form_password").fill(value)
await self.page.locator("#login_form_password").fill(value)

@pytest.mark.asyncio
async def click_continue_login(self):
Expand All @@ -340,6 +335,20 @@ async def logout_link_is_visible(self):
async def click_logout_link(self):
await self.page.get_by_role("menuitem", name="Log out").click()

@property
def small_login_box(self):
return self.page.get_by_text(
"Log in to highlight and take notes. It’s 100% free.Log inCancel"
)

@pytest.mark.asyncio
async def click_small_login_box_cancel(self):
await self.page.get_by_role("button", name="Cancel").click()

@pytest.mark.asyncio
async def click_small_login_box_login(self):
await self.page.get_by_test_id("confirm").click()

# Book chapter section

@pytest.mark.asyncio
Expand All @@ -354,27 +363,47 @@ async def click_other_text(self):
async def select_text(self):
await self.page.locator("p:has-text('impact history')").select_text()

@pytest.mark.asyncio
async def select_text_block_in_solution(self):
await self.page.locator(
"p:has-text('formula. Repeat with values')"
).select_text()

@pytest.mark.asyncio
async def click_astronomy_book_chapter93(self):
await self.page.get_by_test_id("content-link-test").get_by_text(
"Impact Craters"
).click()

# Highlight box and highlights

@pytest.mark.asyncio
async def highlight_box_trash_icon_is_visible(self):
return (
await self.page.locator("div")
.get_by_test_id("editcard-trash-icon")
.is_visible()
)
return await self.page.get_by_label("Deselect current highlight").is_visible()

@pytest.mark.asyncio
async def click_highlight_box_trash_icon(self):
await self.page.get_by_label("Deselect current highlight").click()

@pytest.mark.asyncio
async def oneclick_highlight_infobox(self):
await self.page.get_by_label("Edit highlighted note").click()

@property
def highlight_infobox(self):
return self.page.get_by_label("Edit highlighted note")

@pytest.mark.asyncio
async def highlight_box_is_visible(self):
return await self.page.locator("id=note-textarea").is_visible()
return await self.page.locator("#note-textarea").is_visible()

@pytest.mark.asyncio
async def click_highlight_box_note_field(self):
await self.page.locator("id=note-textarea").click()
await self.page.locator("#note-textarea").click()

@pytest.mark.asyncio
async def fill_highlight_box_note_field(self, value):
await self.page.locator("id=note-textarea").fill(value)
await self.page.locator("#note-textarea").fill(value)

@pytest.mark.asyncio
async def highlight_box_colours_are_visible(self):
Expand All @@ -392,25 +421,13 @@ async def click_highlight_box_purple_colour(self):
async def click_highlights_option_green_colour(self):
await self.page.locator("div").get_by_title("green").first.click()

@property
def highlights_option_text_colour_purple(self):
return self.page.locator(
"div.HighlightListElement__HighlightContentWrapper-s4j4lf-1.ibAyfS"
)

@property
def highlights_option_text_colour_green(self):
return self.page.locator(
"div.HighlightListElement__HighlightContentWrapper-s4j4lf-1.kuxHtj"
)

@property
def highlights_option_text_colour_check_purple(self):
return self.highlights_option_text_colour_purple.get_attribute("color")
return self.page.locator('div[color="purple"]').get_attribute("color")

@property
def highlights_option_text_colour_check_green(self):
return self.highlights_option_text_colour_green.get_attribute("color")
return self.page.locator('div[color="green"]').get_attribute("color")

@pytest.mark.asyncio
async def small_highlighted_note_box_is_visible(self):
Expand All @@ -428,6 +445,10 @@ async def click_small_highlight_box_delete_button(self):
async def click_delete_highlight_button(self):
await self.page.locator("div").get_by_test_id("confirm").click()

@pytest.mark.asyncio
async def click_small_highlight_box_edit_button(self):
await self.page.get_by_test_id("card").get_by_text("Edit").click()

@pytest.mark.asyncio
async def yellow_highlighted_text_is_visible(self):
return await self.page.locator("mark > span:nth-child(1)").all()
Expand All @@ -454,7 +475,7 @@ async def click_new_chapter(self):

@pytest.mark.asyncio
async def click_show_hide_solution_link(self):
await self.page.locator("id=fs-id1165134108429").get_by_title(
await self.page.locator("#fs-id1165134108429").get_by_title(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these ids are book page-specific, it's probably not great to rely on them.

Copy link
Contributor Author

@omehes omehes Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I need a book/page/text block specific element within the solution box as per the aim of the test and this is the best I was able to come up... targetting this text block with this id

"Show/Hide Solution"
).click()

Expand Down Expand Up @@ -520,6 +541,10 @@ async def click_search(self):
async def fill_search_field(self, value):
await self.content_search_field_is_visible.fill(value)

@pytest.mark.asyncio
async def click_search_magnifier_icon(self):
await self.page.get_by_role("button", name="Search").click()

@property
def search_result_is_visible(self):
return self.page.get_by_test_id("search-results-sidebar")
Expand Down
113 changes: 100 additions & 13 deletions playwright/e2e/ui/test_highlight_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@pytest.mark.parametrize(
"book_slug, page_slug", [("astronomy-2e", "9-3-impact-craters")]
)
async def test_highlight_box_dismiss_with_esc(
async def test_highlight_box_opens_on_enter(
chrome_page, base_url, book_slug, page_slug, rex_user, rex_password
):

Expand All @@ -24,29 +24,36 @@ async def test_highlight_box_dismiss_with_esc(

await home.click_continue_login()

# THEN: Book page opens, highlight box appears, then disappears on Escape key
# THEN: Book page opens, highlight infobox and edit box appears

await chrome_page.keyboard.press("Escape")

await home.double_click_text()

assert await home.highlight_infobox.is_visible()

await chrome_page.keyboard.press("Enter")

assert await home.highlight_box_is_visible()

assert await home.highlight_box_colours_are_visible()
assert await home.highlight_box_trash_icon_is_visible()

await chrome_page.keyboard.press("Escape")
await home.click_highlight_box_trash_icon()

# Adjusting the test until the expected behaviour is implemented for Escape key (to avoid test fail)
assert await home.highlight_box_is_visible()
# await home.click_highlights_option()
# assert "You have no highlights in this book" not in await home.highlights_option_page_is_empty.inner_text()
await home.click_highlights_option()

assert (
"You have no highlights in this book"
in await home.highlights_option_page_is_empty.inner_text()
)


@pytest.mark.asyncio
@pytest.mark.parametrize(
"book_slug, page_slug", [("astronomy-2e", "9-3-impact-craters")]
)
async def test_highlight_box_dismiss_with_click(
async def test_highlight_box_opens_on_one_click(
chrome_page, base_url, book_slug, page_slug, rex_user, rex_password
):

Expand All @@ -63,17 +70,22 @@ async def test_highlight_box_dismiss_with_click(

await home.click_continue_login()

# THEN: Book page opens, highlight box appears, then disappears on clicking away from the box
# THEN: Book page opens, highlight infobox and edit box appears

await chrome_page.keyboard.press("Escape")

await home.double_click_text()

assert await home.highlight_infobox.is_visible()

await home.oneclick_highlight_infobox()

assert await home.highlight_box_is_visible()

await home.click_other_text()
assert await home.highlight_box_colours_are_visible()
assert await home.highlight_box_trash_icon_is_visible()

assert not await home.highlight_box_is_visible()
await home.click_highlight_box_trash_icon()

await home.click_highlights_option()

Expand All @@ -87,7 +99,7 @@ async def test_highlight_box_dismiss_with_click(
@pytest.mark.parametrize(
"book_slug, page_slug", [("astronomy-2e", "9-3-impact-craters")]
)
async def test_highlight_box_click_highlights_option_after_highlighting_text(
async def test_highlight_is_created_without_annotation_on_enter(
chrome_page, base_url, book_slug, page_slug, rex_user, rex_password
):

Expand All @@ -104,21 +116,96 @@ async def test_highlight_box_click_highlights_option_after_highlighting_text(

await home.click_continue_login()

# THEN: Book page opens, highlight box appears, then disappears on clicking the highlights option page
# THEN: Book page opens, highlight infobox and edit box appears

await chrome_page.keyboard.press("Escape")

await home.double_click_text()

assert await home.highlight_infobox.is_visible()

await chrome_page.keyboard.press("Enter")

assert await home.highlight_box_is_visible()

await chrome_page.keyboard.press("Escape")

assert not await home.highlight_box_is_visible()

await chrome_page.keyboard.press("Enter")

await home.click_highlights_option()

assert (
"You have no highlights in this book"
not in await home.highlights_option_page_is_empty.inner_text()
)

# THEN: Delete the created highlight

await home.click_highlights_option_page_menu()

await home.click_highlights_option_page_menu_delete()
await home.click_highlights_option_page_menu_delete_delete()

assert (
"You have no highlights in this book"
in await home.highlights_option_page_is_empty.inner_text()
)


@pytest.mark.asyncio
@pytest.mark.parametrize(
"book_slug, page_slug", [("astronomy-2e", "9-3-impact-craters")]
)
async def test_highlight_is_created_without_annotation_on_one_click(
chrome_page, base_url, book_slug, page_slug, rex_user, rex_password
):

# GIVEN: Playwright, chromium and the rex_base_url

# WHEN: The Home page is fully loaded
await chrome_page.goto(f"{base_url}/books/{book_slug}/pages/{page_slug}")
home = HomeRex(chrome_page)

await home.click_login()

await home.fill_user_field(rex_user)
await home.fill_password_field(rex_password)

await home.click_continue_login()

# THEN: Book page opens, highlight infobox and edit box appears

await chrome_page.keyboard.press("Escape")

await home.double_click_text()

assert await home.highlight_infobox.is_visible()

await home.oneclick_highlight_infobox()

assert await home.highlight_box_is_visible()

await chrome_page.keyboard.press("Escape")

assert not await home.highlight_box_is_visible()

await home.click_highlights_option()

assert (
"You have no highlights in this book"
not in await home.highlights_option_page_is_empty.inner_text()
)

# THEN: Delete the created highlight

await home.click_highlights_option_page_menu()

await home.click_highlights_option_page_menu_delete()
await home.click_highlights_option_page_menu_delete_delete()

assert (
"You have no highlights in this book"
in await home.highlights_option_page_is_empty.inner_text()
)
Loading