Files
blackcanyontickets/reactrebuild0825/tests/create-ticket-type-modal.spec.ts
dzinesco aa81eb5adb 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>
2025-08-26 09:25:10 -06:00

248 lines
9.7 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('CreateTicketTypeModal', () => {
test.beforeEach(async ({ page }) => {
// Navigate to login and authenticate as admin
await page.goto('/login');
await page.fill('[data-testid="email-input"]', 'admin@test.com');
await page.fill('[data-testid="password-input"]', 'password');
await page.click('[data-testid="login-button"]');
// Wait for redirect to dashboard
await expect(page).toHaveURL('/dashboard');
// Navigate to a specific event detail page
await page.goto('/events/evt-1');
await expect(page.getByTestId('event-detail-page')).toBeVisible();
});
test('should open modal when Add Ticket Type button is clicked', async ({ page }) => {
// Click the Add Ticket Type button
await page.click('[data-testid="add-ticket-type-button"]');
// Check that modal opens
await expect(page.getByRole('dialog')).toBeVisible();
await expect(page.getByRole('heading', { name: 'Create Ticket Type' })).toBeVisible();
});
test('should validate required fields', async ({ page }) => {
// Open modal
await page.click('[data-testid="add-ticket-type-button"]');
// Try to submit empty form
await page.click('button[type="submit"]');
// Check for validation errors
await expect(page.getByText('Name must be at least 2 characters')).toBeVisible();
await expect(page.getByText('Price must be greater than 0')).toBeVisible();
});
test('should validate name length constraints', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Test minimum length
await page.fill('input[name="name"]', 'A');
await page.click('button[type="submit"]');
await expect(page.getByText('Name must be at least 2 characters')).toBeVisible();
// Test maximum length
const longName = 'A'.repeat(61);
await page.fill('input[name="name"]', longName);
await page.click('button[type="submit"]');
await expect(page.getByText('Name must be 60 characters or less')).toBeVisible();
});
test('should validate price constraints', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill required name field
await page.fill('input[name="name"]', 'Test Ticket');
// Test negative price
await page.fill('input[type="number"][step="0.01"]', '-10');
await page.click('button[type="submit"]');
await expect(page.getByText('Price cannot be negative')).toBeVisible();
// Test zero price (should be allowed for free tickets)
await page.fill('input[type="number"][step="0.01"]', '0');
await page.fill('input[name="inventory"]', '100');
// Should not show price error for free tickets
await expect(page.getByText('Price must be greater than 0')).not.toBeVisible();
});
test('should validate inventory constraints', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill required fields
await page.fill('input[name="name"]', 'Test Ticket');
await page.fill('input[type="number"][step="0.01"]', '25.00');
// Test negative inventory
await page.fill('input[name="inventory"]', '-1');
await page.click('button[type="submit"]');
await expect(page.getByText('Inventory cannot be negative')).toBeVisible();
});
test('should validate sales date constraints', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill required fields
await page.fill('input[name="name"]', 'Test Ticket');
await page.fill('input[type="number"][step="0.01"]', '25.00');
await page.fill('input[name="inventory"]', '100');
// Set sales end before sales start
await page.fill('input[name="salesStart"]', '2024-12-25T10:00');
await page.fill('input[name="salesEnd"]', '2024-12-20T10:00');
await page.click('button[type="submit"]');
await expect(page.getByText('Sales end date must be after sales start date')).toBeVisible();
});
test('should convert price from dollars to cents correctly', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form with valid data
await page.fill('input[name="name"]', 'General Admission');
await page.fill('input[type="number"][step="0.01"]', '25.99');
await page.fill('input[name="inventory"]', '100');
// Submit form
await page.click('button[type="submit"]');
// Check for success message
await expect(page.getByText(/created successfully/)).toBeVisible({ timeout: 10000 });
// Modal should close after success
await expect(page.getByRole('dialog')).not.toBeVisible({ timeout: 3000 });
});
test('should create active ticket type successfully', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form completely
await page.fill('input[name="name"]', 'VIP Access');
await page.fill('input[type="number"][step="0.01"]', '150.00');
await page.fill('input[name="inventory"]', '50');
await page.fill('input[name="salesStart"]', '2024-12-01T09:00');
await page.fill('input[name="salesEnd"]', '2024-12-31T23:59');
// Select active status (should be default)
await page.selectOption('[role="combobox"]', 'active');
// Submit form
await page.click('button[type="submit"]');
// Wait for success
await expect(page.getByText(/VIP Access.*created successfully/)).toBeVisible({ timeout: 10000 });
// Check that new ticket type appears in the list
await expect(page.getByText('VIP Access')).toBeVisible();
await expect(page.getByText('$150.00')).toBeVisible();
await expect(page.getByText('0 / 50 sold')).toBeVisible();
});
test('should create paused ticket type successfully', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form
await page.fill('input[name="name"]', 'Early Bird');
await page.fill('input[type="number"][step="0.01"]', '75.00');
await page.fill('input[name="inventory"]', '25');
// Select paused status
await page.click('[role="combobox"]');
await page.click('button[role="option"]:has-text("Paused")');
// Submit form
await page.click('button[type="submit"]');
// Wait for success
await expect(page.getByText(/Early Bird.*created successfully/)).toBeVisible({ timeout: 10000 });
// Check that new ticket type appears with paused status
await expect(page.getByText('Early Bird')).toBeVisible();
await expect(page.getByText('paused')).toBeVisible();
});
test('should handle form reset when cancelled', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form partially
await page.fill('input[name="name"]', 'Test Ticket');
await page.fill('input[type="number"][step="0.01"]', '50.00');
// Cancel modal
await page.click('button:has-text("Cancel")');
// Modal should close
await expect(page.getByRole('dialog')).not.toBeVisible();
// Reopen modal and check form is reset
await page.click('[data-testid="add-ticket-type-button"]');
await expect(page.locator('input[name="name"]')).toHaveValue('');
await expect(page.locator('input[type="number"][step="0.01"]')).toHaveValue('');
});
test('should close modal with escape key', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
await expect(page.getByRole('dialog')).toBeVisible();
// Press escape
await page.keyboard.press('Escape');
// Modal should close
await expect(page.getByRole('dialog')).not.toBeVisible();
});
test('should show permission error for unauthorized users', async ({ page }) => {
// Logout and login as regular user (assuming they don't have tickets:write permission)
await page.goto('/login');
await page.fill('[data-testid="email-input"]', 'user@test.com');
await page.fill('[data-testid="password-input"]', 'password');
await page.click('[data-testid="login-button"]');
// Navigate to event detail page
await page.goto('/events/evt-1');
// Add Ticket Type button should not be visible for regular users
await expect(page.getByTestId('add-ticket-type-button')).not.toBeVisible();
});
test('should handle loading states correctly', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form
await page.fill('input[name="name"]', 'Loading Test');
await page.fill('input[type="number"][step="0.01"]', '30.00');
await page.fill('input[name="inventory"]', '75');
// Submit form and check loading state
await page.click('button[type="submit"]');
// Submit button should show loading state
await expect(page.locator('button[type="submit"]')).toBeDisabled();
// Wait for completion
await expect(page.getByText(/created successfully/)).toBeVisible({ timeout: 10000 });
});
test('should create free ticket (price = 0) successfully', async ({ page }) => {
await page.click('[data-testid="add-ticket-type-button"]');
// Fill form with free ticket
await page.fill('input[name="name"]', 'Free Community Pass');
await page.fill('input[type="number"][step="0.01"]', '0.00');
await page.fill('input[name="inventory"]', '200');
// Submit form
await page.click('button[type="submit"]');
// Should succeed without price validation error
await expect(page.getByText(/Free Community Pass.*created successfully/)).toBeVisible({ timeout: 10000 });
// Check that ticket appears with $0.00 price
await expect(page.getByText('Free Community Pass')).toBeVisible();
await expect(page.getByText('$0.00')).toBeVisible();
});
});