简体   繁体   English

如果我已经有了FindsBy的元素,如何与硒一起使用Wait.Until

[英]How to use Wait.Until with Selenium if I already have the element with FindsBy

I am using Wait.Until method to check if my page is already loaded or if it still loading . 我正在使用Wait.Until方法来检查我的页面是否已经加载或仍在加载。 This is how it looks like : 这是这样的:

protected IWebElement FindElement(By by, int timeoutInSeconds)
    {
        StackTrace stackTrace = new StackTrace();
        string callingMethod = stackTrace.GetFrame(1).GetMethod().Name;

        string message = "Error finding element in method: " + callingMethod;

        if (timeoutInSeconds > 0)
        {
            try
            {
                WebDriverWait wait = new WebDriverWait(chromeDriver, TimeSpan.FromSeconds(timeoutInSeconds));
                wait.Until(ExpectedConditions.ElementIsVisible(by));
                Thread.Sleep(800);
            }
            catch (Exception)
            {
                Assert(false, message);
                throw new Exception(message);
            }
        }

        return chromeDriver.FindElement(by);
    }

But now we want to change our automation pages and start using FindBy foe every element , like this : 但是现在我们要更改自动化页面,并开始对每个元素使用FindBy,如下所示:

  [FindsBy(How = How.Id, Using = "username")]
    public IWebElement _logInUserName;

but wait.until needs "by" element . 但是wait.until需要“ by”元素。

I saw the abstract solution for this problem , but it is no good for my case . 我看到了此问题的抽象解决方案,但这对我的情况不利。 can anyone know another solution that i can use ? 谁能知道我可以使用的另一种解决方案?

There is a ByFactory class in Selenium .NET solution . Selenium .NET解决方案中有一个ByFactory I took this implementation to achieve what you want: 我采用此实现来实现您想要的:

using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace SeleniumPlayground
{
    public static class SeleniumHelper
    {
        public static FindsByAttribute GetFindsByAttributeFromField(Type pageObject, string iwebElementFieldName)
        {

            FieldInfo fi = pageObject.GetField(iwebElementFieldName);

            FindsByAttribute attr = (FindsByAttribute)fi.GetCustomAttributes(typeof(FindsByAttribute), false).FirstOrDefault();

            return attr;
        }

        public static By GeyByFromFindsBy(FindsByAttribute attribute)
        {
            var how = attribute.How;
            var usingValue = attribute.Using;
            switch (how)
            {
                case How.Id:
                    return By.Id(usingValue);
                case How.Name:
                    return By.Name(usingValue);
                case How.TagName:
                    return By.TagName(usingValue);
                case How.ClassName:
                    return By.ClassName(usingValue);
                case How.CssSelector:
                    return By.CssSelector(usingValue);
                case How.LinkText:
                    return By.LinkText(usingValue);
                case How.PartialLinkText:
                    return By.PartialLinkText(usingValue);
                case How.XPath:
                    return By.XPath(usingValue);
                case How.Custom:
                    if (attribute.CustomFinderType == null)
                    {
                        throw new ArgumentException("Cannot use How.Custom without supplying a custom finder type");
                    }

                    if (!attribute.CustomFinderType.IsSubclassOf(typeof(By)))
                    {
                        throw new ArgumentException("Custom finder type must be a descendent of the By class");
                    }

                    ConstructorInfo ctor = attribute.CustomFinderType.GetConstructor(new Type[] { typeof(string) });
                    if (ctor == null)
                    {
                        throw new ArgumentException("Custom finder type must expose a public constructor with a string argument");
                    }

                    By finder = ctor.Invoke(new object[] { usingValue }) as By;
                    return finder;
            }

            throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Did not know how to construct How from how {0}, using {1}", how, usingValue));
      }
}

And here's an example usage: 这是一个示例用法:

public class Page
{
    private IWebDriver driver;

    [FindsBy(How = How.Id, Using = "content")]
    public IWebElement ele;

    public Page(IWebDriver _driver)
    {
        this.driver = _driver;
    }
}

Use as follows: 用法如下:

Page page = PageFactory.InitElements<Page>(driver);

FindsByAttribute findsBy = SeleniumHelper.GetFindsByAttributeFromField(typeof(Page), "ele");

By by = SeleniumHelper.GeyByFromFindsBy(findsBy);

I found a way to o this :) 我找到了解决这个问题的方法:)

        public static IWebElement FindElement( IWebElement element, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(chromeDriver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => element);
        }
        return element;
    }

We faced the same issue when using selenium for testing. 使用硒进行测试时,我们面临同样的问题。 So we created a mini framework on top of selenium which keeps trying to do (whatever you are trying to do with selenium). 因此,我们在硒的基础上创建了一个微型框架,该框架一直在尝试做(无论您要如何使用硒)。 Or otherwise you can provide a custom pre or post condition. 否则,您可以提供自定义的前提条件。

https://github.com/LiquidThinking/Xenon https://github.com/LiquidThinking/Xenon

It is very simple to setup and all information is available on github, plus it comes with Screen objects which can help to reuse your code. 它的设置非常简单,所有信息都可以在github上获得,此外它还带有Screen对象,可以帮助重用您的代码。

For example 例如

new XenonTest(new SeleniumXenonBrowser())
        .GoToUrl("http://www.google.co.uk", a => a.PageContains("google") );

So in this example, we added a pre wait condition which says "before going to google.co.uk make sure that the current page contains "google" in page source. Which is obviously incorrect way to do it but it explains how to use pre or post wait conditions. 因此,在此示例中,我们添加了一个预等待条件,该条件表示“在转到google.co.uk之前,请确保当前页面的页面源中包含” google”。这显然是错误的方式,但是它说明了如何使用之前或之后的等待条件。

If you do not specify any wait condition then for some actions, there is a default wait action. 如果您未指定任何等待条件,则对于某些操作,将存在默认的等待操作。 for eg https://github.com/LiquidThinking/Xenon/blob/master/Xenon/BaseXenonTest.cs#L72 See how we check if a customPreWait is available for "Click" and if not then we added a custom pre-wait to check if that css selectors exists on the page before performing the "actual click action". 例如,例如https://github.com/LiquidThinking/Xenon/blob/master/Xenon/BaseXenonTest.cs#L72看看我们如何检查customPreWait是否可用于“点击”,如果没有,那么我们将自定义预等待添加到在执行“实际点击操作”之前,请检查页面上是否存在CSS选择器。

Hope it will help you, it is on nuget or otherwise just use the code which you want. 希望它能对您有所帮助,它位于nuget上,否则仅使用您想要的代码即可。 it is under MIT license. 它已获得MIT许可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM