Files
Reklamator/tests/integration/test_dashboard_access_flow.py
T

248 lines
8.7 KiB
Python
Raw Normal View History

"""Integration test for complete dashboard access flow"""
import pytest
import os
import yaml
from app.models.user import User
@pytest.fixture
def test_product_with_feedback(app):
"""Create a test product with multiple feedback items"""
with app.app_context():
# Create test product directory and config
product_dir = os.path.join(app.config['DATA_DIR'], 'products', 'dashboard-test-product')
os.makedirs(product_dir, exist_ok=True)
# Create product config
config_file = os.path.join(product_dir, 'config.yaml')
config_data = {
'product_id': 'dashboard-test-product',
'name': 'Dashboard Test Product',
'submission_url_slug': 'dashboard-test-product',
'owner_language': 'en',
'assigned_owner_ids': ['usr_dashboard_owner'],
'status': 'active'
}
with open(config_file, 'w') as f:
yaml.dump(config_data, f)
# Create feedback directory
feedback_dir = os.path.join(product_dir, 'feedback')
os.makedirs(feedback_dir, exist_ok=True)
# Create multiple test feedback items
feedback_items = [
{
'id': 'feedback-bug-001',
'category': 'bug',
'status': 'new',
'content': 'Found a critical bug in the login system',
'has_attachments': True,
'attachment': 'bug-screenshot.png'
},
{
'id': 'feedback-feature-001',
'category': 'feature_request',
'status': 'new',
'content': 'Please add dark mode to the application',
'has_attachments': False,
'attachment': None
},
{
'id': 'feedback-bug-002',
'category': 'bug',
'status': 'in_progress',
'content': 'Error when uploading large files',
'has_attachments': True,
'attachment': 'error.log'
}
]
for item in feedback_items:
feedback_path = os.path.join(feedback_dir, item['id'])
os.makedirs(feedback_path, exist_ok=True)
# Create metadata
metadata = {
'feedback_id': item['id'],
'product_id': 'dashboard-test-product',
'status': item['status'],
'submitted_at': '2025-10-16T10:00:00Z',
'has_attachments': item['has_attachments'],
'attachment_count': 1 if item['has_attachments'] else 0,
'category': item['category'],
'original_language': 'en'
}
with open(os.path.join(feedback_path, 'metadata.yaml'), 'w') as f:
yaml.dump(metadata, f)
# Create content
with open(os.path.join(feedback_path, 'content.txt'), 'w') as f:
f.write(item['content'])
# Create attachment if needed
if item['has_attachments']:
attachments_dir = os.path.join(feedback_path, 'attachments')
os.makedirs(attachments_dir, exist_ok=True)
with open(os.path.join(attachments_dir, item['attachment']), 'w') as f:
f.write(f'Attachment content for {item["id"]}')
yield {
'product_id': 'dashboard-test-product',
'feedback_items': feedback_items
}
@pytest.fixture
def dashboard_test_users(app):
"""Create test users for dashboard testing"""
users_file = os.path.join(app.config['DATA_DIR'], 'users.yaml')
# User model expects format: {'users': {user_id: user_data}}
users_data = {
'users': {
'usr_dashboard_owner': {
'user_id': 'usr_dashboard_owner',
'username': 'dashboard_owner',
'email': 'dashboard@example.com',
'password_hash': User.hash_password('dashboard123'),
'role': 'product_owner',
'product_ids': ['dashboard-test-product'],
'is_active': True
}
}
}
with open(users_file, 'w') as f:
yaml.dump(users_data, f)
yield users_data
@pytest.mark.integration
def test_complete_dashboard_access_flow(client, app, test_product_with_feedback, dashboard_test_users):
"""T105: Integration test for complete dashboard access flow
Test the entire product owner journey:
1. Owner logs in with credentials
2. Owner views dashboard with feedback list
3. Owner filters feedback by category
4. Owner searches for specific feedback
5. Owner views feedback detail
6. Owner downloads attachment
7. Owner updates feedback status
8. Owner logs out
"""
# Step 1: Login as product owner
login_response = client.post('/login', data={
'username': 'dashboard_owner',
'password': 'dashboard123'
}, follow_redirects=False)
assert login_response.status_code == 302 # Redirect after successful login
# Step 2: View dashboard with feedback list
dashboard_response = client.get('/dashboard')
assert dashboard_response.status_code == 200
assert b'feedback' in dashboard_response.data.lower() or b'dashboard' in dashboard_response.data.lower()
# Verify feedback items are shown
# (At least should show some feedback indicators)
# Step 3: Filter feedback by category (bug)
filter_response = client.get('/dashboard?category=bug')
assert filter_response.status_code == 200
# Step 4: Search for specific feedback
search_response = client.get('/dashboard?search=login')
assert search_response.status_code == 200
# Step 5: View feedback detail
feedback_id = test_product_with_feedback['feedback_items'][0]['id']
detail_response = client.get(f'/feedback/{feedback_id}')
assert detail_response.status_code == 200
# Should show the feedback content
assert b'Found a critical bug in the login system' in detail_response.data or b'feedback' in detail_response.data.lower()
# Step 6: Download attachment
attachment_response = client.get(f'/feedback/{feedback_id}/attachment/bug-screenshot.png')
assert attachment_response.status_code == 200
assert b'Attachment content' in attachment_response.data
# Should have download headers
assert 'Content-Disposition' in attachment_response.headers or 'content-disposition' in attachment_response.headers
# Step 7: Update feedback status
status_update_response = client.post(f'/feedback/{feedback_id}/status', data={
'status': 'in_progress'
}, follow_redirects=False)
assert status_update_response.status_code in [200, 302]
# Verify status was updated in filesystem
with app.app_context():
data_dir = app.config['DATA_DIR']
metadata_file = os.path.join(
data_dir,
'products',
'dashboard-test-product',
'feedback',
feedback_id,
'metadata.yaml'
)
with open(metadata_file, 'r') as f:
metadata = yaml.safe_load(f)
assert metadata['status'] == 'in_progress'
# Step 8: Logout
logout_response = client.get('/logout', follow_redirects=False)
assert logout_response.status_code == 302
# Verify user is logged out (accessing dashboard should redirect to login)
protected_response = client.get('/dashboard', follow_redirects=False)
assert protected_response.status_code == 302
assert '/login' in protected_response.location
@pytest.mark.integration
def test_dashboard_access_control_enforcement(client, app, test_product_with_feedback, dashboard_test_users):
"""Integration test for access control - owner can only see assigned products"""
# Create another product owner with different product access
users_file = os.path.join(app.config['DATA_DIR'], 'users.yaml')
with open(users_file, 'r') as f:
users_data = yaml.safe_load(f)
# Add new user to the users dict
users_data['users']['usr_other_owner'] = {
'user_id': 'usr_other_owner',
'username': 'other_owner',
'email': 'other@example.com',
'password_hash': User.hash_password('other123'),
'role': 'product_owner',
'product_ids': ['different-product'],
'is_active': True
}
with open(users_file, 'w') as f:
yaml.dump(users_data, f)
# Login as owner without access to dashboard-test-product
client.post('/login', data={
'username': 'other_owner',
'password': 'other123'
})
# Try to access feedback from product they don't own
feedback_id = test_product_with_feedback['feedback_items'][0]['id']
response = client.get(f'/feedback/{feedback_id}')
# Should be denied access (403 Forbidden)
assert response.status_code == 403