Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
- pytest framework with fixtures for auth (auth_client, admin_client) - Unit tests for SearchService - Integration tests for auth flow - Security tests (OWASP Top 10: SQL injection, XSS, CSRF) - Smoke tests for production health and backup monitoring - E2E tests with Playwright (basic structure) - DR tests for backup/restore procedures - GitHub Actions CI/CD workflow (.github/workflows/test.yml) - Coverage configuration (.coveragerc) with 80% minimum - DR documentation and restore script Staging environment: VM 248, staging.nordabiznes.pl Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
160 lines
5.3 KiB
Python
160 lines
5.3 KiB
Python
"""
|
|
E2E tests for login flow using Playwright
|
|
==========================================
|
|
|
|
These tests run in a real browser and test the complete user flow.
|
|
|
|
Requirements:
|
|
pip install playwright pytest-playwright
|
|
playwright install chromium
|
|
|
|
Usage:
|
|
pytest tests/e2e/ --base-url=https://staging.nordabiznes.pl
|
|
"""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
# Skip all tests if playwright not installed
|
|
pytest.importorskip("playwright")
|
|
|
|
from playwright.sync_api import Page, expect
|
|
|
|
pytestmark = pytest.mark.e2e
|
|
|
|
# Test credentials
|
|
TEST_USER_EMAIL = 'test@nordabiznes.pl'
|
|
TEST_USER_PASSWORD = '&Rc2LdbSw&jiGR0ek@Bz'
|
|
TEST_ADMIN_EMAIL = 'testadmin@nordabiznes.pl'
|
|
TEST_ADMIN_PASSWORD = 'cSfQbbwegwv1v3Q2Dm0Q'
|
|
|
|
# Base URL (override with --base-url or environment variable)
|
|
BASE_URL = os.environ.get('BASE_URL', 'https://staging.nordabiznes.pl')
|
|
|
|
|
|
@pytest.fixture
|
|
def base_url():
|
|
"""Get base URL for tests."""
|
|
return BASE_URL
|
|
|
|
|
|
class TestLoginFlow:
|
|
"""Tests for login user flow."""
|
|
|
|
def test_login_page_loads(self, page: Page, base_url):
|
|
"""Login page should load correctly."""
|
|
page.goto(f'{base_url}/auth/login')
|
|
|
|
# Should have login form
|
|
expect(page.locator('input[name="email"]')).to_be_visible()
|
|
expect(page.locator('input[name="password"]')).to_be_visible()
|
|
expect(page.locator('button[type="submit"]')).to_be_visible()
|
|
|
|
def test_user_can_login(self, page: Page, base_url):
|
|
"""User should be able to log in with valid credentials."""
|
|
page.goto(f'{base_url}/auth/login')
|
|
|
|
# Fill login form
|
|
page.fill('input[name="email"]', TEST_USER_EMAIL)
|
|
page.fill('input[name="password"]', TEST_USER_PASSWORD)
|
|
page.click('button[type="submit"]')
|
|
|
|
# Should redirect to dashboard
|
|
page.wait_for_url('**/dashboard**', timeout=10000)
|
|
expect(page).to_have_url(f'{base_url}/dashboard')
|
|
|
|
def test_invalid_login_shows_error(self, page: Page, base_url):
|
|
"""Invalid credentials should show error message."""
|
|
page.goto(f'{base_url}/auth/login')
|
|
|
|
page.fill('input[name="email"]', 'wrong@test.pl')
|
|
page.fill('input[name="password"]', 'wrongpassword')
|
|
page.click('button[type="submit"]')
|
|
|
|
# Should stay on login page with error
|
|
page.wait_for_timeout(2000)
|
|
expect(page).to_have_url(f'{base_url}/auth/login')
|
|
|
|
def test_user_can_logout(self, page: Page, base_url):
|
|
"""User should be able to log out."""
|
|
# First login
|
|
page.goto(f'{base_url}/auth/login')
|
|
page.fill('input[name="email"]', TEST_USER_EMAIL)
|
|
page.fill('input[name="password"]', TEST_USER_PASSWORD)
|
|
page.click('button[type="submit"]')
|
|
page.wait_for_url('**/dashboard**', timeout=10000)
|
|
|
|
# Then logout
|
|
page.click('text=Wyloguj') # or find logout button/link
|
|
|
|
# Should redirect to home or login
|
|
page.wait_for_timeout(2000)
|
|
|
|
|
|
@pytest.fixture
|
|
def logged_in_page(page: Page, base_url):
|
|
"""Fixture that provides a page with logged in user."""
|
|
page.goto(f'{base_url}/auth/login')
|
|
page.fill('input[name="email"]', TEST_USER_EMAIL)
|
|
page.fill('input[name="password"]', TEST_USER_PASSWORD)
|
|
page.click('button[type="submit"]')
|
|
page.wait_for_url('**/dashboard**', timeout=10000)
|
|
return page
|
|
|
|
|
|
class TestDashboard:
|
|
"""Tests for dashboard functionality."""
|
|
|
|
def test_dashboard_shows_user_info(self, logged_in_page: Page):
|
|
"""Dashboard should show user information."""
|
|
expect(logged_in_page.locator('body')).to_contain_text('Witaj')
|
|
|
|
def test_dashboard_has_navigation(self, logged_in_page: Page):
|
|
"""Dashboard should have navigation menu."""
|
|
expect(logged_in_page.locator('nav')).to_be_visible()
|
|
|
|
|
|
class TestCompanyCatalog:
|
|
"""Tests for company catalog browsing."""
|
|
|
|
def test_catalog_shows_companies(self, page: Page, base_url):
|
|
"""Catalog should show list of companies."""
|
|
page.goto(f'{base_url}/companies')
|
|
|
|
# Should have company cards/list
|
|
page.wait_for_selector('.company-card, .company-item, [data-company]', timeout=10000)
|
|
|
|
def test_company_detail_accessible(self, page: Page, base_url):
|
|
"""Company detail page should be accessible."""
|
|
page.goto(f'{base_url}/companies')
|
|
|
|
# Click first company
|
|
page.locator('.company-card, .company-item, [data-company]').first.click()
|
|
|
|
# Should navigate to detail page
|
|
page.wait_for_url('**/company/**', timeout=10000)
|
|
|
|
|
|
class TestChat:
|
|
"""Tests for NordaGPT chat functionality."""
|
|
|
|
def test_chat_responds_to_question(self, logged_in_page: Page, base_url):
|
|
"""Chat should respond to user questions."""
|
|
logged_in_page.goto(f'{base_url}/chat')
|
|
|
|
# Find chat input
|
|
chat_input = logged_in_page.locator('#chat-input, input[name="message"], textarea')
|
|
expect(chat_input).to_be_visible()
|
|
|
|
# Send a question
|
|
chat_input.fill('Kto w Izbie zajmuje się IT?')
|
|
logged_in_page.click('#send-button, button[type="submit"]')
|
|
|
|
# Wait for response
|
|
logged_in_page.wait_for_selector('.chat-response, .message-ai, [data-role="assistant"]', timeout=30000)
|
|
|
|
# Response should contain something
|
|
response = logged_in_page.locator('.chat-response, .message-ai, [data-role="assistant"]').last
|
|
expect(response).to_be_visible()
|