Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding basic python playwright test #3382

Merged
merged 14 commits into from
Feb 5, 2024
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ functional: install-dev need-kinto-running
$(VENV)/bin/py.test tests/functional.py

browser-test: need-kinto-running
$(VENV)/bin/playwright install firefox
$(VENV)/bin/py.test tests/browser.py

clean:
Expand Down
2 changes: 1 addition & 1 deletion constraints.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ bravado_core
pytest
pytest-cache
pytest-cov
selenium
playwright
webtest
# dev
build
Expand Down
47 changes: 11 additions & 36 deletions constraints.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --strip-extras
# pip-compile --output-file=constraints.txt --strip-extras constraints.in
#
arrow==1.3.0
# via isoduration
attrs==23.2.0
# via
# jsonschema
# outcome
# referencing
# trio
bcrypt==4.1.2
# via -r constraints.in
beautifulsoup4==4.12.3
Expand All @@ -23,7 +21,6 @@ build==1.0.3
certifi==2023.11.17
# via
# requests
# selenium
# sentry-sdk
charset-normalizer==3.3.2
# via requests
Expand All @@ -46,27 +43,21 @@ coverage==7.4.0
dockerflow==2024.1.0
# via -r constraints.in
exceptiongroup==1.2.0
# via
# pytest
# trio
# trio-websocket
# via pytest
execnet==2.0.2
# via pytest-cache
fqdn==1.5.1
# via jsonschema
greenlet==3.0.3
# via sqlalchemy
h11==0.14.0
# via wsproto
# via
# playwright
# sqlalchemy
hupper==1.12
# via pyramid
idna==3.6
# via
# jsonschema
# requests
# trio
importlib-metadata==7.0.1
# via build
iniconfig==2.0.0
# via pytest
iso8601==2.1.0
Expand Down Expand Up @@ -96,8 +87,6 @@ msgpack==1.0.7
# via bravado-core
newrelic==9.6.0
# via -r constraints.in
outcome==1.3.0.post0
# via trio
packaging==23.2
# via
# build
Expand All @@ -111,10 +100,14 @@ plaster==1.1.2
# pyramid
plaster-pastedeploy==1.0.1
# via pyramid
playwright==1.41.1
# via -r constraints.in
pluggy==1.3.0
# via pytest
psycopg2==2.9.9
# via -r constraints.in
pyee==11.0.1
# via playwright
pyproject-hooks==1.0.0
# via build
pyramid==2.0.2
Expand All @@ -130,8 +123,6 @@ pyramid-multiauth==1.0.1
# via -r constraints.in
pyramid-tm==2.5
# via -r constraints.in
pysocks==1.7.1
# via urllib3
pytest==7.4.4
# via
# -r constraints.in
Expand Down Expand Up @@ -176,8 +167,6 @@ rpds-py==0.17.1
# referencing
ruff==0.1.15
# via -r constraints.in
selenium==4.12.0
# via -r constraints.in
sentry-sdk==1.39.2
# via -r constraints.in
simplejson==3.19.2
Expand All @@ -188,10 +177,6 @@ six==1.16.0
# cornice-swagger
# python-dateutil
# rfc3339-validator
sniffio==1.3.0
# via trio
sortedcontainers==2.4.0
# via trio
soupsieve==2.5
# via beautifulsoup4
sqlalchemy==2.0.25
Expand Down Expand Up @@ -220,24 +205,18 @@ translationstring==1.4
# via
# colander
# pyramid
trio==0.24.0
# via
# selenium
# trio-websocket
trio-websocket==0.11.1
# via selenium
types-python-dateutil==2.8.19.20240106
# via arrow
typing-extensions==4.9.0
# via
# pyee
# sqlalchemy
# swagger-spec-validator
uri-template==1.3.0
# via jsonschema
urllib3==2.1.0
# via
# requests
# selenium
# sentry-sdk
venusian==3.1.0
# via
Expand All @@ -257,10 +236,6 @@ webtest==3.0.0
# via -r constraints.in
werkzeug==3.0.1
# via -r constraints.in
wsproto==1.2.0
# via trio-websocket
zipp==3.17.0
# via importlib-metadata
zope-deprecation==5.0
# via pyramid
zope-interface==6.1
Expand Down
11 changes: 1 addition & 10 deletions docs/community.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,16 +235,7 @@ In another terminal, run the end-to-end tests with:

