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