353 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { STAGING_URL, PATHS, TIMEOUTS } from './config/staging-config';
 | |
| import { test, expect } from '@playwright/test';
 | |
| import { LoginPage } from './pages/LoginPage';
 | |
| import { DashboardPage } from './pages/DashboardPage';
 | |
| import { CreateEventPage } from './pages/CreateEventPage';
 | |
| import { EventSummaryPage } from './pages/EventSummaryPage';
 | |
| import { ModifyEventPage } from './pages/ModifyEventPage';
 | |
| import { TEST_USERS } from './data/test-users';
 | |
| import { TEST_EVENTS } from './data/test-events';
 | |
| 
 | |
| // STAGING_URL is now imported from config
 | |
| 
 | |
| test.describe('Trainer User Journey - Updated', () => {
 | |
|     let loginPage: LoginPage;
 | |
|     let dashboardPage: DashboardPage;
 | |
|     let createEventPage: CreateEventPage;
 | |
|     let eventSummaryPage: EventSummaryPage;
 | |
|     let modifyEventPage: ModifyEventPage;
 | |
|     
 | |
|     const trainer = TEST_USERS.trainer;
 | |
| 
 | |
|     test.beforeEach(async ({ page }) => {
 | |
|         loginPage = new LoginPage(page);
 | |
|         dashboardPage = new DashboardPage(page);
 | |
|         createEventPage = new CreateEventPage(page);
 | |
|         eventSummaryPage = new EventSummaryPage(page);
 | |
|         modifyEventPage = new ModifyEventPage(page);
 | |
|         
 | |
|         // Set base URL
 | |
|         page.context().setDefaultNavigationTimeout(TIMEOUTS.navigation);
 | |
|         await page.goto(STAGING_URL);
 | |
|     });
 | |
| 
 | |
|     test('Step 1 & 2: Trainer Login', async ({ page }) => {
 | |
|         // Navigate to login page
 | |
|         await loginPage.navigateToLogin();
 | |
|         await expect(page).toHaveURL(/.*community-login/);
 | |
|         
 | |
|         // Verify login form is visible
 | |
|         expect(await loginPage.isLoginFormVisible()).toBe(true);
 | |
|         
 | |
|         // Login with test trainer credentials
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         
 | |
|         // Verify successful login and redirect to dashboard
 | |
|         await expect(page).toHaveURL(/.*hvac-dashboard/);
 | |
|         await page.screenshot({ path: 'test-results/screenshots/login-success.png' });
 | |
|     });
 | |
| 
 | |
|     test('Step 3: Access Dashboard', async ({ page }) => {
 | |
|         // Login first
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         
 | |
|         // Wait for dashboard to load
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         await expect(page).toHaveURL(/hvac-dashboard/);
 | |
|         
 | |
|         // Verify dashboard elements are visible
 | |
|         expect(await dashboardPage.isEventsTableVisible()).toBe(true);
 | |
|         
 | |
|         // Get and verify statistics
 | |
|         const stats = await dashboardPage.getStatistics();
 | |
|         expect(stats.totalEvents).toBeDefined();
 | |
|         expect(stats.upcomingEvents).toBeDefined();
 | |
|         expect(stats.pastEvents).toBeDefined();
 | |
|         expect(stats.revenue).toBeDefined();
 | |
|         
 | |
|         await page.screenshot({ path: 'test-results/screenshots/dashboard-view.png' });
 | |
|     });
 | |
| 
 | |
|     test('Step 4a: Create Event', async ({ page }) => {
 | |
|         // Login and navigate to dashboard
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         
 | |
|         // Click create event button
 | |
|         await dashboardPage.clickCreateEvent();
 | |
|         await expect(page).toHaveURL(/.*manage-event/);
 | |
|         
 | |
|         // Fill event details
 | |
|         const eventData = TEST_EVENTS.basicEvent;
 | |
|         await createEventPage.fillEventDetails(eventData);
 | |
|         
 | |
|         // Submit event
 | |
|         await createEventPage.submitEvent();
 | |
|         
 | |
|         // Wait for the page to update after submission
 | |
|         await page.waitForTimeout(3000);
 | |
|         
 | |
|         // Verify submission - we remain on the manage-event page but with different content
 | |
|         await expect(page).toHaveURL(/manage-event/);
 | |
|         
 | |
|         // Check for success indicator - the button is all caps
 | |
|         const viewYourEventsButtonVisible = await page.locator('text="VIEW YOUR SUBMITTED EVENTS"').isVisible().catch(() => false);
 | |
|         console.log('View Your Events Button Visible:', viewYourEventsButtonVisible);
 | |
|         
 | |
|         // Alternative check - the form updated, showing the event title is filled
 | |
|         const titleFilled = await page.locator('input[name="post_title"]').inputValue();
 | |
|         console.log('Title field value:', titleFilled);
 | |
|         
 | |
|         expect(viewYourEventsButtonVisible).toBeTruthy();
 | |
|         
 | |
|         await page.screenshot({ path: 'test-results/screenshots/event-created.png' });
 | |
|     });
 | |
| 
 | |
|     test('Step 4b: Manage Events - View Event List', async ({ page }) => {
 | |
|         // Login
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         
 | |
|         // Navigate to My Events instead of dashboard
 | |
|         await page.goto(`${STAGING_URL}/my-events/`);
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         
 | |
|         // Check upcoming events
 | |
|         const upcomingMessage = await page.locator('text="You have no upcoming events"').isVisible();
 | |
|         
 | |
|         // Check past events
 | |
|         await page.click('a:has-text("PAST EVENTS")');
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         
 | |
|         // Look for events in the past events tab
 | |
|         const eventRows = page.locator('tr.community-events-event-row');
 | |
|         const rowCount = await eventRows.count();
 | |
|         
 | |
|         if (rowCount > 0) {
 | |
|             const firstRow = eventRows.first();
 | |
|             const title = await firstRow.locator('a.url').innerText();
 | |
|             console.log('Found past event:', title);
 | |
|             
 | |
|             await page.screenshot({ path: 'test-results/screenshots/past-events-list.png' });
 | |
|         }
 | |
|         
 | |
|         // Verify filter tabs are present
 | |
|         const filterTabs = ['UPCOMING EVENTS', 'PAST EVENTS'];
 | |
|         for (const filter of filterTabs) {
 | |
|             const filterVisible = await page.locator(`a:has-text("${filter}")`).isVisible();
 | |
|             expect(filterVisible).toBe(true);
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     test('Step 4c: Manage Events - Modify Event from Past Events', async ({ page }) => {
 | |
|         // Login and navigate to My Events
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         await page.goto(`${STAGING_URL}/my-events/`);
 | |
|         
 | |
|         // Go to past events tab
 | |
|         await page.click('a:has-text("PAST EVENTS")');
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         
 | |
|         // Get the first past event
 | |
|         const eventRows = page.locator('tr.community-events-event-row');
 | |
|         const rowCount = await eventRows.count();
 | |
|         
 | |
|         if (rowCount > 0) {
 | |
|             // Click the Edit link in the first row
 | |
|             const firstRow = eventRows.first();
 | |
|             const editLink = firstRow.locator('a:has-text("Edit")');
 | |
|             
 | |
|             if (await editLink.count() > 0) {
 | |
|                 await editLink.click();
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 
 | |
|                 const modifyUrl = page.url();
 | |
|                 console.log('Modify page URL:', modifyUrl);
 | |
|                 await page.screenshot({ path: 'test-results/screenshots/modify-event-page.png' });
 | |
|                 
 | |
|                 // Modify event details
 | |
|                 const updatedEvent = {
 | |
|                     ...TEST_EVENTS.basicEvent,
 | |
|                     title: 'Updated Event Title',
 | |
|                     description: 'This event has been modified for testing.'
 | |
|                 };
 | |
|                 
 | |
|                 // Clear existing fields and fill new values
 | |
|                 await page.fill('input[name="post_title"]', updatedEvent.title);
 | |
|                 
 | |
|                 // Update description in TinyMCE
 | |
|                 try {
 | |
|                     const frame = page.frameLocator('iframe[id$="_ifr"]');
 | |
|                     await frame.locator('body').fill(updatedEvent.description);
 | |
|                 } catch (e) {
 | |
|                     // Fallback to textarea
 | |
|                     await page.fill('textarea[name="post_content"]', updatedEvent.description);
 | |
|                 }
 | |
|                 
 | |
|                 // Look for update button
 | |
|                 const updateButtonVisible = await page.locator('input[name="community-event"][value="Update"]').isVisible();
 | |
|                 
 | |
|                 if (updateButtonVisible) {
 | |
|                     await page.click('input[name="community-event"][value="Update"]');
 | |
|                 } else {
 | |
|                     await page.click('input[name="community-event"][value="Submit Event"]');
 | |
|                 }
 | |
|                 
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 await page.screenshot({ path: 'test-results/screenshots/event-updated.png' });
 | |
|                 
 | |
|                 // Verify update by going back to My Events
 | |
|                 await page.goto(`${STAGING_URL}/my-events/`);
 | |
|                 await page.click('a:has-text("PAST EVENTS")');
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 
 | |
|                 const updatedTitle = await eventRows.first().locator('a.url').innerText();
 | |
|                 console.log('Updated event title:', updatedTitle);
 | |
|             }
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     test('Step 4d: Manage Events - Delete Event', async ({ page }) => {
 | |
|         // Login and navigate to My Events
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         await page.goto(`${STAGING_URL}/my-events/`);
 | |
|         
 | |
|         // Go to past events tab
 | |
|         await page.click('a:has-text("PAST EVENTS")');
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         
 | |
|         // Get initial event count
 | |
|         const eventRows = page.locator('tr.community-events-event-row');
 | |
|         const initialCount = await eventRows.count();
 | |
|         console.log('Initial event count:', initialCount);
 | |
|         
 | |
|         if (initialCount > 0) {
 | |
|             // Click Edit on the first event
 | |
|             const firstRow = eventRows.first();
 | |
|             const editLink = firstRow.locator('a:has-text("Edit")');
 | |
|             
 | |
|             if (await editLink.count() > 0) {
 | |
|                 await editLink.click();
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 
 | |
|                 // Look for delete link/button
 | |
|                 const deleteLink = page.locator('a:has-text("Delete Event")');
 | |
|                 const deleteButton = page.locator('button:has-text("Delete")');
 | |
|                 
 | |
|                 if (await deleteLink.count() > 0) {
 | |
|                     await deleteLink.click();
 | |
|                     // Handle confirmation if present
 | |
|                     const confirmButton = page.locator('button:has-text("Yes, Delete")');
 | |
|                     if (await confirmButton.isVisible()) {
 | |
|                         await confirmButton.click();
 | |
|                     }
 | |
|                 } else if (await deleteButton.count() > 0) {
 | |
|                     await deleteButton.click();
 | |
|                     // Handle confirmation if present
 | |
|                     const confirmButton = page.locator('button:has-text("Yes, Delete")');
 | |
|                     if (await confirmButton.isVisible()) {
 | |
|                         await confirmButton.click();
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 await page.screenshot({ path: 'test-results/screenshots/event-deleted.png' });
 | |
|                 
 | |
|                 // Go back to My Events to verify deletion
 | |
|                 await page.goto(`${STAGING_URL}/my-events/`);
 | |
|                 await page.click('a:has-text("PAST EVENTS")');
 | |
|                 await page.waitForLoadState('networkidle');
 | |
|                 
 | |
|                 const finalCount = await eventRows.count();
 | |
|                 console.log('Final event count:', finalCount);
 | |
|                 expect(finalCount).toBeLessThanOrEqual(initialCount);
 | |
|             }
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     test('Step 5: View Event Details from Past Events', async ({ page }) => {
 | |
|         // Login and navigate to My Events
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login(trainer.username, trainer.password);
 | |
|         await page.goto(`${STAGING_URL}/my-events/`);
 | |
|         
 | |
|         // Go to past events tab
 | |
|         await page.click('a:has-text("PAST EVENTS")');
 | |
|         await page.waitForLoadState('networkidle');
 | |
|         
 | |
|         // Get the first past event
 | |
|         const eventRows = page.locator('tr.community-events-event-row');
 | |
|         const rowCount = await eventRows.count();
 | |
|         
 | |
|         if (rowCount > 0) {
 | |
|             // Click on the event title
 | |
|             const firstRow = eventRows.first();
 | |
|             const eventLink = firstRow.locator('a.url');
 | |
|             const eventTitle = await eventLink.innerText();
 | |
|             console.log('Viewing event:', eventTitle);
 | |
|             
 | |
|             await eventLink.click();
 | |
|             await page.waitForLoadState('networkidle');
 | |
|             
 | |
|             const eventUrl = page.url();
 | |
|             console.log('Event detail URL:', eventUrl);
 | |
|             await page.screenshot({ path: 'test-results/screenshots/event-detail-page.png' });
 | |
|             
 | |
|             // Check for event details on the page
 | |
|             const titleElement = page.locator('h1, h2').first();
 | |
|             const titleText = await titleElement.innerText();
 | |
|             expect(titleText).toBeTruthy();
 | |
|             
 | |
|             // Look for event metadata
 | |
|             const dateInfo = page.locator('.tribe-events-event-meta');
 | |
|             const hasDateInfo = await dateInfo.count() > 0;
 | |
|             expect(hasDateInfo).toBe(true);
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     // Phase 2 and Phase 3 tests remain skipped
 | |
|     test.skip('Step 9: Email Communication (Phase 2)', async ({ page }) => {
 | |
|         // This will be implemented when Phase 2 is deployed
 | |
|     });
 | |
| 
 | |
|     test.skip('Step 10: Attendee Check-in', async ({ page }) => {
 | |
|         // This will be implemented when the feature is available
 | |
|     });
 | |
| 
 | |
|     test.skip('Step 11: Certificate Generation (Phase 3)', async ({ page }) => {
 | |
|         // This will be implemented when Phase 3 is deployed
 | |
|     });
 | |
| });
 | |
| 
 | |
| // Error Scenario Tests
 | |
| test.describe('Trainer Journey - Error Scenarios', () => {
 | |
|     let loginPage: LoginPage;
 | |
|     
 | |
|     test.beforeEach(async ({ page }) => {
 | |
|         loginPage = new LoginPage(page);
 | |
|         await page.goto(STAGING_URL);
 | |
|     });
 | |
| 
 | |
|     test('Invalid Login Credentials', async ({ page }) => {
 | |
|         await loginPage.navigateToLogin();
 | |
|         await loginPage.login('invalid_user', 'wrong_password');
 | |
|         
 | |
|         // Should remain on login page
 | |
|         await expect(page).toHaveURL(/.*community-login/);
 | |
|         
 | |
|         // Error message should be visible
 | |
|         const errorMessage = await loginPage.getErrorMessage();
 | |
|         expect(errorMessage).toContain('Invalid username or password');
 | |
|     });
 | |
| 
 | |
|     test('Access Dashboard Without Login', async ({ page }) => {
 | |
|         // Try to access dashboard directly
 | |
|         await page.goto(PATHS.dashboard);
 | |
|         
 | |
|         // Should be redirected to login
 | |
|         await expect(page).toHaveURL(/.*community-login/);
 | |
|     });
 | |
| }); |