import pytest import asyncio from playwright.async_api import expect from datetime import datetime, date from mywebdav.billing.models import UsageAggregate, Invoice from mywebdav.models import User @pytest.mark.asyncio class TestBillingIntegrationFlow: async def test_01_complete_user_journey(self, page, base_url): await page.goto(f"{base_url}/") await page.wait_for_load_state("networkidle") await page.fill('input[name="username"]', 'testuser') await page.fill('input[name="password"]', 'testpassword123') await page.click('button[type="submit"]') await page.wait_for_load_state("networkidle") await page.click('text=Files') await page.wait_for_load_state("networkidle") await page.wait_for_timeout(1000) await page.click('text=Billing') await page.wait_for_load_state("networkidle") await expect(page.locator('.billing-dashboard')).to_be_visible() await page.wait_for_timeout(2000) async def test_02_verify_usage_tracking_after_operations(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") initial_storage = await page.locator('.usage-value').first.text_content() await page.goto(f"{base_url}/files") await page.wait_for_load_state("networkidle") await page.wait_for_timeout(1000) await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") current_storage = await page.locator('.usage-value').first.text_content() assert current_storage is not None async def test_03_verify_cost_calculation_updates(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.estimated-cost')).to_be_visible() cost_text = await page.locator('.estimated-cost').text_content() assert '$' in cost_text await page.reload() await page.wait_for_load_state("networkidle") new_cost_text = await page.locator('.estimated-cost').text_content() assert '$' in new_cost_text async def test_04_verify_subscription_consistency(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") subscription_badge = page.locator('.subscription-badge') await expect(subscription_badge).to_be_visible() badge_classes = await subscription_badge.get_attribute('class') assert 'active' in badge_classes or 'inactive' in badge_classes async def test_05_verify_pricing_consistency_across_pages(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") storage_price_user = await page.locator('.pricing-item:has-text("Storage")').last.text_content() await page.goto(f"{base_url}/admin/billing") await page.wait_for_load_state("networkidle") config_value = await page.locator('.pricing-table tbody tr').first.locator('.config-value').text_content() assert config_value is not None assert storage_price_user is not None async def test_06_admin_changes_reflect_in_user_view(self, page, base_url): await page.goto(f"{base_url}/admin/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.pricing-table')).to_be_visible() await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.pricing-card')).to_be_visible() async def test_07_navigation_flow_consistency(self, page, base_url): await page.goto(f"{base_url}/") await page.wait_for_load_state("networkidle") await page.click('text=Billing') await page.wait_for_url("**/billing") await page.click('text=Dashboard') await page.wait_for_url("**/dashboard") await page.click('text=Billing') await page.wait_for_url("**/billing") await expect(page.locator('.billing-dashboard')).to_be_visible() async def test_08_refresh_maintains_state(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") usage_before = await page.locator('.usage-value').first.text_content() await page.reload() await page.wait_for_load_state("networkidle") usage_after = await page.locator('.usage-value').first.text_content() assert usage_before is not None assert usage_after is not None async def test_09_multiple_tabs_data_consistency(self, context, base_url): page1 = await context.new_page() page2 = await context.new_page() await page1.goto(f"{base_url}/billing") await page1.wait_for_load_state("networkidle") await page2.goto(f"{base_url}/billing") await page2.wait_for_load_state("networkidle") usage1 = await page1.locator('.usage-value').first.text_content() usage2 = await page2.locator('.usage-value').first.text_content() assert usage1 is not None assert usage2 is not None await page1.close() await page2.close() async def test_10_api_and_ui_data_consistency(self, page, base_url): token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') api_response = await page.request.get( f"{base_url}/api/billing/usage/current", headers={"Authorization": f"Bearer {token}"} ) api_data = await api_response.json() await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.usage-card')).to_be_visible() assert api_data['storage_gb'] >= 0 async def test_11_error_handling_invalid_invoice_id(self, page, base_url): token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') response = await page.request.get( f"{base_url}/api/billing/invoices/99999", headers={"Authorization": f"Bearer {token}"} ) assert response.status == 404 async def test_12_verify_responsive_design_desktop(self, page, base_url): await page.set_viewport_size({"width": 1920, "height": 1080}) await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.billing-cards')).to_be_visible() cards = page.locator('.billing-card') count = await cards.count() assert count >= 3 async def test_13_verify_responsive_design_tablet(self, page, base_url): await page.set_viewport_size({"width": 768, "height": 1024}) await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.billing-dashboard')).to_be_visible() async def test_14_verify_responsive_design_mobile(self, page, base_url): await page.set_viewport_size({"width": 375, "height": 667}) await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.billing-dashboard')).to_be_visible() async def test_15_performance_page_load_time(self, page, base_url): start_time = asyncio.get_event_loop().time() await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") end_time = asyncio.get_event_loop().time() load_time = end_time - start_time assert load_time < 5.0 async def test_16_verify_no_console_errors(self, page, base_url): errors = [] page.on("console", lambda msg: errors.append(msg) if msg.type == "error" else None) await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await page.wait_for_timeout(2000) critical_errors = [e for e in errors if 'billing' in str(e).lower()] assert len(critical_errors) == 0 async def test_17_complete_admin_workflow(self, page, base_url): await page.goto(f"{base_url}/") await page.wait_for_load_state("networkidle") await page.fill('input[name="username"]', 'adminuser') await page.fill('input[name="password"]', 'adminpassword123') await page.click('button[type="submit"]') await page.wait_for_load_state("networkidle") await page.click('text=Admin') await page.wait_for_load_state("networkidle") await page.click('text=Billing') await page.wait_for_load_state("networkidle") await expect(page.locator('.admin-billing')).to_be_visible() await expect(page.locator('.stats-cards')).to_be_visible() await expect(page.locator('.pricing-config-section')).to_be_visible() await expect(page.locator('.invoice-generation-section')).to_be_visible() await page.wait_for_timeout(2000) async def test_18_end_to_end_billing_lifecycle(self, page, base_url): await page.goto(f"{base_url}/billing") await page.wait_for_load_state("networkidle") await expect(page.locator('.billing-dashboard')).to_be_visible() await expect(page.locator('.usage-card')).to_be_visible() await expect(page.locator('.cost-card')).to_be_visible() await expect(page.locator('.pricing-card')).to_be_visible() await expect(page.locator('.invoices-section')).to_be_visible() await expect(page.locator('.payment-methods-section')).to_be_visible() await page.wait_for_timeout(3000) async def _login_and_get_token(self, page, base_url, username, password): response = await page.request.post( f"{base_url}/api/auth/login", data={"username": username, "password": password} ) if response.ok: data = await response.json() return data.get('access_token', '') return ''