265 lines
9.9 KiB
Python
Raw Normal View History

2025-11-10 15:46:40 +01:00
import pytest
import asyncio
from playwright.async_api import expect
from datetime import datetime, date
from rbox.billing.models import UsageAggregate, Invoice
from rbox.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 ''