0
votes

Capybara n'attend pas la fin du téléchargement du fichier

J'écris un scénario avec Ruby et Capybara. Ce script doit télécharger un fichier et une fois le fichier téléchargé, le script doit cliquer sur le bouton "Enregistrer". J'ai réussi à faire démarrer le téléchargement du fichier, mais après plusieurs secondes, le script s'arrête. En fin de compte, le fichier n'est pas téléchargé et je dois tout recommencer à zéro.

Il y a un bouton "Enregistrer" sur la page qui reste désactivé jusqu'à ce que le fichier soit téléchargé. J'ai donc essayé d'utiliser son état comme indicateur. Mais Capybara ne le reconnaît pas.

Mon code:

upload_btn = browser.all(:element, 'span', text: 'Upload')
browser.attach_file($app_path) do
  upload_btn[0].click
end
browser.has_button?('Save', wait: 200)
browser.click_on('Save')

A quoi ressemble l'interface utilisateur de la page (désolé pour la capture d'écran): entrez la description de l'image ici

Je suppose que cela ne fonctionne pas car ce n'est pas un button mais un button material-button et Capybara ne reconnaît pas cet élément. Utiliser des classes / identifiants n'est pas la meilleure idée car toutes les classes sont dynamiques et je ne peux pas compter dessus

Pourriez-vous nous dire ce qui pourrait être fait ici? Ou comment faire attendre capybara jusqu'à ce que ce bouton soit désactivé?

Merci!


0 commentaires

3 Réponses :


1
votes

En supposant que la classe is_disabled et l'attribut disabled sont supprimés lorsque le bouton devient actif, vous pouvez utiliser l'un des éléments suivants (en supposant que 200 secondes suffisent pour que le téléchargement se termine)

find(:element, 'material-design', 'debug-id': 'save-button', disabled: false, wait: 200).click
find(:element, 'material-design', disabled: false, text: 'Save', wait: 200).click

Si le debug-id est disponible et stable, vous pouvez ignorer l'option de text , qui sera plus efficace

find("material-button[debug-id='save-button']:not([disabled])", wait:200).click

Une dernière option serait d'utiliser le type de sélecteur Capybara: élément

find('material-button:not([disabled])', text: 'Save', wait: 200).click
find('material-button:not(.is_disabled)', text: 'Save', wait:200).click
find('material-button', class: '^is_disabled', text: 'Save', wait: 200).click # The ^ in front of the class name indicates to negate


4 commentaires

Non pas que je sois un expert mais l'attente est-elle réellement nécessaire? Il semble que (selon ma lecture) capybara attendra automatiquement de trouver jusqu'à ce que le match se produise.


@engineersmnky Par défaut, Capybara attendra jusqu'à Capybara.default_max_wait_time qu'une condition soit remplie. La valeur par défaut est de 2 secondes, et en fonction du matériel utilisé pour les tests, elle est généralement définie quelque part dans la plage de 1 à 5 secondes. Sur la base de la publication originale, je suppose que le téléchargement ne se termine pas dans cette plage, donc j'ai inclus l'option d' wait . C'est un temps d'attente maximum, donc quand la condition est remplie, elle continuerait (c'est-à-dire qu'elle n'attendrait pas les 200 pleins) donc le pire des cas est qu'elle retarde les cas d'échec si / quand le téléchargement échoue réellement.


Parfait. Considérez-moi édifié. J'apprécie la clarification et maintenant je sais si j'aurais besoin d'utiliser capybara à l'avenir.


Le revirement pour moi était un peu différent de ce que vous avez écrit. Mais la plus proche était la dernière variante que vous avez proposée. Je vais poster la solution maintenant ci-dessous. Merci pour vos conseils, les gars!



0
votes

Donc, le redressement n'était peut-être pas des plus professionnels, mais au moins cela a fonctionné et je peux automatiser certaines choses maintenant.

Fondamentalement, j'ai utilisé has_button? pour que mon script attende que le fichier APK soit téléchargé. 200 secondes suffisent pour le téléchargement de fichiers (statistiquement). À la fin, le script fait une pause mais j'ai décidé d'ajouter sleep 3 à la fin juste pour être du bon côté.

Voici la fonction qui télécharge l'APK pour moi. Peut-être que quelqu'un en aura besoin

 def create_release
   puts('Create release and upload APK')
   browser.find(:element, 'div', role: 'menuitem', text: 'Production').click
   create_release_btn = browser.all(:button, text: 'Create new release')
   create_release_btn[0].click

   #OPT out
   browser.click_button('Manage preferences', wait: 200)
   sleep 2
   browser.choose('Opt out of app signing by Google Play')
   browser.click_button('Update', wait: 100)
   sleep 3
   op_out_btn = browser.all(:button, text: 'Opt out', wait: 500)
   op_out_btn[0].click
   sleep 4

   #File upload part and saving
   upload_btn = browser.all(:element, 'span', text: 'Upload')
   browser.attach_file($app_path) do
     upload_btn[0].click
   end
   save_btn = browser.all(:element, 'material-button', text: 'Save', disabled: false, wait: 200)
   browser.has_button?(save_btn, disabled: false, wait: 200)
   button_test = browser.all(:button, text: 'Save', wait: 100)
   button_test[0].click

   sleep 3
end


0 commentaires

1
votes

Maintenant que OP a publié sa méthode complète, pour quiconque aborde cette question plus tard, veuillez ne pas écrire de code Capybara comme dans la réponse actuellement acceptée.

  1. N'utilisez pas all lorsque vous vous souciez uniquement du first élément

  2. N'utilisez pas le type de sélecteur d'élément: lorsque vous n'en avez pas vraiment besoin

  3. N'utilisez pas les méthodes de prédicat juste pour attendre

  4. Préférez une attente / une affirmation plutôt que de simplement dormir

Cela se résume à quelque chose de plus comme

def create_release
  puts('Create release and upload APK')
  browser.find('div[role="menuitem"]', text: 'Production').click
  browser.first(:button, 'Create new release').click

  #OPT out
  browser.click_button('Manage preferences', wait: 200) # 200 seems like a really long max wait time here
  browser.choose('Opt out of app signing by Google Play')
  browser.click_button('Update', wait: 100) # again - seems really long

  browser.first(:button, 'Opt out', wait: 500).click # and again

  #File upload part and saving
  browser.attach_file($app_path) do
    browser.first('span', text: 'Upload').click
  end

  expect(browser).to have_selector(:element, 'material-button', text: 'Save', disabled: false, wait: 200)
  browser.first(:button, 'Save', wait: 300).click

  expect(browser).to ... # whatever change clicking the button triggers 
end


1 commentaires

Sympa, merci Thomas, je vais essayer de le mettre en œuvre