chore: kanban template

This commit is contained in:
e2e
2026-06-21 21:47:10 +02:00
commit 908a5eae6c
209 changed files with 215578 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
import { World, setWorldConstructor } from '@cucumber/cucumber'
import {
chromium,
type Browser,
type BrowserContext,
type Page,
} from '@playwright/test'
import { config } from './types.js'
/**
* AppWorld — generic Playwright world for portal-style apps.
*
* Exposes the primitives every feature needs:
* - openBrowser / closeBrowser — lifecycle
* - gotoApp(path) — navigate within the frontend
* - login(email, password) — fill + submit /login, wait for redirect
* - logout() — visit /logout
* - expectText(text) — assert visible text
*
* Project-specific helpers (e.g. createBooking, assignRoom) belong in
* step files, not here. Keep this generic.
*/
export class AppWorld extends World {
browser!: Browser
context!: BrowserContext
page!: Page
async openBrowser() {
const headed = process.env.HEADED === '1' || process.env.HEADED === 'true'
this.browser = await chromium.launch({
headless: !headed,
slowMo: headed ? 150 : 0,
})
this.context = await this.browser.newContext(
process.env.E2E_LOCALE ? { locale: process.env.E2E_LOCALE } : undefined,
)
this.page = await this.context.newPage()
this.page.setDefaultTimeout(config.responseTimeout)
}
async closeBrowser() {
await this.context?.close()
await this.browser?.close()
}
async gotoApp(path: string) {
const url = path.startsWith('http')
? path
: `${config.appUrl}${path.startsWith('/') ? path : `/${path}`}`
await this.page.goto(url)
}
/**
* Fills the login form on /login and waits for navigation away from it.
* Assumes the login form has inputs named/typed `email` and a password
* input. Override per-project if the form differs.
*/
async login(email: string, password: string) {
await this.gotoApp('/login')
await this.page.locator('input[type="email"]').fill(email)
await this.page.locator('input[type="password"]').fill(password)
await this.page.getByRole('button', { name: /(sign in|login|anmelden)/i }).click()
await this.page.waitForURL((url) => !url.pathname.startsWith('/login'), {
timeout: config.responseTimeout,
})
}
async logout() {
await this.gotoApp('/logout')
}
async expectText(text: string) {
await this.page.getByText(text, { exact: false }).first().waitFor({
state: 'visible',
timeout: config.responseTimeout,
})
}
async getPageText(): Promise<string> {
return this.page.innerText('body')
}
}
setWorldConstructor(AppWorld)