2011-03-04 56 views
19

Tengo una página web que abre un div al hacer clic en un botón. Este div le permite arrastrar un archivo desde su escritorio a su área; el archivo luego se carga al servidor. Estoy trabajando con la implementación Ruby de Selenium.Uso de Selenium para imitar arrastrar un archivo a un elemento de carga

Al usar el depurador de JavaScript en Firefox, puedo ver que un evento llamado "soltar" se está pasando a un código JavaScript "handleFileDrop (event)". Supongo que si tuviera que crear un evento simulado y dispararlo de alguna manera, podría activar este código.

Si encontraste un interesting article que parecía apuntarme en una dirección prometedora, pero todavía estoy corto de descifrarlo todo. Puedo pasar JavaScript a la página usando el método get_eval de Selenium. Los métodos de llamada que usan this.browserbot me están dando los elementos que necesito.

Así:

  1. ¿Cómo construir el objeto archivo que tiene que ser parte de la maqueta evento de colocación ?
  2. ¿Cómo disparo el evento de caída para que se recoja como si hubiera soltado un archivo en el div?

Respuesta

0

Puede utilizar Blueduck SDA (http://sda.blueducktesting.com) es un OSS que ha implementado todas las funciones de selenio (Se trabaja con RC selenio) pero permite automatizar acciones de Windows. Entonces puedes probar la web e interactuar con el sistema operativo. Para que pueda hacer su prueba, y luego, simplemente dígale al mouse que haga clic en el elemento y lo deje donde lo desee.

¡Buenas pruebas!

+0

Parece que podría ser una opción, aunque estoy trabajando g en OSX, no en Windows. También soy técnicamente curioso sobre la interacción con el navegadorbot y los eventos de disparo en el contexto de JavaScript. –

28

Publiqué una prueba de RSpec que simula archivos de arrastrar y soltar usando Selenium webdriver. Utiliza jQuery para crear y desencadenar un evento falso 'drop'.

Este código simula arrastrar y soltar un único archivo. En aras de la simplicidad, eliminé el código que permite que caigan varios archivos. Dime si lo necesitas.

describe "when user drop files", :js => true do 
    before do 
    page.execute_script("seleniumUpload = window.$('<input/>').attr({id: 'seleniumUpload', type:'file'}).appendTo('body');") 

    attach_file('seleniumUpload', Rails.root + 'spec/support/pdffile/pdfTest.pdf') 

    # Trigger the drop event 
    page.execute_script("e = $.Event('drop'); e.originalEvent = {dataTransfer : { files : seleniumUpload.get(0).files } }; $('#fileDropArea').trigger(e);") 
    end 

    it "should ..." do 
    should have_content '...' 
    end 

P.S .: Recuerde reemplazar #fileDropArea con la identificación de su área de caída.

P.P.S: no utilice eval_script en lugar de execute_script, de lo contrario selenium quedará atascado evaluando objetos jQuery complejos!

ACTUALIZACIÓN: He escrito un método que puede volver a utilizar y hacer las cosas escritas arriba.

def drop_files files, drop_area_id 
    js_script = "fileList = Array();" 
    files.count.times do |i| 
    # Generate a fake input selector 
    page.execute_script("if ($('#seleniumUpload#{i}').length == 0) { seleniumUpload#{i} = window.$('<input/>').attr({id: 'seleniumUpload#{i}', type:'file'}).appendTo('body'); }") 
    # Attach file to the fake input selector through Capybara 
    attach_file("seleniumUpload#{i}", files[i]) 
    # Build up the fake js event 
    js_script = "#{js_script} fileList.push(seleniumUpload#{i}.get(0).files[0]);" 
    end 

    # Trigger the fake drop event 
    page.execute_script("#{js_script} e = $.Event('drop'); e.originalEvent = {dataTransfer : { files : fileList } }; $('##{drop_area_id}').trigger(e);") 
end 

Uso:

describe "when user drop files", :js => true do 
    before do 
    files = [ Rails.root + 'spec/support/pdffile/pdfTest1.pdf', 
       Rails.root + 'spec/support/pdffile/pdfTest2.pdf', 
       Rails.root + 'spec/support/pdffile/pdfTest3.pdf' ] 
    drop_files files, 'fileDropArea' 
    end 

    it "should ..." do 
    should have_content '...' 
    end 
end 
+0

Esto se ve bien - No estoy trabajando con RSpec en mi proyecto actual, así que si alguien más puede confirmar que esto funciona en los comentarios, entonces aceptaré esta respuesta. –

+0

Confirmado en rspec - ¡funciona perfectamente! Señor, usted hizo mi día! :) –

+0

Gracias por esto: he traducido el código con éxito para trabajar en mis pruebas con C#. –

3

Como @Shmoopy pidió, aquí hay un C# traducción del código proporcionado por @micred

private void DropImage(string dropBoxId, string filePath) 
{ 
    var javascriptDriver = this.Driver as IJavaScriptExecutor; 
    var inputId = dropBoxId + "FileUpload"; 

    // append input to HTML to add file path 
    javascriptDriver.ExecuteScript(inputId + " = window.$('<input id=\"" + inputId + "\"/>').attr({type:'file'}).appendTo('body');"); 
    this.Driver.FindElement(By.Id(inputId)).SendKeys(filePath); 

    // fire mock event pointing to inserted file path 
    javascriptDriver.ExecuteScript("e = $.Event('drop'); e.originalEvent = {dataTransfer : { files : " + inputId + ".get(0).files } }; $('#" + dropBoxId + "').trigger(e);"); 
} 
+2

Gracias, esto me ayudó. Aunque recibí un error 'Selenium Error inesperado. la propiedad tipo no se puede cambiar'. Se corrigió cambiando '$ (''). Attr ({type: 'file'})' to '$ (' ') '. –

0

Nota: es recomendable añadir

e.originalEvent.dataTransfer.types = [ 'Files' ]; 
Cuestiones relacionadas