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

7 screen play #5

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
File renamed without changes.
Empty file.
23 changes: 23 additions & 0 deletions interactions/duckduckgo/pages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
This module contains DuckDuckGo pages.
"""

from playwright.sync_api import Page


class SearchPage:

URL = 'https://www.duckduckgo.com'

def __init__(self, page: Page) -> None:
self.page = page
self.search_button = page.locator('#search_button_homepage')
self.search_input = page.locator('#search_form_input_homepage')


class ResultPage:
def __init__(self, page: Page) -> None:
self.page = page
self.result_links = page.locator('a[data-testid="result-title-a"]')
self.search_input = page.locator('#search_form_input')

35 changes: 35 additions & 0 deletions interactions/duckduckgo/questions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
This module contains DuckDuckGo Questions.
"""

from abc import ABC, abstractmethod
from interactions.duckduckgo.pages import ResultPage
from playwright.sync_api import Page
from screenplay.pattern import Actor, Question, Answer


# ------------------------------------------------------------
# DuckDuckGo Question parent class
# ------------------------------------------------------------

class DuckDuckGoQuestion(Question[Answer], ABC):

@abstractmethod
def request_on_page(self, actor: Actor, page: Page) -> Answer:
pass

def request_as(self, actor: Actor) -> Answer:
page: Page = actor.using('page')
return self.request_on_page(actor, page)


# ------------------------------------------------------------
# DuckDuckGo Questions
# ------------------------------------------------------------

class result_link_titles(DuckDuckGoQuestion[list[str]]):

def request_on_page(self, _, page: Page) -> list[str]:
result_page = ResultPage(page)
result_page.result_links.nth(4).wait_for()
return result_page.result_links.all_text_contents()
80 changes: 80 additions & 0 deletions interactions/duckduckgo/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
This module contains DuckDuckGo Tasks.
"""

from abc import ABC, abstractmethod
from interactions.duckduckgo.pages import ResultPage, SearchPage
from interactions.duckduckgo.questions import result_link_titles
from playwright.sync_api import Page, expect
from screenplay.pattern import Actor, Task


# ------------------------------------------------------------
# DuckDuckGo Task parent class
# ------------------------------------------------------------

class DuckDuckGoTask(Task, ABC):

@abstractmethod
def perform_on_page(self, actor: Actor, page: Page) -> None:
pass

def perform_as(self, actor: Actor) -> None:
page: Page = actor.using('page')
self.perform_on_page(actor, page)


# ------------------------------------------------------------
# DuckDuckGo Tasks
# ------------------------------------------------------------

class load_duckduckgo(DuckDuckGoTask):

def perform_on_page(self, _, page: Page) -> None:
page.goto(SearchPage.URL)


class search_duckduckgo_for(DuckDuckGoTask):

def __init__(self, phrase: str) -> None:
super().__init__()
self.phrase = phrase

def perform_on_page(self, _, page: Page) -> None:
search_page = SearchPage(page)
search_page.search_input.fill(self.phrase)
search_page.search_button.click()


class verify_page_title_is(DuckDuckGoTask):

def __init__(self, title: str) -> None:
super().__init__()
self.title = title

def perform_on_page(self, _, page: Page) -> None:
expect(page).to_have_title(self.title)


class verify_result_link_titles_contain(Task):

def __init__(self, phrase: str, minimum: int = 1) -> None:
super().__init__()
self.phrase = phrase
self.minimum = minimum

def perform_as(self, actor: Actor) -> None:
titles = actor.asks_for(result_link_titles())
matches = [t for t in titles if self.phrase.lower() in t.lower()]
assert len(matches) >= self.minimum


class verify_search_result_query_is(DuckDuckGoTask):

def __init__(self, phrase: str) -> None:
super().__init__()
self.phrase = phrase

def perform_on_page(self, _, page: Page) -> None:
result_page = ResultPage(page)
expect(result_page.search_input).to_have_value(self.phrase)
Empty file added interactions/github/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions interactions/github/calls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
This module contains REST API calls for GitHub Projects.
"""

from abc import ABC, abstractmethod
from playwright.sync_api import APIRequestContext, APIResponse, expect
from screenplay.pattern import Actor, Question


# ------------------------------------------------------------
# GitHub Project Call parent class
# ------------------------------------------------------------

