"""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