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

test: added multi paste and delete paste scenarios, added info about … #178

Merged
merged 1 commit into from
Jul 31, 2023
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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,25 @@ History
=======
This pastebin has quite a long history which isn't reflected entirely in its
repository.

Testing
=======
There are 2 types of tests available to verify that the application still works correctly after the changes:
* unit test
* browser e2e tests

Unit tests are run by pytest by default when executing (the browser tests will be skipped)
```
€ pytest
```
If you'd like to run browser tests you need to pass the `--browser` option to the pytest command.
```
€ pytest --browser
```
The browser tests are executed by [Playwright](https://playwright.dev/python/docs/intro).
The tests by default will be run in the headless mode.
But it's possible to run them in the headed mode as well to be able to observe the execution of the tests.
For that, you just need to pass the `--headed` option to the `pytest --browser` command:
```
€ pytest --browser --headed
```
31 changes: 31 additions & 0 deletions test/e2e/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import Generator
import pytest
import subprocess
import sys
import logging
from playwright.sync_api import Page
from test.e2e.env_config import PORT
from test.e2e.pageobjects.create_paste_page import CreatePastePage

log = logging.getLogger(__name__)


@pytest.fixture(scope="session", autouse=True)
def application() -> Generator[None, None, None]:
# Before All
log.info(f"Starting Pinnwand application on port {PORT}")
proc = subprocess.Popen(
[sys.executable, "-m", "pinnwand", "http", "--port", str(PORT)]
)
yield
# After All
log.info("Terminating Pinnwand application")
proc.terminate()


@pytest.fixture
def create_paste_page(page: Page) -> CreatePastePage:
create_paste_page = CreatePastePage(page)
create_paste_page.open()
create_paste_page.should_be_opened()
return create_paste_page
24 changes: 7 additions & 17 deletions test/e2e/env_config.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from typing import Generator
import pytest
import subprocess
import sys
import logging
import socket

log = logging.getLogger(__name__)


def is_headless():
if "--headed" in sys.argv:
return False
else:
return True


def select_port():
sock = socket.socket()
sock.bind(("", 0))
Expand All @@ -16,17 +20,3 @@ def select_port():

PORT = str(select_port())
BASE_URL = f"http://localhost:{PORT}/"


@pytest.mark.e2e
@pytest.fixture(scope="session", autouse=True)
def application() -> Generator[None, None, None]:
# Before All
log.info(f"Starting Pinnwand application on port {PORT}")
proc = subprocess.Popen(
[sys.executable, "-m", "pinnwand", "http", "--port", PORT]
)
yield
# After All
log.info("Terminating Pinnwand application")
proc.terminate()
20 changes: 18 additions & 2 deletions test/e2e/pageobjects/base_page.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
from playwright.sync_api import Locator, expect
from playwright.sync_api import Page, Locator, expect
import logging

log = logging.getLogger(__name__)


class BasePage:
def __init__(self, locator: Locator, name) -> None:
def __init__(self, page: Page, locator: Locator, name) -> None:
self.page = page
self.page_locator = locator
self.page_name = name

def open(self, paste_url):
log.info(f"Opening page at {paste_url}")
self.page.goto(paste_url)

def current_url(self):
return self.page.url

# Expectations
def should_be_opened(self):
expect(
self.page_locator, f"{self.page_name} was not opened"
).to_be_visible()

def should_have_title(self, title):
expect(
self.page, f"{self.page_name} had incorrect title"
).to_have_title(title)
32 changes: 23 additions & 9 deletions test/e2e/pageobjects/create_paste_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,54 @@
from test.e2e.env_config import BASE_URL
from test.e2e.pageobjects.base_page import BasePage
import logging
import string

log = logging.getLogger(__name__)


class CreatePastePage(BasePage):
def __init__(self, page: Page) -> None:
super().__init__(
page.locator(".file-part textarea"), "Create Paste Page"
page, page.locator(".file-part textarea"), "Create Paste Page"
)
self.page = page
self.url = BASE_URL
self.paste_input = page.locator(".file-part textarea")
self.submit_button = page.locator(".paste-submit button[type=submit]")
self.add_another_paste_button = page.locator("button.add")

def open(self):
log.info(f"Opening Pinnwand at {self.url}")
self.page.goto(self.url)

def type_paste(self, text):
def type_paste(self, text, paste_number=0):
log.info(f"Typing {text} in Paste Input")
self.paste_input.type(text)
self.paste_input.nth(paste_number).type(text)

def click_submit(self):
log.info("Clicking Submit Button")
self.submit_button.click()

def click_add_another_file_button(self):
log.info("Clicking Add Another Paste Button")
self.add_another_paste_button.click()

# Step sequences
def paste_random_text(self, paste_number=0):
paste_text = string.ascii_letters + string.digits
self.type_paste(paste_text, paste_number)
self.should_have_value_in_paste_input(paste_text, paste_number)
return paste_text

# Expectations
def should_have_title(self, title):
def should_have_value_in_paste_input(self, value, paste_number=0):
expect(
self.page, f"{self.page_name} had incorrect title"
).to_have_title(title)
self.paste_input.nth(paste_number),
f"Paste Input had incorrect value on {self.page_name}",
).to_have_value(value)

def should_have_value_in_paste_input(self, value):
def should_have_no_value_in_paste_input(self):
expect(
self.paste_input,
f"Paste Input had incorrect value on {self.page_name}",
).to_have_value(value)
f"Paste Input was not empty on {self.page_name}",
).to_be_empty()
22 changes: 22 additions & 0 deletions test/e2e/pageobjects/error_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from test.e2e.pageobjects.base_page import BasePage
from playwright.sync_api import Page, expect
import logging


