package browser import ( "context" "fmt" "os" "path/filepath" ) // UploadFile sube un archivo a un input de tipo file func (b *Browser) UploadFile(ctx context.Context, selector string, filePath string) error { return b.UploadFiles(ctx, selector, []string{filePath}) } // UploadFiles sube múltiples archivos a un input de tipo file func (b *Browser) UploadFiles(ctx context.Context, selector string, filePaths []string) error { // Validar que todos los archivos existen var absolutePaths []string for _, path := range filePaths { // Convertir a path absoluto absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("invalid file path %s: %w", path, err) } // Verificar que existe if _, err := os.Stat(absPath); os.IsNotExist(err) { return fmt.Errorf("file does not exist: %s", absPath) } absolutePaths = append(absolutePaths, absPath) } // Obtener el nodeId del input nodeID, err := b.querySelector(ctx, selector) if err != nil { return fmt.Errorf("file input not found: %w", err) } // Verificar que es un input de tipo file script := fmt.Sprintf(` (() => { const input = document.querySelector('%s'); return input && input.tagName === 'INPUT' && input.type === 'file'; })() `, selector) result, err := b.Evaluate(ctx, script) if err != nil { return err } isFileInput, ok := result.Value.(bool) if !ok || !isFileInput { return fmt.Errorf("element is not a file input: %s", selector) } // Establecer archivos usando CDP params := map[string]interface{}{ "files": absolutePaths, "nodeId": nodeID, } if err := b.cdpClient.Execute(ctx, "DOM.setFileInputFiles", params, nil); err != nil { return fmt.Errorf("failed to set files: %w", err) } return nil } // SetFileInput es un alias de UploadFiles func (b *Browser) SetFileInput(ctx context.Context, selector string, files []string) error { return b.UploadFiles(ctx, selector, files) } // ClearFileInput limpia un input de tipo file func (b *Browser) ClearFileInput(ctx context.Context, selector string) error { nodeID, err := b.querySelector(ctx, selector) if err != nil { return fmt.Errorf("file input not found: %w", err) } // Establecer array vacío params := map[string]interface{}{ "files": []string{}, "nodeId": nodeID, } if err := b.cdpClient.Execute(ctx, "DOM.setFileInputFiles", params, nil); err != nil { return fmt.Errorf("failed to clear files: %w", err) } return nil } // GetFileInputValue obtiene los nombres de archivos seleccionados func (b *Browser) GetFileInputValue(ctx context.Context, selector string) ([]string, error) { script := fmt.Sprintf(` (() => { const input = document.querySelector('%s'); if (!input || input.type !== 'file') return null; const files = Array.from(input.files); return files.map(f => f.name); })() `, selector) result, err := b.Evaluate(ctx, script) if err != nil { return nil, err } if result.Value == nil { return []string{}, nil } // Convertir resultado a []string filesInterface, ok := result.Value.([]interface{}) if !ok { return nil, fmt.Errorf("unexpected result type") } var files []string for _, fileInterface := range filesInterface { if fileName, ok := fileInterface.(string); ok { files = append(files, fileName) } } return files, nil } // IsFileInputMultiple verifica si un input acepta múltiples archivos func (b *Browser) IsFileInputMultiple(ctx context.Context, selector string) (bool, error) { script := fmt.Sprintf(` (() => { const input = document.querySelector('%s'); return input && input.multiple === true; })() `, selector) result, err := b.Evaluate(ctx, script) if err != nil { return false, err } isMultiple, ok := result.Value.(bool) if !ok { return false, nil } return isMultiple, nil }