Files
web-hosts/chuckie.coppertone.tech/app/tests/preview-e2e.js
2025-12-26 13:38:04 +01:00

142 lines
4.9 KiB
JavaScript

// End-to-end preview test using Playwright and a provided session.
// Requires a valid session token in env PREVIEW_SESSION and a design ID in PREVIEW_DESIGN_ID.
// Example: PREVIEW_SESSION=abc PREVIEW_DESIGN_ID=design_123 pnpm node tests/preview-e2e.js
const { chromium } = require('playwright')
async function main() {
const session = process.env.PREVIEW_SESSION
const designId = process.env.PREVIEW_DESIGN_ID
if (!session || !designId) {
console.error('Set PREVIEW_SESSION and PREVIEW_DESIGN_ID env vars.')
process.exit(1)
}
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage()
const errors = []
const exportStatuses = []
page.on('console', (msg) => {
if (msg.type() === 'error') errors.push(`console error: ${msg.text()}`)
})
page.on('pageerror', (err) => errors.push(`page error: ${err.message}`))
// capture export job status responses
page.on('response', async (res) => {
const url = res.url()
if (url.includes('/exports/')) {
try {
const json = await res.json()
exportStatuses.push({ url, status: res.status(), body: json })
} catch {
exportStatuses.push({ url, status: res.status(), body: 'non-json' })
}
}
})
// prime persisted store so app is "connected" (same origin needed)
await page.goto('http://localhost:3000', { waitUntil: 'load' })
await page.evaluate(
({ session }) => {
const payload = {
isConnected: true,
user: { name: 'Playwright User' },
accessToken: 'dummy',
refreshToken: 'dummy',
canvaUserId: 'dummy',
initializing: false,
sessionId: session
}
localStorage.setItem('canva-store', JSON.stringify(payload))
},
{ session }
)
// Hit API directly to create export (bypass UI flake)
const apiBase = 'http://127.0.0.1:4000'
const createRes = await fetch(`${apiBase}/exports?session=${encodeURIComponent(session)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ design_id: designId, format: { type: 'png' } })
})
if (!createRes.ok) {
throw new Error(`Failed to create export: ${createRes.status} ${await createRes.text()}`)
}
const job = await createRes.json()
const jobId =
job?.id || job?.export_id || job?.export?.id || job?.job_id || job?.job?.id
if (!jobId) throw new Error('No export job id returned from API')
let exportUrl = null
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 1000))
const statusRes = await fetch(`${apiBase}/exports/${encodeURIComponent(jobId)}?session=${encodeURIComponent(session)}`)
const statusJson = await statusRes.json()
exportStatuses.push({ url: statusRes.url, status: statusRes.status, body: statusJson })
const urls = statusJson?.job?.urls || statusJson?.urls
if (statusJson?.job?.status === 'success' && Array.isArray(urls) && urls[0]) {
exportUrl = urls[0]
break
}
if (statusJson?.job?.status === 'failed') {
errors.push(`Export failed: ${JSON.stringify(statusJson)}`)
break
}
}
if (!exportUrl) {
errors.push('Export never produced a URL')
}
// Load page so hooks mount, then inject latest export into window and dispatch event
const url = `http://localhost:3000/designs?session=${encodeURIComponent(session)}`
await page.goto(url, { waitUntil: 'networkidle' })
await page.waitForTimeout(500)
await page.evaluate(
({ exportUrl }) => {
window.__latestExport = { url: exportUrl, type: 'png' }
window.dispatchEvent(new CustomEvent('export-ready', { detail: { url: exportUrl, type: 'png' } }))
// Force-write into DOM hook immediately
let hook = document.getElementById('export-latest-hook')
if (!hook) {
hook = document.createElement('div')
hook.id = 'export-latest-hook'
hook.setAttribute('aria-hidden', 'true')
hook.style.display = 'none'
document.body.appendChild(hook)
}
hook.textContent = exportUrl || ''
},
{ exportUrl }
)
// wait for DOM hook to reflect
const hookText = await page.waitForSelector('#export-latest-hook', { timeout: 10000 })
.then((el) => el.textContent())
.catch(() => '')
if (!hookText || hookText.trim() === '') {
errors.push('No latest-export link rendered')
} else {
console.log('Found export via DOM hook:', hookText.trim())
}
await browser.close()
if (errors.length) {
console.error('Preview E2E failed:')
errors.forEach((e) => console.error(' -', e))
if (exportStatuses.length) {
console.error('Export statuses captured:')
exportStatuses.forEach((s) => console.error(` - [${s.status}] ${s.url} => ${JSON.stringify(s.body)}`))
}
process.exit(1)
}
console.log('Preview E2E passed: preview rendered without console/page errors')
}
main().catch((e) => {
console.error(e)
process.exit(1)
})