Skip to content
Draft
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 pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
python_files = test_*
python_classes = *Tests
python_functions = test_*
addopts = -ra -v
addopts = -ra -v --browser chromium --browser firefox --browser webkit --screenshot only-on-failure --output screenshots
testpaths = test
markers =
dev: "the current test(s) you're working on for developing"
Expand Down
215 changes: 185 additions & 30 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@

from pathlib import Path
from typing import Dict, Generator, List, Tuple, Callable
from typing import Generator, Callable
from pytest import fixture
from _pytest.fixtures import SubRequest
from pytest_base_url.plugin import base_url
from playwright.sync_api import Playwright, APIRequestContext, Route, Page, Browser
import json


@fixture
def get_test_dir() -> Path:
return Path(__file__).parent.absolute()


@fixture
def screenshot_dir() -> Path:
return Path('screenshots/')
Expand Down Expand Up @@ -47,7 +48,20 @@ def mobile_device_tuple(
# from the pytest-base-url plugin Playwright installs (automatically)
# so we're not having to hard-code the URL
base_url: base_url,
) -> Tuple[Page,str]:
) -> tuple[Page,str]:
"""
identified all possible device types by running the following in a python interpreter + shell commands

# python interpreter
with sync_playwright() as playwright:
Path('./devices.json').write_text(j_dumps(playwright.devices, indent=2))

# shell cmd
jq '. | keys' devices.json| less

also should be able to view them here:
https://github.com/microsoft/playwright/blob/v1.25.2/packages/playwright-core/src/server/deviceDescriptorsSource.json
"""

# based on here: https://playwright.dev/python/docs/emulation#devices
context = browser.new_context(
Expand All @@ -57,26 +71,26 @@ def mobile_device_tuple(
)
try:
# essentially a "return", but used with generators
yield (context.new_page(), request.param)
except Exception as excpt:
raise excpt
yield context.new_page(), request.param
except Exception as e:
raise e
finally:
# supposed to get rid of coookies/other stored info after generator is done
# supposed to get rid of cookies/other stored info after generator is done
# https://playwright.dev/python/docs/api/class-apirequestcontext#api-request-context-dispose
# https://github.com/microsoft/playwright.dev/blob/d9b4a2f3bd0510ea89c87ed230b8241eb33b6688/python/docs/api-testing.mdx#writing-api-test
context.close()

# https://playwright.dev/python/docs/api-testing#configure
# used for doing similar requests to API calls

@fixture(scope="session")
def api_request_context(
# base playwright context/object
playwright: Playwright,
# from the pytest-base-url plugin Playwright installs (automatically)
# so we're not having to hard-code the URL
base_url: base_url,
# Generator is returned based on Playwright docs
) -> Generator[APIRequestContext, None, None]:
playwright: Playwright, # base playwright context/object
# From the pytest-base-url plugin Playwright installs (automatically) so we're not having to hard-code the URL
base_url: base_url,
) -> Generator[APIRequestContext, None, None]: # Generator is returned based on Playwright docs
"""
https://playwright.dev/python/docs/api-testing#configure
used for doing similar requests to API calls
"""
# creates APIRequestContext to allow requests to be made
# using the base_url variable (from the plugin) to define
# the base_url which'll allow requests relative to that base_url
Expand All @@ -88,21 +102,106 @@ def api_request_context(
# https://github.com/microsoft/playwright.dev/blob/d9b4a2f3bd0510ea89c87ed230b8241eb33b6688/python/docs/api-testing.mdx#writing-api-test
request_context.dispose()


@fixture(
# doing session so it doesn't have to be re-created for each usage
scope="session",
# some example phone sizes to use
params=[
"iPhone 13",
"Pixel 5",
"Galaxy S9+",
]
)
def mobile_device_tuple(
# how to access the params
request: SubRequest,
# browser object given by playwright built-in fixture
browser: Browser,
# Playwright object given by playwright built-in fixture
playwright: Playwright,
# from the pytest-base-url plugin Playwright installs (automatically)
# so we're not having to hard-code the URL
base_url: base_url,
) -> tuple[Page, str]:
"""
identified all possible device types by running the following in a python interpreter + shell commands

# python interpreter
with sync_playwright() as playwright:
Path('./devices.json').write_text(j_dumps(playwright.devices, indent=2))

# shell cmd
jq '. | keys' devices.json| less

also should be able to view them here:
https://github.com/microsoft/playwright/blob/v1.25.2/packages/playwright-core/src/server/deviceDescriptorsSource.json
"""
params=playwright.devices[request.param]


# based on here: https://playwright.dev/python/docs/emulation#devices
params = playwright.devices[request.param]
if browser.browser_type.name == "firefox":
# bug in playwright for firefox https://github.com/microsoft/playwright/issues/16622
# https://github.com/Lookyloo/PlaywrightCapture/blob/34ab2c3e096fc3bc1ebef217063b78f3554d8a42/playwrightcapture/capture.py#L188
del params['is_mobile']

context = browser.new_context(
base_url=base_url,
# based on this info: https://playwright.dev/python/docs/emulation#devices
**params
)
try:
# essentially a "return", but used with generators
yield context.new_page(), request.param
except Exception as e:
raise e
finally:
# supposed to get rid of cookies/other stored info after generator is done
# https://playwright.dev/python/docs/api/class-apirequestcontext#api-request-context-dispose
# https://github.com/microsoft/playwright.dev/blob/d9b4a2f3bd0510ea89c87ed230b8241eb33b6688/python/docs/api-testing.mdx#writing-api-test
context.close()


@fixture(scope="session")
def api_request_context(
playwright: Playwright, # base playwright context/object
# From the pytest-base-url plugin Playwright installs (automatically) so we're not having to hard-code the URL
base_url: base_url,
) -> Generator[APIRequestContext, None, None]: # Generator is returned based on Playwright docs
"""
https://playwright.dev/python/docs/api-testing#configure
used for doing similar requests to API calls
"""
# creates APIRequestContext to allow requests to be made
# using the base_url variable (from the plugin) to define
# the base_url which'll allow requests relative to that base_url
request_context = playwright.request.new_context(base_url=base_url)
# essentially a "return", but used with generators
yield request_context
# supposed to get rid of coookies/other stored info after generator is done
# https://playwright.dev/python/docs/api/class-apirequestcontext#api-request-context-dispose
# https://github.com/microsoft/playwright.dev/blob/d9b4a2f3bd0510ea89c87ed230b8241eb33b6688/python/docs/api-testing.mdx#writing-api-test
request_context.dispose()


@fixture
def expected_rss_feeds() -> List[Dict[str,str,]]:
def expected_rss_feeds() -> list[dict[str, str, ]]:
return [
{ 'href': 'http://feeds2.feedburner.com/JupiterBroadcasting', 'title': 'All Shows Feed - Audio'},
{ 'href': 'http://feeds2.feedburner.com/AllJupiterVideos', 'title': 'All Shows Feed - Video'},
{ 'href': 'https://coder.show/rss', 'title': 'Coder Radio'},
{ 'href': 'https://extras.show/rss', 'title': 'Jupiter EXTRAS'},
{ 'href': 'https://linuxactionnews.com/rss', 'title': 'Linux Action News'},
{ 'href': 'https://linuxunplugged.com/rss', 'title': 'LINUX Unplugged'},
{ 'href': 'https://www.officehours.hair/rss', 'title': 'Office Hours'},
{ 'href': 'https://selfhosted.show/rss', 'title': 'Self-Hosted'}
{'href': 'http://feeds2.feedburner.com/JupiterBroadcasting', 'title': 'All Shows Feed - Audio'},
{'href': 'http://feeds2.feedburner.com/AllJupiterVideos', 'title': 'All Shows Feed - Video'},
{'href': 'https://coder.show/rss', 'title': 'Coder Radio'},
{'href': 'https://extras.show/rss', 'title': 'Jupiter EXTRAS'},
{'href': 'https://linuxactionnews.com/rss', 'title': 'Linux Action News'},
{'href': 'https://linuxunplugged.com/rss', 'title': 'LINUX Unplugged'},
{'href': 'https://www.officehours.hair/rss', 'title': 'Office Hours'},
{'href': 'https://selfhosted.show/rss', 'title': 'Self-Hosted'}
]


@fixture
def expected_dropdown_items() -> Dict[str,List[Dict[str,str]]]:
def expected_dropdown_items() -> dict[str, list[dict[str, str]]]:
return {
"Shows": [
{'href': '/show/coder-radio/', 'title': 'Coder Radio'},
Expand Down Expand Up @@ -131,16 +230,18 @@ def expected_dropdown_items() -> Dict[str,List[Dict[str,str]]]:
]
}


@fixture
def expected_dropdowns() -> List[Dict[str,str]]:
def expected_dropdowns() -> list[dict[str, str]]:
return [
{'title': 'Shows', 'href': '/show/'},
{'title': 'People', 'href': "/people/"},
{'title': 'Community', 'href': "/community/"}
]


@fixture
def expect_nav_items() -> List[Dict[str,str]]:
def expect_nav_items() -> list[dict[str, str]]:
return [
{'title': 'Sponsors', 'href': '/sponsors/'},
{'title': 'Live', 'href': '/live/'},
Expand All @@ -150,10 +251,12 @@ def expect_nav_items() -> List[Dict[str,str]]:
{'title': 'Membership', 'href': '/membership/'},
# commenting out for now PR #399
# {'title': 'Archive', 'href': '/archive'},
# failing on tests here: https://github.com/JupiterBroadcasting/jupiterbroadcasting.com/runs/8254156209?check_suite_focus=true#step:9:26
# failing on tests here:
# https://github.com/JupiterBroadcasting/jupiterbroadcasting.com/runs/8254156209?check_suite_focus=true#step:9:26
{'title': 'Contact', 'href': '/contact/'},
]


@fixture
def set_live() -> Callable:
return _replace_live_event
Expand All @@ -179,4 +282,56 @@ def handle_route(route: Route) -> None:
page.route(
"https://jupiter.tube/api/v1/video-channels/live/**",
handle_route
)
)


