返回

如何使用 Selenium 和 C# 访问包装在“.lazyload-wrapper”中的元素?

发布时间:2022-09-02 13:50:59 299
# 工具

我正在为澳大利亚一家流行的五金店网站构建一个测试工具。我希望我的测试转到包含例如 36 个结果的页面(该页面实际上显示“显示 151 个结果中的 36 个”),然后单击一个随机选择的产品中的“添加到购物车”按钮。为此,我尝试driver.FindElements 使用 CssSelector 捕获页面中的所有 36 个按钮。

我面临的问题是我只能获得前 12 件物品,因为其余 24 件物品都包裹在 a 中class=lazyload-wrapper,而我无法让司机捕获它们。我尝试将页面滚动到底部,我尝试在任何地方插入 Thread.Sleep,我尝试过WebDriverWait,我还从 ExpectedConditions 重新创建了一些不推荐使用的函数以使其工作,但我仍然只得到 12 个元素。

我在这里和其他论坛上阅读了几乎所有关于类似问题的帖子,但我仍然被相同的 12 个项目所困扰。也许 Selenium 不是做到这一点的最佳选择。如果有人能对这一挑战有所了解,将不胜感激。

这是我用来与页面交互的类,请原谅我留下所有注释掉的代码,它只是为了显示所有失败的尝试:

using System;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using System.Linq;

namespace Model.Pages
{
    public class CarAccessoriesPage : BasePage
    {
        public CarAccessoriesPage(IWebDriver driver) : base(driver)
        {
        }

        ///
        /// Add a random product to the shopping cart.
        /// 
        public CarAccessoriesPage AddRandomItemToCart()
        {
            // smooth scrolling down to force loading did not work
            // IJavaScriptExecutor jsex = (IJavaScriptExecutor)driver;
            // jsex.ExecuteScript("window.scrollTo({left:0, top:document.body.scrollHeight, behavior:'smooth'});");

            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));

            // Scroll
            IJavaScriptExecutor jsex = (IJavaScriptExecutor)driver;
            jsex.ExecuteScript("window.scrollTo(0, document.body.scrollHeight);");

            // maybe wait for the page to load? Did not work.
            wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete"));
            
            // Maybe inserting an ugly pause... no bueno
            Thread.Sleep(3000);

            // driver.FindElement(By.CssSelector("[data-index='35']")); // this element is not found

            Random r = new Random();
            int i = r.Next(0, GetPartialResultsCount());

            // First approach throws OutOfRangeException because only 12 elements are found
            // IWebElement itemElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5))
            //     .Until(d => d.FindElements(By.CssSelector("[data-locator='atcButton']")))[i];

            // Implementing a function from ExpectedConditions deprecated in C#, no good enough
            var elements = wait
                .Until(PresenceOfAllElementsLocatedBy(By.CssSelector("[data-locator='atcButton']")));

            // maybe trying access the article elements inside the wrapper... fail
            // var elements = driver.FindElements(By.CssSelector("article.lazyload-wrapper "));

            Console.WriteLine(elements.Count); // Always 12!!! I know there are better ways to log

            IWebElement ranItem = elements[i]; // Throws an OutOfRangeException if i > 11
            Thread.Sleep(1000);
            // center the element so the tob and bottom banners don intercept the click
            jsex.ExecuteScript("arguments[0].scrollIntoView({block: 'center'});", ranItem);
            Thread.Sleep(1000);
            ranItem.Click();

            Thread.Sleep(1000); // important or last function in test does not work (assertion fails: expected != actual)
            return this;
        }

        ///
        /// Get the number of items in the shopping cart.
        /// 
        public int GetCartCount()
        {
            return Int32.Parse(driver.FindElement(By.ClassName("cartItemCount")).Text);
        }


        private Func<IWebDriver, ReadOnlyCollection> PresenceOfAllElementsLocatedBy(By locator)
        {
            return (driver) =>
            {
                try
                {
                    var elements = driver.FindElements(locator);
                    return elements.Any() ? elements : null;
                }
                catch (StaleElementReferenceException)
                {
                    return null;
                }
            };
        }

        ///
        /// Generate a random int no larger than the Collection of products
        /// in the page. But due to lazy loading, the number generated was causing an out of range exception.
        /// 
        private int GetPartialResultsCount()
        {
            string partialResultsCount = driver.FindElement(By.CssSelector(".resultsCount > p")).Text;
            return Int32.Parse(Regex.Match(partialResultsCount, @"\d+").Value);
        }

    }
}

测试本身实际上非常直接:

using NUnit.Framework;
using Model.Pages;

namespace Tests
{
    public class ShoppingCartTests : BaseTests
    {

        [Test]
        public void ValidateCartItemsCount()
        {
            int cartCount = open()
                .GoToCarAccessoriesPage()
                .AddRandomItemToCart()
                .AddRandomItemToCart()
                .GetCartCount();

            // Validate cart has 2 items
            Assert.AreEqual(2, cartCount);
        }
    }
}

最后,我可能只需要提到,如果我只考虑12个项目,测试就会运行并工作,但获取用户可以在页面中看到的所有项目就像个人痴迷一样。此外,不确定我是否应该共享我正在测试的实际网站,或者这违反了社区规则或最佳实践。可以说,这是澳大利亚最受欢迎的五金店,网站相当复杂。谢谢

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(1)
按点赞数排序
用户头像