Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ba1882c
adds new audiobook test and reorganizes tests
omehes Mar 31, 2026
715b991
resolves conflict
omehes Apr 9, 2026
e81a45b
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
3385ae7
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
5934bec
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
0be7b3f
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
c4679ac
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
93e2347
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
d769f69
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
0e5d4d1
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
dbb8bad
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
f19f344
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
fd22385
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
94cd82f
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
1ac76e4
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
118e904
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
1b2f99c
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
4b867ce
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
920050a
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
3ff9631
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
3af6b68
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
8ecd878
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
16fbbee
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
72727f1
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
c750497
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
ccfdb7f
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
28500c8
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
d12ff6b
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
1101efc
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
6a80025
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
6c4d784
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
4f4110e
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
aef4bdc
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
d2e4b42
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
0415241
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
f8771b1
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
68481ca
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
9c0bffc
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
ec93ae8
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
1a3d456
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
ede8077
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
ca27609
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
221897b
Merge branch 'main' into audio
staxly[bot] Apr 9, 2026
a53799b
Merge branch 'main' into audio
staxly[bot] Apr 10, 2026
8dfacc6
Merge branch 'main' into audio
staxly[bot] Apr 13, 2026
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
87 changes: 0 additions & 87 deletions e2e_tests/docx-tools/test_compare_unzipped_docxs.py

This file was deleted.

144 changes: 144 additions & 0 deletions e2e_tests/docx-tools/test_compare_zip_or_docx_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import pytest
import os
import shutil
import zipfile
import textwrap
from deepdiff import DeepDiff
import docx2txt

"""
Compares docx files. To run:
1. run two docx jobs in corgi
2. download the docx zip files or docx files from corgi (by default to Downloads folder on Mac)
- make sure that BASE_TO_DIR exists and contains 2 subdirectories named 0 and 1
3. make sure that BASE_FROM_DIR variable is set correctly and files are copied there from Downloads folder
4. run 'pytest -k test_compare_zip_or_docx_files.py docx-tools > docx_diffs.txt'

Note, that the test accepts two .zip files from corgi docx job, two .docx files (or one of each)

Latest update on March 31st, 2026
"""

HOME_DIR = os.path.expanduser("~")
BASE_FROM_DIR = f"{HOME_DIR}/Downloads/2pdfs"
BASE_TO_DIR = f"{os.getcwd()}/docx_old_new"
MAX_WIDTH = 120


def unzip_file(zip_path, extract_to):
"""Unzips a zip file into extract_to directory."""
with zipfile.ZipFile(zip_path) as z:
z.extractall(extract_to)


def get_docx_texts_from_dir(directory):
"""Returns a dict of {book_name: {filename: text}} for all docx files in subdirs."""
result = {}
for sub in os.listdir(directory):
sub_path = os.path.join(directory, sub)
if os.path.isdir(sub_path):
result[sub] = {
f: docx2txt.process(os.path.join(sub_path, f))
for f in os.listdir(sub_path)
if f.endswith(".docx")
}
return result


def get_docx_texts_from_file(docx_path):
"""Returns a dict for a single docx file."""
filename = os.path.basename(docx_path)
return {filename: docx2txt.process(docx_path)}


def prepare_files(file_path, dest_dir):
"""
Copies and extracts zip files or copies docx files to dest_dir.
Returns a dict of docx texts.
"""
file_path = str(file_path)
dest_dir = str(dest_dir)

os.makedirs(dest_dir, exist_ok=True)

if file_path.endswith(".zip"):
dest_path = os.path.join(dest_dir, os.path.basename(file_path))
shutil.copy(file_path, dest_path)
unzip_file(dest_path, dest_dir)
return get_docx_texts_from_dir(dest_dir)

elif file_path.endswith(".docx"):
dest_path = os.path.join(dest_dir, os.path.basename(file_path))
shutil.copy(file_path, dest_path)
return get_docx_texts_from_file(dest_path)

else:
pytest.fail(
f"Unsupported file type: {file_path}. Only .zip and .docx are supported."
)


def print_diffs(diffs):
for diff_type, changes in diffs.items():
# Diff type header
print(f"\n{'#' * 60}")
print(f" {diff_type.replace('_', ' ').upper()}")
print(f"{'#' * 60}")

for key, value in changes.items():
# Extract book/file name from key for readability
print(f"\n {'─' * 40}")
print(f" LOCATION: {key}")
print(f" {'─' * 40}")

# Handle old/new values separately if present
if hasattr(value, "get"):
old_val = str(value.get("old_value", ""))
new_val = str(value.get("new_value", ""))
if old_val:
print(f"\n OLD VALUE:")
for line in textwrap.wrap(old_val, width=MAX_WIDTH):
print(f" {line}")
if new_val:
print(f"\n NEW VALUE:")
for line in textwrap.wrap(new_val, width=MAX_WIDTH):
print(f" {line}")
else:
print(f"\n CHANGE:")
for line in textwrap.wrap(str(value), width=MAX_WIDTH):
print(f" {line}")


def test_compare_zip_or_docx_files():
# Part 1: Find zip or docx files
all_files = [
f
for f in os.listdir(BASE_FROM_DIR)
if f.endswith(".zip") or f.endswith(".docx")
]

if len(all_files) != 2:
pytest.fail(
f"Two files required (.zip or .docx): {len(all_files)} file(s) available"
)

file1 = os.path.join(BASE_FROM_DIR, all_files[0])
file2 = os.path.join(BASE_FROM_DIR, all_files[1])

print(f"\nFile 1: {all_files[0]}")
print(f"File 2: {all_files[1]}")

