chore: perauset customer project

This commit is contained in:
e2e
2026-07-11 08:21:55 +02:00
commit 52cd52e41a
293 changed files with 28412 additions and 0 deletions

124
e2e/tests/support/world.ts Normal file
View File

@@ -0,0 +1,124 @@
import { World, setWorldConstructor, type IWorldOptions } from '@cucumber/cucumber'
import { strict as assert } from 'assert'
import { apiGet, apiPost, apiPut, apiDelete } from './api-client.js'
import { config } from './config.js'
import { getUserId, TEST_PASSWORD } from './db.js'
export class PerausetWorld extends World {
lastResponse: Response | null = null
lastBody: any = null
cookies: string = ''
currentUserId: string = ''
currentEmail: string = ''
createdUsers: Record<string, string> = {}
lastAssignmentId: string = ''
constructor(options: IWorldOptions) {
super(options)
}
/**
* Authenticate as the given user via better-auth's email/password sign-in.
* POST /api/auth/sign-in/email with JSON {email, password} and capture the
* session cookie from the response.
*/
async login(email: string): Promise<void> {
const res = await fetch(`${config.apiUrl}/api/auth/sign-in/email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
// better-auth requires a trusted Origin for state-changing auth calls.
Origin: config.apiUrl,
},
body: JSON.stringify({ email, password: TEST_PASSWORD }),
redirect: 'manual',
})
if (!res.ok) {
const text = await res.text().catch(() => '')
throw new Error(`Login failed for ${email}: ${res.status} ${text}`)
}
this.cookies = this.extractSetCookies(res)
this.currentEmail = email
}
/**
* Look up the current user's id from the SQLite DB using the stored email.
*/
async getSessionUserId(): Promise<string> {
assert.ok(this.currentEmail, 'No current email set -- did you call login() first?')
return getUserId(this.currentEmail)
}
async get(path: string): Promise<void> {
this.lastResponse = await apiGet(config.apiUrl, path, this.cookies)
this.lastBody = await this.lastResponse.clone().json().catch(() => null)
this.captureCookies()
}
async post(path: string, body: any): Promise<void> {
this.lastResponse = await apiPost(config.apiUrl, path, body, this.cookies)
this.lastBody = await this.lastResponse.clone().json().catch(() => null)
this.captureCookies()
}
async put(path: string, body: any): Promise<void> {
this.lastResponse = await apiPut(config.apiUrl, path, body, this.cookies)
this.lastBody = await this.lastResponse.clone().json().catch(() => null)
this.captureCookies()
}
async delete(path: string): Promise<void> {
this.lastResponse = await apiDelete(config.apiUrl, path, this.cookies)
this.lastBody = await this.lastResponse.clone().json().catch(() => null)
this.captureCookies()
}
expectStatus(status: number): void {
assert.ok(this.lastResponse, 'No response received')
assert.equal(
this.lastResponse.status,
status,
`Expected status ${status} but got ${this.lastResponse.status}. Body: ${JSON.stringify(this.lastBody)}`
)
}
private captureCookies(): void {
const setCookie = this.lastResponse?.headers.get('set-cookie')
if (setCookie) {
this.cookies = this.mergeCookies(this.cookies, setCookie)
}
}
private extractSetCookies(res: Response): string {
// getSetCookie() returns individual set-cookie values as an array
const raw = (res.headers as any).getSetCookie?.() as string[] | undefined
if (raw && raw.length > 0) {
return raw.map((c: string) => c.split(';')[0]).join('; ')
}
// Fallback: use get('set-cookie') which may be comma-joined
const header = res.headers.get('set-cookie')
if (!header) return ''
return header
.split(/,(?=\s*\w+=)/)
.map((c: string) => c.split(';')[0].trim())
.join('; ')
}
private mergeCookies(existing: string, incoming: string): string {
if (!existing) return incoming
if (!incoming) return existing
const map = new Map<string, string>()
for (const part of existing.split(';').map((s) => s.trim()).filter(Boolean)) {
const [name] = part.split('=', 1)
map.set(name, part)
}
for (const part of incoming.split(';').map((s) => s.trim()).filter(Boolean)) {
const [name] = part.split('=', 1)
map.set(name, part)
}
return [...map.values()].join('; ')
}
}
setWorldConstructor(PerausetWorld)