mirror of
https://github.com/Hopiu/bowser.git
synced 2026-03-16 19:10:24 +00:00
Refactor test files to remove unnecessary imports and improve readability
- Removed unused imports from various test files to streamline code. - Cleaned up whitespace in test cases for better consistency. - Updated dependency management in `uv.lock` to reflect changes in optional dependencies. - Ensured all tests maintain functionality while enhancing clarity and organization.
This commit is contained in:
parent
4b3ba9144d
commit
c9ef5e5c44
29 changed files with 989 additions and 625 deletions
345
.github/skills/skills.md
vendored
Normal file
345
.github/skills/skills.md
vendored
Normal file
|
|
@ -0,0 +1,345 @@
|
||||||
|
# Skills Index
|
||||||
|
|
||||||
|
This file defines **canonical project skills** the LLM must follow. Each skill specifies the *one correct command* for a common project action.
|
||||||
|
|
||||||
|
1. **Run the Project** → `uv run bowser`
|
||||||
|
2. **Test the Project** → `uv run pytest`
|
||||||
|
3. **Lint the Project** → `uv run ruff`
|
||||||
|
|
||||||
|
Deviating from these commands is considered incorrect behavior unless explicitly instructed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Skill: Run the Project with `uv run bowser`
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Teach the LLM **how and when to run this project** using the canonical command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run bowser
|
||||||
|
```
|
||||||
|
|
||||||
|
This skill ensures the LLM consistently uses the correct entry point, avoids ad‑hoc commands, and follows project conventions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Canonical Command
|
||||||
|
|
||||||
|
**Always run the project using:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run bowser
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not**:
|
||||||
|
- Call `python` directly
|
||||||
|
- Run scripts via file paths
|
||||||
|
- Use alternative task runners (e.g. `make`, `poetry run`, `pipenv run`)
|
||||||
|
|
||||||
|
`uv` is the authoritative environment and dependency manager for this project, and `bowser` is the defined runtime entry point.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What `uv run bowser` Means
|
||||||
|
|
||||||
|
- `uv run`:
|
||||||
|
- Ensures dependencies are resolved and installed according to the project configuration
|
||||||
|
- Executes commands inside the correct, isolated environment
|
||||||
|
|
||||||
|
- `bowser`:
|
||||||
|
- The project’s primary executable / CLI
|
||||||
|
- Encapsulates startup logic, configuration loading, and runtime behavior
|
||||||
|
|
||||||
|
Together, they guarantee a reproducible and correct execution environment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When to Use This Command
|
||||||
|
|
||||||
|
Use `uv run bowser` whenever you need to:
|
||||||
|
|
||||||
|
- Start the application
|
||||||
|
- Run the main service or agent
|
||||||
|
- Execute project logic end‑to‑end
|
||||||
|
- Validate runtime behavior
|
||||||
|
- Demonstrate how the project is launched
|
||||||
|
|
||||||
|
If the task says **“run the project”**, **“start the app”**, or **“execute Bowser”**, this is the command.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When *Not* to Use This Command
|
||||||
|
|
||||||
|
Do **not** use `uv run bowser` when:
|
||||||
|
|
||||||
|
- Running tests (use the project’s test command instead)
|
||||||
|
- Running one‑off scripts unless explicitly routed through `bowser`
|
||||||
|
- Installing dependencies
|
||||||
|
- Linting or formatting code
|
||||||
|
|
||||||
|
If unsure, default to **not running anything** and explain what would be executed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Explain This to Humans
|
||||||
|
|
||||||
|
When documenting or instructing users, say:
|
||||||
|
|
||||||
|
> “Run the project with `uv run bowser`.”
|
||||||
|
|
||||||
|
Optionally add:
|
||||||
|
|
||||||
|
> “This ensures the correct environment and entry point are used.”
|
||||||
|
|
||||||
|
Do **not** over‑explain unless the user asks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling Guidance
|
||||||
|
|
||||||
|
If `uv run bowser` fails:
|
||||||
|
|
||||||
|
1. Assume a dependency or configuration issue
|
||||||
|
2. Report the error output verbatim
|
||||||
|
3. Do **not** substitute another execution method
|
||||||
|
4. Suggest fixing the root cause, not changing the command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mental Model for the LLM
|
||||||
|
|
||||||
|
- There is **one** correct way to run the project
|
||||||
|
- That way is **stable and intentional**
|
||||||
|
- Deviating from it is a bug
|
||||||
|
|
||||||
|
Think of `uv run bowser` as:
|
||||||
|
|
||||||
|
> “The project’s on‑switch.”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary (Checklist)
|
||||||
|
|
||||||
|
Before suggesting how to run the project, verify:
|
||||||
|
|
||||||
|
- [ ] You are using `uv run`
|
||||||
|
- [ ] You are invoking `bowser`
|
||||||
|
- [ ] You are not calling Python directly
|
||||||
|
- [ ] You are not inventing alternate commands
|
||||||
|
|
||||||
|
If all are true, you are doing it right.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Skill: Test the Project with `uv run pytest`
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Teach the LLM **how and when to run tests** for this project using the canonical command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
This skill ensures tests are executed in the correct environment, using the project’s standard tooling, without inventing alternate commands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Canonical Command
|
||||||
|
|
||||||
|
**Always run tests using:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not**:
|
||||||
|
- Call `pytest` directly
|
||||||
|
- Use `python -m pytest`
|
||||||
|
- Run tests via ad-hoc scripts or task runners
|
||||||
|
|
||||||
|
`uv` is the authoritative environment manager, and `pytest` is the test runner for this project.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What `uv run pytest` Means
|
||||||
|
|
||||||
|
- `uv run`:
|
||||||
|
- Ensures dependencies (including test dependencies) are resolved correctly
|
||||||
|
- Runs inside the same environment model as the application
|
||||||
|
|
||||||
|
- `pytest`:
|
||||||
|
- Discovers and runs the project’s test suite
|
||||||
|
- Applies project-level configuration (e.g. `pytest.ini`, `pyproject.toml`)
|
||||||
|
|
||||||
|
Together, they guarantee consistent and reproducible test execution.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When to Use This Command
|
||||||
|
|
||||||
|
Use `uv run pytest` whenever you need to:
|
||||||
|
|
||||||
|
- Run the full test suite
|
||||||
|
- Verify a change before or after modifying code
|
||||||
|
- Reproduce a failing test
|
||||||
|
- Validate behavior without starting the application
|
||||||
|
|
||||||
|
If the task says **“run tests”**, **“test the project”**, or **“verify with pytest”**, this is the command.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When *Not* to Use This Command
|
||||||
|
|
||||||
|
Do **not** use `uv run pytest` when:
|
||||||
|
|
||||||
|
- Running the application (use `uv run bowser`)
|
||||||
|
- Installing dependencies
|
||||||
|
- Linting or formatting code
|
||||||
|
- Executing non-test scripts
|
||||||
|
|
||||||
|
If unsure, default to explaining what tests would be run rather than executing them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling Guidance
|
||||||
|
|
||||||
|
If `uv run pytest` fails:
|
||||||
|
|
||||||
|
1. Capture and report the full pytest output
|
||||||
|
2. Identify whether the failure is:
|
||||||
|
- A test assertion failure
|
||||||
|
- A missing dependency or import error
|
||||||
|
- A configuration issue
|
||||||
|
3. Do **not** change the command to work around the failure
|
||||||
|
4. Fix the underlying cause, then re-run the same command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mental Model for the LLM
|
||||||
|
|
||||||
|
- There is **one** correct way to run tests
|
||||||
|
- Test execution should mirror the real runtime environment
|
||||||
|
- Consistency matters more than convenience
|
||||||
|
|
||||||
|
Think of `uv run pytest` as:
|
||||||
|
|
||||||
|
> “The project’s truth-check.”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary (Checklist)
|
||||||
|
|
||||||
|
Before suggesting how to test the project, verify:
|
||||||
|
|
||||||
|
- [ ] You are using `uv run`
|
||||||
|
- [ ] You are invoking `pytest`
|
||||||
|
- [ ] You are not calling Python directly
|
||||||
|
- [ ] You are not inventing alternate test commands
|
||||||
|
|
||||||
|
If all are true, you are doing it right.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Skill: Lint the Project with `uv run ruff`
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Teach the LLM **how and when to lint the project** using the canonical command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run ruff
|
||||||
|
```
|
||||||
|
|
||||||
|
This skill ensures linting is performed consistently, using the project’s configured rules and environment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Canonical Command
|
||||||
|
|
||||||
|
**Always lint the project using:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run ruff
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not**:
|
||||||
|
- Call `ruff` directly
|
||||||
|
- Use alternative linters unless explicitly instructed
|
||||||
|
- Invoke formatting or linting via ad-hoc scripts
|
||||||
|
|
||||||
|
`uv` guarantees the correct environment, and `ruff` enforces the project’s linting standards.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What `uv run ruff` Means
|
||||||
|
|
||||||
|
- `uv run`:
|
||||||
|
- Executes linting inside the managed project environment
|
||||||
|
- Ensures the correct version of `ruff` and dependencies are used
|
||||||
|
|
||||||
|
- `ruff`:
|
||||||
|
- Performs fast, opinionated linting
|
||||||
|
- Applies rules configured in project files (e.g. `pyproject.toml`)
|
||||||
|
|
||||||
|
Together, they provide deterministic and repeatable lint results.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When to Use This Command
|
||||||
|
|
||||||
|
Use `uv run ruff` whenever you need to:
|
||||||
|
|
||||||
|
- Check code quality
|
||||||
|
- Identify linting or style issues
|
||||||
|
- Validate changes before committing
|
||||||
|
- Respond to a request to “lint the project” or “run ruff”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When *Not* to Use This Command
|
||||||
|
|
||||||
|
Do **not** use `uv run ruff` when:
|
||||||
|
|
||||||
|
- Running the application (`uv run bowser`)
|
||||||
|
- Running tests (`uv run pytest`)
|
||||||
|
- Formatting code unless `ruff` is explicitly configured to do so
|
||||||
|
- Installing dependencies
|
||||||
|
|
||||||
|
If unsure, explain what linting would check instead of executing it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling Guidance
|
||||||
|
|
||||||
|
If `uv run ruff` reports issues:
|
||||||
|
|
||||||
|
1. Treat findings as authoritative
|
||||||
|
2. Report errors or warnings clearly
|
||||||
|
3. Do **not** suppress or bypass lint rules
|
||||||
|
4. Fix the code, then re-run the same command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mental Model for the LLM
|
||||||
|
|
||||||
|
- Linting enforces shared standards
|
||||||
|
- Speed and consistency matter more than flexibility
|
||||||
|
- There is **one** correct linting command
|
||||||
|
|
||||||
|
Think of `uv run ruff` as:
|
||||||
|
|
||||||
|
> “The project’s code-quality gate.”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary (Checklist)
|
||||||
|
|
||||||
|
Before suggesting how to lint the project, verify:
|
||||||
|
|
||||||
|
- [ ] You are using `uv run`
|
||||||
|
- [ ] You are invoking `ruff`
|
||||||
|
- [ ] You are not inventing alternate linting tools
|
||||||
|
|
||||||
|
If all are true, you are doing it right.
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ dependencies = [
|
||||||
"Jinja2>=3.0", # Template engine for pages
|
"Jinja2>=3.0", # Template engine for pages
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"pytest>=9.0.0",
|
"pytest>=9.0.0",
|
||||||
"pytest-cov>=7.0.0",
|
"pytest-cov>=7.0.0",
|
||||||
|
|
@ -35,12 +35,14 @@ managed = true
|
||||||
packages = ["src"]
|
packages = ["src"]
|
||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 100
|
line-length = 120
|
||||||
target-version = ["py311"]
|
target-version = ["py311"]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 100
|
line-length = 120
|
||||||
target-version = "py311"
|
target-version = "py311"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "W"]
|
select = ["E", "F", "W"]
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
# ruff: noqa: E402
|
||||||
"""Browser entry and orchestration."""
|
"""Browser entry and orchestration."""
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
# ruff: noqa: E402
|
||||||
"""Browser chrome (Adwaita UI)."""
|
"""Browser chrome (Adwaita UI)."""
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
@ -433,8 +434,10 @@ class Chrome:
|
||||||
# Store sub-timings for display
|
# Store sub-timings for display
|
||||||
if self.debug_mode:
|
if self.debug_mode:
|
||||||
self._render_sub_timings = sub_timings
|
self._render_sub_timings = sub_timings
|
||||||
self._visible_line_count = len([l for l in self.text_layout
|
self._visible_line_count = len([
|
||||||
if self.scroll_y - 50 <= l["y"] + l["font_size"] <= self.scroll_y + height + 50])
|
line for line in self.text_layout
|
||||||
|
if self.scroll_y - 50 <= line["y"] + line["font_size"] <= self.scroll_y + height + 50
|
||||||
|
])
|
||||||
|
|
||||||
def _draw_selection_highlight(self, canvas, width: int):
|
def _draw_selection_highlight(self, canvas, width: int):
|
||||||
"""Draw selection highlight rectangle."""
|
"""Draw selection highlight rectangle."""
|
||||||
|
|
@ -531,7 +534,13 @@ class Chrome:
|
||||||
if self._render_sub_timings:
|
if self._render_sub_timings:
|
||||||
y += 16
|
y += 16
|
||||||
text_paint.setColor(skia.Color(150, 200, 255, 255))
|
text_paint.setColor(skia.Color(150, 200, 255, 255))
|
||||||
canvas.drawString(f"render_dom breakdown ({self._visible_line_count} lines):", panel_x + 5, y, small_font, text_paint)
|
canvas.drawString(
|
||||||
|
f"render_dom breakdown ({self._visible_line_count} lines):",
|
||||||
|
panel_x + 5,
|
||||||
|
y,
|
||||||
|
small_font,
|
||||||
|
text_paint,
|
||||||
|
)
|
||||||
|
|
||||||
sub_sorted = sorted(self._render_sub_timings.items(), key=lambda x: x[1], reverse=True)
|
sub_sorted = sorted(self._render_sub_timings.items(), key=lambda x: x[1], reverse=True)
|
||||||
for name, duration in sub_sorted:
|
for name, duration in sub_sorted:
|
||||||
|
|
@ -750,7 +759,7 @@ class Chrome:
|
||||||
line_bottom = line_info["y"] + line_info["height"]
|
line_bottom = line_info["y"] + line_info["height"]
|
||||||
line_left = line_info["x"]
|
line_left = line_info["x"]
|
||||||
char_positions = line_info.get("char_positions", [])
|
char_positions = line_info.get("char_positions", [])
|
||||||
text = line_info["text"]
|
# text not needed for highlight geometry
|
||||||
|
|
||||||
# Skip lines completely outside selection
|
# Skip lines completely outside selection
|
||||||
if line_bottom < sel_start[1] or line_top > sel_end[1]:
|
if line_bottom < sel_start[1] or line_top > sel_end[1]:
|
||||||
|
|
@ -764,13 +773,21 @@ class Chrome:
|
||||||
if line_top <= sel_start[1] < line_bottom:
|
if line_top <= sel_start[1] < line_bottom:
|
||||||
# Find character index at sel_start x
|
# Find character index at sel_start x
|
||||||
start_char_idx = self._x_to_char_index(sel_start[0], line_left, char_positions)
|
start_char_idx = self._x_to_char_index(sel_start[0], line_left, char_positions)
|
||||||
hl_left = line_left + char_positions[start_char_idx] if start_char_idx < len(char_positions) else line_left
|
hl_left = (
|
||||||
|
line_left + char_positions[start_char_idx]
|
||||||
|
if start_char_idx < len(char_positions)
|
||||||
|
else line_left
|
||||||
|
)
|
||||||
|
|
||||||
# If this line contains the end of selection
|
# If this line contains the end of selection
|
||||||
if line_top <= sel_end[1] < line_bottom:
|
if line_top <= sel_end[1] < line_bottom:
|
||||||
# Find character index at sel_end x
|
# Find character index at sel_end x
|
||||||
end_char_idx = self._x_to_char_index(sel_end[0], line_left, char_positions)
|
end_char_idx = self._x_to_char_index(sel_end[0], line_left, char_positions)
|
||||||
hl_right = line_left + char_positions[end_char_idx] if end_char_idx < len(char_positions) else hl_right
|
hl_right = (
|
||||||
|
line_left + char_positions[end_char_idx]
|
||||||
|
if end_char_idx < len(char_positions)
|
||||||
|
else hl_right
|
||||||
|
)
|
||||||
|
|
||||||
# Draw highlight
|
# Draw highlight
|
||||||
if hl_right > hl_left:
|
if hl_right > hl_left:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""Tab and frame orchestration stubs."""
|
"""Tab and frame orchestration stubs."""
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional, TYPE_CHECKING
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ..network.url import URL
|
from ..network.url import URL
|
||||||
|
|
@ -8,6 +8,9 @@ from ..network import http
|
||||||
from ..parser.html import parse_html, Element
|
from ..parser.html import parse_html, Element
|
||||||
from ..templates import render_startpage, render_error_page
|
from ..templates import render_startpage, render_error_page
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .browser import Browser
|
||||||
|
|
||||||
|
|
||||||
class Frame:
|
class Frame:
|
||||||
def __init__(self, tab: "Tab", parent_frame=None, frame_element=None):
|
def __init__(self, tab: "Tab", parent_frame=None, frame_element=None):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
from ..parser.html import Element, Text
|
from ..parser.html import Element, Text
|
||||||
from ..render.fonts import get_font, linespace
|
from ..render.fonts import get_font, linespace
|
||||||
from .block import BlockLayout, LineLayout
|
|
||||||
|
|
||||||
|
|
||||||
class LayoutLine:
|
class LayoutLine:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""Inline and text layout."""
|
"""Inline and text layout."""
|
||||||
|
|
||||||
from ..render.fonts import get_font, measure_text, linespace
|
from ..render.fonts import get_font, linespace
|
||||||
|
|
||||||
|
|
||||||
class TextLayout:
|
class TextLayout:
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,12 @@ import logging
|
||||||
from .url import URL
|
from .url import URL
|
||||||
|
|
||||||
|
|
||||||
def request(url: URL, payload: Optional[bytes] = None, method: str = "GET", max_redirects: int = 10) -> Tuple[int, str, bytes]:
|
def request(
|
||||||
|
url: URL,
|
||||||
|
payload: Optional[bytes] = None,
|
||||||
|
method: str = "GET",
|
||||||
|
max_redirects: int = 10,
|
||||||
|
) -> Tuple[int, str, bytes]:
|
||||||
"""
|
"""
|
||||||
Fetch a URL and follow redirects, returning (status_code, content_type, body).
|
Fetch a URL and follow redirects, returning (status_code, content_type, body).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from typing import Optional
|
||||||
from ..parser.html import Element
|
from ..parser.html import Element
|
||||||
from ..layout.document import DocumentLayout
|
from ..layout.document import DocumentLayout
|
||||||
from .fonts import get_font
|
from .fonts import get_font
|
||||||
from .paint import DisplayList, DrawText, DrawRect
|
from .paint import DisplayList
|
||||||
|
|
||||||
|
|
||||||
class RenderPipeline:
|
class RenderPipeline:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Template rendering utilities."""
|
"""Template rendering utilities."""
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
import logging
|
import logging
|
||||||
|
|
@ -66,13 +65,7 @@ def render_error_page(status_code: int, url: str = "", error_message: str = "")
|
||||||
"""
|
"""
|
||||||
logger = logging.getLogger("bowser.templates")
|
logger = logging.getLogger("bowser.templates")
|
||||||
|
|
||||||
# Map common status codes to templates
|
# Determine template per status
|
||||||
template_map = {
|
|
||||||
404: "error_404.html",
|
|
||||||
500: "error_500.html",
|
|
||||||
# Network errors
|
|
||||||
"network": "error_network.html",
|
|
||||||
}
|
|
||||||
|
|
||||||
if status_code == 404:
|
if status_code == 404:
|
||||||
template = "error_404.html"
|
template = "error_404.html"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for browser tab management."""
|
"""Tests for browser tab management."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
from src.browser.browser import Browser
|
from src.browser.browser import Browser
|
||||||
from src.browser.tab import Tab
|
from src.browser.tab import Tab
|
||||||
|
|
@ -140,7 +139,7 @@ class TestBrowser:
|
||||||
browser.chrome.tabs_box = Mock()
|
browser.chrome.tabs_box = Mock()
|
||||||
|
|
||||||
tab1 = browser.new_tab("https://example.com")
|
tab1 = browser.new_tab("https://example.com")
|
||||||
tab2 = browser.new_tab("https://other.com")
|
_ = browser.new_tab("https://other.com")
|
||||||
|
|
||||||
browser.set_active_tab(tab1)
|
browser.set_active_tab(tab1)
|
||||||
assert browser.active_tab is tab1
|
assert browser.active_tab is tab1
|
||||||
|
|
@ -168,7 +167,7 @@ class TestBrowser:
|
||||||
browser.chrome.paint = Mock()
|
browser.chrome.paint = Mock()
|
||||||
browser.chrome.tabs_box = Mock()
|
browser.chrome.tabs_box = Mock()
|
||||||
|
|
||||||
tab1 = browser.new_tab("https://example.com")
|
_ = browser.new_tab("https://example.com")
|
||||||
tab2 = browser.new_tab("https://other.com")
|
tab2 = browser.new_tab("https://other.com")
|
||||||
tab3 = browser.new_tab("https://third.com")
|
tab3 = browser.new_tab("https://third.com")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for cookie management."""
|
"""Tests for cookie management."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.network.cookies import CookieJar
|
from src.network.cookies import CookieJar
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
"""Tests for DOM graph visualization."""
|
"""Tests for DOM graph visualization."""
|
||||||
|
|
||||||
import pytest
|
from src.parser.html import parse_html
|
||||||
from src.parser.html import parse_html, Element, Text
|
|
||||||
from src.debug.dom_graph import generate_dot_graph, print_dom_tree
|
from src.debug.dom_graph import generate_dot_graph, print_dom_tree
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,8 +92,8 @@ class TestDOMGraph:
|
||||||
# Should have increasing indentation
|
# Should have increasing indentation
|
||||||
lines = tree.split('\n')
|
lines = tree.split('\n')
|
||||||
# Find the nested <p> line - should be more indented than <div>
|
# Find the nested <p> line - should be more indented than <div>
|
||||||
p_line = [l for l in lines if '<p>' in l][0]
|
p_line = [line for line in lines if '<p>' in line][0]
|
||||||
div_line = [l for l in lines if '<div>' in l][0]
|
div_line = [line for line in lines if '<div>' in line][0]
|
||||||
|
|
||||||
# Count leading spaces
|
# Count leading spaces
|
||||||
p_indent = len(p_line) - len(p_line.lstrip())
|
p_indent = len(p_line) - len(p_line.lstrip())
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
"""Tests for DOM graph page rendering."""
|
"""Tests for DOM graph page rendering."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.templates import render_dom_graph_page
|
from src.templates import render_dom_graph_page
|
||||||
from pathlib import Path
|
|
||||||
import tempfile
|
import tempfile
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
"""Tests for Frame and content loading."""
|
"""Tests for Frame and content loading."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
from src.browser.tab import Frame, Tab
|
from src.browser.tab import Tab
|
||||||
from src.network.url import URL
|
from src.network.url import URL
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for HTML parsing functionality."""
|
"""Tests for HTML parsing functionality."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.parser.html import parse_html, Text, Element
|
from src.parser.html import parse_html, Text, Element
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""Tests for HTTP functionality."""
|
"""Tests for HTTP functionality."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import Mock, patch, MagicMock
|
from unittest.mock import Mock, patch
|
||||||
from src.network.url import URL
|
from src.network.url import URL
|
||||||
from src.network import http
|
from src.network import http
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
# ruff: noqa: E402
|
||||||
"""Tests for layout components."""
|
"""Tests for layout components."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
from unittest.mock import Mock, patch, MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
# Mock skia before importing layout modules
|
# Mock skia before importing layout modules
|
||||||
mock_skia = MagicMock()
|
mock_skia = MagicMock()
|
||||||
|
|
@ -131,7 +132,12 @@ class TestDocumentLayout:
|
||||||
body = Element("body")
|
body = Element("body")
|
||||||
p = Element("p")
|
p = Element("p")
|
||||||
# Long text that should wrap
|
# Long text that should wrap
|
||||||
p.children = [Text("This is a very long paragraph that should wrap to multiple lines when the width is narrow enough")]
|
p.children = [
|
||||||
|
Text(
|
||||||
|
"This is a very long paragraph that should wrap to multiple lines "
|
||||||
|
"when the width is narrow enough"
|
||||||
|
)
|
||||||
|
]
|
||||||
body.children = [p]
|
body.children = [p]
|
||||||
|
|
||||||
layout = DocumentLayout(body)
|
layout = DocumentLayout(body)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for HTML parsing."""
|
"""Tests for HTML parsing."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.parser.html import Text, Element, print_tree
|
from src.parser.html import Text, Element, print_tree
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
# ruff: noqa: E402
|
||||||
"""Tests for rendering primitives."""
|
"""Tests for rendering primitives."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
from unittest.mock import Mock, patch, MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
# Mock skia before importing render modules
|
# Mock skia before importing render modules
|
||||||
mock_skia = MagicMock()
|
mock_skia = MagicMock()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for template rendering."""
|
"""Tests for template rendering."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.templates import render_template, render_error_page, render_startpage
|
from src.templates import render_template, render_error_page, render_startpage
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for URL parsing and resolution."""
|
"""Tests for URL parsing and resolution."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.network.url import URL
|
from src.network.url import URL
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
"""Tests for URL normalization."""
|
"""Tests for URL normalization."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from src.browser.browser import Browser
|
from src.browser.browser import Browser
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
17
uv.lock
17
uv.lock
|
|
@ -49,7 +49,7 @@ dependencies = [
|
||||||
{ name = "skia-python" },
|
{ name = "skia-python" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.optional-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "black" },
|
{ name = "black" },
|
||||||
{ name = "mypy" },
|
{ name = "mypy" },
|
||||||
|
|
@ -60,16 +60,19 @@ dev = [
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "black", marker = "extra == 'dev'", specifier = ">=25.0" },
|
|
||||||
{ name = "jinja2", specifier = ">=3.0" },
|
{ name = "jinja2", specifier = ">=3.0" },
|
||||||
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.9.0" },
|
|
||||||
{ name = "pygobject", specifier = ">=3.54.0" },
|
{ name = "pygobject", specifier = ">=3.54.0" },
|
||||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.0" },
|
|
||||||
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=7.0.0" },
|
|
||||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9.0" },
|
|
||||||
{ name = "skia-python", specifier = ">=87.9" },
|
{ name = "skia-python", specifier = ">=87.9" },
|
||||||
]
|
]
|
||||||
provides-extras = ["dev"]
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "black", specifier = ">=25.0" },
|
||||||
|
{ name = "mypy", specifier = ">=1.9.0" },
|
||||||
|
{ name = "pytest", specifier = ">=9.0.0" },
|
||||||
|
{ name = "pytest-cov", specifier = ">=7.0.0" },
|
||||||
|
{ name = "ruff", specifier = ">=0.9.0" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue