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/); }); });