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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,8 @@ cython_debug/
requirements.txt
generated
tests/test_codegen.py
.streamlit/*
!.streamlit/config.yaml
!.streamlit/secrets.toml.example
playwright/.auth/*
!playwright/.auth/.gitkeep
17 changes: 17 additions & 0 deletions .streamlit/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
credentials:
usernames:
jsmith:
email: [email protected]
name: John Smith
password: abc # To be replaced with hashed password
rbriggs:
email: [email protected]
name: Rebecca Briggs
password: def # To be replaced with hashed password
cookie:
expiry_days: 30
key: random_signature_key # Must be string
name: random_cookie_name
preauthorized:
emails:
- [email protected]
8 changes: 8 additions & 0 deletions .streamlit/secrets.toml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "xxx"

[auth.microsoft]
client_id = "your-client-id"
client_secret = "your-client-secret"
server_metadata_url = "https://login.microsoftonline.com/consumers/v2.0/.well-known/openid-configuration"
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
GIT_REVISION ?= $(shell git rev-parse --short HEAD)
GIT_TAG ?= $(shell git describe --tags --abbrev=0 --always | sed -e s/v//g)

# Project
SKIP_TEST ?= true

.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
Expand Down Expand Up @@ -40,7 +43,7 @@ lint: ## lint

.PHONY: test
test: ## run tests
uv run pytest --capture=no -vv
SKIP_TEST=$(SKIP_TEST) uv run pytest --capture=no -vv

.PHONY: ci-test
ci-test: install-deps-dev format-check lint test ## run CI tests
Expand Down Expand Up @@ -123,4 +126,5 @@ show-trace: ## show trace
.PHONY: codegen
codegen: ## generate test code
uv run playwright codegen \
--target python-pytest \
--output tests/test_codegen.py
9 changes: 9 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
pgadmin:
image: dpage/pgadmin4
ports:
- "8888:80"
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: very-strong-password
PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION: "False"
72 changes: 71 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ make install-deps-dev

- [[BUG] Host system is missing dependencies to run browsers (WSL2) #19100](https://github.com/microsoft/playwright/issues/19100)

## Guides
## Fundamentals

To run some demos, please follow the instructions below.

Expand All @@ -30,8 +30,78 @@ make show-trace
make codegen
```

## Guides

### Authentication

0. Run an application server

```shell
docker compose up
```

1. Run code generator and log in to the app manually.

```shell
make codegen
```

2. Update the generated codes for storing state via `context.storage_state()` method

3. Run the updated script named as `save_context.py`

```shell
uv run scripts/save_context.py
```

4. Run the following command to access to the app without logging in.

```shell
uv run scripts/load_context.py
```

## [Microsoft Playwright Testing](https://learn.microsoft.com/ja-jp/azure/playwright-testing/)

- [Get Started Sample](https://github.com/microsoft/playwright-testing-service/tree/main/samples/get-started)

## [Playwright MCP server](https://github.com/microsoft/playwright-mcp)

## Custom apps

### Credentials

Run the following command to set up the credentials for the application.

```shell
# Run the application
uv run streamlit run workshop_playwright_python/apps/streamlit_authentication.py
```

To login, type your credentials described in [.streamlit/config.yaml](../.streamlit/config.yaml) and click the "Login" button. (e.g. `jsmith:abc`, `rbriggs:def`)

### OpenID Connect

To run a frontend application with authentication, you can refer to the following links.

- [User authentication and information](https://docs.streamlit.io/develop/concepts/connections/authentication)
- [Use Microsoft Entra to authenticate users](https://docs.streamlit.io/develop/tutorials/authentication/microsoft)

For example, you can use the following file [.streamlit/secrets.toml](../.streamlit/secrets.toml.example) to set up authentication with Microsoft Entra ID.

```toml
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "xxx"

[auth.microsoft]
client_id = "your-client-id"
client_secret = "your-client-secret"
server_metadata_url = "https://login.microsoftonline.com/consumers/v2.0/.well-known/openid-configuration"
```

Then, run the application using the following command:

```shell
# Run the application
uv run streamlit run workshop_playwright_python/apps/authentication.py
```
Empty file added playwright/.auth/.gitkeep
Empty file.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ description = "A GitHub template repository for Python"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"authlib>=1.5.2",
"playwright>=1.52.0",
"pytest-playwright>=0.7.0",
"streamlit>=1.45.0",
"streamlit-authenticator>=0.4.2",
]

[project.optional-dependencies]
Expand Down
20 changes: 20 additions & 0 deletions scripts/load_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from playwright.sync_api import Playwright, expect, sync_playwright


def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context(
storage_state="playwright/.auth/storage.json",
)
page = context.new_page()
page.goto("http://localhost:8888/")

expect(page.get_by_role("heading", name="Feature rich | Maximises")).to_be_visible()

# ---------------------
context.close()
browser.close()


with sync_playwright() as playwright:
run(playwright)
24 changes: 24 additions & 0 deletions scripts/save_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import json

from playwright.sync_api import Playwright, StorageState, sync_playwright


def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("http://localhost:8888/")
page.get_by_role("textbox", name="Email Address / Username").fill("[email protected]")
page.get_by_role("textbox", name="Password").fill("very-strong-password")
page.get_by_role("button", name="Login").click()

storage: StorageState = context.storage_state(path="playwright/.auth/storage.json")
print(json.dumps(storage, indent=2))

# ---------------------
context.close()
browser.close()


with sync_playwright() as playwright:
run(playwright)
3 changes: 3 additions & 0 deletions tests/flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from os import getenv

SKIP = getenv("SKIP_TEST", "true").lower() == "true"
1 change: 0 additions & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import re

from playwright.sync_api import Page, expect

from workshop_playwright_python.core import hello_world


Expand Down
4 changes: 4 additions & 0 deletions tests/test_hatena_bookmark.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import json

import pytest

from playwright.sync_api import Page
from tests import flags


@pytest.mark.skipif(flags.SKIP, reason="This test is skipped because it requires a live server.")
def test_hatena_bookmark(page: Page):
page.goto("https://b.hatena.ne.jp/hotentry/all")

Expand Down
Loading