# Part 2: Prepare and extract text
dest_dir_0 = os.path.join(BASE_TO_DIR, "0")
dest_dir_1 = os.path.join(BASE_TO_DIR, "1")

dict_old = prepare_files(file1, dest_dir_0)
dict_new = prepare_files(file2, dest_dir_1)

# Part 3: Compare and print diffs
diffs = DeepDiff(dict_new, dict_old, verbose_level=2)

if not diffs:
print("------>>>>> NO DIFFERENCES <<<<<------")
else:
print_diffs(diffs)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

The test function is missing an assertion or failure case. When differences are found in the docx files, the test should fail rather than just printing the diffs. The test currently prints the diffs and exits successfully even if there are differences, which defeats the purpose of a test.

Suggested change
print_diffs(diffs)
print_diffs(diffs)
pytest.fail("Differences found between DOCX/ZIP contents. See printed diffs above.")

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no need for this

Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,6 @@
import sys


@pytest.mark.asyncio
async def test_book_title_links_to_books_detail_page(chrome_page_unlogged, base_url):

# GIVEN: Playwright, chromium and the rex_base_url

# WHEN: The Home page is fully loaded
await chrome_page_unlogged.goto(f"{base_url}/subjects")
home = HomeRex(chrome_page_unlogged)

await chrome_page_unlogged.keyboard.press("Escape")

assert await home.subject_listing_book_is_visible()

await home.click_subject_listing_book()

await home.click_book_selection()

# THEN: The page navigates to {base_url}/details/books/astronomy-2e
assert "astronomy" in chrome_page_unlogged.url.lower()


@pytest.mark.parametrize("book_slug", ["physics"])
@pytest.mark.asyncio
async def test_buy_print_copy_link(chrome_page_unlogged, base_url, book_slug):
Expand Down Expand Up @@ -80,44 +59,6 @@ async def test_order_options_link(chrome_page_unlogged, base_url, book_slug):
assert "Kendall_Hunt" in await home.order_options_href()


@pytest.mark.parametrize(
"book_slug, page_slug", [("astronomy-2e", "1-3-the-laws-of-nature")]
)
@pytest.mark.asyncio
async def test_accessibility_help(chrome_page_unlogged, base_url, book_slug, page_slug):
# Verifies the hidden 'Go to accessibility page'

# GIVEN: Open osweb book details page

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

await chrome_page_unlogged.keyboard.press("Escape")

try:
await home.click_cookieyes_accept()

except TimeoutError as te:
print(f"{te}\nNo Cookies dialog, continue testing... ", file=sys.stderr)

finally:

await chrome_page_unlogged.keyboard.press("Tab")
await chrome_page_unlogged.keyboard.press("Tab")

await chrome_page_unlogged.keyboard.press("Enter")

# THEN: Accessibility help opens

accessibility_page_content = await home.accessibility_help_content.inner_text()

assert (
"Accessibility" in accessibility_page_content
and "OpenStax" in accessibility_page_content
)


@pytest.mark.parametrize("book_slug", ["algebra-and-trigonometry-2e"])
@pytest.mark.asyncio
async def test_toc_slideout(chrome_page_unlogged, base_url, book_slug):
Expand Down Expand Up @@ -164,3 +105,23 @@ async def test_resources_tabs(chrome_page_unlogged, base_url, book_slug):
await home.click_student_resources_tab()

assert "Student" in chrome_page_unlogged.url


@pytest.mark.parametrize("book_slug", ["anatomy-and-physiology-2e"])
@pytest.mark.asyncio
async def test_audiobook_link(chrome_page_unlogged, base_url, book_slug):

# GIVEN: Open osweb book details page

# WHEN: The Home page is fully loaded
details_books_url = f"{base_url}/details/books/{book_slug}"

await chrome_page_unlogged.goto(details_books_url)
home = HomeRex(chrome_page_unlogged)

await chrome_page_unlogged.keyboard.press("Escape")

# THEN: Audiobook link is visible and clickable
assert await home.audiobook_link_is_visible()

assert await home.audiobook_link_purchase_options.is_enabled()
21 changes: 21 additions & 0 deletions e2e_tests/e2e/osweb/test_subjects_books_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,24 @@ async def test_subjects_books_pages_load(chrome_page_unlogged, base_url):
mod_hrefs = mhrefs.replace("-", " ")

assert await home.subjects_title() in mod_hrefs


@pytest.mark.asyncio
async def test_book_title_links_to_books_detail_page(chrome_page_unlogged, base_url):

# GIVEN: Playwright, chromium and the rex_base_url

# WHEN: The Home page is fully loaded
await chrome_page_unlogged.goto(f"{base_url}/subjects")
home = HomeRex(chrome_page_unlogged)

await chrome_page_unlogged.keyboard.press("Escape")

assert await home.subject_listing_book_is_visible()

await home.click_subject_listing_book()

await home.click_book_selection()

# THEN: The page navigates to {base_url}/details/books/astronomy-2e
assert "astronomy" in chrome_page_unlogged.url.lower()
8 changes: 8 additions & 0 deletions e2e_tests/e2e/ui/pages/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,14 @@ async def toc_is_visible(self):
.is_visible()
)

@pytest.mark.asyncio
async def audiobook_link_is_visible(self):
return await self.page.get_by_role("heading", name="Audiobook").is_visible()

@property
def audiobook_link_purchase_options(self):
return self.page.get_by_role("link", name="Purchase options")

# Accessibility page (hidden link: go to accessibility page)

@property
Expand Down
Loading
Loading