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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ dist
codegen.log
Brewfile.lock.json
screenshot.png
openapi.v1.yaml
**/.DS_Store
78 changes: 78 additions & 0 deletions examples/e2e/test_playwright.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
from typing import Generator

import pytest
from dotenv import load_dotenv
from playwright.sync_api import Playwright, sync_playwright

from browserbase import Browserbase

from .. import (
BROWSERBASE_API_KEY,
playwright_basic,
playwright_proxy,
playwright_upload,
playwright_captcha,
playwright_contexts,
playwright_downloads,
)

bb = Browserbase(api_key=BROWSERBASE_API_KEY)
load_dotenv()

CI = os.getenv("CI", "false").lower() == "true"


@pytest.fixture(scope="session")
def playwright() -> Generator[Playwright, None, None]:
with sync_playwright() as p:
yield p


def test_playwright_basic(playwright: Playwright) -> None:
playwright_basic.run(playwright)


@pytest.mark.skipif(True, reason="Flaky and fails often")
def test_playwright_captcha(playwright: Playwright) -> None:
playwright_captcha.run(playwright)


def test_playwright_contexts(playwright: Playwright) -> None:
playwright_contexts.run(playwright)


def test_playwright_downloads(playwright: Playwright) -> None:
playwright_downloads.run(playwright)


def test_playwright_proxy_enable_via_create_session(playwright: Playwright) -> None:
playwright_proxy.run_enable_via_create_session(playwright)


