chore: perauset customer project
This commit is contained in:
124
e2e/tests/support/world.ts
Normal file
124
e2e/tests/support/world.ts
Normal 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)
|
||||
Reference in New Issue
Block a user