@fixture
def live_event_json(get_test_dir: Path) -> str:
return Path(get_test_dir / 'fixture_files/jb-live_sample-live-event.json').read_text()

@fixture
def replace_live_event(page: Page) -> Callable:
def handle_route(route: Route, p: Page, live_event: str) -> Callable[[Page, str], None]:
# fetch original response
response = p.request.fetch(route.request)

# setting live event
route.fulfill(
# Pass all fields from the response
response=response,
# override body
body=live_event.strip()
)

def mock_jb_tube_request(p: Page, live_event: str):
p.route(
"https://jupiter.tube/api/v1/video-channels/live/videos?isLive=true&skipCount=false&count=1&sort=-createdAt",
lambda route: handle_route(route, p, live_event)
)

return mock_jb_tube_request


@fixture
def set_live(get_live_event: str) -> tuple[Callable, str]:
return _replace_live_event, get_live_event
# return replace_live_event


@staticmethod
def _replace_live_event(page: Page, live_event: str) -> None:
def handle_route(route: Route) -> None:
# fetch original response
response = page.request.fetch(route.request)

# setting live event
route.fulfill(
# Pass all fields from the response
response=response,
# override body
body=live_event.strip()
)
page.route(
"https://jupiter.tube/api/v1/video-channels/live/videos?isLive=true&skipCount=false&count=1&sort=-createdAt",
handle_route
)
21 changes: 21 additions & 0 deletions test/e2e/test_404.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pytest import fixture
from playwright.sync_api import Page, expect


@fixture(autouse=True)
def setup(page: Page):
"""
Code here will run for every test in this file
"""
page.goto("/404.html") # TODO: Change to random address once #483 is merged


def test_404_contents(page: Page):
"""
Ensure text "Page Not Found" and unicorn image is present on the 404 page
"""
title = page.locator(".title.has-text-centered")
expect(title).to_contain_text("Page Not Found")

unicorn = page.locator("#img-404")
expect(unicorn).to_be_visible()
11 changes: 11 additions & 0 deletions test/e2e/test_calendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pytest import fixture
from playwright.sync_api import Page, expect, FrameLocator, Locator


@fixture(autouse=True)
def setup(page: Page):
"""
Code here will run for every test in this file
"""
page.goto("/calendar")
page.wait_for_load_state("networkidle")
Loading