def test_playwright_proxy_enable_via_querystring(playwright: Playwright) -> None:
playwright_proxy.run_enable_via_querystring_with_created_session(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_country(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_country(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_state(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_state(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_american_city(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_american_city(playwright)


@pytest.mark.skipif(CI, reason="Flaky and fails on CI")
def test_playwright_proxy_geolocation_non_american_city(playwright: Playwright) -> None:
playwright_proxy.run_geolocation_non_american_city(playwright)


def test_playwright_upload(playwright: Playwright) -> None:
playwright_upload.run(playwright)
21 changes: 0 additions & 21 deletions examples/e2e/test_playwright_basic.py

This file was deleted.

1 change: 1 addition & 0 deletions examples/packages/extensions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.zip
5 changes: 5 additions & 0 deletions examples/packages/extensions/browserbase-test/hello.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
<h1>Hello Extensions</h1>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions examples/packages/extensions/browserbase-test/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"manifest_version": 3,
"name": "Browserbase Extension Test",
"description": "Test extension for browserbase",
"version": "1.0",
"action": {
"default_popup": "hello.html"
},
"content_scripts": [
{
"matches": ["https://www.browserbase.com/*"],
"js": ["scripts/content.js"]
}
],
"web_accessible_resources": [
{
"resources": ["images/logo.png"],
"matches": ["https://www.browserbase.com/*"]
}
]
}
11 changes: 11 additions & 0 deletions examples/packages/extensions/browserbase-test/scripts/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const imageUrl = chrome.runtime.getURL("images/logo.png");
window
.fetch(imageUrl)
.then((response) => {
if (response.ok) {
console.log("browserbase test extension image loaded");
}
})
.catch((error) => {
console.log(error);
});
Binary file added examples/packages/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 2 additions & 7 deletions examples/playwright_basic.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
from playwright.sync_api import Playwright, sync_playwright

from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
BROWSERBASE_CONNECT_URL,
bb,
)


def run(playwright: Playwright):
def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
assert session.id is not None
assert session.status == "RUNNING", f"Session status is {session.status}"

# Connect to the remote session
connect_url = (
f"{BROWSERBASE_CONNECT_URL}?sessionId={session.id}&apiKey={BROWSERBASE_API_KEY}"
)
chromium = playwright.chromium
browser = chromium.connect_over_cdp(connect_url)
browser = chromium.connect_over_cdp(session.connect_url)
context = browser.contexts[0]
page = context.pages[0]

Expand Down
60 changes: 60 additions & 0 deletions examples/playwright_captcha.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from playwright.sync_api import Playwright, ConsoleMessage, sync_playwright

from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
BROWSERBASE_CONNECT_URL,
bb,
)

DEFAULT_CAPTCHA_URL = "https://www.google.com/recaptcha/api2/demo"
OVERRIDE_TIMEOUT = 60000 # 60 seconds, adjust as needed


def run(playwright: Playwright) -> None:
# Create a session on Browserbase
session = bb.sessions.create(project_id=BROWSERBASE_PROJECT_ID)
assert session.id is not None
assert session.status == "RUNNING", f"Session status is {session.status}"

# Connect to the remote session
connect_url = (
f"{BROWSERBASE_CONNECT_URL}?sessionId={session.id}&apiKey={BROWSERBASE_API_KEY}"
)
chromium = playwright.chromium
browser = chromium.connect_over_cdp(connect_url)
context = browser.contexts[0]
page = context.pages[0]

captcha_solving_started = False
captcha_solving_finished = False

# Browserbase logs messages to the console to indicate when captcha solving has started and finished
# We can track these messages to know when the captcha solving has started and finished
def handle_console(msg: ConsoleMessage) -> None:
nonlocal captcha_solving_started, captcha_solving_finished
if msg.text == "browserbase-solving-started":
captcha_solving_started = True
page.evaluate("window.captchaSolvingFinished = false;")
elif msg.text == "browserbase-solving-finished":
captcha_solving_finished = True
page.evaluate("window.captchaSolvingFinished = true;")

page.on("console", handle_console)

page.goto(DEFAULT_CAPTCHA_URL, wait_until="networkidle")
page.wait_for_function(
"() => window.captchaSolvingFinished === true", timeout=OVERRIDE_TIMEOUT
)

assert captcha_solving_started, "Captcha solving did not start"
assert captcha_solving_finished, "Captcha solving did not finish"

page.close()
browser.close()
print("Done!")


if __name__ == "__main__":
with sync_playwright() as playwright:
run(playwright)
128 changes: 128 additions & 0 deletions examples/playwright_contexts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import time
from typing import Optional

from playwright.sync_api import Cookie, Browser, Playwright, sync_playwright

from examples import (
BROWSERBASE_API_KEY,
BROWSERBASE_PROJECT_ID,
BROWSERBASE_CONNECT_URL,
bb,
)
from browserbase.types.session_create_params import (
BrowserSettings,
BrowserSettingsContext,
)

CONTEXT_TEST_URL = "https://www.browserbase.com"
SECOND = 1000


def add_hour(date: float) -> int:
return int((date + 3600) * 1000) // SECOND


def find_cookie(browser: Browser, name: str) -> Optional[Cookie]:
default_context = browser.contexts[0]
cookies = default_context.cookies()
return next((cookie for cookie in cookies if cookie.get("name") == name), None)


def run(playwright: Playwright) -> None:
context_id = None
session_id = None
test_cookie_name = None
test_cookie_value = None

# Step 1: Creates a context
context = bb.contexts.create(project_id=BROWSERBASE_PROJECT_ID)
assert context.id is not None
context_id = context.id

uploaded_context = bb.contexts.retrieve(id=context_id)
assert uploaded_context.id == context_id

# Step 2: Creates a session with the context
session = bb.sessions.create(
project_id=BROWSERBASE_PROJECT_ID,
browser_settings=BrowserSettings(
context=BrowserSettingsContext(id=context_id, persist=True),
),
)

assert (
session.context_id == context_id
), f"Session context_id is {session.context_id}, expected {context_id}"
session_id = session.id

# Step 3: Populates and persists the context
print(f"Populating context {context_id} during session {session_id}")
connect_url = (
f"{BROWSERBASE_CONNECT_URL}?sessionId={session_id}&apiKey={BROWSERBASE_API_KEY}"
)
browser = playwright.chromium.connect_over_cdp(connect_url)
page = browser.contexts[0].pages[0]

page.goto(CONTEXT_TEST_URL, wait_until="domcontentloaded")

now = time.time()
test_cookie_name = f"bb_{int(now * 1000)}"
test_cookie_value = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime(now))
browser.contexts[0].add_cookies(
[
{
"domain": ".browserbase.com",
"expires": add_hour(now),
"name": test_cookie_name,
"path": "/",
"value": test_cookie_value,
}
]
)

assert find_cookie(browser, test_cookie_name) is not None

page.goto("https://www.google.com", wait_until="domcontentloaded")
page.go_back()

assert find_cookie(browser, test_cookie_name) is not None

page.close()
browser.close()

time.sleep(5)

# Step 4: Creates another session with the same context
session = bb.sessions.create(
project_id=BROWSERBASE_PROJECT_ID,
browser_settings=BrowserSettings(
context=BrowserSettingsContext(id=context_id, persist=True)
),
)
assert (
session.context_id == context_id
), f"Session context_id is {session.context_id}, expected {context_id}"
session_id = session.id

# Step 5: Uses context to find previous state
print(f"Reusing context {context_id} during session {session_id}")
connect_url = (
f"{BROWSERBASE_CONNECT_URL}?sessionId={session_id}&apiKey={BROWSERBASE_API_KEY}"
)
browser = playwright.chromium.connect_over_cdp(connect_url)
page = browser.contexts[0].pages[0]

page.goto(CONTEXT_TEST_URL, wait_until="domcontentloaded")

found_cookie = find_cookie(browser, test_cookie_name)
print(found_cookie)
assert found_cookie is not None
assert found_cookie.get("value") == test_cookie_value

page.close()
browser.close()


if __name__ == "__main__":
with sync_playwright() as playwright:
run(playwright)
Loading