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:
378
test-ticket-creation-diagnosis.cjs
Normal file
378
test-ticket-creation-diagnosis.cjs
Normal file
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
* Playwright test to diagnose ticket creation button issues
|
||||
* on the event management page
|
||||
*/
|
||||
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
test('Diagnose ticket creation button issues', async ({ page }) => {
|
||||
// Enable console logging to catch React errors
|
||||
const consoleMessages = [];
|
||||
const consoleErrors = [];
|
||||
|
||||
page.on('console', msg => {
|
||||
const text = msg.text();
|
||||
consoleMessages.push({ type: msg.type(), text });
|
||||
|
||||
if (msg.type() === 'error') {
|
||||
consoleErrors.push(text);
|
||||
console.log(`❌ Console Error: ${text}`);
|
||||
} else if (msg.type() === 'warn') {
|
||||
console.log(`⚠️ Console Warning: ${text}`);
|
||||
} else if (text.includes('TicketsTab') || text.includes('ticket') || text.includes('React')) {
|
||||
console.log(`🔍 Relevant Console: [${msg.type()}] ${text}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Catch page errors
|
||||
page.on('pageerror', error => {
|
||||
console.log(`❌ Page Error: ${error.message}`);
|
||||
consoleErrors.push(`Page Error: ${error.message}`);
|
||||
});
|
||||
|
||||
console.log('🚀 Starting diagnosis...');
|
||||
|
||||
// Step 1: Navigate to login page
|
||||
console.log('📝 Step 1: Navigating to login page...');
|
||||
await page.goto('http://localhost:3000/login');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Step 2: Login with provided credentials
|
||||
console.log('🔐 Step 2: Logging in...');
|
||||
await page.fill('input[type="email"]', 'tyler@zest.is');
|
||||
await page.fill('input[type="password"]', 'Test123!');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Wait for redirect to dashboard
|
||||
await page.waitForURL('**/dashboard', { timeout: 10000 });
|
||||
console.log('✅ Successfully logged in and redirected to dashboard');
|
||||
|
||||
// Step 3: Find and navigate to an event management page
|
||||
console.log('🎪 Step 3: Looking for events to manage...');
|
||||
|
||||
// Wait for events to load
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Look for event links - try multiple selectors
|
||||
const eventSelectors = [
|
||||
'a[href*="/events/"][href*="/manage"]',
|
||||
'a[href*="/events/"]',
|
||||
'[data-testid="event-card"] a',
|
||||
'.event-card a',
|
||||
'.bg-white\\/10 a'
|
||||
];
|
||||
|
||||
let eventLinks = [];
|
||||
for (const selector of eventSelectors) {
|
||||
eventLinks = await page.locator(selector).all();
|
||||
if (eventLinks.length > 0) {
|
||||
console.log(`Found ${eventLinks.length} event links using selector: ${selector}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventLinks.length === 0) {
|
||||
console.log('⚠️ No event links found. Checking page content...');
|
||||
|
||||
// Get page title and URL for debugging
|
||||
const title = await page.title();
|
||||
const url = page.url();
|
||||
console.log(`Current page: ${title} at ${url}`);
|
||||
|
||||
// Try to find any clickable elements related to events
|
||||
const eventText = await page.locator('text=/event/i').all();
|
||||
console.log(`Found ${eventText.length} elements containing "event"`);
|
||||
|
||||
// Take a screenshot to see what's on the dashboard
|
||||
await page.screenshot({
|
||||
path: '/home/tyler/apps/bct-whitelabel/dashboard-state.png',
|
||||
fullPage: true
|
||||
});
|
||||
console.log('Dashboard screenshot saved as dashboard-state.png');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigate to first available event management page
|
||||
let eventManageUrl;
|
||||
const firstLink = eventLinks[0];
|
||||
eventManageUrl = await firstLink.getAttribute('href');
|
||||
|
||||
// Make sure it's a manage URL
|
||||
if (!eventManageUrl.includes('/manage')) {
|
||||
eventManageUrl = eventManageUrl + '/manage';
|
||||
}
|
||||
|
||||
console.log(`🎯 Step 4: Navigating to event management: ${eventManageUrl}`);
|
||||
await page.goto(`http://localhost:3000${eventManageUrl}`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Wait a bit for React components to mount
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Step 5: Check current tab and navigate to Ticketing & Access if needed
|
||||
console.log('📋 Step 5: Checking current tab...');
|
||||
|
||||
// Look for active tab first
|
||||
const activeTab = page.locator('.tab-active, [aria-selected="true"], .active').first();
|
||||
if (await activeTab.isVisible()) {
|
||||
const activeTabText = await activeTab.textContent();
|
||||
console.log(`Current active tab: "${activeTabText}"`);
|
||||
}
|
||||
|
||||
// Look for Ticketing & Access tab specifically
|
||||
const ticketingTabSelectors = [
|
||||
'text="Ticketing & Access"',
|
||||
'text="Tickets"',
|
||||
'[data-tab="tickets"]',
|
||||
'button:has-text("Ticket")',
|
||||
'a:has-text("Ticket")'
|
||||
];
|
||||
|
||||
let ticketingTab = null;
|
||||
for (const selector of ticketingTabSelectors) {
|
||||
ticketingTab = page.locator(selector).first();
|
||||
if (await ticketingTab.isVisible()) {
|
||||
console.log(`🎫 Found Ticketing tab using selector: ${selector}`);
|
||||
break;
|
||||
}
|
||||
ticketingTab = null;
|
||||
}
|
||||
|
||||
if (ticketingTab) {
|
||||
console.log('🎫 Clicking Ticketing & Access tab...');
|
||||
await ticketingTab.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check console for any new messages after tab click
|
||||
console.log('Checking for console messages after tab click...');
|
||||
} else {
|
||||
console.log('⚠️ Ticketing & Access tab not found. Available tabs:');
|
||||
|
||||
// List all tabs/buttons that might be tabs
|
||||
const potentialTabs = await page.locator('button, a[role="tab"], [class*="tab"]').all();
|
||||
for (let i = 0; i < Math.min(potentialTabs.length, 10); i++) {
|
||||
const tabText = await potentialTabs[i].textContent();
|
||||
const isVisible = await potentialTabs[i].isVisible();
|
||||
console.log(` Tab ${i + 1}: "${tabText}" (visible: ${isVisible})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6: Inspect DOM for TicketsTab component and React mounting
|
||||
console.log('🔍 Step 6: Inspecting DOM for React components...');
|
||||
|
||||
// Check for React component indicators
|
||||
const reactInspection = await page.evaluate(() => {
|
||||
// Check for React DevTools
|
||||
const hasReactDevTools = window.__REACT_DEVTOOLS_GLOBAL_HOOK__ !== undefined;
|
||||
|
||||
// Check for React roots
|
||||
const reactRoots = document.querySelectorAll('[data-reactroot]');
|
||||
|
||||
// Check for any elements with React-like attributes or classes
|
||||
const reactElements = document.querySelectorAll('[data-react*], [class*="react"], [class*="React"]');
|
||||
|
||||
// Look for TicketsTab specifically
|
||||
const ticketsTabElements = document.querySelectorAll('[class*="TicketsTab"], [data-component*="TicketsTab"], [data-testid*="tickets"]');
|
||||
|
||||
// Check for Astro islands (which contain React components)
|
||||
const astroIslands = document.querySelectorAll('astro-island');
|
||||
|
||||
// Check for script tags that might contain React components
|
||||
const reactScripts = Array.from(document.scripts)
|
||||
.map(s => s.src)
|
||||
.filter(src => src && (src.includes('react') || src.includes('React') || src.includes('tickets') || src.includes('TicketsTab')));
|
||||
|
||||
// Look for any divs that might be React mount points
|
||||
const mountPoints = document.querySelectorAll('div[id*="react"], div[id*="tickets"], div[data-*]');
|
||||
|
||||
return {
|
||||
hasReactDevTools,
|
||||
reactRootsCount: reactRoots.length,
|
||||
reactElementsCount: reactElements.length,
|
||||
ticketsTabElementsCount: ticketsTabElements.length,
|
||||
astroIslandsCount: astroIslands.length,
|
||||
reactScripts,
|
||||
mountPointsCount: mountPoints.length,
|
||||
bodyClasses: document.body.className,
|
||||
documentTitle: document.title
|
||||
};
|
||||
});
|
||||
|
||||
console.log('React Environment Check:', JSON.stringify(reactInspection, null, 2));
|
||||
|
||||
// Step 7: Look for ticket creation buttons with detailed search
|
||||
console.log('🔘 Step 7: Looking for ticket creation buttons...');
|
||||
|
||||
const buttonSelectors = [
|
||||
'text="Create Your First Ticket Type"',
|
||||
'text="Add Ticket Type"',
|
||||
'text="Create Ticket"',
|
||||
'button:has-text("ticket")',
|
||||
'button:has-text("Ticket")',
|
||||
'button[class*="ticket"]',
|
||||
'[data-testid*="ticket"] button',
|
||||
'.ticket button',
|
||||
'button:has-text("Add")',
|
||||
'button:has-text("Create")'
|
||||
];
|
||||
|
||||
const allButtons = [];
|
||||
for (const selector of buttonSelectors) {
|
||||
const buttons = await page.locator(selector).all();
|
||||
if (buttons.length > 0) {
|
||||
console.log(`Found ${buttons.length} buttons with selector: ${selector}`);
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
const button = buttons[i];
|
||||
const text = await button.textContent();
|
||||
const isVisible = await button.isVisible();
|
||||
const isEnabled = await button.isEnabled();
|
||||
allButtons.push({ button, text, isVisible, isEnabled, selector });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Total potential ticket creation buttons found: ${allButtons.length}`);
|
||||
|
||||
// Step 8: Try to find the actual TicketsTab component mount point
|
||||
console.log('⚛️ Step 8: Looking for TicketsTab component mount points...');
|
||||
|
||||
// Check for Astro islands that might contain the TicketsTab
|
||||
const astroIslands = await page.locator('astro-island').all();
|
||||
console.log(`Found ${astroIslands.length} Astro islands`);
|
||||
|
||||
for (let i = 0; i < astroIslands.length; i++) {
|
||||
const island = astroIslands[i];
|
||||
const componentName = await island.getAttribute('component-export');
|
||||
const componentUrl = await island.getAttribute('component-url');
|
||||
const props = await island.getAttribute('props');
|
||||
|
||||
console.log(`Island ${i + 1}:`);
|
||||
console.log(` Component: ${componentName}`);
|
||||
console.log(` URL: ${componentUrl}`);
|
||||
console.log(` Props: ${props}`);
|
||||
|
||||
if (componentName && componentName.includes('TicketsTab')) {
|
||||
console.log(`🎯 Found TicketsTab component island!`);
|
||||
|
||||
// Check if the island has rendered content
|
||||
const islandContent = await island.innerHTML();
|
||||
console.log(` Island content length: ${islandContent.length}`);
|
||||
console.log(` Island content preview: ${islandContent.substring(0, 200)}...`);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 9: Check for specific TicketsTab content
|
||||
console.log('🎫 Step 9: Searching for TicketsTab-specific content...');
|
||||
|
||||
// Look for text that should be in TicketsTab
|
||||
const ticketTabContent = [
|
||||
'No ticket types created yet',
|
||||
'Create Your First Ticket Type',
|
||||
'Ticket Types',
|
||||
'Add Ticket Type',
|
||||
'General Admission',
|
||||
'VIP',
|
||||
'Early Bird'
|
||||
];
|
||||
|
||||
for (const content of ticketTabContent) {
|
||||
const element = page.locator(`text="${content}"`).first();
|
||||
const isVisible = await element.isVisible();
|
||||
if (isVisible) {
|
||||
console.log(`✅ Found TicketsTab content: "${content}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 10: Try clicking ticket creation buttons if found
|
||||
console.log('🖱️ Step 10: Attempting to interact with ticket creation buttons...');
|
||||
|
||||
const workingButtons = allButtons.filter(b => b.isVisible && b.isEnabled);
|
||||
console.log(`Found ${workingButtons.length} clickable buttons`);
|
||||
|
||||
if (workingButtons.length > 0) {
|
||||
const button = workingButtons[0];
|
||||
console.log(`Attempting to click: "${button.text}" (${button.selector})`);
|
||||
|
||||
// Monitor console messages during click
|
||||
const beforeClickMessages = consoleMessages.length;
|
||||
|
||||
try {
|
||||
await button.button.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check for new console messages
|
||||
const newMessages = consoleMessages.slice(beforeClickMessages);
|
||||
if (newMessages.length > 0) {
|
||||
console.log('New console messages after click:');
|
||||
newMessages.forEach(msg => console.log(` [${msg.type}] ${msg.text}`));
|
||||
}
|
||||
|
||||
// Check if a modal or form appeared
|
||||
const modalSelectors = [
|
||||
'[role="dialog"]',
|
||||
'.modal',
|
||||
'[class*="modal"]',
|
||||
'[class*="popup"]',
|
||||
'[data-testid*="modal"]'
|
||||
];
|
||||
|
||||
for (const selector of modalSelectors) {
|
||||
const modals = await page.locator(selector).all();
|
||||
if (modals.length > 0) {
|
||||
console.log(`✅ Found ${modals.length} modals after click using selector: ${selector}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(`❌ Error clicking button: ${error.message}`);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ No clickable ticket creation buttons found');
|
||||
}
|
||||
|
||||
// Step 11: Final diagnosis and screenshot
|
||||
console.log('\n📊 FINAL DIAGNOSIS:');
|
||||
console.log('='.repeat(60));
|
||||
console.log(`Console Errors: ${consoleErrors.length}`);
|
||||
if (consoleErrors.length > 0) {
|
||||
console.log('Console Errors:');
|
||||
consoleErrors.forEach((error, i) => console.log(` ${i + 1}. ${error}`));
|
||||
}
|
||||
|
||||
console.log(`\nTotal Console Messages: ${consoleMessages.length}`);
|
||||
console.log(`React DevTools Available: ${reactInspection.hasReactDevTools ? '✅' : '❌'}`);
|
||||
console.log(`Astro Islands Found: ${reactInspection.astroIslandsCount}`);
|
||||
console.log(`React Elements Found: ${reactInspection.reactElementsCount}`);
|
||||
console.log(`TicketsTab Elements Found: ${reactInspection.ticketsTabElementsCount}`);
|
||||
console.log(`Potential Ticket Buttons: ${allButtons.length}`);
|
||||
console.log(`Clickable Ticket Buttons: ${allButtons.filter(b => b.isVisible && b.isEnabled).length}`);
|
||||
|
||||
// Check for specific console messages that indicate the problem
|
||||
const ticketTabMessages = consoleMessages.filter(msg =>
|
||||
msg.text.includes('TicketsTab') ||
|
||||
msg.text.includes('tickets') ||
|
||||
msg.text.includes('React') ||
|
||||
msg.text.includes('component')
|
||||
);
|
||||
|
||||
if (ticketTabMessages.length === 0) {
|
||||
console.log('\n🚨 CRITICAL FINDING: No TicketsTab console messages detected!');
|
||||
console.log('This suggests the TicketsTab React component is not mounting at all.');
|
||||
} else {
|
||||
console.log('\nTicketsTab related console messages:');
|
||||
ticketTabMessages.forEach(msg => console.log(` [${msg.type}] ${msg.text}`));
|
||||
}
|
||||
|
||||
// Take final screenshot
|
||||
console.log('\n📸 Taking final screenshot...');
|
||||
await page.screenshot({
|
||||
path: '/home/tyler/apps/bct-whitelabel/ticket-creation-final-diagnosis.png',
|
||||
fullPage: true
|
||||
});
|
||||
console.log('Screenshot saved as: ticket-creation-final-diagnosis.png');
|
||||
|
||||
// Keep browser open briefly for manual inspection
|
||||
console.log('\n🔍 Diagnosis complete. Check the screenshots and console output above.');
|
||||
await page.waitForTimeout(5000);
|
||||
});
|
||||
Reference in New Issue
Block a user