chore: perauset customer project

This commit is contained in:
e2e
2026-07-11 08:54:43 +02:00
commit 49d05dfa0b
293 changed files with 28421 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
import { World, setWorldConstructor, type IWorldOptions } from '@cucumber/cucumber'
import { chromium, type Browser, type BrowserContext, type Page } from 'playwright'
import { expect } from '@playwright/test'
import { browserConfig } from './browser-config.js'
export class BrowserWorld extends World {
browser: Browser | null = null
context: BrowserContext | null = null
page: Page | null = null
constructor(options: IWorldOptions) {
super(options)
}
async openBrowser(): Promise<void> {
this.browser = await chromium.launch({
headless: !browserConfig.headed,
})
this.context = await this.browser.newContext({
viewport: { width: 1280, height: 720 },
})
this.page = await this.context.newPage()
this.page.setDefaultTimeout(browserConfig.timeout)
}
async closeBrowser(): Promise<void> {
if (this.page) {
await this.page.close().catch(() => {})
this.page = null
}
if (this.context) {
await this.context.close().catch(() => {})
this.context = null
}
if (this.browser) {
await this.browser.close().catch(() => {})
this.browser = null
}
}
async login(email: string): Promise<void> {
const page = this.getPage()
await page.goto(`${browserConfig.appUrl}/login`, { waitUntil: 'networkidle' })
// The login page pre-fills demo credentials; overwrite with the test user.
const emailInput = page.locator('input[type="email"]')
await emailInput.fill(email)
const passwordInput = page.locator('input[type="password"]')
await passwordInput.fill('test')
await page.getByRole('button', { name: /sign in/i }).click()
// Wait for redirect away from /login, then for the app shell heading.
await page.waitForURL((url) => !url.pathname.includes('/login'), { timeout: 60_000 })
await page.getByRole('heading', { name: 'Dashboard' }).first().waitFor({ state: 'visible', timeout: 30_000 })
}
async navigateTo(path: string): Promise<void> {
const page = this.getPage()
await page.goto(`${browserConfig.appUrl}${path}`, { waitUntil: 'networkidle', timeout: 30_000 })
// Wait for client components to hydrate
await page.waitForTimeout(1000)
}
async clickLink(name: string): Promise<void> {
const page = this.getPage()
await page.getByRole('link', { name }).click()
// Small wait for navigation
await page.waitForLoadState('networkidle')
}
async clickButton(name: string): Promise<void> {
const page = this.getPage()
const btn = page.getByRole('button', { name, exact: true })
const count = await btn.count()
if (count > 1) {
// Multiple buttons — close any open dropdowns first, then click the last one (in drawer)
await page.keyboard.press('Escape')
await page.waitForTimeout(300)
// Re-query after Escape (drawer might have closed)
const btn2 = page.getByRole('button', { name, exact: true })
const count2 = await btn2.count()
const target = count2 > 1 ? btn2.nth(count2 - 1) : btn2
await target.scrollIntoViewIfNeeded()
await target.click({ timeout: 10_000 })
} else {
await btn.scrollIntoViewIfNeeded()
await btn.click({ timeout: 10_000 })
}
await page.waitForTimeout(500)
}
async fillField(label: string, value: string): Promise<void> {
const page = this.getPage()
const scope =
(await page.getByRole('dialog').count()) > 0
? page.getByRole('dialog')
: page
const control = page.locator('input:not([type="hidden"]), textarea')
let input = scope.getByLabel(label, { exact: true }).and(control)
if ((await input.count()) === 0) {
input = scope.getByLabel(label).and(control)
}
const field = input.first()
await field.clear()
await field.fill(value)
}
async selectOption(label: string, value: string): Promise<void> {
const page = this.getPage()
const scope =
(await page.getByRole('dialog').count()) > 0
? page.getByRole('dialog')
: page
const control = page.locator('input, [role="combobox"], select')
let input = scope.getByLabel(label, { exact: true }).and(control)
if ((await input.count()) === 0) {
input = scope.getByLabel(label).and(control)
}
await input.first().click()
await page.getByRole('option', { name: value, exact: true }).first().click()
}
async expectText(text: string): Promise<void> {
const page = this.getPage()
await expect(page.getByText(text, { exact: false }).first()).toBeVisible({ timeout: 10_000 })
}
async expectNoText(text: string): Promise<void> {
const page = this.getPage()
await expect(page.getByText(text, { exact: false })).not.toBeVisible({ timeout: 5_000 })
}
async expectHeading(text: string): Promise<void> {
const page = this.getPage()
await expect(page.getByRole('heading', { name: text }).first()).toBeVisible({ timeout: 10_000 })
}
getPage(): Page {
if (!this.page) {
throw new Error('Browser not open — did the Before hook run?')
}
return this.page
}
}
setWorldConstructor(BrowserWorld)