Working with playwright

tursu does not provice playwright option, but you can works with both playwright and tursu for testing your web application.

Actually, it has been develop for that!

Installation

uv add tursu pytest-playwright
uv run playwright install chromium
uv tursu init --no-dummies -o tests/functionals-playwright/
  • playwright requires to download its own browsers, refer to the playwright documentation for more options.

  • The --no-dummies does not create dummy scenario.

Create a step

from playwright.sync_api import Page, expect

from tursu import given, then, when


@given("anonymous user on {path}")
@when("I visit {path}")
def i_visit(page: Page, path: str):
    page.goto(path)


@then('I see the text "{text}"')
def assert_text(page: Page, text: str):
    loc = page.get_by_text(text)
    expect(loc).to_be_visible()

That’s it. You can just use the “Page” fixture provided by pytest-playwright directly.

Create a scenario

@wip
Feature: Basic Test

  Scenario: Hello world
    Given anonymous user on /
    Then I see the text "Hello, World!"

Run the test

uv run pytest --base-url http://localhost:8888 --browser chromium -v tests/using_playwright/

Sure this tests will fail, this is BDD :)

Adding a fixture

import socket
import threading
import time
from http.server import BaseHTTPRequestHandler, HTTPServer

import pytest

from tursu.plugin import tursu_collect_file

tursu_collect_file()


class HelloWorldHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(b"<body>Hello, World!</body>")


def wait_for_socket(host: str, port: int, timeout: int = 5):
    """Wait until the socket is open before proceeding."""
    for _ in range(timeout * 10):  # Check every 0.1s for `timeout` seconds
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            if sock.connect_ex((host, port)) == 0:
                return  # Socket is open
        time.sleep(0.1)
    raise RuntimeError(f"Server on {host}:{port} did not start in time.")


@pytest.fixture(autouse=True)
def http_server():
    """Start the service I test in a thread."""
    server_address = ("127.0.0.1", 8888)
    httpd = HTTPServer(server_address, HelloWorldHandler)

    thread = threading.Thread(target=httpd.serve_forever, daemon=True)
    thread.start()

    wait_for_socket(*server_address)
    yield

    httpd.shutdown()
    thread.join()

Run the test

$ uv run pytest --base-url http://localhost:8888 --browser chromium -v tests/using_playwright/
================================= test session starts =================================
baseurl: http://localhost:8888
configfile: pyproject.toml
plugins: cov-6.0.0, playwright-0.7.0, base-url-2.1.0
collected 1 item

📄 Document: 01_basic.feature_Basic_Test.py::test_2_Hello_world[chromium]
🥒 Feature: Basic Test
🎬 Scenario: Hello world
✅ Given anonymous user on /
✅ Then I see the text "Hello, World!"
                                                                           PASSED [100%]

================================== 1 passed in 0.94s ==================================

Tip

While doing continuous integration, always activate the option --tracing on from pytest-playright, it will generate a trace.zip file in a test-results directory to configured as a build artefact.

Afterwhat you can see all step of the scenario using the show-trace command:

$ uv run playwright show-trace test-results/**/trace.zip