J'essaie de tester une interface javascript compliquée avec Selenium (à l'aide de l'interface Python et de plusieurs navigateurs). J'ai un certain nombre de boutons de la forme:
<div>My Button</div>
J'aimerais pouvoir rechercher des boutons basés sur "Mon bouton" (ou des correspondances partielles non sensibles à la casse, telles que "mon bouton" ou "bouton")
Je trouve cela incroyablement difficile, dans la mesure où je sens que je manque quelque chose d’évident. La meilleure chose que j'ai à ce jour est:
driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')
Ceci est sensible à la casse, cependant. L'autre chose que j'ai essayée est de parcourir tous les divs de la page et de vérifier la propriété element.text. Cependant, chaque fois que vous obtenez une situation de la forme:
<div class="outer"><div class="inner">My Button</div></div>
div.outer a aussi "My Button" comme texte. Pour résoudre ce problème, j'ai essayé de voir si div.outer était le parent de div.inner, mais je ne savais pas comment le faire (element.get_element_by_xpath ('..') renvoie le parent d'un élément, mais tests pas égal à div.outer). En outre, parcourir tous les éléments de la page semble être très lent, du moins à l'aide du navigateur Web Chrome.
Des idées?
Edit: Cette question est un peu vague. Demandé (et répondu) une version plus spécifique ici: Comment obtenir le texte d'un élément dans Selenium WebDriver (via l'API Python) sans inclure le texte de l'élément enfant?
Essayez ce qui suit:
driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")
vous pouvez essayer un xpath comme:
'//div[contains(text(), "{0}") and @class="inner"]'.format(text)
Vous pouvez également l'utiliser avec un modèle d'objet de page, par exemple:
Essayez ce code:
@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;
// * recherchera une balise HTML. Où si du texte est commun aux balises Button et div et si // * est une catégorie, cela ne fonctionnera pas comme prévu. Si vous devez sélectionner un élément spécifique, vous pouvez l'obtenir en déclarant la balise HTML Element. Comme:
driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
String yourButtonName=driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));
Il est intéressant de noter que pratiquement toutes les réponses tournent autour de la fonction contains()
de xpath, en négligeant le fait qu'il est un cas sensible - contrairement à la demande de OP.
Si vous avez besoin d'une insensibilité à la casse, cela est réalisable dans xpath 1.0 (la version supportée par les navigateurs contemporains)}, bien que ce ne soit pas joli - en utilisant la fonction translate()
. Il substitue un caractère source à la forme souhaitée en utilisant une table de traduction.
Construire une table de tous les caractères majuscules transformera effectivement le texte du nœud en sa forme lower () - permettant ainsi une correspondance insensible à la casse (voici juste la prérogative)}:
[
contains(
translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
'my button'
)
]
# will match a source text like "mY bUTTon"
L'appel python complet:
driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")
Naturellement, cette approche a ses inconvénients: elle ne fonctionnera que pour le texte latin; si vous voulez couvrir les caractères unicode, vous devrez les ajouter à la table de traduction. Je l'ai fait dans l'exemple ci-dessus - le dernier caractère est le symbole cyrillique "Й"
.
Et si nous vivions dans un monde où les navigateurs supportaient xpath 2.0 et supérieur ((mais ne se produisant pas dans un instant)}, nous aurions pu utiliser les fonctions lower-case()
(encore, pas totalement compatible avec les paramètres régionaux), et matches
(pour les recherches sur les expressions rationnelles, avec l'indicateur respectant la casse ('i'
)).
Utilisez driver.find_elements_by_xpath et correspond à la fonction de correspondance regex pour la recherche non sensible à la casse de l'élément par son texte.
driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")
Problème similaire: Find <button>Advanced...</button>
Cela vous donnera peut-être quelques idées (veuillez transférer le concept de Java vers Python):
wait.until(ExpectedConditions.elementToBeClickable(//
driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();