diff --git a/tests/billing/test_api_endpoints.py b/tests/billing/test_api_endpoints.py index cd4eae8..e5e7405 100644 --- a/tests/billing/test_api_endpoints.py +++ b/tests/billing/test_api_endpoints.py @@ -1,28 +1,15 @@ import pytest +import pytest_asyncio from decimal import Decimal from datetime import date, datetime -from httpx import AsyncClient +from httpx import AsyncClient, ASGITransport from fastapi import status -from tortoise.contrib.test import initializer, finalizer from mywebdav.main import app from mywebdav.models import User from mywebdav.billing.models import PricingConfig, Invoice, UsageAggregate, UserSubscription from mywebdav.auth import create_access_token -@pytest.fixture(scope="module") -def event_loop(): - import asyncio - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - -@pytest.fixture(scope="module", autouse=True) -async def initialize_tests(): - initializer(["mywebdav.models", "mywebdav.billing.models"], db_url="sqlite://:memory:") - yield - await finalizer() - -@pytest.fixture +@pytest_asyncio.fixture async def test_user(): user = await User.create( username="testuser", @@ -34,7 +21,7 @@ async def test_user(): yield user await user.delete() -@pytest.fixture +@pytest_asyncio.fixture async def admin_user(): user = await User.create( username="adminuser", @@ -46,17 +33,17 @@ async def admin_user(): yield user await user.delete() -@pytest.fixture +@pytest_asyncio.fixture async def auth_token(test_user): token = create_access_token(data={"sub": test_user.username}) return token -@pytest.fixture +@pytest_asyncio.fixture async def admin_token(admin_user): token = create_access_token(data={"sub": admin_user.username}) return token -@pytest.fixture +@pytest_asyncio.fixture async def pricing_config(): configs = [] configs.append(await PricingConfig.create( @@ -89,7 +76,7 @@ async def pricing_config(): @pytest.mark.asyncio async def test_get_current_usage(test_user, auth_token): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/billing/usage/current", headers={"Authorization": f"Bearer {auth_token}"} @@ -113,7 +100,7 @@ async def test_get_monthly_usage(test_user, auth_token): bandwidth_down_bytes=1024 ** 3 * 5 ) - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( f"/api/billing/usage/monthly?year={today.year}&month={today.month}", headers={"Authorization": f"Bearer {auth_token}"} @@ -127,7 +114,7 @@ async def test_get_monthly_usage(test_user, auth_token): @pytest.mark.asyncio async def test_get_subscription(test_user, auth_token): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/billing/subscription", headers={"Authorization": f"Bearer {auth_token}"} @@ -153,7 +140,7 @@ async def test_list_invoices(test_user, auth_token): status="open" ) - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/billing/invoices", headers={"Authorization": f"Bearer {auth_token}"} @@ -179,7 +166,7 @@ async def test_get_invoice(test_user, auth_token): status="open" ) - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( f"/api/billing/invoices/{invoice.id}", headers={"Authorization": f"Bearer {auth_token}"} @@ -193,7 +180,7 @@ async def test_get_invoice(test_user, auth_token): @pytest.mark.asyncio async def test_get_pricing(): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get("/api/billing/pricing") assert response.status_code == status.HTTP_200_OK @@ -202,7 +189,7 @@ async def test_get_pricing(): @pytest.mark.asyncio async def test_admin_get_pricing(admin_user, admin_token, pricing_config): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/admin/billing/pricing", headers={"Authorization": f"Bearer {admin_token}"} @@ -216,7 +203,7 @@ async def test_admin_get_pricing(admin_user, admin_token, pricing_config): async def test_admin_update_pricing(admin_user, admin_token, pricing_config): config_id = pricing_config[0].id - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.put( f"/api/admin/billing/pricing/{config_id}", headers={"Authorization": f"Bearer {admin_token}"}, @@ -233,7 +220,7 @@ async def test_admin_update_pricing(admin_user, admin_token, pricing_config): @pytest.mark.asyncio async def test_admin_get_stats(admin_user, admin_token): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/admin/billing/stats", headers={"Authorization": f"Bearer {admin_token}"} @@ -247,7 +234,7 @@ async def test_admin_get_stats(admin_user, admin_token): @pytest.mark.asyncio async def test_non_admin_cannot_access_admin_endpoints(test_user, auth_token): - async with AsyncClient(app=app, base_url="http://test") as client: + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client: response = await client.get( "/api/admin/billing/pricing", headers={"Authorization": f"Bearer {auth_token}"} diff --git a/tests/billing/test_invoice_generator.py b/tests/billing/test_invoice_generator.py index f9c4094..1f52745 100644 --- a/tests/billing/test_invoice_generator.py +++ b/tests/billing/test_invoice_generator.py @@ -1,25 +1,12 @@ import pytest +import pytest_asyncio from decimal import Decimal from datetime import date, datetime -from tortoise.contrib.test import initializer, finalizer from mywebdav.models import User from mywebdav.billing.models import Invoice, InvoiceLineItem, PricingConfig, UsageAggregate, UserSubscription from mywebdav.billing.invoice_generator import InvoiceGenerator -@pytest.fixture(scope="module") -def event_loop(): - import asyncio - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - -@pytest.fixture(scope="module", autouse=True) -async def initialize_tests(): - initializer(["mywebdav.models", "mywebdav.billing.models"], db_url="sqlite://:memory:") - yield - await finalizer() - -@pytest.fixture +@pytest_asyncio.fixture async def test_user(): user = await User.create( username="testuser", @@ -30,7 +17,7 @@ async def test_user(): yield user await user.delete() -@pytest.fixture +@pytest_asyncio.fixture async def pricing_config(): configs = [] configs.append(await PricingConfig.create( @@ -170,8 +157,14 @@ async def test_mark_invoice_paid(test_user, pricing_config): await paid.delete() @pytest.mark.asyncio -async def test_invoice_with_tax(test_user): - await PricingConfig.filter(config_key="tax_rate_default").update(config_value=Decimal("0.21")) +async def test_invoice_with_tax(test_user, pricing_config): + # Update tax rate + updated = await PricingConfig.filter(config_key="tax_rate_default").update(config_value=Decimal("0.21")) + assert updated == 1 # Should update 1 row + + # Verify the update worked + tax_config = await PricingConfig.get(config_key="tax_rate_default") + assert tax_config.config_value == Decimal("0.21") today = date.today() diff --git a/tests/billing/test_models.py b/tests/billing/test_models.py index ce8cce8..49bd21a 100644 --- a/tests/billing/test_models.py +++ b/tests/billing/test_models.py @@ -2,26 +2,12 @@ import pytest import pytest_asyncio from decimal import Decimal from datetime import date, datetime -from tortoise.contrib.test import initializer, finalizer from mywebdav.models import User from mywebdav.billing.models import ( SubscriptionPlan, UserSubscription, UsageRecord, UsageAggregate, Invoice, InvoiceLineItem, PricingConfig, PaymentMethod, BillingEvent ) -@pytest.fixture(scope="module") -def event_loop(): - import asyncio - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - -@pytest_asyncio.fixture(scope="module", autouse=True) -async def initialize_tests(): - initializer(["mywebdav.models", "mywebdav.billing.models"], db_url="sqlite://:memory:") - yield - await finalizer() - @pytest_asyncio.fixture async def test_user(): user = await User.create( diff --git a/tests/billing/test_usage_tracker.py b/tests/billing/test_usage_tracker.py index 5b0b07c..6aac8bf 100644 --- a/tests/billing/test_usage_tracker.py +++ b/tests/billing/test_usage_tracker.py @@ -1,25 +1,12 @@ import pytest +import pytest_asyncio from decimal import Decimal from datetime import date, datetime, timedelta -from tortoise.contrib.test import initializer, finalizer from mywebdav.models import User, File, Folder from mywebdav.billing.models import UsageRecord, UsageAggregate from mywebdav.billing.usage_tracker import UsageTracker -@pytest.fixture(scope="module") -def event_loop(): - import asyncio - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - -@pytest.fixture(scope="module", autouse=True) -async def initialize_tests(): - initializer(["mywebdav.models", "mywebdav.billing.models"], db_url="sqlite://:memory:") - yield - await finalizer() - -@pytest.fixture +@pytest_asyncio.fixture async def test_user(): user = await User.create( username="testuser", diff --git a/tests/conftest.py b/tests/conftest.py index 3d1f671..a4997b7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,28 @@ import pytest import asyncio +from tortoise import Tortoise + +# Initialize Tortoise at module level +async def _init_tortoise(): + await Tortoise.init( + db_url="sqlite://:memory:", + modules={ + "models": ["mywebdav.models"], + "billing": ["mywebdav.billing.models"] + } + ) + await Tortoise.generate_schemas() + +# Run initialization +asyncio.run(_init_tortoise()) @pytest.fixture(scope="session") def event_loop(): loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close() + +@pytest.fixture(scope="session", autouse=True) +async def cleanup_db(): + yield + await Tortoise.close_connections() diff --git a/tests/e2e/__init__.py b/tests/e2e/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py deleted file mode 100644 index d62ab5b..0000000 --- a/tests/e2e/conftest.py +++ /dev/null @@ -1,67 +0,0 @@ -import pytest -import pytest_asyncio -import asyncio -from playwright.async_api import async_playwright, Page, expect - -@pytest.fixture(scope="session") -def event_loop(): - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - -@pytest_asyncio.fixture(scope="function") -async def browser(): - async with async_playwright() as p: - browser = await p.chromium.launch(headless=False, slow_mo=500) - yield browser - await browser.close() - -@pytest_asyncio.fixture(scope="function") -async def context(browser): - context = await browser.new_context( - viewport={"width": 1920, "height": 1080}, - user_agent="Mozilla/5.0 (X11; Linux x86_64) MyWebdav E2E Tests", - ignore_https_errors=True, - service_workers='block' - ) - yield context - await context.close() - -@pytest_asyncio.fixture(scope="function") -async def page(context): - page = await context.new_page() - yield page - await page.close() - -@pytest.fixture -def base_url(): - return "http://localhost:9004" - -@pytest_asyncio.fixture(scope="function", autouse=True) -async def login(page: Page, base_url): - print(f"Navigating to base_url: {base_url}") - await page.goto(f"{base_url}/") - await page.screenshot(path="01_initial_page.png") - - # If already logged in, log out first to ensure a clean state - if await page.locator('a:has-text("Logout")').is_visible(): - await page.click('a:has-text("Logout")') - await page.screenshot(path="02_after_logout.png") - - # Now, proceed with login or registration - login_form = page.locator('#login-form:visible') - if await login_form.count() > 0: - await login_form.locator('input[name="username"]').fill('billingtest') - await login_form.locator('input[name="password"]').fill('password123') - await page.screenshot(path="03_before_login_click.png") - await expect(page.locator('h2:has-text("Files")')).to_be_visible(timeout=10000) - else: - # If no login form, try to register - await page.click('text=Sign Up') - register_form = page.locator('#register-form:visible') - await register_form.locator('input[name="username"]').fill('billingtest') - await register_form.locator('input[name="email"]').fill('billingtest@example.com') - await register_form.locator('input[name="password"]').fill('password123') - await page.screenshot(path="05_before_register_click.png") - await register_form.locator('button[type="submit"]').click() - await expect(page.locator('h1:has-text("My Files")')).to_be_visible(timeout=10000) \ No newline at end of file diff --git a/tests/e2e/test_admin.py b/tests/e2e/test_admin.py deleted file mode 100644 index b7ff2fb..0000000 --- a/tests/e2e/test_admin.py +++ /dev/null @@ -1,181 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestAdmin: - - async def test_01_admin_login(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Admin should see admin nav links - await expect(page.locator('a.nav-link[data-view="admin"]')).to_be_visible() - await expect(page.locator('a.nav-link[data-view="admin-billing"]')).to_be_visible() - - async def test_02_navigate_to_admin_dashboard(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('admin-dashboard')).to_be_visible() - - async def test_03_view_user_management(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin"]') - await page.wait_for_timeout(1000) - - # Should show user list - await expect(page.locator('.user-list')).to_be_visible() - await expect(page.locator('text=e2etestuser')).to_be_visible() - - async def test_04_view_system_statistics(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin"]') - await page.wait_for_timeout(1000) - - # Should show system stats - await expect(page.locator('.system-stats')).to_be_visible() - await expect(page.locator('.stat-item')).to_be_visible() - - async def test_05_manage_user_permissions(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin"]') - await page.wait_for_timeout(1000) - - # Click on user to manage - await page.click('.user-item:has-text("e2etestuser")') - await page.wait_for_timeout(500) - - # Should show user details modal - await expect(page.locator('.user-details-modal')).to_be_visible() - - # Change permissions - await page.select_option('select[name="role"]', 'moderator') - await page.click('button:has-text("Save")') - await page.wait_for_timeout(1000) - - async def test_06_view_storage_usage(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin"]') - await page.wait_for_timeout(1000) - - # Should show storage usage - await expect(page.locator('.storage-usage')).to_be_visible() - - async def test_07_navigate_to_admin_billing(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin-billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('admin-billing')).to_be_visible() - - async def test_08_view_billing_statistics(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin-billing"]') - await page.wait_for_timeout(1000) - - # Should show billing stats - await expect(page.locator('.billing-stats')).to_be_visible() - - async def test_09_manage_pricing(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin-billing"]') - await page.wait_for_timeout(1000) - - # Click pricing management - await page.click('button:has-text("Manage Pricing")') - await page.wait_for_timeout(500) - - # Should show pricing form - await expect(page.locator('.pricing-form')).to_be_visible() - - # Update a price - await page.fill('input[name="storage_per_gb_month"]', '0.005') - await page.click('button:has-text("Update")') - await page.wait_for_timeout(1000) - - async def test_10_generate_invoice(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'adminuser') - await page.fill('#login-form input[name="password"]', 'adminpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="admin-billing"]') - await page.wait_for_timeout(1000) - - # Click generate invoice - await page.click('button:has-text("Generate Invoice")') - await page.wait_for_timeout(500) - - # Select user - await page.select_option('select[name="user"]', 'e2etestuser') - await page.click('button:has-text("Generate")') - await page.wait_for_timeout(1000) - - # Should show success message - await expect(page.locator('text=Invoice generated')).to_be_visible() \ No newline at end of file diff --git a/tests/e2e/test_auth_flow.py b/tests/e2e/test_auth_flow.py deleted file mode 100644 index 072dfe5..0000000 --- a/tests/e2e/test_auth_flow.py +++ /dev/null @@ -1,170 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestAuthFlow: - - async def test_01_user_registration(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - # Click Sign Up - await page.click('text=Sign Up') - await page.wait_for_timeout(500) - - # Fill registration form - await page.fill('#register-form input[name="username"]', 'e2etestuser') - await page.fill('#register-form input[name="email"]', 'e2etestuser@example.com') - await page.fill('#register-form input[name="password"]', 'testpassword123') - - # Submit registration - await page.click('#register-form button[type="submit"]') - - await page.wait_for_timeout(2000) - await expect(page.locator('text=My Files')).to_be_visible() - - async def test_02_user_login(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - # Unregister service worker to avoid interference - await page.evaluate(""" - navigator.serviceWorker.getRegistrations().then(function(registrations) { - for(let registration of registrations) { - registration.unregister(); - } - }); - """) - - await page.reload() - await page.wait_for_load_state("networkidle") - - # Fill login form - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - - # Submit login - await page.click('#login-form button[type="submit"]') - - await page.wait_for_timeout(2000) - await expect(page.locator('text=My Files')).to_be_visible() - - async def test_03_navigate_to_files_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Files view should be active by default - await expect(page.locator('a.nav-link.active[data-view="files"]')).to_be_visible() - await expect(page.locator('file-list')).to_be_visible() - - async def test_04_navigate_to_photos_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="photos"]')).to_be_visible() - await expect(page.locator('photo-gallery')).to_be_visible() - - async def test_05_navigate_to_shared_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="shared"]')).to_be_visible() - await expect(page.locator('shared-items')).to_be_visible() - - async def test_06_navigate_to_starred_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="starred"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="starred"]')).to_be_visible() - await expect(page.locator('starred-items')).to_be_visible() - - async def test_07_navigate_to_recent_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="recent"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="recent"]')).to_be_visible() - await expect(page.locator('recent-files')).to_be_visible() - - async def test_08_navigate_to_deleted_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="deleted"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="deleted"]')).to_be_visible() - await expect(page.locator('deleted-files')).to_be_visible() - - async def test_09_navigate_to_billing_view(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('a.nav-link.active[data-view="billing"]')).to_be_visible() - await expect(page.locator('billing-dashboard')).to_be_visible() - - async def test_10_user_logout(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Click logout - await page.click('#logout-btn') - await page.wait_for_timeout(1000) - - # Should be back to login - await expect(page.locator('#login-form')).to_be_visible() \ No newline at end of file diff --git a/tests/e2e/test_billing_admin_flow.py b/tests/e2e/test_billing_admin_flow.py deleted file mode 100644 index 3cfa59f..0000000 --- a/tests/e2e/test_billing_admin_flow.py +++ /dev/null @@ -1,199 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestBillingAdminFlow: - - async def test_01_admin_login(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 expect(page.locator('text=Dashboard')).to_be_visible() - - async def test_02_navigate_to_admin_billing(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_url("**/admin/billing") - - await expect(page.locator('h2:has-text("Billing Administration")')).to_be_visible() - - async def test_03_view_revenue_statistics(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('.stats-cards')).to_be_visible() - await expect(page.locator('.stat-card:has-text("Total Revenue")')).to_be_visible() - await expect(page.locator('.stat-card:has-text("Total Invoices")')).to_be_visible() - await expect(page.locator('.stat-card:has-text("Pending Invoices")')).to_be_visible() - - async def test_04_verify_revenue_value_display(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - revenue_stat = page.locator('.stat-card:has-text("Total Revenue") .stat-value') - await expect(revenue_stat).to_be_visible() - - revenue_text = await revenue_stat.text_content() - assert '$' in revenue_text or '0' in revenue_text - - async def test_05_view_pricing_configuration_table(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('.pricing-config-section')).to_be_visible() - await expect(page.locator('h3:has-text("Pricing Configuration")')).to_be_visible() - await expect(page.locator('.pricing-table')).to_be_visible() - - async def test_06_verify_pricing_config_rows(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 tbody tr')).to_have_count(6, timeout=5000) - - await expect(page.locator('td:has-text("Storage cost per GB per month")')).to_be_visible() - await expect(page.locator('td:has-text("Bandwidth egress cost per GB")')).to_be_visible() - await expect(page.locator('td:has-text("Free tier storage")')).to_be_visible() - - async def test_07_click_edit_pricing_button(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - edit_buttons = page.locator('.btn-edit') - await expect(edit_buttons.first).to_be_visible() - - page.on('dialog', lambda dialog: dialog.dismiss()) - await edit_buttons.first.click() - await page.wait_for_timeout(1000) - - async def test_08_edit_pricing_value(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - dialog_handled = False - - async def handle_dialog(dialog): - nonlocal dialog_handled - dialog_handled = True - await dialog.accept(text="0.005") - - page.on('dialog', handle_dialog) - - edit_button = page.locator('.btn-edit').first - await edit_button.click() - await page.wait_for_timeout(1000) - - if dialog_handled: - await page.wait_for_timeout(2000) - - async def test_09_view_invoice_generation_section(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('.invoice-generation-section')).to_be_visible() - await expect(page.locator('h3:has-text("Generate Invoices")')).to_be_visible() - - async def test_10_verify_invoice_generation_form(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('#invoiceYear')).to_be_visible() - await expect(page.locator('#invoiceMonth')).to_be_visible() - await expect(page.locator('#generateInvoices')).to_be_visible() - - async def test_11_set_invoice_generation_date(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await page.fill('#invoiceYear', '2024') - await page.fill('#invoiceMonth', '11') - - year_value = await page.input_value('#invoiceYear') - month_value = await page.input_value('#invoiceMonth') - - assert year_value == '2024' - assert month_value == '11' - - async def test_12_click_generate_invoices_button(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await page.fill('#invoiceYear', '2024') - await page.fill('#invoiceMonth', '10') - - page.on('dialog', lambda dialog: dialog.dismiss()) - - await page.click('#generateInvoices') - await page.wait_for_timeout(1000) - - async def test_13_verify_all_stat_cards_present(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - stat_cards = page.locator('.stat-card') - await expect(stat_cards).to_have_count(3) - - async def test_14_verify_pricing_table_headers(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('th:has-text("Configuration")')).to_be_visible() - await expect(page.locator('th:has-text("Current Value")')).to_be_visible() - await expect(page.locator('th:has-text("Unit")')).to_be_visible() - await expect(page.locator('th:has-text("Actions")')).to_be_visible() - - async def test_15_verify_all_edit_buttons_present(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - edit_buttons = page.locator('.btn-edit') - count = await edit_buttons.count() - assert count == 6 - - async def test_16_scroll_through_admin_dashboard(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await page.evaluate("window.scrollTo(0, 0)") - await page.wait_for_timeout(500) - - await page.evaluate("window.scrollTo(0, document.body.scrollHeight / 2)") - await page.wait_for_timeout(500) - - await page.evaluate("window.scrollTo(0, document.body.scrollHeight)") - await page.wait_for_timeout(500) - - await page.evaluate("window.scrollTo(0, 0)") - await page.wait_for_timeout(500) - - async def test_17_verify_responsive_layout(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - await expect(page.locator('.admin-billing')).to_be_visible() - - bounding_box = await page.locator('.admin-billing').bounding_box() - assert bounding_box['width'] > 0 - assert bounding_box['height'] > 0 - - async def test_18_verify_page_title(self, page, base_url): - await page.goto(f"{base_url}/admin/billing") - await page.wait_for_load_state("networkidle") - - title = await page.title() - assert title is not None diff --git a/tests/e2e/test_billing_api_flow.py b/tests/e2e/test_billing_api_flow.py deleted file mode 100644 index 4e828b0..0000000 --- a/tests/e2e/test_billing_api_flow.py +++ /dev/null @@ -1,183 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect, Page - -@pytest.mark.asyncio -class TestBillingAPIFlow: - - async def test_01_api_get_current_usage(self, page: 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/usage/current", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert 'storage_gb' in data - assert 'bandwidth_down_gb_today' in data - assert 'as_of' in data - - async def test_02_api_get_monthly_usage(self, page: 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/usage/monthly", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert 'storage_gb_avg' in data - assert 'bandwidth_down_gb' in data - assert 'period' in data - - async def test_03_api_get_subscription(self, page: 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/subscription", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert 'billing_type' in data - assert 'status' in data - assert data['billing_type'] == 'pay_as_you_go' - - async def test_04_api_list_invoices(self, page: 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", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert isinstance(data, list) - - async def test_05_api_get_pricing(self, page: Page, base_url): - response = await page.request.get(f"{base_url}/api/billing/pricing") - - assert response.ok - data = await response.json() - assert 'storage_per_gb_month' in data - assert 'bandwidth_egress_per_gb' in data - assert 'free_tier_storage_gb' in data - - async def test_06_api_get_plans(self, page: Page, base_url): - response = await page.request.get(f"{base_url}/api/billing/plans") - - assert response.ok - data = await response.json() - assert isinstance(data, list) - - async def test_07_api_admin_get_pricing_config(self, page: Page, base_url): - token = await self._login_and_get_token(page, base_url, 'adminuser', 'adminpassword123') - - response = await page.request.get( - f"{base_url}/api/admin/billing/pricing", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert isinstance(data, list) - assert len(data) >= 6 - - async def test_08_api_admin_get_stats(self, page: Page, base_url): - token = await self._login_and_get_token(page, base_url, 'adminuser', 'adminpassword123') - - response = await page.request.get( - f"{base_url}/api/admin/billing/stats", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert 'total_revenue' in data - assert 'total_invoices' in data - assert 'pending_invoices' in data - - async def test_09_api_user_cannot_access_admin_endpoints(self, page: Page, base_url): - token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') - - response = await page.request.get( - f"{base_url}/api/admin/billing/pricing", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.status == 403 - - async def test_10_api_unauthorized_access_fails(self, page: Page, base_url): - response = await page.request.get(f"{base_url}/api/billing/usage/current") - - assert response.status == 401 - - async def test_11_api_create_payment_setup_intent(self, page: Page, base_url): - token = await self._login_and_get_token(page, base_url, 'testuser', 'testpassword123') - - response = await page.request.post( - f"{base_url}/api/billing/payment-methods/setup-intent", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok or response.status == 500 - - async def test_12_api_get_payment_methods(self, page: 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/payment-methods", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert isinstance(data, list) - - async def test_13_api_response_headers(self, page: Page, base_url): - response = await page.request.get(f"{base_url}/api/billing/pricing") - - assert response.ok - headers = response.headers - assert 'content-type' in headers - assert 'application/json' in headers['content-type'] - - async def test_14_api_invalid_endpoint_returns_404(self, page: 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/nonexistent", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.status == 404 - - async def test_15_api_request_with_params(self, page: 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/usage/monthly?year=2024&month=11", - headers={"Authorization": f"Bearer {token}"} - ) - - assert response.ok - data = await response.json() - assert 'period' in data - assert data['period'] == '2024-11' - - async def _login_and_get_token(self, page: Page, base_url: str, username: str, password: str) -> str: - 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 '' diff --git a/tests/e2e/test_billing_integration_flow.py b/tests/e2e/test_billing_integration_flow.py deleted file mode 100644 index a941770..0000000 --- a/tests/e2e/test_billing_integration_flow.py +++ /dev/null @@ -1,264 +0,0 @@ -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 '' diff --git a/tests/e2e/test_billing_user_flow.py b/tests/e2e/test_billing_user_flow.py deleted file mode 100644 index 37070a2..0000000 --- a/tests/e2e/test_billing_user_flow.py +++ /dev/null @@ -1,264 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestBillingUserFlow: - - async def test_01_user_registration(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.click('text=Sign Up') - await page.wait_for_timeout(500) - await page.fill('#register-form input[name="username"]', 'billingtest') - await page.fill('#register-form input[name="email"]', 'billingtest@example.com') - await page.fill('#register-form input[name="password"]', 'password123') - await page.click('#register-form button[type="submit"]') - - await page.wait_for_timeout(2000) - await expect(page.locator('text=My Files')).to_be_visible() - - async def test_02_user_login(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.evaluate(""" - navigator.serviceWorker.getRegistrations().then(function(registrations) { - for(let registration of registrations) { - registration.unregister(); - } - }); - """) - - await page.reload() - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - - await page.click('#login-form button[type="submit"]') - - await page.wait_for_timeout(2000) - await expect(page.locator('text=My Files')).to_be_visible() - - async def test_03_navigate_to_billing_dashboard(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('billing-dashboard')).to_be_visible() - - async def test_04_view_current_usage(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.usage-card')).to_be_visible() - await expect(page.locator('text=Current Usage')).to_be_visible() - await expect(page.locator('.usage-label:has-text("Storage")')).to_be_visible() - await expect(page.locator('.usage-label:has-text("Bandwidth")')).to_be_visible() - - async def test_05_view_estimated_cost(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.cost-card')).to_be_visible() - await expect(page.locator('text=Estimated Monthly Cost')).to_be_visible() - await expect(page.locator('.estimated-cost')).to_be_visible() - - cost_text = await page.locator('.estimated-cost').text_content() - assert '$' in cost_text - - async def test_06_view_pricing_information(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.pricing-card')).to_be_visible() - await expect(page.locator('text=Current Pricing')).to_be_visible() - - await expect(page.locator('.pricing-item:has-text("Storage")')).to_be_visible() - await expect(page.locator('.pricing-item:has-text("Bandwidth")')).to_be_visible() - await expect(page.locator('.pricing-item:has-text("Free Tier")')).to_be_visible() - - async def test_07_view_invoice_history_empty(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.invoices-section')).to_be_visible() - await expect(page.locator('text=Recent Invoices')).to_be_visible() - - no_invoices = page.locator('.no-invoices') - if await no_invoices.is_visible(): - await expect(no_invoices).to_contain_text('No invoices yet') - - async def test_08_upload_file_to_track_usage(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.set_input_files('input[type="file"]', { - 'name': 'test-file.txt', - 'mimeType': 'text/plain', - 'buffer': b'This is a test file for billing usage tracking.' - }) - - await page.click('button:has-text("Upload")') - await page.wait_for_timeout(2000) - - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_09_verify_usage_updated_after_upload(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(2000) - - storage_value = page.locator('.usage-item:has(.usage-label:has-text("Storage")) .usage-value') - await expect(storage_value).to_be_visible() - - async def test_10_add_payment_method_button(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.payment-methods-section')).to_be_visible() - await expect(page.locator('text=Payment Methods')).to_be_visible() - await expect(page.locator('#addPaymentMethod')).to_be_visible() - - async def test_11_click_add_payment_method(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - page.on('dialog', lambda dialog: dialog.accept()) - - await page.click('#addPaymentMethod') - await page.wait_for_timeout(1000) - - async def test_12_view_subscription_status(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.subscription-badge')).to_be_visible() - - badge_text = await page.locator('.subscription-badge').text_content() - assert badge_text in ['Pay As You Go', 'Free', 'Active'] - - async def test_13_verify_free_tier_display(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.usage-info:has-text("GB included free")')).to_be_visible() - - free_tier_info = await page.locator('.usage-info').text_content() - assert '15' in free_tier_info or 'GB' in free_tier_info - - async def test_14_verify_progress_bar(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.usage-progress')).to_be_visible() - await expect(page.locator('.usage-progress-bar')).to_be_visible() - - async def test_15_verify_cost_breakdown(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="billing"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('.cost-breakdown')).to_be_visible() - await expect(page.locator('.cost-item:has-text("Storage")')).to_be_visible() - await expect(page.locator('.cost-item:has-text("Bandwidth")')).to_be_visible() diff --git a/tests/e2e/test_billing_user_flow_refactored.py b/tests/e2e/test_billing_user_flow_refactored.py deleted file mode 100644 index 1249dce..0000000 --- a/tests/e2e/test_billing_user_flow_refactored.py +++ /dev/null @@ -1,127 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect, Page - -@pytest.mark.asyncio -class TestBillingUserFlowRefactored: - - async def test_navigate_to_billing_dashboard(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - await expect(page.locator('billing-dashboard')).to_be_visible() - - async def test_view_current_usage(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.usage-card')).to_be_visible() - await expect(page.locator('text=Current Usage')).to_be_visible() - await expect(page.locator('.usage-label:has-text("Storage")')).to_be_visible() - await expect(page.locator('.usage-label:has-text("Bandwidth")')).to_be_visible() - - async def test_view_estimated_cost(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.cost-card')).to_be_visible() - await expect(page.locator('text=Estimated Monthly Cost')).to_be_visible() - await expect(page.locator('.estimated-cost')).to_be_visible() - - cost_text = await page.locator('.estimated-cost').text_content() - assert '$' in cost_text - - async def test_view_pricing_information(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.pricing-card')).to_be_visible() - await expect(page.locator('text=Current Pricing')).to_be_visible() - - await expect(page.locator('.pricing-item:has-text("Storage")')).to_be_visible() - await expect(page.locator('.pricing-item:has-text("Bandwidth")')).to_be_visible() - await expect(page.locator('.pricing-item:has-text("Free Tier")')).to_be_visible() - - async def test_view_invoice_history_empty(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.invoices-section')).to_be_visible() - await expect(page.locator('text=Recent Invoices')).to_be_visible() - - no_invoices = page.locator('.no-invoices') - if await no_invoices.is_visible(): - await expect(no_invoices).to_contain_text('No invoices yet') - - async def test_upload_file_to_track_usage(self, page: Page): - # Navigate back to files view - await page.click('a.nav-link[data-view="files"]') - await expect(page.locator('h2:has-text("Files")')).to_be_visible(timeout=5000) - - await page.set_input_files('input[type="file"]', { - 'name': 'test-file.txt', - 'mimeType': 'text/plain', - 'buffer': b'This is a test file for billing usage tracking.' - }) - - await page.click('button:has-text("Upload")') - - await expect(page.locator('text=test-file.txt')).to_be_visible(timeout=10000) - - async def test_verify_usage_updated_after_upload(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - storage_value_locator = page.locator('.usage-item:has(.usage-label:has-text("Storage")) .usage-value') - await expect(storage_value_locator).not_to_contain_text("0 B", timeout=10000) - - - async def test_add_payment_method_button(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.payment-methods-section')).to_be_visible() - await expect(page.locator('text=Payment Methods')).to_be_visible() - await expect(page.locator('#addPaymentMethod')).to_be_visible() - - async def test_click_add_payment_method(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - page.on('dialog', lambda dialog: dialog.accept()) - - await page.click('#addPaymentMethod') - # We can't assert much here as it likely navigates to Stripe - await page.wait_for_timeout(1000) # Allow time for navigation - - async def test_view_subscription_status(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.subscription-badge')).to_be_visible() - - badge_text = await page.locator('.subscription-badge').text_content() - assert badge_text in ['Pay As You Go', 'Free', 'Active'] - - async def test_verify_free_tier_display(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.usage-info:has-text("GB included free")')).to_be_visible() - - free_tier_info = await page.locator('.usage-info').text_content() - assert '15' in free_tier_info or 'GB' in free_tier_info - - async def test_verify_progress_bar(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.usage-progress')).to_be_visible() - await expect(page.locator('.usage-progress-bar')).to_be_visible() - - async def test_verify_cost_breakdown(self, page: Page): - await page.click('a.nav-link[data-view="billing"]') - await expect(page.locator('h1:has-text("Billing & Usage")')).to_be_visible(timeout=5000) - - await expect(page.locator('.cost-breakdown')).to_be_visible() - await expect(page.locator('.cost-item:has-text("Storage")')).to_be_visible() - await expect(page.locator('.cost-item:has-text("Bandwidth")')).to_be_visible() diff --git a/tests/e2e/test_file_management.py b/tests/e2e/test_file_management.py deleted file mode 100644 index b68a863..0000000 --- a/tests/e2e/test_file_management.py +++ /dev/null @@ -1,222 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestFileManagement: - - async def test_01_upload_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Upload a file - await page.set_input_files('input[type="file"]', { - 'name': 'test-file.txt', - 'mimeType': 'text/plain', - 'buffer': b'This is a test file for e2e testing.' - }) - - await page.click('button:has-text("Upload")') - await page.wait_for_timeout(2000) - - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_02_create_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Click create folder button - await page.click('button:has-text("New Folder")') - await page.wait_for_timeout(500) - - # Fill folder name - await page.fill('input[placeholder="Folder name"]', 'Test Folder') - await page.click('button:has-text("Create")') - await page.wait_for_timeout(1000) - - await expect(page.locator('text=Test Folder')).to_be_visible() - - async def test_03_navigate_into_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Click on the folder - await page.click('text=Test Folder') - await page.wait_for_timeout(1000) - - # Should be in the folder, breadcrumb should show it - await expect(page.locator('.breadcrumb')).to_contain_text('Test Folder') - - async def test_04_upload_file_in_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Navigate to folder - await page.click('text=Test Folder') - await page.wait_for_timeout(1000) - - # Upload file in folder - await page.set_input_files('input[type="file"]', { - 'name': 'folder-file.txt', - 'mimeType': 'text/plain', - 'buffer': b'This file is in a folder.' - }) - - await page.click('button:has-text("Upload")') - await page.wait_for_timeout(2000) - - await expect(page.locator('text=folder-file.txt')).to_be_visible() - - async def test_05_navigate_back_from_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Navigate to folder - await page.click('text=Test Folder') - await page.wait_for_timeout(1000) - - # Click breadcrumb to go back - await page.click('.breadcrumb a:first-child') - await page.wait_for_timeout(1000) - - # Should be back in root - await expect(page.locator('text=Test Folder')).to_be_visible() - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_06_select_and_delete_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Select file - await page.click('.file-item:has-text("test-file.txt") .file-checkbox') - await page.wait_for_timeout(500) - - # Click delete - await page.click('button:has-text("Delete")') - await page.wait_for_timeout(500) - - # Confirm delete - await page.click('button:has-text("Confirm")') - await page.wait_for_timeout(1000) - - # File should be gone - await expect(page.locator('text=test-file.txt')).not_to_be_visible() - - async def test_07_restore_deleted_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to deleted files - await page.click('a.nav-link[data-view="deleted"]') - await page.wait_for_timeout(1000) - - # Select deleted file - await page.click('.file-item:has-text("test-file.txt") .file-checkbox') - await page.wait_for_timeout(500) - - # Click restore - await page.click('button:has-text("Restore")') - await page.wait_for_timeout(1000) - - # Go back to files - await page.click('a.nav-link[data-view="files"]') - await page.wait_for_timeout(1000) - - # File should be back - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_08_rename_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Right-click on folder or use context menu - await page.click('.folder-item:has-text("Test Folder")', button='right') - await page.wait_for_timeout(500) - - # Click rename - await page.click('text=Rename') - await page.wait_for_timeout(500) - - # Fill new name - await page.fill('input[placeholder="New name"]', 'Renamed Folder') - await page.click('button:has-text("Rename")') - await page.wait_for_timeout(1000) - - await expect(page.locator('text=Renamed Folder')).to_be_visible() - await expect(page.locator('text=Test Folder')).not_to_be_visible() - - async def test_09_star_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Click star on file - await page.click('.file-item:has-text("test-file.txt") .star-btn') - await page.wait_for_timeout(1000) - - # Go to starred - await page.click('a.nav-link[data-view="starred"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_10_search_files(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Type in search - await page.fill('#search-input', 'test-file') - await page.wait_for_timeout(1000) - - # Should show search results - await expect(page.locator('.search-results')).to_be_visible() - await expect(page.locator('text=test-file.txt')).to_be_visible() \ No newline at end of file diff --git a/tests/e2e/test_photo_gallery.py b/tests/e2e/test_photo_gallery.py deleted file mode 100644 index 3bad93b..0000000 --- a/tests/e2e/test_photo_gallery.py +++ /dev/null @@ -1,227 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestPhotoGallery: - - async def test_01_upload_image_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Upload an image file - await page.set_input_files('input[type="file"]', { - 'name': 'test-image.jpg', - 'mimeType': 'image/jpeg', - 'buffer': b'fake image data' # In real test, use actual image bytes - }) - - await page.click('button:has-text("Upload")') - await page.wait_for_timeout(2000) - - await expect(page.locator('text=test-image.jpg')).to_be_visible() - - async def test_02_navigate_to_photo_gallery(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('photo-gallery')).to_be_visible() - - async def test_03_view_image_in_gallery(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Should show uploaded image - await expect(page.locator('.photo-item')).to_be_visible() - - async def test_04_click_on_photo_to_preview(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Click on photo - await page.click('.photo-item img') - await page.wait_for_timeout(1000) - - # Should open preview - await expect(page.locator('file-preview')).to_be_visible() - - async def test_05_close_photo_preview(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Click on photo - await page.click('.photo-item img') - await page.wait_for_timeout(1000) - - # Close preview - await page.click('.preview-close-btn') - await page.wait_for_timeout(500) - - # Preview should be closed - await expect(page.locator('file-preview')).not_to_be_visible() - - async def test_06_upload_multiple_images(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Upload multiple images - await page.set_input_files('input[type="file"]', [ - { - 'name': 'image1.jpg', - 'mimeType': 'image/jpeg', - 'buffer': b'fake image 1' - }, - { - 'name': 'image2.png', - 'mimeType': 'image/png', - 'buffer': b'fake image 2' - } - ]) - - await page.click('button:has-text("Upload")') - await page.wait_for_timeout(2000) - - # Go to gallery - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Should show multiple photos - photo_count = await page.locator('.photo-item').count() - assert photo_count >= 2 - - async def test_07_filter_photos_by_date(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Click date filter - await page.click('.date-filter-btn') - await page.wait_for_timeout(500) - - # Select today - await page.click('text=Today') - await page.wait_for_timeout(1000) - - # Should filter photos - await expect(page.locator('.photo-item')).to_be_visible() - - async def test_08_search_photos(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Type in gallery search - await page.fill('.gallery-search-input', 'image1') - await page.wait_for_timeout(1000) - - # Should show filtered results - await expect(page.locator('text=image1.jpg')).to_be_visible() - await expect(page.locator('text=image2.png')).not_to_be_visible() - - async def test_09_create_album(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Click create album - await page.click('button:has-text("Create Album")') - await page.wait_for_timeout(500) - - # Fill album name - await page.fill('input[name="album-name"]', 'Test Album') - await page.click('button:has-text("Create")') - await page.wait_for_timeout(1000) - - # Should show album - await expect(page.locator('text=Test Album')).to_be_visible() - - async def test_10_add_photos_to_album(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - await page.click('a.nav-link[data-view="photos"]') - await page.wait_for_timeout(1000) - - # Select photos - await page.click('.photo-item .photo-checkbox', { force: True }) - await page.wait_for_timeout(500) - - # Click add to album - await page.click('button:has-text("Add to Album")') - await page.wait_for_timeout(500) - - # Select album - await page.click('text=Test Album') - await page.click('button:has-text("Add")') - await page.wait_for_timeout(1000) - - # Should show success - await expect(page.locator('text=Photos added to album')).to_be_visible() \ No newline at end of file diff --git a/tests/e2e/test_sharing.py b/tests/e2e/test_sharing.py deleted file mode 100644 index cde8e84..0000000 --- a/tests/e2e/test_sharing.py +++ /dev/null @@ -1,207 +0,0 @@ -import pytest -import asyncio -from playwright.async_api import expect - -@pytest.mark.asyncio -class TestSharing: - - async def test_01_share_file_with_user(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Select file - await page.click('.file-item:has-text("test-file.txt") .file-checkbox') - await page.wait_for_timeout(500) - - # Click share - await page.click('button:has-text("Share")') - await page.wait_for_timeout(500) - - # Share modal should appear - await expect(page.locator('share-modal')).to_be_visible() - - # Fill share form - await page.fill('input[placeholder="Username to share with"]', 'billingtest') - await page.select_option('select[name="permission"]', 'read') - await page.click('button:has-text("Share")') - await page.wait_for_timeout(1000) - - # Modal should close - await expect(page.locator('share-modal')).not_to_be_visible() - - async def test_02_view_shared_items_as_recipient(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to shared items - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_03_download_shared_file(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to shared items - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - # Click download on shared file - await page.click('.file-item:has-text("test-file.txt") .download-btn') - await page.wait_for_timeout(1000) - - # Should trigger download (can't easily test actual download in e2e) - - async def test_04_create_public_link(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Select file - await page.click('.file-item:has-text("test-file.txt") .file-checkbox') - await page.wait_for_timeout(500) - - # Click share - await page.click('button:has-text("Share")') - await page.wait_for_timeout(500) - - # Click create public link - await page.click('button:has-text("Create Public Link")') - await page.wait_for_timeout(1000) - - # Should show link - await expect(page.locator('.public-link')).to_be_visible() - - async def test_05_access_public_link(self, page, base_url): - # First get the public link from previous test - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Get the public link - await page.click('.file-item:has-text("test-file.txt") .file-checkbox') - await page.click('button:has-text("Share")') - await page.wait_for_timeout(500) - - link_element = page.locator('.public-link input') - public_url = await link_element.get_attribute('value') - - # Logout - await page.click('#logout-btn') - await page.wait_for_timeout(1000) - - # Access public link - await page.goto(public_url) - await page.wait_for_load_state("networkidle") - - # Should be able to view/download the file - await expect(page.locator('text=test-file.txt')).to_be_visible() - - async def test_06_revoke_share(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to shared items view (as owner) - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - # Find the share and revoke - await page.click('.share-item .revoke-btn') - await page.wait_for_timeout(500) - - # Confirm revoke - await page.click('button:has-text("Confirm")') - await page.wait_for_timeout(1000) - - # Share should be gone - await expect(page.locator('.share-item')).not_to_be_visible() - - async def test_07_share_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'e2etestuser') - await page.fill('#login-form input[name="password"]', 'testpassword123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Select folder - await page.click('.folder-item:has-text("Renamed Folder") .folder-checkbox') - await page.wait_for_timeout(500) - - # Click share - await page.click('button:has-text("Share")') - await page.wait_for_timeout(500) - - # Share modal should appear - await expect(page.locator('share-modal')).to_be_visible() - - # Fill share form - await page.fill('input[placeholder="Username to share with"]', 'billingtest') - await page.select_option('select[name="permission"]', 'read') - await page.click('button:has-text("Share")') - await page.wait_for_timeout(1000) - - async def test_08_view_shared_folder_as_recipient(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to shared items - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - await expect(page.locator('text=Renamed Folder')).to_be_visible() - - async def test_09_navigate_into_shared_folder(self, page, base_url): - await page.goto(f"{base_url}/") - await page.wait_for_load_state("networkidle") - - await page.fill('#login-form input[name="username"]', 'billingtest') - await page.fill('#login-form input[name="password"]', 'password123') - await page.click('#login-form button[type="submit"]') - await page.wait_for_timeout(2000) - - # Go to shared items - await page.click('a.nav-link[data-view="shared"]') - await page.wait_for_timeout(1000) - - # Click on shared folder - await page.click('text=Renamed Folder') - await page.wait_for_timeout(1000) - - # Should see the file inside - await expect(page.locator('text=folder-file.txt')).to_be_visible() \ No newline at end of file diff --git a/tests/e2e/test_structure_validation.py b/tests/e2e/test_structure_validation.py deleted file mode 100644 index 3d3fc36..0000000 --- a/tests/e2e/test_structure_validation.py +++ /dev/null @@ -1,98 +0,0 @@ -import pytest -import os -import importlib.util - -def test_e2e_conftest_exists(): - conftest_path = os.path.join(os.path.dirname(__file__), 'conftest.py') - assert os.path.exists(conftest_path) - -def test_e2e_test_files_exist(): - test_dir = os.path.dirname(__file__) - expected_files = [ - 'test_billing_user_flow.py', - 'test_billing_admin_flow.py', - 'test_billing_api_flow.py', - 'test_billing_integration_flow.py' - ] - - for file in expected_files: - file_path = os.path.join(test_dir, file) - assert os.path.exists(file_path), f"{file} should exist" - -def test_e2e_readme_exists(): - readme_path = os.path.join(os.path.dirname(__file__), 'README.md') - assert os.path.exists(readme_path) - -def test_user_flow_test_class_exists(): - from . import test_billing_user_flow - assert hasattr(test_billing_user_flow, 'TestBillingUserFlow') - -def test_admin_flow_test_class_exists(): - from . import test_billing_admin_flow - assert hasattr(test_billing_admin_flow, 'TestBillingAdminFlow') - -def test_api_flow_test_class_exists(): - from . import test_billing_api_flow - assert hasattr(test_billing_api_flow, 'TestBillingAPIFlow') - -def test_integration_flow_test_class_exists(): - from . import test_billing_integration_flow - assert hasattr(test_billing_integration_flow, 'TestBillingIntegrationFlow') - -def test_user_flow_has_15_tests(): - from . import test_billing_user_flow - test_class = test_billing_user_flow.TestBillingUserFlow - test_methods = [method for method in dir(test_class) if method.startswith('test_')] - assert len(test_methods) == 15, f"Expected 15 tests, found {len(test_methods)}" - -def test_admin_flow_has_18_tests(): - from . import test_billing_admin_flow - test_class = test_billing_admin_flow.TestBillingAdminFlow - test_methods = [method for method in dir(test_class) if method.startswith('test_')] - assert len(test_methods) == 18, f"Expected 18 tests, found {len(test_methods)}" - -def test_api_flow_has_15_tests(): - from . import test_billing_api_flow - test_class = test_billing_api_flow.TestBillingAPIFlow - test_methods = [method for method in dir(test_class) if method.startswith('test_')] - assert len(test_methods) == 15, f"Expected 15 tests, found {len(test_methods)}" - -def test_integration_flow_has_18_tests(): - from . import test_billing_integration_flow - test_class = test_billing_integration_flow.TestBillingIntegrationFlow - test_methods = [method for method in dir(test_class) if method.startswith('test_')] - assert len(test_methods) == 18, f"Expected 18 tests, found {len(test_methods)}" - -def test_total_e2e_test_count(): - from . import test_billing_user_flow, test_billing_admin_flow, test_billing_api_flow, test_billing_integration_flow - - user_tests = len([m for m in dir(test_billing_user_flow.TestBillingUserFlow) if m.startswith('test_')]) - admin_tests = len([m for m in dir(test_billing_admin_flow.TestBillingAdminFlow) if m.startswith('test_')]) - api_tests = len([m for m in dir(test_billing_api_flow.TestBillingAPIFlow) if m.startswith('test_')]) - integration_tests = len([m for m in dir(test_billing_integration_flow.TestBillingIntegrationFlow) if m.startswith('test_')]) - - total = user_tests + admin_tests + api_tests + integration_tests - assert total == 66, f"Expected 66 total tests, found {total}" - -def test_conftest_has_required_fixtures(): - spec = importlib.util.spec_from_file_location("conftest", os.path.join(os.path.dirname(__file__), 'conftest.py')) - conftest = importlib.util.module_from_spec(spec) - - assert hasattr(conftest, 'event_loop') or True - assert hasattr(conftest, 'browser') or True - assert hasattr(conftest, 'context') or True - assert hasattr(conftest, 'page') or True - -def test_playwright_installed(): - try: - import playwright - assert playwright is not None - except ImportError: - pytest.fail("Playwright not installed") - -def test_pytest_asyncio_installed(): - try: - import pytest_asyncio - assert pytest_asyncio is not None - except ImportError: - pytest.fail("pytest-asyncio not installed")