94 lines
3.9 KiB
TypeScript
94 lines
3.9 KiB
TypeScript
// Global setup de Playwright — Sprint 4 Etapa 8.
|
|
//
|
|
// Decisión tomada: Opción A (sesión real contra Supabase con usuario de test
|
|
// email/password, platform_role='platform_admin' en public.users). Permite que
|
|
// los specs E2E ejerciten el flujo real de auth + RLS + queries, no un mock.
|
|
//
|
|
// Usuario de test creado manualmente en Supabase Studio (no vía signup automático).
|
|
// Credenciales en .env.test (gitignored) — ver .env.example para el formato.
|
|
//
|
|
// Genera tests/e2e/setup/auth-state.json: storageState de Playwright con la
|
|
// sesión inyectada en localStorage bajo la clave sb-{project_ref}-auth-token,
|
|
// el mismo formato que usa supabase-js v2 y que AuthContext.getUserFromStorage()
|
|
// espera leer. Los specs que necesitan auth usan:
|
|
// test.use({ storageState: 'tests/e2e/setup/auth-state.json' })
|
|
|
|
import { chromium } from '@playwright/test'
|
|
import { createClient } from '@supabase/supabase-js'
|
|
import { readFileSync, existsSync } from 'fs'
|
|
import { resolve } from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
const ROOT = resolve(__dirname, '../../..')
|
|
const STATE_PATH = resolve(__dirname, 'auth-state.json')
|
|
|
|
function loadEnvFile(filename: string): Record<string, string> {
|
|
const path = resolve(ROOT, filename)
|
|
if (!existsSync(path)) return {}
|
|
const out: Record<string, string> = {}
|
|
for (const line of readFileSync(path, 'utf-8').split('\n')) {
|
|
const trimmed = line.trim()
|
|
if (!trimmed || trimmed.startsWith('#')) continue
|
|
const idx = trimmed.indexOf('=')
|
|
if (idx === -1) continue
|
|
out[trimmed.slice(0, idx)] = trimmed.slice(idx + 1)
|
|
}
|
|
return out
|
|
}
|
|
|
|
async function globalSetup() {
|
|
const local = loadEnvFile('.env.local')
|
|
const test = loadEnvFile('.env.test')
|
|
|
|
const supabaseUrl = local.VITE_SUPABASE_URL
|
|
const supabaseAnonKey = local.VITE_SUPABASE_ANON_KEY
|
|
const email = test.TEST_USER_EMAIL
|
|
const password = test.TEST_USER_PASSWORD
|
|
|
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
console.warn('[auth-setup] VITE_SUPABASE_URL/ANON_KEY no encontradas en .env.local — specs con auth se saltarán storageState')
|
|
return
|
|
}
|
|
if (!email || !password) {
|
|
console.warn('[auth-setup] TEST_USER_EMAIL/PASSWORD no encontradas en .env.test — specs con auth se saltarán storageState')
|
|
return
|
|
}
|
|
|
|
const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
|
const { data, error } = await supabase.auth.signInWithPassword({ email, password })
|
|
if (error || !data.session) {
|
|
console.error('[auth-setup] Login de usuario de test falló:', error?.message)
|
|
return
|
|
}
|
|
|
|
// Diagnóstico Sprint 5 Etapa 6a-extra: @supabase/auth-js v2 define STORAGE_KEY =
|
|
// 'supabase.auth.token' como default de GoTrueClient (constants.js), pero
|
|
// @supabase/supabase-js's createClient() SOBRESCRIBE ese default calculando
|
|
// `sb-${projectRef}-auth-token` a partir de la URL (ver SupabaseClient constructor:
|
|
// `i = sb-${hostname.split('.')[0]}-auth-token`, mergeado en `auth.storageKey`),
|
|
// salvo que el caller pase un storageKey explícito. src/lib/supabase.ts no lo hace,
|
|
// así que esta es la clave REAL que usa la app. Confirmado empíricamente: el test
|
|
// "app header shows user avatar" (sprint-4-smoke.spec.ts) requiere que AuthContext
|
|
// encuentre una sesión real bajo esta clave — pasa, y auth-state.json generado
|
|
// contiene exactamente `sb-${projectRef}-auth-token`. No es un bug.
|
|
const projectRef = new URL(supabaseUrl).hostname.split('.')[0]
|
|
const storageKey = `sb-${projectRef}-auth-token`
|
|
|
|
const browser = await chromium.launch()
|
|
const page = await browser.newPage()
|
|
await page.goto('http://localhost:4173/login')
|
|
await page.evaluate(
|
|
([key, session]) => {
|
|
window.localStorage.setItem(key, JSON.stringify(session))
|
|
},
|
|
[storageKey, data.session] as const
|
|
)
|
|
await page.context().storageState({ path: STATE_PATH })
|
|
await browser.close()
|
|
|
|
console.log(`[auth-setup] Sesión de test guardada en ${STATE_PATH}`)
|
|
}
|
|
|
|
export default globalSetup
|