Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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"
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
Loading