class GitHubProjectCall(Question[APIResponse], ABC):

@abstractmethod
def call_as(self, actor: Actor, context: APIRequestContext) -> APIResponse:
pass

def request_as(self, actor: Actor) -> APIResponse:
context: APIRequestContext = actor.using('gh_context')
return self.call_as(actor, context)


# ------------------------------------------------------------
# GitHub Project Calls
# ------------------------------------------------------------

class create_card(GitHubProjectCall):

def __init__(self, column_id: str, note: str | None = None) -> None:
self.column_id = column_id
self.note = note

def call_as(self, actor: Actor, context: APIRequestContext) -> APIResponse:
response = context.post(
f'/projects/columns/{self.column_id}/cards',
data={'note': self.note})
expect(response).to_be_ok()
assert response.json()['note'] == self.note
return response


class retrieve_card(GitHubProjectCall):

def __init__(self, card_id: str) -> None:
self.card_id = card_id

def call_as(self, actor: Actor, context: APIRequestContext) -> APIResponse:
response = context.get(f'/projects/columns/cards/{self.card_id}')
expect(response).to_be_ok()
return response
70 changes: 70 additions & 0 deletions interactions/github/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
This module contains GitHub Project Tasks.
"""

from abc import ABC, abstractmethod
from playwright.sync_api import Page, expect
from screenplay.pattern import Actor, Task


# ------------------------------------------------------------
# GitHub Project Task parent class
# ------------------------------------------------------------

class GitHubProjectTask(Task, ABC):

@abstractmethod
def perform_on_page(self, actor: Actor, page: Page) -> None:
pass

def perform_as(self, actor: Actor) -> None:
page: Page = actor.using('page')
self.perform_on_page(actor, page)


# ------------------------------------------------------------
# GitHub Project Tasks
# ------------------------------------------------------------

class log_into_github_as(GitHubProjectTask):

def __init__(self, username: str, password: str) -> None:
self.username = username
self.password = password

def perform_on_page(self, actor: Actor, page: Page) -> None:
page.goto(f'https://github.com/login')
page.locator('id=login_field').fill(self.username)
page.locator('id=password').fill(self.password)
page.locator('input[name="commit"]').click()


class load_github_project_for(GitHubProjectTask):

def __init__(self, username: str, project_number: str) -> None:
self.username = username
self.project_number = project_number

def perform_on_page(self, actor: Actor, page: Page) -> None:
page.goto(f'https://github.com/users/{self.username}/projects/{self.project_number}')


class verify_card_appears_with(GitHubProjectTask):

def __init__(self, column_id: str, note: str) -> None:
self.column_id = column_id
self.note = note

def perform_on_page(self, actor: Actor, page: Page) -> None:
card_xpath = f'//div[@id="column-cards-{self.column_id}"]//p[contains(text(), "{self.note}")]'
expect(page.locator(card_xpath)).to_be_visible()


class move_card_to(GitHubProjectTask):

def __init__(self, column_id: str, note: str) -> None:
self.column_id = column_id
self.note = note

def perform_on_page(self, actor: Actor, page: Page) -> None:
page.drag_and_drop(f'text="{self.note}"', f'id=column-cards-{self.column_id}')
24 changes: 0 additions & 24 deletions pages/result.py

This file was deleted.

23 changes: 0 additions & 23 deletions pages/search.py

This file was deleted.

16 changes: 9 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@
import os
import pytest

from pages.result import DuckDuckGoResultPage
from pages.search import DuckDuckGoSearchPage
from playwright.sync_api import Playwright, APIRequestContext, Page, expect
from screenplay.pattern import Actor
from typing import Generator


# ------------------------------------------------------------
# DuckDuckGo search fixtures
# Screenplay fixtures
# ------------------------------------------------------------

@pytest.fixture
def result_page(page: Page) -> DuckDuckGoResultPage:
return DuckDuckGoResultPage(page)
def actor(page: Page) -> Actor:
actor = Actor()
actor.can_use(page=page)
return actor


@pytest.fixture
def search_page(page: Page) -> DuckDuckGoSearchPage:
return DuckDuckGoSearchPage(page)
def gh_actor(actor: Actor, gh_context: APIRequestContext) -> Actor:
actor.can_use(gh_context=gh_context)
return actor


# ------------------------------------------------------------
Expand Down
Loading