Skip to content
Closed
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
11 changes: 8 additions & 3 deletions sentience/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(
self,
api_key: Optional[str] = None,
api_url: Optional[str] = None,
headless: bool = False
headless: Optional[bool] = None
):
"""
Initialize Sentience browser
Expand All @@ -36,7 +36,7 @@ def __init__(
If None and api_key is provided, uses default URL
If None and no api_key, uses free tier (local extension only)
If 'local' or Docker sidecar URL, uses Enterprise tier
headless: Whether to run in headless mode
headless: Whether to run in headless mode. If None, defaults to True in CI, False otherwise
"""
self.api_key = api_key
# Only set api_url if api_key is provided, otherwise None (free tier)
Expand All @@ -45,7 +45,12 @@ def __init__(
self.api_url = api_url or "https://api.sentienceapi.com"
else:
self.api_url = None
self.headless = headless
# Default to headless=True in CI (no X server), headless=False locally
if headless is None:
import os
self.headless = os.getenv("CI", "").lower() in ("true", "1", "yes")
else:
self.headless = headless
self.playwright: Optional[Playwright] = None
self.context: Optional[BrowserContext] = None
self.page: Optional[Page] = None
Expand Down
8 changes: 8 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ def pytest_configure(config):
)


@pytest.fixture
def headless():
"""Fixture that returns headless mode based on CI environment"""
# In CI, always use headless mode (no X server available)
# Locally, default to False (headed) for better debugging
return os.getenv("CI", "").lower() in ("true", "1", "yes")


@pytest.fixture(scope="session")
def extension_available():
"""Check if the sentience-chrome extension is available"""
Expand Down
6 changes: 3 additions & 3 deletions tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

def test_click():
"""Test click action"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -24,7 +24,7 @@ def test_click():

def test_type_text():
"""Test type action"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
# Use a page with a text input
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")
Expand All @@ -41,7 +41,7 @@ def test_type_text():

def test_press():
"""Test press action"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
12 changes: 6 additions & 6 deletions tests/test_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

def test_generator_python():
"""Test Python script generation"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -37,7 +37,7 @@ def test_generator_python():

def test_generator_typescript():
"""Test TypeScript script generation"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -57,7 +57,7 @@ def test_generator_typescript():

def test_generator_save_python():
"""Test saving generated Python script"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -82,7 +82,7 @@ def test_generator_save_python():

def test_generator_save_typescript():
"""Test saving generated TypeScript script"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -107,7 +107,7 @@ def test_generator_save_typescript():

def test_generator_without_selector():
"""Test generator handles steps without selectors"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -124,7 +124,7 @@ def test_generator_without_selector():

def test_generate_helper():
"""Test generate() helper function"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
8 changes: 4 additions & 4 deletions tests/test_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

def test_inspector_start_stop():
"""Test inspector can start and stop"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -28,7 +28,7 @@ def test_inspector_start_stop():

def test_inspector_context_manager():
"""Test inspector as context manager"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -44,7 +44,7 @@ def test_inspector_context_manager():

def test_inspector_mouse_move_detection():
"""Test inspector detects mouse move"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -60,7 +60,7 @@ def test_inspector_mouse_move_detection():

def test_inspector_click_detection():
"""Test inspector detects clicks"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
4 changes: 2 additions & 2 deletions tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def test_match_element():

def test_query_integration():
"""Test query on real page"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -174,7 +174,7 @@ def test_query_integration():

def test_find_integration():
"""Test find on real page"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
18 changes: 9 additions & 9 deletions tests/test_recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

def test_recorder_start_stop():
"""Test recorder can start and stop"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -26,7 +26,7 @@ def test_recorder_start_stop():

def test_recorder_context_manager():
"""Test recorder as context manager"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -39,7 +39,7 @@ def test_recorder_context_manager():

def test_recorder_navigation():
"""Test recording navigation events"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -53,7 +53,7 @@ def test_recorder_navigation():

def test_recorder_click():
"""Test recording click events"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -68,7 +68,7 @@ def test_recorder_click():

def test_recorder_type():
"""Test recording type events"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -84,7 +84,7 @@ def test_recorder_type():

def test_recorder_type_masking():
"""Test text masking in type events"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -98,7 +98,7 @@ def test_recorder_type_masking():

def test_recorder_press():
"""Test recording key press events"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -112,7 +112,7 @@ def test_recorder_press():

def test_trace_save_load():
"""Test trace save and load"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down Expand Up @@ -142,7 +142,7 @@ def test_trace_save_load():

def test_trace_format():
"""Test trace format matches spec"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
6 changes: 3 additions & 3 deletions tests/test_smart_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

def test_smart_selector_inference():
"""Test that recorder infers selectors automatically"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -30,7 +30,7 @@ def test_smart_selector_inference():

def test_smart_selector_with_text():
"""Test selector inference for elements with text"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -54,7 +54,7 @@ def test_smart_selector_with_text():

def test_smart_selector_validation():
"""Test that inferred selectors are validated"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
6 changes: 3 additions & 3 deletions tests/test_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@pytest.mark.requires_extension
def test_snapshot_basic():
"""Test basic snapshot on example.com"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -33,7 +33,7 @@ def test_snapshot_roundtrip():
]

for site in sites:
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto(site)
browser.page.wait_for_load_state("networkidle")

Expand Down Expand Up @@ -66,7 +66,7 @@ def test_snapshot_save():
import os
import json

with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
2 changes: 1 addition & 1 deletion tests/test_spec_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def test_snapshot_matches_spec():
"""Test that snapshot response matches spec schema"""
schema = load_schema()

with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
2 changes: 1 addition & 1 deletion tests/test_stealth.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_stealth_features():
print("Bot Evasion / Stealth Mode Test")
print("=" * 60)

browser = SentienceBrowser(headless=False)
browser = SentienceBrowser()

try:
browser.start()
Expand Down
10 changes: 6 additions & 4 deletions tests/test_wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"""

import pytest
import os
from sentience import SentienceBrowser, wait_for, expect


def test_wait_for():
"""Test wait_for element"""
with SentienceBrowser(headless=False) as browser:
# Auto-detect headless mode (True in CI, False locally)
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -21,7 +23,7 @@ def test_wait_for():

def test_wait_for_timeout():
"""Test wait_for timeout"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -33,7 +35,7 @@ def test_wait_for_timeout():

def test_expect_to_exist():
"""Test expect().to_exist()"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand All @@ -44,7 +46,7 @@ def test_expect_to_exist():

def test_expect_to_be_visible():
"""Test expect().to_be_visible()"""
with SentienceBrowser(headless=False) as browser:
with SentienceBrowser() as browser:
browser.page.goto("https://example.com")
browser.page.wait_for_load_state("networkidle")

Expand Down
Loading