2

我正在使用 Wait.Until 方法来检查我的页面是否已加载或是否仍在加载。这是它的样子:

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);
    }

但是现在我们想改变我们的自动化页面并开始使用 FindBy 敌人每个元素,像这样:

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

但是 wait.until 需要“by”元素。

我看到了这个问题的抽象解决方案,但这对我的情况没有好处。谁能知道我可以使用的另一种解决方案?

4

3 回答 3

2

Selenium .NET 解决方案中有一个ByFactory 。我采取了这个实现来实现你想要的:

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));
      }
}

这是一个示例用法:

public class Page
{
    private IWebDriver driver;

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

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

使用如下:

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

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

By by = SeleniumHelper.GeyByFromFindsBy(findsBy);
于 2017-01-05T13:51:03.743 回答
1

我找到了一种方法:)

        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;
    }
于 2016-03-13T12:25:17.740 回答
1

我们在使用 selenium 进行测试时遇到了同样的问题。所以我们在 selenium 之上创建了一个迷你框架,它一直在尝试做(无论你想用 selenium 做什么)。或者,您可以提供自定义的前置或后置条件。

https://github.com/LiquidThinking/Xenon

它的设置非常简单,所有信息都可以在 github 上找到,而且它带有 Screen 对象,可以帮助重用您的代码。

例如

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

所以在这个例子中,我们添加了一个预先等待条件,上面写着“在访问 google.co.uk 之前,请确保当前页面在页面源中包含“google”。这显然是不正确的做法,但它解释了如何使用前或后等待条件。

如果您没有指定任何等待条件,那么对于某些操作,有一个默认的等待操作。例如https://github.com/LiquidThinking/Xenon/blob/master/Xenon/BaseXenonTest.cs#L72 查看我们如何检查 customPreWait 是否可用于“单击”,如果没有,我们添加了自定义预等待在执行“实际点击操作”之前检查页面上是否存在 CSS 选择器。

希望它会对您有所帮助,它在 nuget 上,或者只是使用您想要的代码。它在 MIT 许可下。

于 2016-03-13T12:27:41.347 回答