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
15 changes: 15 additions & 0 deletions integration_tests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
PYTEST:=./venv/bin/pytest
PIP:=./venv/bin/pip

.PHONY: clean
clean:
rm -rf ./venv

.PHONY: venv
venv: clean
python3.11 -m venv venv
$(PIP) install -r requirements.txt

.PHONY: test
test:
$(PYTEST)
28 changes: 28 additions & 0 deletions integration_tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Elekto integration tests
This directory contains the integration tests for Elekto. These test focus on the integration with Github and the way
Github usernames flow through the Elekto application.

## Running tests
The setup is not bootstrapped (yet), so various manual steps are required to run the required local infra. Then the
integration tests can be run.

### Infra
These tests require the following to be running:
- elekto
- Change the Github endpoints in `elekto/constants.py` to:
- GITHUB_AUTHORIZE = 'http://localhost:9000/login/oauth/authorize'
- GITHUB_ACCESS = 'http://localhost:9000/login/oauth/access_token'
- GITHUB_PROFILE = 'http://localhost:9000/user'
- Start with `python console --run` (in the Elekto project).
- Optionally also do `docker compose up` if you want to use the Postgres database it provides.
- github-static-mock
- https://github.com/oduludo/github-oauth-mock
- Start the required Redis server with `docker compose up` in the github-oauth-mock project.
- Install dependencies with `poetry install`.
- Start the mock server with `poetry run start`.

### Tests
Tests can be run from the `elekto/integration_tests` directory. Tests runner is Pytest, headless browser testing is done
using Playwright. A virtual environment is required to run the tests. Tests assume all infra runs at the default ports.
- Create the virtual env with `make venv`. This will also install dependencies.
- Run tests with `make test`.
28 changes: 28 additions & 0 deletions integration_tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
attrs==25.4.0
certifi==2025.10.5
charset-normalizer==3.4.3
greenlet==3.2.4
h11==0.16.0
idna==3.10
iniconfig==2.1.0
outcome==1.3.0.post0
packaging==25.0
playwright==1.55.0
pluggy==1.6.0
pyee==13.0.0
Pygments==2.19.2
PySocks==1.7.1
pytest==8.4.2
pytest-base-url==2.1.0
pytest-playwright==0.7.1
python-slugify==8.0.4
requests==2.32.5
sniffio==1.3.1
sortedcontainers==2.4.0
text-unidecode==1.3
trio==0.31.0
trio-websocket==0.12.2
typing_extensions==4.15.0
urllib3==2.5.0
websocket-client==1.9.0
wsproto==1.2.0
33 changes: 33 additions & 0 deletions integration_tests/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pytest

from utils.github_mock.client import GithubMockUtilityClient


@pytest.fixture
def host() -> str:
return 'http://localhost:8000'


@pytest.fixture
def login_url(host: str) -> str:
return f'{host}/login'


@pytest.fixture
def logout_url(host: str) -> str:
return f'{host}/logout'


@pytest.fixture
def app_url(host: str) -> str:
return f'{host}/app'


@pytest.fixture
def github_mock_host() -> str:
return 'http://localhost:9000'


@pytest.fixture
def github_mock_utility(github_mock_host: str) -> GithubMockUtilityClient:
return GithubMockUtilityClient(host=github_mock_host)
38 changes: 38 additions & 0 deletions integration_tests/tests/test_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest
from playwright.sync_api import Page, expect

from utils.github_mock import GithubMockUtilityClient, User


def logout(page: Page) -> None:
page.goto('http://localhost:8000/app')
logout_link = page.get_by_role('link', name='Logout')
if logout_link.is_visible():
logout_link.click()


@pytest.mark.parametrize(
'user',
[
User(name='Jack', login='jack'),
User(name='Jill', login='jill'),
]
)
def test_login(page: Page, login_url: str, logout_url: str, github_mock_utility: GithubMockUtilityClient, user: User) -> None:
"""
Test that login is working as expected.

Multiple users should be able to log in and the dashboard should change content based on the authenticated user.
"""
logout(page) # Ensure we start with fresh state

github_mock_utility.store_upcoming_user(user=user)

page.goto(login_url)

expect(page.get_by_text('Sign in with Github')).to_be_visible()

page.get_by_role('button', name='Sign in with Github').click()
expect(page).to_have_title('Dashboard | Elekto')
expect(page.get_by_text(f'Welcome! {user.name}')).to_be_visible()
logout(page)
Empty file.
4 changes: 4 additions & 0 deletions integration_tests/tests/utils/github_mock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .client import GithubMockUtilityClient
from .models import User

__all__ = ['GithubMockUtilityClient', 'User']
28 changes: 28 additions & 0 deletions integration_tests/tests/utils/github_mock/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import requests

from .models import User


class GithubMockUtilityClient:
def __init__(self, host: str):
self.host = host

def store_upcoming_user(self, user: User) -> None:
"""
Set user data for the next mocked Github login.

IRL users would log in at Github and then return to Elekto with a code. Elekto uses the code to get data for
that authenticated user. Our tests mock the Github part, causing the code to not point to a particular user. To
make up for this, we can set fake user data in the mock server. The next user lookup populates the 'name' and
'login' fields with the fake data we sent in using the /system/upcoming-user call.

Args:
user: The User object to set mock data from.

Returns: None

"""
resp = requests.post(f'{self.host}/system/upcoming-user', json=user.to_dict())

if resp.status_code != 201:
raise Exception(resp.text)
10 changes: 10 additions & 0 deletions integration_tests/tests/utils/github_mock/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class User:
def __init__(self, name: str, login: str):
self.name = name
self.login = login

def to_dict(self) -> dict:
return {
'login': self.login,
'name': self.name,
}