Initialize fork and rebrand app to event_manager
CI / Server (push) Has been cancelled
Linters / Frappe Linter (push) Has been cancelled
Linters / Vulnerable Dependency Check (push) Has been cancelled
UI Tests / Playwright E2E Tests (push) Has been cancelled

This commit is contained in:
2026-05-11 09:56:57 +02:00
parent f82bb803ac
commit 786cbc724f
500 changed files with 41152 additions and 2 deletions
+120
View File
@@ -0,0 +1,120 @@
import { expect, Locator, Page } from "@playwright/test";
export class BookingPage {
private page: Page;
attendeeNameInput: Locator;
attendeeEmailInput: Locator;
ticketTypeSelect: Locator;
addOnCheckboxes: Locator;
private bookButton: Locator;
private addAttendeeButton: Locator;
private bookingForm: Locator;
private summarySection: Locator;
constructor(page: Page) {
this.page = page;
// Form elements
this.attendeeNameInput = page
.locator('input[placeholder*="name" i], input[name*="name" i]')
.first();
this.attendeeEmailInput = page
.locator('input[type="email"], input[placeholder*="email" i]')
.first();
this.ticketTypeSelect = page.locator('select, [data-testid="ticket-type"]').first();
// Add-ons
this.addOnCheckboxes = page.locator('input[type="checkbox"]');
// Buttons
this.bookButton = page.locator('button[type="submit"]');
this.addAttendeeButton = page.locator('button:has-text("Add Another Attendee")');
// Sections
this.bookingForm = page.locator("form");
this.summarySection = page.locator('[class*="summary" i]').first();
}
// Navigate to the booking page for a specific event.
async goto(eventRoute: string): Promise<void> {
await this.page.goto(`/dashboard/book-tickets/${eventRoute}`);
await this.page.waitForLoadState("networkidle");
}
// Wait for the booking form to fully load.
async waitForFormLoad(): Promise<void> {
await expect(this.bookingForm).toBeVisible({ timeout: 15000 });
}
// Fill in attendee details.
async fillAttendeeDetails(name: string, email: string): Promise<void> {
await this.attendeeNameInput.fill(name);
await this.attendeeEmailInput.fill(email);
}
// Select a ticket type by its visible text.
async selectTicketType(ticketTitle: string): Promise<void> {
const ticketOption = this.page.locator(`text=${ticketTitle}`).first();
if (await ticketOption.isVisible()) {
await ticketOption.click();
}
}
/**
* Toggle an add-on by its title.
*/
async toggleAddOn(addOnTitle: string): Promise<void> {
const addOnLabel = this.page.locator(`label:has-text("${addOnTitle}")`).first();
if (await addOnLabel.isVisible()) {
await addOnLabel.click();
}
}
// Add another attendee to the booking.
async addAnotherAttendee(): Promise<void> {
await this.addAttendeeButton.click();
}
// Submit the booking form.
async submit(): Promise<void> {
await this.bookButton.click();
}
// Get the booking button text.
async getBookButtonText(): Promise<string | null> {
return this.bookButton.textContent();
}
// Assert that the booking form is visible.
async expectFormVisible(): Promise<void> {
await expect(this.bookingForm).toBeVisible();
}
// Assert that ticket types are displayed.
async expectTicketTypesVisible(): Promise<void> {
// Check for any ticket-related content
const ticketContent = this.page
.locator('[class*="ticket"], select, input[type="radio"]')
.first();
await expect(ticketContent).toBeVisible({ timeout: 10000 });
}
// Assert that add-ons are displayed.
async expectAddOnsVisible(): Promise<void> {
const addOnCount = await this.addOnCheckboxes.count();
expect(addOnCount).toBeGreaterThan(0);
}
// Assert that the book button is visible with expected text.
async expectBookButtonVisible(): Promise<void> {
await expect(this.bookButton).toBeVisible();
const text = await this.bookButton.textContent();
expect(text?.match(/Book|Pay|Register/i)).toBeTruthy();
}
// Get the count of attendee forms on the page.
async getAttendeeCount(): Promise<number> {
const attendeeForms = this.page.locator('[class*="attendee"], [class*="Attendee"]');
return await attendeeForms.count();
}
}
+96
View File
@@ -0,0 +1,96 @@
import { expect, Locator, Page } from "@playwright/test";
export class CustomFormPage {
private page: Page;
private form: Locator;
private submitButton: Locator;
private successBanner: Locator;
private closedBanner: Locator;
private errorBanner: Locator;
constructor(page: Page) {
this.page = page;
this.form = page.locator("form");
this.submitButton = page.locator('button[type="submit"]').filter({ hasText: /^Submit$/ });
this.successBanner = page.locator(".bg-surface-green-1");
this.closedBanner = page.locator(".bg-surface-orange-1");
this.errorBanner = page.locator(".bg-surface-amber-1");
}
async goto(eventRoute: string, formRoute: string): Promise<void> {
await this.page.goto(`/dashboard/events/${eventRoute}/forms/${formRoute}`);
await this.page.waitForLoadState("networkidle");
}
async waitForFormLoad(): Promise<void> {
await expect(this.form).toBeVisible({ timeout: 15000 });
}
getInputByLabel(label: string): Locator {
return this.page
.locator(`label:has-text("${label}")`)
.locator("..")
.locator("input, textarea, select")
.first();
}
async submit(): Promise<void> {
await this.submitButton.click();
}
async expectFormVisible(): Promise<void> {
await expect(this.form).toBeVisible();
}
async expectFormTitle(title: string): Promise<void> {
await expect(this.page.locator(`h1:has-text("${title}")`)).toBeVisible();
}
async expectFieldVisible(label: string): Promise<void> {
await expect(this.page.locator(`label:has-text("${label}")`)).toBeVisible();
}
async expectSubmitButtonVisible(): Promise<void> {
await expect(this.submitButton).toBeVisible();
const text = await this.submitButton.textContent();
expect(text?.match(/Submit/i)).toBeTruthy();
}
async submitAndExpectResponse(): Promise<{ succeeded: boolean; status: number }> {
const responsePromise = this.page.waitForResponse(
(resp) => resp.url().includes("submit_custom_form"),
{ timeout: 20000 },
);
await this.submitButton.click();
const response = await responsePromise;
const status = response.status();
const succeeded = status === 200;
if (succeeded) {
await expect(this.successBanner).toBeVisible({ timeout: 15000 });
} else {
await expect(this.form).toBeVisible();
}
return { succeeded, status };
}
async expectSuccess(): Promise<void> {
await expect(this.successBanner).toBeVisible({ timeout: 15000 });
}
async expectClosed(): Promise<void> {
await expect(this.closedBanner).toBeVisible({ timeout: 15000 });
}
async expectNotFound(): Promise<void> {
await expect(this.errorBanner).toBeVisible({ timeout: 15000 });
}
async getFieldLabels(): Promise<string[]> {
const labels = this.page.locator("form label");
return labels.allTextContents();
}
}
+81
View File
@@ -0,0 +1,81 @@
import { expect, Locator, Page } from "@playwright/test";
export class EventProposalPage {
private page: Page;
private form: Locator;
private submitButton: Locator;
private successBanner: Locator;
private notFoundBanner: Locator;
constructor(page: Page) {
this.page = page;
this.form = page.locator("form");
this.submitButton = page.locator('button[type="submit"]').filter({ hasText: /^Submit$/ });
this.successBanner = page.locator(".bg-surface-green-1");
this.notFoundBanner = page.locator(".bg-surface-amber-1");
}
async goto(): Promise<void> {
await this.page.goto("/dashboard/event-proposal");
await this.page.waitForLoadState("networkidle");
}
async waitForFormLoad(): Promise<void> {
await expect(this.form).toBeVisible({ timeout: 15000 });
}
getInputByLabel(label: string): Locator {
return this.page
.locator(`label:has-text("${label}")`)
.locator("..")
.locator("input, textarea, select")
.first();
}
async expectFormVisible(): Promise<void> {
await expect(this.form).toBeVisible();
}
async expectBannerTitle(title: string): Promise<void> {
await expect(this.page.locator(`h1:has-text("${title}")`)).toBeVisible();
}
async expectFieldVisible(label: string): Promise<void> {
await expect(this.page.locator(`label:has-text("${label}")`)).toBeVisible();
}
async expectSubmitButtonVisible(): Promise<void> {
await expect(this.submitButton).toBeVisible();
}
async expectSuccess(): Promise<void> {
await expect(this.successBanner).toBeVisible({ timeout: 15000 });
}
async expectNotFound(): Promise<void> {
await expect(this.notFoundBanner).toBeVisible({ timeout: 15000 });
}
async submit(): Promise<void> {
await this.submitButton.click();
}
async submitAndExpectResponse(): Promise<{ succeeded: boolean; status: number }> {
const responsePromise = this.page.waitForResponse(
(resp) => resp.url().includes("submit_event_proposal"),
{ timeout: 20000 },
);
await this.submitButton.click();
const response = await responsePromise;
const status = response.status();
const succeeded = status === 200;
if (succeeded) {
await expect(this.successBanner).toBeVisible({ timeout: 15000 });
}
return { succeeded, status };
}
}
+4
View File
@@ -0,0 +1,4 @@
export { LoginPage } from "./login.page";
export { BookingPage } from "./booking.page";
export { CustomFormPage } from "./custom-form.page";
export { EventProposalPage } from "./event-proposal.page";
+69
View File
@@ -0,0 +1,69 @@
import { expect, Locator, Page } from "@playwright/test";
/**
* Page Object for the Frappe login page.
*/
export class LoginPage {
private page: Page;
private emailInput: Locator;
private passwordInput: Locator;
private submitButton: Locator;
private errorMessage: Locator;
constructor(page: Page) {
this.page = page;
// Frappe login page selectors
this.emailInput = page.locator("#login_email");
this.passwordInput = page.locator("#login_password");
this.submitButton = page.locator("button.btn-login");
this.errorMessage = page.locator(".msgprint, .alert-danger").first();
}
/**
* Navigate to the login page.
*/
async goto(): Promise<void> {
await this.page.goto("/login");
await this.page.waitForLoadState("networkidle");
}
/**
* Fill in the login form with credentials.
*/
async fillCredentials(email: string, password: string): Promise<void> {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
}
/**
* Submit the login form.
*/
async submit(): Promise<void> {
await this.submitButton.click();
}
/**
* Perform a complete login.
*/
async login(email = "Administrator", password = "admin"): Promise<void> {
await this.goto();
await this.fillCredentials(email, password);
await this.submit();
await this.page.waitForURL(/\/(app|desk|event_manager)/, { timeout: 30000 });
}
/**
* Assert that login failed with an error.
*/
async expectLoginError(): Promise<void> {
await expect(this.errorMessage).toBeVisible();
}
/**
* Assert that we're on the login page.
*/
async expectToBeOnLoginPage(): Promise<void> {
await expect(this.page).toHaveURL(/.*login.*/);
}
}