Browser Tests
-------------

Make sure the `geckodriver <https://github.com/mozilla/geckodriver/releases>`_ binary is available in your path.

.. note::

If your installation of *Firefox* is custom, specify the path of its binary using an alias:

::

alias geckodriver="geckodriver --binary /path/to/firefox"
We use `playwright <https://playwright.dev/>`_ for browser testing. The tests included in this repo are very simple and verify the admin UI can at least authenticate with the current kinto back-end. Comprehensive unit tests are maintained in the kinto-admin repo.


In a terminal, run an instance with the provided ``browser.ini`` configuration:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ test = [
"pytest",
"pytest-cache",
"pytest-cov",
"selenium",
"playwright",
"webtest",
]
dev = [
Expand Down
78 changes: 24 additions & 54 deletions tests/browser.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,38 @@
import time
import re
import unittest
from urllib.parse import urljoin

import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from playwright.sync_api import expect, sync_playwright


SERVER_URL = "http://localhost:8888/v1"
DEFAULT_AUTH = ("user", "p4ssw0rd")
baseUrl = "http://localhost:8888/v1/"
auth = {"user": "user", "password": "p4ssw0rd"}

browser = sync_playwright().start().firefox.launch()
context = browser.new_context(base_url=baseUrl)
page = browser.new_page()


class BrowserTest(unittest.TestCase):
def setUp(self):
options = webdriver.FirefoxOptions()
options.headless = True
self.driver = webdriver.Firefox(options=options)
self.driver.implicitly_wait(10) # seconds

@classmethod
def setUpClass(cls):
# Make sure our user exists.
requests.post(
urljoin(SERVER_URL, "/accounts"),
json={"data": {"id": DEFAULT_AUTH[0], "password": DEFAULT_AUTH[1]}},
)

# Create a bucket and a collection for our user.
bucket_url = urljoin(SERVER_URL, "/buckets/workspace")
collection_url = f"{bucket_url}/collections/articles"
session = requests.Session()
session.auth = DEFAULT_AUTH
resp = session.put(bucket_url)
resp.raise_for_status()
resp = session.put(collection_url)
resp.raise_for_status()
request = context.request

def tearDown(self):
self.driver.close()
request.post("accounts", data={"data": {"id": auth["user"], "password": auth["password"]}})

def test_admin_ui_renders_properly(self):
base_url = urljoin(SERVER_URL, "/v1/admin/")
self.driver.get(base_url)
def test_login_and_view_home_page(self):
page.goto(f"{baseUrl}admin/")

# Load auth page.
header = self.driver.find_element(By.CSS_SELECTOR, ".content div > h1")
self.assertIn("Administration", header.text)
self.assertTrue(header.is_displayed())
expect(page).to_have_title(re.compile("Kinto Administration"))

# Select Kinto Accounts.
radio = self.driver.find_element(By.XPATH, "//label[contains(.,'Kinto Account Auth')]")
radio.click()
page.get_by_label("Kinto Account Auth").click()
txtUsername = page.get_by_label(re.compile("Username"))
txtPassword = page.get_by_label(re.compile("Password"))

# Fill username and password.
user_field = self.driver.find_element(By.ID, "root_credentials_username")
user_field.send_keys(DEFAULT_AUTH[0])
user_pass = self.driver.find_element(By.ID, "root_credentials_password")
user_pass.send_keys(DEFAULT_AUTH[1])
# Login
submit = self.driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
submit.click()
txtUsername.fill(auth["user"])
txtPassword.fill(auth["password"])
page.get_by_text(re.compile("Sign in using Kinto Account Auth")).click()

# Navigate to simple review page (uses React Hooks and broke a few times)
review_url = base_url + "#/buckets/workspace/collections/articles/simple-review"
self.driver.get(review_url)
time.sleep(1)
self.assertTrue(self.driver.find_element(By.CSS_SELECTOR, ".alert-warning").is_displayed())
expect(page.get_by_text("Kinto Administration")).to_be_visible()
expect(page.get_by_text("project_name")).to_be_visible()
expect(page.get_by_text("project_version")).to_be_visible()
expect(page.get_by_text("http_api_version")).to_be_visible()
expect(page.get_by_text("project_docs")).to_be_visible()
Loading