feat: add advanced analytics and territory management system
- Add comprehensive analytics components with export functionality - Implement territory management with manager performance tracking - Add seatmap components for venue layout management - Create customer management features with modal interface - Add advanced hooks for dashboard flags and territory data - Implement seat selection and venue management utilities - Add type definitions for ticketing and seatmap systems 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
163
reactrebuild0825/tests/event-detail.spec.ts
Normal file
163
reactrebuild0825/tests/event-detail.spec.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* EventDetailPage E2E Tests
|
||||
*
|
||||
* Tests for the event detail page header actions:
|
||||
* - Add Ticket Type button functionality
|
||||
* - Publish button behavior (disabled when already published)
|
||||
* - Open Scanner button functionality
|
||||
* - Payment warning chip display
|
||||
*/
|
||||
|
||||
test.describe('EventDetailPage', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Navigate to login and authenticate as organizer
|
||||
await page.goto('/login');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Login with organizer credentials (has unpublished events)
|
||||
await page.fill('input[name="email"]', 'organizer@example.com');
|
||||
await page.fill('input[name="password"]', 'password123');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Wait for redirect to dashboard
|
||||
await page.waitForURL('/dashboard');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Navigate to events page
|
||||
await page.goto('/events');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Click on first event to go to detail page
|
||||
const firstEventLink = page.locator('[data-testid="event-card"]').first();
|
||||
await firstEventLink.click();
|
||||
|
||||
// Wait for event detail page to load
|
||||
await page.waitForSelector('[data-testid="event-detail-page"]');
|
||||
});
|
||||
|
||||
test('renders action buttons with correct data-testids', async ({ page }) => {
|
||||
// Verify all required buttons are present with correct test ids
|
||||
await expect(page.locator('[data-testid="addTicketTypeBtn"]')).toBeVisible();
|
||||
await expect(page.locator('[data-testid="publishBtn"]')).toBeVisible();
|
||||
await expect(page.locator('[data-testid="openScannerBtn"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Add Ticket Type button opens modal', async ({ page }) => {
|
||||
// Click the add ticket type button
|
||||
await page.click('[data-testid="addTicketTypeBtn"]');
|
||||
|
||||
// Verify the modal opens
|
||||
await expect(page.locator('.modal')).toBeVisible();
|
||||
await expect(page.getByText('Create Ticket Type')).toBeVisible();
|
||||
|
||||
// Close modal
|
||||
await page.keyboard.press('Escape');
|
||||
});
|
||||
|
||||
test('Publish button shows correct state and opens modal', async ({ page }) => {
|
||||
const publishBtn = page.locator('[data-testid="publishBtn"]');
|
||||
|
||||
// For draft events, button should be enabled and say "Publish"
|
||||
const eventStatus = await page.locator('[data-testid="event-status-badge"]').textContent();
|
||||
|
||||
if (eventStatus?.includes('draft')) {
|
||||
await expect(publishBtn).toBeEnabled();
|
||||
await expect(publishBtn).toContainText('Publish');
|
||||
|
||||
// Click to open publish modal
|
||||
await publishBtn.click();
|
||||
await expect(page.getByText('Publish Event')).toBeVisible();
|
||||
|
||||
// Close modal
|
||||
await page.keyboard.press('Escape');
|
||||
} else if (eventStatus?.includes('published')) {
|
||||
// For published events, button should be disabled and say "Published"
|
||||
await expect(publishBtn).toBeDisabled();
|
||||
await expect(publishBtn).toContainText('Published');
|
||||
}
|
||||
});
|
||||
|
||||
test('Open Scanner button navigates to scanner with eventId', async ({ page }) => {
|
||||
// Get current URL to extract eventId
|
||||
const currentUrl = page.url();
|
||||
const eventIdMatch = currentUrl.match(/\/events\/([^\/]+)/);
|
||||
const eventId = eventIdMatch?.[1];
|
||||
|
||||
expect(eventId).toBeTruthy();
|
||||
|
||||
// Click the scanner button
|
||||
await page.click('[data-testid="openScannerBtn"]');
|
||||
|
||||
// Verify navigation to scanner with eventId query parameter
|
||||
await page.waitForURL(`/scan?eventId=${eventId}`);
|
||||
|
||||
// Verify we're on the scanner page
|
||||
await expect(page.locator('text=Scanner')).toBeVisible();
|
||||
});
|
||||
|
||||
test('displays payment banner for organization without connected payment', async ({ page }) => {
|
||||
// Check if payment banner is visible (depends on mock user data)
|
||||
const paymentBanner = page.locator('[data-testid="payment-banner"]');
|
||||
|
||||
// The organizer mock user has payment.connected: false, so banner should show
|
||||
await expect(paymentBanner).toBeVisible();
|
||||
|
||||
// Verify banner contains link to payment settings
|
||||
const paymentLink = paymentBanner.locator('a');
|
||||
await expect(paymentLink).toContainText(/connect|payment/i);
|
||||
});
|
||||
|
||||
test('ticket type section shows add button when user can edit', async ({ page }) => {
|
||||
// Verify the ticket types section has an add button
|
||||
const ticketTypesCard = page.locator('text=Ticket Types').locator('..');
|
||||
await expect(ticketTypesCard.locator('[data-testid="addTicketTypeBtn"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('event stats display correctly', async ({ page }) => {
|
||||
// Verify the three stat cards are displayed
|
||||
await expect(page.getByText('Tickets Sold')).toBeVisible();
|
||||
await expect(page.getByText('Revenue')).toBeVisible();
|
||||
await expect(page.getByText('Ticket Types')).toBeVisible();
|
||||
|
||||
// Verify numeric values are displayed
|
||||
const ticketsSoldValue = page.locator('text=Tickets Sold').locator('..').locator('.text-2xl');
|
||||
const revenueValue = page.locator('text=Revenue').locator('..').locator('.text-2xl');
|
||||
const ticketTypesValue = page.locator('text=Ticket Types').locator('..').locator('.text-2xl');
|
||||
|
||||
await expect(ticketsSoldValue).toBeVisible();
|
||||
await expect(revenueValue).toBeVisible();
|
||||
await expect(ticketTypesValue).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('EventDetailPage - Published Event', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Login as admin (has published events)
|
||||
await page.goto('/login');
|
||||
await page.fill('input[name="email"]', 'admin@example.com');
|
||||
await page.fill('input[name="password"]', 'password123');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await page.waitForURL('/dashboard');
|
||||
await page.goto('/events');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Look for a published event or navigate to first event
|
||||
await page.locator('[data-testid="event-card"]').first().click();
|
||||
await page.waitForSelector('[data-testid="event-detail-page"]');
|
||||
});
|
||||
|
||||
test('publish button is disabled for published events', async ({ page }) => {
|
||||
// Check if this event is published
|
||||
const statusBadge = page.locator('[data-testid="event-status-badge"]');
|
||||
const status = await statusBadge.textContent();
|
||||
|
||||
if (status?.includes('published')) {
|
||||
const publishBtn = page.locator('[data-testid="publishBtn"]');
|
||||
await expect(publishBtn).toBeDisabled();
|
||||
await expect(publishBtn).toContainText('Published');
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user