c165f2f788
Agrega 19 issues técnicas documentando funcionalidades implementadas y pendientes. Issues completadas (movidas a dev/issues/completed/): - 001-conversor-web-markdown.md - 002-accessibility-tree.md - 003-gestion-cookies-perfil.md - 004-gestion-extensiones-chrome.md - 005-eliminar-timeouts-innecesarios.md Issues implementadas: - 006-manejo-tabs-ventanas.md - 016-manejo-iframes.md - 017-actions-api.md - 018-file-uploads.md - 019-expected-conditions-mejoradas.md Issues pendientes (media prioridad): - 007-alert-prompt-confirm-handling.md - 008-screenshot-elementos-especificos.md - 009-pdf-generation.md - 010-device-emulation-completo.md - 011-downloads-handling.md Issues pendientes (baja prioridad / avanzado): - 012-browser-contexts-multi-sesion.md - 013-video-recording.md - 014-network-mocking-avanzado.md - 015-geolocation-permissions.md Incluye también dev/NUEVAS_FUNCIONALIDADES.md con resumen completo. Directorio: dev/
168 lines
4.5 KiB
Markdown
168 lines
4.5 KiB
Markdown
# Issue #005: Eliminar timeouts innecesarios del código
|
|
|
|
**Tipo**: Improvement
|
|
**Prioridad**: Alta
|
|
**Estado**: Pendiente
|
|
|
|
## Descripción
|
|
|
|
Eliminar todos los `time.Sleep()` y timeouts hardcodeados innecesarios del código, reemplazándolos con esperas basadas en eventos CDP cuando sea posible.
|
|
|
|
## Problema actual
|
|
|
|
El código tiene múltiples `time.Sleep()` arbitrarios:
|
|
- `time.Sleep(2 * time.Second)` en examples/basic.go
|
|
- `time.Sleep(3 * time.Second)` en cmd/list_blog.go
|
|
- Timeouts hardcodeados en navegación
|
|
|
|
Estos timeouts son problemáticos porque:
|
|
- No se adaptan a velocidad real de carga
|
|
- Desperdicían tiempo en conexiones rápidas
|
|
- Fallan en conexiones lentas
|
|
- Hacen el código menos robusto
|
|
|
|
## Estrategia de reemplazo
|
|
|
|
### 1. Eventos CDP de carga de página
|
|
|
|
En lugar de:
|
|
```go
|
|
b.Navigate(ctx, url, nil)
|
|
time.Sleep(3 * time.Second)
|
|
```
|
|
|
|
Usar eventos CDP:
|
|
```go
|
|
opts := browser.DefaultNavigateOptions()
|
|
opts.WaitUntil = "networkidle" // o "load" o "domcontentloaded"
|
|
b.Navigate(ctx, url, opts)
|
|
// No sleep necesario, Navigate espera el evento
|
|
```
|
|
|
|
### 2. Esperar por selectores
|
|
|
|
En lugar de:
|
|
```go
|
|
time.Sleep(2 * time.Second)
|
|
html, _ := b.GetHTML(ctx, ".content")
|
|
```
|
|
|
|
Usar:
|
|
```go
|
|
b.WaitForSelector(ctx, ".content", 30*time.Second)
|
|
html, _ := b.GetHTML(ctx, ".content")
|
|
```
|
|
|
|
### 3. Esperar por condiciones JavaScript
|
|
|
|
En lugar de:
|
|
```go
|
|
time.Sleep(1 * time.Second)
|
|
result, _ := b.Evaluate(ctx, "window.dataReady")
|
|
```
|
|
|
|
Usar:
|
|
```go
|
|
b.WaitForFunction(ctx, "window.dataReady === true", 100*time.Millisecond)
|
|
result, _ := b.Evaluate(ctx, "window.data")
|
|
```
|
|
|
|
### 4. Eventos de red
|
|
|
|
Esperar que network esté idle:
|
|
```go
|
|
// Implementar WaitForNetworkIdle()
|
|
b.WaitForNetworkIdle(ctx, 500*time.Millisecond, 30*time.Second)
|
|
```
|
|
|
|
## Eventos CDP útiles
|
|
|
|
### Page domain
|
|
- `Page.loadEventFired` - Página cargada completamente
|
|
- `Page.domContentEventFired` - DOM listo
|
|
- `Page.frameStoppedLoading` - Frame dejó de cargar
|
|
|
|
### Network domain
|
|
- `Network.requestWillBeSent` - Request iniciado
|
|
- `Network.responseReceived` - Response recibida
|
|
- `Network.loadingFinished` - Recurso terminó de cargar
|
|
- `Network.loadingFailed` - Recurso falló
|
|
|
|
## Métodos a implementar
|
|
|
|
```go
|
|
// WaitForEvent espera un evento CDP específico
|
|
func (b *Browser) WaitForEvent(ctx context.Context, eventName string, timeout time.Duration) error
|
|
|
|
// WaitForNetworkIdle espera que no haya requests de red por X tiempo
|
|
func (b *Browser) WaitForNetworkIdle(ctx context.Context, idleTime, timeout time.Duration) error
|
|
|
|
// WaitForFunction espera que una función JS retorne true
|
|
func (b *Browser) WaitForFunction(ctx context.Context, fn string, checkInterval time.Duration) error
|
|
|
|
// WaitForNavigation espera que navegación complete
|
|
func (b *Browser) WaitForNavigation(ctx context.Context, timeout time.Duration) error
|
|
```
|
|
|
|
## Archivos a revisar y actualizar
|
|
|
|
- [x] `examples/basic.go` - Eliminar time.Sleep
|
|
- [x] `examples/advanced.go` - Reemplazar con esperas basadas en eventos
|
|
- [x] `cmd/list_blog.go` - Usar WaitForSelector
|
|
- [ ] `pkg/browser/navigation.go` - Mejorar Navigate() para esperar eventos
|
|
- [ ] `pkg/browser/browser.go` - Agregar métodos de espera
|
|
|
|
## Implementación en Navigate()
|
|
|
|
```go
|
|
func (b *Browser) Navigate(ctx context.Context, url string, opts *NavigateOptions) error {
|
|
if opts == nil {
|
|
opts = DefaultNavigateOptions()
|
|
}
|
|
|
|
// Registrar listener ANTES de navegar
|
|
loadedChan := make(chan struct{})
|
|
b.client.On("Page.loadEventFired", func() {
|
|
close(loadedChan)
|
|
})
|
|
|
|
// Enviar comando de navegación
|
|
_, err := b.client.SendCommand(ctx, "Page.navigate", map[string]interface{}{
|
|
"url": url,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Esperar evento según opts.WaitUntil
|
|
select {
|
|
case <-loadedChan:
|
|
return nil
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
```
|
|
|
|
## Beneficios
|
|
|
|
✅ **Más rápido**: No espera más de lo necesario
|
|
✅ **Más robusto**: Falla con timeout claro, no con misterioso "elemento no encontrado"
|
|
✅ **Más confiable**: Se adapta a velocidad real de página
|
|
✅ **Mejor UX**: Feedback claro de qué se está esperando
|
|
|
|
## Testing
|
|
|
|
Probar con:
|
|
- Conexiones rápidas (localhost)
|
|
- Conexiones lentas (throttling)
|
|
- Páginas con mucho JavaScript
|
|
- Páginas con assets pesados
|
|
- SPAs (React, Vue) que cargan async
|
|
|
|
## Referencias
|
|
|
|
- CDP Page events: https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-loadEventFired
|
|
- CDP Network events: https://chromedevtools.github.io/devtools-protocol/tot/Network/
|
|
- Puppeteer waitFor: https://pptr.dev/guides/page-interactions#waiting
|