Skip to content
Merged
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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -e .
pip install ruff pytest pytest-asyncio anyio mypy pytest-cov
pip install ruff pytest pytest-asyncio anyio mypy pytest-cov nest-asyncio playwright pytest-playwright

- name: Install Playwright browsers
run: |
playwright install

- name: Lint with ruff
run: |
Expand Down
3 changes: 3 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import threading
from unittest.mock import MagicMock

import nest_asyncio
import pytest

# Mock browser-specific modules before any other imports
sys.modules["js"] = MagicMock()
sys.modules["pyodide"] = MagicMock()
sys.modules["pyodide.ffi"] = MagicMock()

def pytest_configure():
nest_asyncio.apply()

PORT = 8000

Expand Down
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@

await pyodide.loadPackage("micropip");
const micropip = pyodide.pyimport("micropip");
await micropip.install("./dist/imposition-0.1.0-py3-none-any.whl");
await micropip.install("./dist/imposition-0.1.0-py2.py3-none-any.whl");

const response = await fetch("run_imposition.py");
const pythonScript = await response.text();

try {
await pyodide.runPythonAsync(pythonScript);
await pyodide.globals.get("main")();
} catch (e) {
console.error("Error running Python script:", e);
}
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ dependencies = [
"pytest-asyncio",
"anyio",
"mypy",
"pytest-cov"
"pytest-cov",
"playwright",
"pytest-playwright",
"nest-asyncio"
]

[tool.hatch.envs.default.scripts]
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[pytest]
asyncio_mode = auto
testpaths = tests
norecursedirs = tests/integration
5 changes: 0 additions & 5 deletions run_imposition.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import asyncio
import js
from pyodide.ffi import JsProxy
from imposition.book import Book
from imposition.rendition import Rendition
from imposition.dom import PyodideDOMAdapter

async def main() -> None:
print("Starting Python script")
response: JsProxy = await js.pyfetch("test_book.epub")
epub_bytes_proxy: JsProxy = await response.bytes()
epub_bytes: bytes = epub_bytes_proxy.to_py()
Expand All @@ -19,6 +17,3 @@ async def main() -> None:

rendition.display_toc()
rendition.display(book.spine[0])

if __name__ == "__main__":
asyncio.run(main())
4 changes: 2 additions & 2 deletions src/imposition/rendition.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def __init__(self, book: Book, dom_adapter: DOMAdapter, target_id: str) -> None:

def display_toc(self) -> None:
"""
Renders the table of contents into the 'toc-container' element.
Renders the table of contents into the 'toc' element.
"""
toc_container: DOMElement = self.dom_adapter.get_element_by_id('toc-container')
toc_container: DOMElement = self.dom_adapter.get_element_by_id('toc')
toc_container.innerHTML = ''
ul: DOMElement = self.dom_adapter.create_element('ul')

Expand Down
7 changes: 7 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sys
from unittest.mock import MagicMock

# Mock browser-specific modules before any other imports
sys.modules["js"] = MagicMock()
sys.modules["pyodide"] = MagicMock()
sys.modules["pyodide.ffi"] = MagicMock()
3 changes: 3 additions & 0 deletions tests/integration/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
asyncio_mode = auto
testpaths = .
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
sys.modules["js"] = MagicMock()

# Add the 'src' directory to the Python path
project_root = Path(__file__).parent.parent
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root / "src"))
# Also add the project root to find run_imposition
sys.path.insert(0, str(project_root))
Expand Down
Binary file modified tests/screenshots/test_renders_first_chapter_passed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions tests/test_e2e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from playwright.sync_api import Page, expect
import os
import pytest

SCREENSHOT_DIR = "tests/screenshots"

def test_renders_first_chapter(page: Page, http_server):
os.makedirs(SCREENSHOT_DIR, exist_ok=True)

# Listen for uncaught exceptions
error_logs = []
page.on("pageerror", lambda exc: error_logs.append(exc))

page.goto(http_server)

# The viewer div should be present
viewer = page.locator("#viewer")
expect(viewer).to_be_visible()

# The iframe should be created inside the viewer
iframe = viewer.locator("iframe")
expect(iframe).to_be_visible(timeout=15000)

# The iframe should contain the cover image
iframe_element = iframe.element_handle()
assert iframe_element is not None
frame = iframe_element.content_frame()
assert frame is not None
expect(frame.locator("img.x-ebookmaker-cover")).to_be_visible()

# Take a screenshot on success
page.screenshot(path=f"{SCREENSHOT_DIR}/test_renders_first_chapter_passed.png")

# Assert that there were no uncaught exceptions
if error_logs:
# On failure, take a screenshot
page.screenshot(path=f"{SCREENSHOT_DIR}/test_renders_first_chapter_failed.png")
pytest.fail(f"Uncaught exception in browser console: {error_logs[0]}")
2 changes: 1 addition & 1 deletion tests/test_rendition.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_display_toc(mock_book, mock_dom_adapter):
rendition = Rendition(mock_book, mock_dom_adapter, "viewer")
rendition.display_toc()

toc_container = mock_dom_adapter.get_element_by_id("toc-container")
toc_container = mock_dom_adapter.get_element_by_id("toc")
assert toc_container.innerHTML == ''
assert len(toc_container.children) == 1

Expand Down