C# проблема с поиском элемента и ожиданием

Привет,

Помогите пожалуйста разобраться, почему поиск элемента срабатывает через раз.
public IWebElement lblProcesses => PropertiesCollection.Driver.FindElementExt(By.XPath("//blablabla"), 20);
(по xpath находит единственный элемент без проблем, проверяла через дев тул)

У меня такой ощущение, что не ждет 20 секунд, а сразу бежит жать кнопку и даже попытки не делает.
Вопрос: как можно сделать так, что бы в случае не удачного поиска, делалась попытка найти еще раз?

 public static IWebElement FindElementExt(this IWebDriver driver, By by, int timeoutInSeconds)
        {
            if (timeoutInSeconds > 0)
            {
                var attempt = 0;
                try
                {
                    var wait = new WebDriverWait(PropertiesCollection.Driver, TimeSpan.FromSeconds(timeoutInSeconds));
                    //return
                    wait.Until(Driver => Driver.FindElement(by).Displayed);
                    wait.Until(Driver => Driver.FindElement(by).Enabled);
                }
                catch (StaleElementReferenceException)
                {
                    if (++attempt == 7)
                    {
                        Console.WriteLine(by);
                        throw;
                    }
                    Thread.Sleep(5);
                }   
            }
            return driver.FindElement(by);
        }
    }

Кнопка может быть Enabled и Displayed но иметь аттрибут “disabled = true” или какой-нибуть другой.
Попробуй посмотреть на елемент пока консоль грузится и добавь.
wait.Until(d => webElement.GetAttribute(attributeName) == attributeValue);

1 лайк

Прошла в дебагере.Каждый раз эксепшин, но локатор возвращает.

Т.е. данный элемент находит. И глобально, 80% локаторов находит, но некоторые не может. И как-то все с эксепшинами не красиво смотрится.

2019-05-14_1235

А почему контейнс, а не //a[@href=’#/home’].

Можешь пробовать

var a = drv.findElements(by).Count() или .Any()
Thread.Sleep(2000);
var b = drv.findElements(by).Count() или .Any()

Если сработает второй - то сделай
wait.Until(d => drv.findElements(by).Any() == true);

1 лайк

wait.Until(d => driver.FindElement(by).Count() == true);

Просто скопипастила быстро. Хотя да, если появится еще один home, будет не хорошо.

не driver.FindElement а driver.FindElements

1 лайк

У вас сайт на Angular

  1. Установите Protractor в нюгетах и заверните в него драйвер new NgWebDriver(new ChromeDriver())

  2. Включайте синхронизацию где Angular и выключайте где не работает
    Driver.IgnoreSynchronization = true;

  3. Уберите свой try catch и используйте var wait = new DefaultWait(Driver)
    в него добавьте
    wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));

 public static IWebDriver Driver1 { get; set; }
Driver1 = new NgWebDriver(new ChromeDriver());
            ChromeOptions option = new ChromeOptions();
            option.AddArgument("no-sandbox");
            Driver1 = new ChromeDriver(Utils.AssemblyDirectory, option, TimeSpan.FromSeconds(130));
            Driver1.Manage().Window.Maximize();


Как то совсем все не работает :frowning:

попробуйте искать через NgBy.Repeater( - внутри там javascript

и это должно помочь:

...
public NgByRepeater(string repeat, bool exactMatch)
            : base(ClientSideScripts.FindAllRepeaterRows, repeat, exactMatch)
        {

или посмотрите кокой внутри binding и ишите понему

Форматирование съело кусочек кода так надо new DefaultWait<IWebDriver>(Driver)

Почему driver не используете? А Driver1, через него можно обращаться

public static IWebDriver Driver1 { get; set; }
Замените на
public static NgWebDriver Driver1 { get; set; }

Иначе не увидите свойство
Driver.IgnoreSynchronization = true;

Заменила в тестовых целях исключительно.

Падает. Что-то я делаю не так.

Попробуйте так
wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds); wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));
a потом wait.Until
.Any() == true можно не писать а просто d.findElement(by) и засунуть прям в return

