scripts/capture-app-first-onboarding-media.mjs
Rama main · réplica de lectura del repositorio original.
import { chromium } from 'playwright'
import { execFileSync } from 'node:child_process'
import { mkdir, mkdtempSync, readdirSync, rmSync, statSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
const baseURL = process.env.CAPGO_MEDIA_BASE_URL ?? 'http://localhost:5173'
const email = process.env.CAPGO_MEDIA_EMAIL ?? `media-onboard-${Date.now()}@example.com`
const password = process.env.CAPGO_MEDIA_PASSWORD ?? `CapgoMedia${Date.now()}!Zx`
const outDir = path.resolve('docs/pr/app-first-onboarding')
function isSafeFileName(name) {
return name.length > 0 && !name.includes('/') && !name.includes('\\') && name !== '.' && name !== '..'
}
async function ensureFreshMediaUser(supabaseUrl, anonKey) {
const serviceKey = process.env.SUPABASE_SERVICE_KEY
if (!serviceKey)
return
await fetch(`${supabaseUrl}/auth/v1/admin/users`, {
method: 'POST',
headers: {
Authorization: `Bearer ${serviceKey}`,
apikey: anonKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
email_confirm: true,
user_metadata: { first_name: 'Demo', last_name: 'User' },
}),
}).catch(() => {})
}
async function signInThroughUi(page, supabaseUrl, anonKey) {
await ensureFreshMediaUser(supabaseUrl, anonKey)
await page.goto(`${baseURL}/login`)
await page.fill('[data-test="email"]', email)
await page.click('[data-test="continue"]')
await page.fill('[data-test="password"]', password)
await page.click('[data-test="submit"]')
await page.waitForURL(/\/onboarding\/app/, { timeout: 60000 })
}
async function main() {
await mkdir(outDir, { recursive: true })
const browser = await chromium.launch({ headless: true })
const context = await browser.newContext({
recordVideo: {
dir: outDir,
size: { width: 1280, height: 800 },
},
viewport: { width: 1280, height: 800 },
})
const page = await context.newPage()
const suffix = Date.now()
const appName = `Demo App ${suffix}`
const supabaseUrl = process.env.VITE_SUPABASE_URL ?? 'http://127.0.0.1:55411'
const anonKey = process.env.VITE_SUPABASE_ANON_KEY ?? 'sb_publishable_ACJWlzQHlZjBrEguHvfOxg_3BJgxAaH'
await signInThroughUi(page, supabaseUrl, anonKey)
await page.goto(`${baseURL}/onboarding/app`)
await page.waitForURL(/\/onboarding\/app/, { timeout: 60000 })
await page.waitForSelector('[data-test="onboarding-intent-ota"]', { timeout: 60000 })
await page.locator('[data-test="onboarding-intent-ota"]').click()
await page.screenshot({ path: path.join(outDir, '01-intent-step.png'), fullPage: true })
await page.locator('[data-test="app-onboarding-continue-intent"]').click()
await page.locator('[data-test="app-onboarding-existing-no"]').click()
await page.locator('[data-test="app-onboarding-name"]').fill(appName)
await page.screenshot({ path: path.join(outDir, '02-app-details-filled.png'), fullPage: true })
await page.locator('[data-test="app-onboarding-continue"]').click()
await page.locator('[data-test="onboarding-mode-app-name"]').click()
await page.screenshot({ path: path.join(outDir, '03-organization-step.png'), fullPage: true })
await page.locator('[data-test="onboarding-create-org"]').click()
await page.waitForSelector('[data-test="app-onboarding-command-copy"]', { timeout: 60000 })
await page.screenshot({ path: path.join(outDir, '04-setup-command.png'), fullPage: true })
await context.close()
await browser.close()
convertVideoToWebp()
console.log(`Saved screenshots, video, and webp under ${outDir}`)
}
main().catch((error) => {
console.error(error)
process.exit(1)
})
function convertVideoToWebp() {
const videos = readdirSync(outDir)
.filter(name => name.endsWith('.webm') && !name.startsWith('.') && isSafeFileName(name))
.map(name => ({
name,
mtime: statSync(path.join(outDir, name)).mtimeMs,
}))
.sort((left, right) => right.mtime - left.mtime)
if (!videos.length)
return
const input = path.join(outDir, videos[0].name)
const output = path.join(outDir, 'app-first-onboarding.webp')
const framesDir = mkdtempSync(path.join(tmpdir(), 'capgo-onboard-frames-'))
const framePattern = path.join(framesDir, 'frame_%03d.png')
try {
execFileSync('ffmpeg', ['-y', '-i', input, '-vf', 'fps=10,scale=1280:-1', framePattern], { stdio: 'inherit' })
const frames = readdirSync(framesDir)
.filter(name => name.endsWith('.png') && isSafeFileName(name))
.sort()
if (!frames.length)
return
execFileSync('img2webp', ['-o', output, ...frames.map(frame => path.join(framesDir, frame))], { stdio: 'inherit' })
}
finally {
rmSync(framesDir, { recursive: true, force: true })
}
for (const video of videos)
rmSync(path.join(outDir, video.name), { force: true })
}