import fs from 'node:fs' import path from 'node:path' import { test, expect, type Page, type TestInfo } from '@playwright/test' // @ts-ignore Report metadata does not perform application actions. import { sceneEvidenceBindings } from '../tools/scene-editor-evidence-bindings.mjs' // @ts-ignore Private credentials stay outside the report and repository. import { call, login, teacherLogin, freshScene, registerProject, report, work, fixture } from '../tools/scene-editor-closure-live.mjs' export { call, freshScene, registerProject, report, work, fixture } export async function signIn(page: Page, account = 'teacher') { const session = account === 'teacher' ? await teacherLogin() : await login(account) await page.addInitScript(({ accessToken, refreshToken }) => { if (!sessionStorage.getItem('scene-closure-initialized')) { sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken) sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken || '') sessionStorage.setItem('scene-closure-initialized', '1') } }, { accessToken: session.accessToken, refreshToken: session.refreshToken }) return session.accessToken as string } export const diagnostics = (page: Page) => page.evaluate(() => (window as any).__sceneEditorDiagnostics?.()) export async function ready(page: Page) { await expect(page.locator('.se-shell')).toBeVisible({ timeout: 90000 }) await expect.poll(async () => { const d = await diagnostics(page); return Boolean(d?.readySettled && d.pendingLoads === 0) }, { timeout: 90000 }).toBe(true) } export async function openEditor(page: Page, id: string) { await page.goto(`/content/scenes/${id}/edit`); await ready(page) } export const action = (page: Page, name: string) => page.locator(`.se-shell [data-action="${name}"]`).first() export async function save(page: Page) { await action(page, 'save').click() await expect.poll(async () => { const d = await diagnostics(page); return !d.saving && !d.dirty }).toBe(true) } export async function exportDocument(page: Page) { const waiting = page.waitForEvent('download') await action(page, 'export').click() const download = await waiting const stream = await download.createReadStream() const chunks: Buffer[] = []; for await (const chunk of stream!) chunks.push(chunk) return JSON.parse(Buffer.concat(chunks).toString('utf8')) } export async function shot(page: Page, info: TestInfo, name: string) { const folder = path.join(report, 'screenshots'); fs.mkdirSync(folder, { recursive: true }) const file = path.join(folder, `${name}.png`) await page.screenshot({ path: file, fullPage: true, animations: 'disabled' }) await info.attach(name, { path: file, contentType: 'image/png' }) } export function evidence(name: string, data: unknown) { const folder = path.join(report, 'evidence'); fs.mkdirSync(folder, { recursive: true }) const metadata = { kind: 'browser', status: 'PASS', testTitle: test.info().title, ...(sceneEvidenceBindings[name] || {}) } fs.writeFileSync(path.join(folder, `${name}.json`), JSON.stringify({ time: new Date().toISOString(), data: { ...metadata, ...(data as object) } }, null, 2)) } export async function closeSession(page: Page) { const token = await page.evaluate(() => sessionStorage.getItem('unreal-tran:web:access-token:v1')).catch(() => null) if (token) await call('auth/v1/auth/logout', token, {}).catch(() => {}) }