Проверьте у вас по коду все ок? Ошибка компилятора CS0103 | Microsoft Learn

 public static IWebElement FindElementExt(this IWebDriver driver, By by, int timeoutInSeconds)
        {
            if (timeoutInSeconds > 0)
            {
                var attempt = 0;
                try
                {
                    var wait = new WebDriverWait(PropertiesCollection.Driver, TimeSpan.FromSeconds(timeoutInSeconds));

                     wait.Until(d => driver.FindElements(by).Any() == true);
                    //wait.Until(Driver => Driver.FindElement(by).Displayed);
                    //return 
                    //wait.Until(drv => drv.FindElement(by));

                }
                catch (Exception)
                {
                    if (++attempt == 7)
                    {
                        Console.WriteLine(by);
                        throw;
                    }
                    Thread.Sleep(5000);
                }
                          
            }
            return driver.FindElement(by);
        }

Этот метод работает без падений в дебаг моде. В рабочем режиме, некоторые элементы не успевают найтись и поэтому ошибка
Message: OpenQA.Selenium.ElementNotVisibleException : element not interactable
** (Session info: chrome=74.0.3729.131)**
** (Driver info: chromedriver=74.0.3729.6**

Не хочется боюавлять thread.sleep();

public static IWebElement FindElementExtMES(this NgWebDriver driver1, By by, int timeoutInSeconds)
        {
            var wait = new DefaultWait<IWebDriver>(driver1);
            wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));
            **wait.Until(d => driver1.FindElements(by));**

            return driver1.FindElement(by);
        }

Все равно подает с ошибкой, как раньше

Набросал вам полностью рабочий пример для сайта на Angular, смотрите что у вас не так. Учтите что Синхронизация по дефолту включена и ее нужно выключать на страницах без Angular. Все написано как пример, драйвер можете положить куда угодно и переделать все как вам нужно

using System;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using Protractor;

namespace Sample
{
    public class Test
    {

        [Test]
        public void SampleTest()
        {
            ChromeOptions option = new ChromeOptions();
            option.AddArgument("no-sandbox");
            WebdriverEx.Driver = new NgWebDriver(new ChromeDriver(option));
            WebdriverEx.Driver.Manage().Window.Maximize();

            WebdriverEx.Driver.Navigate().GoToUrl("https://angular.io/");

            WebdriverEx.Driver.FindElementClickable(By.XPath("//*[@href='docs']")).Click();
            WebdriverEx.Driver.FindElementVisible(By.XPath("//*[@placeholder='Search']")).SendKeys("Test Test Test");
            WebdriverEx.Driver?.Quit();
        }
    }


    public static class WebdriverEx
    {
        public static NgWebDriver Driver { get; set; }

        public static IWebElement FindElementExist(this IWebDriver driver, By by, int timeoutInSeconds = 30)
        {
            var wait = new DefaultWait<IWebDriver>(driver);
            wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            return wait.Until(d => driver.FindElement(by));
        }

        public static IWebElement FindElementClickable(this IWebDriver driver, By by, int timeoutInSeconds = 30)
        {
            var wait = new DefaultWait<IWebDriver>(driver);
            wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            wait.Until(d => d.FindElement(by).Displayed && d.FindElement(by).Enabled);
            return driver.FindElement(by);
        }

        public static IWebElement FindElementVisible(this IWebDriver driver, By by, int timeoutInSeconds = 30)
        {
            var wait = new DefaultWait<IWebDriver>(driver);
            wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NoSuchElementException));
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            wait.Until(d => d.FindElement(by).Displayed);
            return driver.FindElement(by);
        }
    }
}

2 лайка

Попробовала . Первые потери:

  1. Не поддерживается Allure ScreenShort
  2. Мне нужно перейти в другое окно , в котором немножко другая имплементация.
    В итоге ошибка
Message: OpenQA.Selenium.WebDriverException : javascript error: angular never provided resumeBootstrap
JavaScript stack:
Error: angular never provided resumeBootstrap
    at check (eval at executeAsyncScript (:448:5), <anonymous>:33:15)
    at eval (eval at executeAsyncScript (:448:5), <anonymous>:38:1)
    at eval (eval at executeAsyncScript (:448:5), <anonymous>:38:12)
    at executeAsyncScript (<anonymous>:448:26)
    at <anonymous>:464:29
    at callFunction (<anonymou
  1. Там где отдаете алюру драйвер сделайте так Driver.WrappedDriver - это драйвер который вы завернули в NgDriver, и делайте так если что то не работает с NgDriver

  2. Driver.IgnoreSynchronization = true; делайте там где angular не работает, и false - там где все ок

  3. Если многопроблем с NgDriver, можете его вобще убрать, но стабильность немного упадет (Это касается только Angular сайтов)

1 лайк

наверно должно быть так

Так как у меня тоже можно, от перестановки мест слагаемых как говорится) И лишний поиск убирается