class ErrorPage(BasePage):
def __init__(self, page: Page) -> None:
super().__init__(page, page.locator("article"), "Error Page")
self.error_code = self.page_locator.locator("h1")
self.error_description = self.page_locator.locator("p")
self.page = page

# Expectations
def should_have_error_text(self, code, description):
expect(
self.error_code,
f"Error code displayed on {self.page_name} was incorrect",
).to_have_text(code)
expect(
self.error_description,
f"Error description displayed on {self.page_name} was incorrect",
).to_have_text(description)
11 changes: 8 additions & 3 deletions test/e2e/pageobjects/view_paste_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@

class ViewPastePage(BasePage):
def __init__(self, page: Page) -> None:
super().__init__(page.locator(".files"), "View Paste Page")
super().__init__(page, page.locator(".files"), "View Paste Page")
self.page = page
self.source = page.locator(".source")

def click_remove_now_button(self):
log.info("Clicking Remove Now Button")
self.page.get_by_role("link", name="Remove now").click()

# Expectations
def should_have_pasted_text(self, text):
def should_have_pasted_text(self, text, paste_number=0):
expect(
self.source, f"Pasted text was incorrect on {self.page_name}"
self.source.nth(paste_number),
f"Pasted text was incorrect on {self.page_name}",
).to_have_text(text)
16 changes: 16 additions & 0 deletions test/e2e/playwright/browser_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from playwright.sync_api import Page, Playwright
import logging
from test.e2e.env_config import is_headless

log = logging.getLogger(__name__)


class BrowserManager:
def __init__(self, playwright: Playwright) -> None:
self.playwright = playwright

def create_new_context(self) -> Page:
log.info("creating new browser context")
browser = self.playwright.chromium.launch(headless=is_headless())
context = browser.new_context()
return context.new_page()
55 changes: 43 additions & 12 deletions test/e2e/testscenarios/test_create_paste.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
from playwright.sync_api import Page
import string
from playwright.sync_api import Page, Playwright
import pytest
from test.e2e.pageobjects.create_paste_page import CreatePastePage
from test.e2e.pageobjects.view_paste_page import ViewPastePage
import pytest
from test.e2e.env_config import application
from test.e2e.playwright.browser_manager import BrowserManager
from test.e2e.conftest import create_paste_page


@pytest.mark.e2e
def test_create_paste(page: Page):
create_paste_page = CreatePastePage(page)
create_paste_page.open()
create_paste_page.should_be_opened()
def test_create_single_paste(
page: Page, playwright: Playwright, create_paste_page: CreatePastePage
):
create_paste_page.should_have_title("Create new paste")

paste_text = string.ascii_letters + string.digits
create_paste_page.type_paste(paste_text)
create_paste_page.should_have_value_in_paste_input(paste_text)
pasted_text = create_paste_page.paste_random_text()
create_paste_page.click_submit()

view_paste_page = ViewPastePage(page)
view_paste_page.should_be_opened()
view_paste_page.should_have_pasted_text(pasted_text)

paste_url = view_paste_page.current_url()
reopen_created_paste(playwright, paste_url)


@pytest.mark.e2e
def test_create_multi_paste(
page: Page, playwright: Playwright, create_paste_page: CreatePastePage
):
first_pasted_text = create_paste_page.paste_random_text(paste_number=0)
create_paste_page.click_add_another_file_button()

second_pasted_text = create_paste_page.paste_random_text(paste_number=1)
create_paste_page.click_add_another_file_button()

third_pasted_text = create_paste_page.paste_random_text(paste_number=2)

create_paste_page.click_submit()

view_paste_page = ViewPastePage(page)
view_paste_page.should_be_opened()
view_paste_page.should_have_pasted_text(paste_text)
view_paste_page.should_have_pasted_text(first_pasted_text, paste_number=0)
view_paste_page.should_have_pasted_text(second_pasted_text, paste_number=1)
view_paste_page.should_have_pasted_text(third_pasted_text, paste_number=2)

paste_url = view_paste_page.current_url()
reopen_created_paste(playwright, paste_url)


def reopen_created_paste(playwright, paste_url):
new_page = BrowserManager(playwright).create_new_context()
new_view_paste_page = ViewPastePage(new_page)
new_view_paste_page.open(paste_url)
new_view_paste_page.should_be_opened()
26 changes: 26 additions & 0 deletions test/e2e/testscenarios/test_delete_paste.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from playwright.sync_api import Page, Playwright
import pytest
from test.e2e.pageobjects.create_paste_page import CreatePastePage
from test.e2e.pageobjects.view_paste_page import ViewPastePage
from test.e2e.pageobjects.error_page import ErrorPage
from test.e2e.conftest import create_paste_page


@pytest.mark.e2e
def test_delete_single_paste(
page: Page, playwright: Playwright, create_paste_page: CreatePastePage
):
create_paste_page.paste_random_text()
create_paste_page.click_submit()

view_paste_page = ViewPastePage(page)
paste_url = view_paste_page.current_url()
view_paste_page.click_remove_now_button()
create_paste_page.should_be_opened()
create_paste_page.should_have_no_value_in_paste_input()

error_page = ErrorPage(page)
error_page.open(paste_url)
error_page.should_be_opened()
error_page.should_have_title("error")
error_page.should_have_error_text("404", "That page does not exist")
Loading