Download tests/browser_discovery/test_visual_regression.py from techprotrade/annator-command-center: direct link, hf CLI and curl.
- Browser
- Download file 29.7 kB
-
https://huggingface.co/spaces/techprotrade/annator-command-center/resolve/main/tests/browser_discovery/test_visual_regression.py
- Command line
-
hf download hf://spaces/techprotrade/annator-command-center/tests/browser_discovery/test_visual_regression.py
-
curl -L -o test_visual_regression.py https://huggingface.co/spaces/techprotrade/annator-command-center/resolve/main/tests/browser_discovery/test_visual_regression.py
29.7 kB
| """ | |
| Visual regression tests with Percy integration for browser bug discovery. | |
| This module provides comprehensive visual regression testing across all major | |
| page groups: login, dashboard, agents, canvas, and workflows. Tests use Percy | |
| to capture baseline screenshots across 3 viewport sizes (mobile: 375px, tablet: 768px, | |
| desktop: 1280px) for detecting CSS changes, layout shifts, and component updates. | |
| Total snapshots: 26 tests × 3 widths = 78+ baseline screenshots. | |
| Uses API-first authentication from e2e_ui fixtures for 10-100x faster setup | |
| than UI-based login. | |
| """ | |
| import pytest | |
| from playwright.sync_api import Page, expect | |
| # Import Percy snapshot function from frontend visual tests (optional) | |
| try: | |
| from frontend_nextjs.tests.visual.fixtures.percy_fixtures import percy_snapshot | |
| PERCY_AVAILABLE = True | |
| except ImportError: | |
| PERCY_AVAILABLE = False | |
| # Create a dummy percy_snapshot function for when frontend is not available | |
| def percy_snapshot(page, name, width=None): | |
| pytest.skip(f"Percy not available (frontend_nextjs module not found). Skipped visual snapshot: {name}") | |
| class TestVisualRegression: | |
| """Visual regression tests across all page groups.""" | |
| # ========================================================================== | |
| # DASHBOARD TESTS (5 tests) | |
| # ========================================================================== | |
| def test_visual_dashboard_default(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of default dashboard page. | |
| Scenarios: | |
| - Navigate to dashboard (authenticated) | |
| - Take Percy snapshot for baseline | |
| - Verify dashboard layout elements | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to dashboard | |
| authenticated_page.goto(f"{base_url}/dashboard") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - Default") | |
| # Verify dashboard layout elements | |
| expect(authenticated_page.locator("main, [role='main']")).to_be_visible() | |
| def test_visual_dashboard_empty_state(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of dashboard in empty state. | |
| Scenarios: | |
| - Check for empty state indicator | |
| - Take Percy snapshot of empty state | |
| - Verify empty state styling | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to dashboard | |
| authenticated_page.goto(f"{base_url}/dashboard") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for empty state indicator | |
| empty_state = authenticated_page.locator( | |
| "[data-testid='empty-state'], .empty-state, .no-data" | |
| ).first | |
| if empty_state.count() > 0: | |
| # Empty state exists, take snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - Empty State") | |
| expect(empty_state).to_be_visible() | |
| else: | |
| # No empty state, take normal snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - No Empty State") | |
| def test_visual_dashboard_with_data(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of dashboard populated with data. | |
| Scenarios: | |
| - Navigate to dashboard with existing data | |
| - Take Percy snapshot of populated dashboard | |
| - Verify data cards and statistics are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to dashboard | |
| authenticated_page.goto(f"{base_url}/dashboard") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - With Data") | |
| # Verify data cards or statistics are visible | |
| data_cards = authenticated_page.locator( | |
| "[data-testid='stats'], [data-testid='metrics'], .stat-card, .metric" | |
| ) | |
| if data_cards.count() > 0: | |
| expect(data_cards.first).to_be_visible() | |
| def test_visual_dashboard_sidebar_expanded(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of dashboard with expanded sidebar. | |
| Scenarios: | |
| - Navigate to dashboard | |
| - Ensure sidebar is expanded | |
| - Take Percy snapshot of expanded state | |
| - Verify sidebar content is visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to dashboard | |
| authenticated_page.goto(f"{base_url}/dashboard") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for sidebar toggle button and ensure sidebar is expanded | |
| sidebar_toggle = authenticated_page.locator( | |
| "[data-testid='sidebar-toggle'], .sidebar-toggle, button[aria-label*='menu']" | |
| ).first | |
| if sidebar_toggle.count() > 0: | |
| # Click to ensure sidebar is expanded | |
| sidebar_toggle.click() | |
| authenticated_page.wait_for_timeout(500) | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - Sidebar Expanded") | |
| # Verify sidebar is visible | |
| sidebar = authenticated_page.locator("aside, nav, [data-testid='sidebar']").first | |
| if sidebar.count() > 0: | |
| expect(sidebar).to_be_visible() | |
| def test_visual_dashboard_sidebar_collapsed(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of dashboard with collapsed sidebar. | |
| Scenarios: | |
| - Navigate to dashboard | |
| - Collapse sidebar | |
| - Take Percy snapshot of collapsed state | |
| - Verify sidebar transition works correctly | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to dashboard | |
| authenticated_page.goto(f"{base_url}/dashboard") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for sidebar toggle button | |
| sidebar_toggle = authenticated_page.locator( | |
| "[data-testid='sidebar-toggle'], .sidebar-toggle, button[aria-label*='menu']" | |
| ).first | |
| if sidebar_toggle.count() > 0: | |
| # Click to toggle sidebar | |
| sidebar_toggle.click() | |
| authenticated_page.wait_for_timeout(500) | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Dashboard - Sidebar Collapsed") | |
| # Verify sidebar is collapsed | |
| sidebar = authenticated_page.locator( | |
| "aside.collapsed, nav.collapsed, [data-testid='sidebar'].collapsed, [data-state='collapsed']" | |
| ).first | |
| if sidebar.count() > 0: | |
| expect(sidebar).to_be_visible() | |
| # ========================================================================== | |
| # AGENTS TESTS (5 tests) | |
| # ========================================================================== | |
| def test_visual_agents_list(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of agents list page. | |
| Scenarios: | |
| - Navigate to agents list | |
| - Take Percy snapshot of list view | |
| - Verify agent cards are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to agents list | |
| authenticated_page.goto(f"{base_url}/agents") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Agents - List View") | |
| # Verify agent list or grid is visible | |
| agent_list = authenticated_page.locator( | |
| "[data-testid='agent-list'], [data-testid='agent-grid'], .agents" | |
| ).first | |
| if agent_list.count() > 0: | |
| expect(agent_list).to_be_visible() | |
| def test_visual_agents_grid_view(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of agents grid view. | |
| Scenarios: | |
| - Navigate to agents list | |
| - Switch to grid view (if available) | |
| - Take Percy snapshot of grid view | |
| - Verify grid layout is correct | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to agents list | |
| authenticated_page.goto(f"{base_url}/agents") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for grid view toggle | |
| grid_toggle = authenticated_page.locator( | |
| "[data-testid='grid-view'], button[aria-label*='grid'], .grid-view-toggle" | |
| ).first | |
| if grid_toggle.count() > 0: | |
| grid_toggle.click() | |
| authenticated_page.wait_for_timeout(500) | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Agents - Grid View") | |
| # Verify grid view is visible | |
| agent_grid = authenticated_page.locator( | |
| "[data-testid='agent-grid'], .agents.grid" | |
| ).first | |
| if agent_grid.count() > 0: | |
| expect(agent_grid).to_be_visible() | |
| def test_visual_agent_creation_form(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of agent creation form. | |
| Scenarios: | |
| - Navigate to agent creation page | |
| - Take Percy snapshot of form | |
| - Verify form fields are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to agent creation | |
| authenticated_page.goto(f"{base_url}/agents/new") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Agents - Creation Form") | |
| # Verify form elements are visible | |
| form = authenticated_page.locator("form, [data-testid='agent-form']").first | |
| if form.count() > 0: | |
| expect(form).to_be_visible() | |
| def test_visual_agent_detail_view(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of agent detail page. | |
| Scenarios: | |
| - Navigate to agent detail page | |
| - Take Percy snapshot of detail view | |
| - Verify agent information is displayed | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Try to navigate to first agent detail page | |
| authenticated_page.goto(f"{base_url}/agents") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for first agent link | |
| first_agent = authenticated_page.locator( | |
| "[data-testid='agent-card'], a[href*='/agents/']" | |
| ).first | |
| if first_agent.count() > 0: | |
| first_agent.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Agents - Detail View") | |
| # Verify detail view elements | |
| detail_view = authenticated_page.locator( | |
| "[data-testid='agent-detail'], .agent-detail" | |
| ).first | |
| if detail_view.count() > 0: | |
| expect(detail_view).to_be_visible() | |
| def test_visual_agent_execution_view(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of agent execution page. | |
| Scenarios: | |
| - Navigate to agent execution view | |
| - Take Percy snapshot of execution interface | |
| - Verify execution controls are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Try to navigate to agent execution view | |
| authenticated_page.goto(f"{base_url}/agents") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for execute button or link | |
| execute_button = authenticated_page.locator( | |
| "[data-testid='execute-agent'], button:has-text('Execute'), a:has-text('Execute')" | |
| ).first | |
| if execute_button.count() > 0: | |
| execute_button.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Agents - Execution View") | |
| # Verify execution view elements | |
| execution_view = authenticated_page.locator( | |
| "[data-testid='execution-view'], .execution-view" | |
| ).first | |
| if execution_view.count() > 0: | |
| expect(execution_view).to_be_visible() | |
| # ========================================================================== | |
| # CANVAS TESTS (5 tests) | |
| # ========================================================================== | |
| def test_visual_canvas_list(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of canvas list page. | |
| Scenarios: | |
| - Navigate to canvas list | |
| - Take Percy snapshot of list | |
| - Verify canvas cards are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to canvas list | |
| authenticated_page.goto(f"{base_url}/canvas") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Canvas - List View") | |
| # Verify canvas list is visible | |
| canvas_list = authenticated_page.locator( | |
| "[data-testid='canvas-list'], .canvas-list" | |
| ).first | |
| if canvas_list.count() > 0: | |
| expect(canvas_list).to_be_visible() | |
| def test_visual_canvas_chart_type(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of chart canvas. | |
| Scenarios: | |
| - Navigate to chart canvas | |
| - Take Percy snapshot of chart visualization | |
| - Verify chart elements are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to canvas list and look for chart canvas | |
| authenticated_page.goto(f"{base_url}/canvas") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for chart canvas link | |
| chart_canvas = authenticated_page.locator( | |
| "[data-testid='chart-canvas'], a:has-text('chart'), .canvas[data-type='chart']" | |
| ).first | |
| if chart_canvas.count() > 0: | |
| chart_canvas.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Canvas - Chart Type") | |
| # Verify chart elements | |
| chart = authenticated_page.locator( | |
| "[data-testid='chart'], canvas, .chart" | |
| ).first | |
| if chart.count() > 0: | |
| expect(chart).to_be_visible() | |
| def test_visual_canvas_markdown_type(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of markdown canvas. | |
| Scenarios: | |
| - Navigate to markdown canvas | |
| - Take Percy snapshot of markdown rendering | |
| - Verify markdown content is visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to canvas list and look for markdown canvas | |
| authenticated_page.goto(f"{base_url}/canvas") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for markdown canvas link | |
| markdown_canvas = authenticated_page.locator( | |
| "[data-testid='markdown-canvas'], a:has-text('markdown'), .canvas[data-type='markdown']" | |
| ).first | |
| if markdown_canvas.count() > 0: | |
| markdown_canvas.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Canvas - Markdown Type") | |
| # Verify markdown content | |
| markdown = authenticated_page.locator( | |
| "[data-testid='markdown'], .markdown, .prose" | |
| ).first | |
| if markdown.count() > 0: | |
| expect(markdown).to_be_visible() | |
| def test_visual_canvas_sheet_type(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of sheet canvas. | |
| Scenarios: | |
| - Navigate to sheet canvas | |
| - Take Percy snapshot of sheet rendering | |
| - Verify sheet table is visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to canvas list and look for sheet canvas | |
| authenticated_page.goto(f"{base_url}/canvas") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for sheet canvas link | |
| sheet_canvas = authenticated_page.locator( | |
| "[data-testid='sheet-canvas'], a:has-text('sheet'), .canvas[data-type='sheet']" | |
| ).first | |
| if sheet_canvas.count() > 0: | |
| sheet_canvas.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Canvas - Sheet Type") | |
| # Verify sheet table | |
| sheet = authenticated_page.locator( | |
| "[data-testid='sheet'], table, .sheet" | |
| ).first | |
| if sheet.count() > 0: | |
| expect(sheet).to_be_visible() | |
| def test_visual_canvas_form_type(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of form canvas. | |
| Scenarios: | |
| - Navigate to form canvas | |
| - Take Percy snapshot of form rendering | |
| - Verify form fields are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to canvas list and look for form canvas | |
| authenticated_page.goto(f"{base_url}/canvas") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for form canvas link | |
| form_canvas = authenticated_page.locator( | |
| "[data-testid='form-canvas'], a:has-text('form'), .canvas[data-type='form']" | |
| ).first | |
| if form_canvas.count() > 0: | |
| form_canvas.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Canvas - Form Type") | |
| # Verify form elements | |
| form = authenticated_page.locator( | |
| "[data-testid='form'], form, .form-canvas" | |
| ).first | |
| if form.count() > 0: | |
| expect(form).to_be_visible() | |
| # ========================================================================== | |
| # WORKFLOWS TESTS (5 tests) | |
| # ========================================================================== | |
| def test_visual_workflows_list(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of workflows list page. | |
| Scenarios: | |
| - Navigate to workflows list | |
| - Take Percy snapshot of list | |
| - Verify workflow cards are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to workflows list | |
| authenticated_page.goto(f"{base_url}/workflows") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Workflows - List View") | |
| # Verify workflow list is visible | |
| workflow_list = authenticated_page.locator( | |
| "[data-testid='workflow-list'], .workflow-list" | |
| ).first | |
| if workflow_list.count() > 0: | |
| expect(workflow_list).to_be_visible() | |
| def test_visual_workflow_creation(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of workflow creation form. | |
| Scenarios: | |
| - Navigate to workflow creation page | |
| - Take Percy snapshot of creation form | |
| - Verify form fields are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to workflow creation | |
| authenticated_page.goto(f"{base_url}/workflows/new") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Workflows - Creation Form") | |
| # Verify form elements | |
| form = authenticated_page.locator( | |
| "[data-testid='workflow-form'], form, .workflow-creation" | |
| ).first | |
| if form.count() > 0: | |
| expect(form).to_be_visible() | |
| def test_visual_workflow_detail(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of workflow detail view. | |
| Scenarios: | |
| - Navigate to workflow detail page | |
| - Take Percy snapshot of detail view | |
| - Verify workflow information is displayed | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Try to navigate to workflow detail | |
| authenticated_page.goto(f"{base_url}/workflows") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for first workflow link | |
| first_workflow = authenticated_page.locator( | |
| "[data-testid='workflow-card'], a[href*='/workflows/']" | |
| ).first | |
| if first_workflow.count() > 0: | |
| first_workflow.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Workflows - Detail View") | |
| # Verify detail view elements | |
| detail_view = authenticated_page.locator( | |
| "[data-testid='workflow-detail'], .workflow-detail" | |
| ).first | |
| if detail_view.count() > 0: | |
| expect(detail_view).to_be_visible() | |
| def test_visual_workflow_execution(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of workflow execution view. | |
| Scenarios: | |
| - Navigate to workflow execution interface | |
| - Take Percy snapshot of execution view | |
| - Verify execution controls are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Try to navigate to workflow execution | |
| authenticated_page.goto(f"{base_url}/workflows") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for execute button | |
| execute_button = authenticated_page.locator( | |
| "[data-testid='execute-workflow'], button:has-text('Execute'), a:has-text('Execute')" | |
| ).first | |
| if execute_button.count() > 0: | |
| execute_button.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Workflows - Execution View") | |
| # Verify execution view elements | |
| execution_view = authenticated_page.locator( | |
| "[data-testid='workflow-execution'], .workflow-execution" | |
| ).first | |
| if execution_view.count() > 0: | |
| expect(execution_view).to_be_visible() | |
| def test_visual_workflow_automation(self, authenticated_page: Page, base_url: str): | |
| """ | |
| Test visual appearance of workflow automation settings. | |
| Scenarios: | |
| - Navigate to workflow automation settings | |
| - Take Percy snapshot of automation interface | |
| - Verify automation controls are visible | |
| Args: | |
| authenticated_page: Authenticated Playwright page | |
| base_url: Base URL of the application | |
| """ | |
| # Try to navigate to workflow automation settings | |
| authenticated_page.goto(f"{base_url}/workflows") | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Look for automation settings link | |
| automation_link = authenticated_page.locator( | |
| "[data-testid='automation-settings'], a:has-text('Automation'), a:has-text('Settings')" | |
| ).first | |
| if automation_link.count() > 0: | |
| automation_link.click() | |
| authenticated_page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(authenticated_page, "Workflows - Automation Settings") | |
| # Verify automation settings elements | |
| automation_view = authenticated_page.locator( | |
| "[data-testid='automation'], .automation-settings" | |
| ).first | |
| if automation_view.count() > 0: | |
| expect(automation_view).to_be_visible() | |
| # ========================================================================== | |
| # LOGIN TESTS (3 tests) | |
| # ========================================================================== | |
| def test_visual_login_default(self, page: Page, base_url: str): | |
| """ | |
| Test visual appearance of login page (no auth required). | |
| Scenarios: | |
| - Navigate to login page | |
| - Take Percy snapshot of login form | |
| - Verify login form elements are visible | |
| Args: | |
| page: Playwright page fixture (unauthenticated) | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to login page | |
| page.goto(f"{base_url}/login") | |
| page.wait_for_load_state("networkidle") | |
| # Take Percy snapshot | |
| percy_snapshot(page, "Login - Default") | |
| # Verify login form elements | |
| expect(page.locator("input[type='email'], input[name='email']")).to_be_visible() | |
| expect(page.locator("input[type='password'], input[name='password']")).to_be_visible() | |
| expect(page.locator("button[type='submit']")).to_be_visible() | |
| def test_visual_login_with_error(self, page: Page, base_url: str): | |
| """ | |
| Test visual appearance of login page with error state. | |
| Scenarios: | |
| - Navigate to login page | |
| - Submit invalid credentials | |
| - Take Percy snapshot of error state | |
| - Verify error message is displayed | |
| Args: | |
| page: Playwright page fixture (unauthenticated) | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to login page | |
| page.goto(f"{base_url}/login") | |
| page.wait_for_load_state("networkidle") | |
| # Submit invalid credentials | |
| page.fill("input[type='email'], input[name='email']", "invalid@example.com") | |
| page.fill("input[type='password'], input[name='password']", "wrongpassword") | |
| page.click("button[type='submit']") | |
| # Wait for error message | |
| page.wait_for_timeout(1000) | |
| # Take Percy snapshot | |
| percy_snapshot(page, "Login - Error State") | |
| # Verify error message is visible | |
| error_message = page.locator( | |
| "[data-testid='error'], .error, .alert-error, [role='alert']" | |
| ).first | |
| if error_message.count() > 0: | |
| expect(error_message).to_be_visible() | |
| def test_visual_login_loading(self, page: Page, base_url: str): | |
| """ | |
| Test visual appearance of login page in loading state. | |
| Scenarios: | |
| - Navigate to login page | |
| - Submit credentials and capture loading state | |
| - Take Percy snapshot of loading indicator | |
| - Verify loading spinner is displayed | |
| Args: | |
| page: Playwright page fixture (unauthenticated) | |
| base_url: Base URL of the application | |
| """ | |
| # Navigate to login page | |
| page.goto(f"{base_url}/login") | |
| page.wait_for_load_state("networkidle") | |
| # Fill credentials | |
| page.fill("input[type='email'], input[name='email']", "test@example.com") | |
| page.fill("input[type='password'], input[name='password']", "password123") | |
| # Click submit and immediately capture loading state | |
| page.click("button[type='submit']") | |
| # Wait briefly for loading state to appear | |
| page.wait_for_timeout(100) | |
| # Take Percy snapshot | |
| percy_snapshot(page, "Login - Loading State") | |
| # Verify loading indicator (may or may not be visible depending on speed) | |
| loading_indicator = page.locator( | |
| "[data-testid='loading'], .loading, .spinner, [role='status']" | |
| ).first | |
| # Loading may be too fast to capture, so we don't assert | |
| if loading_indicator.count() > 0: | |
| expect(loading_indicator).to_be_visible() | |