Issue
on my web page I have a select element that update the page content after clicking on it.
I write a piece of code that allow me to navigate threw the different options of the select element. This part of the code work well but, after those line, when I try to get some "data" using
WebDriver.FindElement().Text
(with the proper XPath of course)
in the loop that allow me to navigate threw options, it seems that the data doesn't properly update on the page.
Here is the snippet I wrote :
foreach(IWebElement option in optionList)
{
option.Click();
var productName = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/h1/span"));
var productPrice = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[3]/div/div/div[1]/div/span[1]/meta"));
var productDescription = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[2]/div/div[1]/div/div/p[5]"));
var productReference = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/div/span"));
var productReferer = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/span/a"));
ProductReference pr = new()
{
DisplayName = productName.Text,
Price = productPrice.Text,
Description = productDescription.Text,
Referer = productReferer.Text,
Reference = productReference.Text,
AttributName = "Couleurs",
AttributValue = option.Text,
};
products.Add(pr);
Console.WriteLine(pr);
}
I don't if there is a way to "Refresh" the browser or anything else.
pr AttributValue is always correct but, for example, the reference is already the same whereas it should be different.
Thank for futur help !
MORE INFORMATIONS :
Here is the code that come before the loop :
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("--headless=new");
chromeOptions.AddExcludedArgument("disable-popup-blocking");
ChromeDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl(url);
IWebElement colorChoiceElmt = driver.FindElement(By.Id("group_4"));
SelectElement select = new SelectElement(colorChoiceElmt);
IList<IWebElement> optionList = select.Options;
ALREADY TESTED CODE :
-- RAMON SUGGESTION --
I tried this after Ramon suggestion. Thing is that on Selenium docs, they ask us to not use ExpectedConditions (and it create an error by using it) so I followed they recommendations and use Explicit wait like this :
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(2));
wait.Until(d => colorChoiceElmt.Displayed);
colorChoiceElmt.SendKeys("Displayed");
-- YAROSLAVM SUGGESTION --
Because ExpectedConditions is not yet supported by Selenium in them lastest version I installed "SeleniumExtras.WaitHelpers" nugget package to the followed code to work. Spoiler, result is the same.
static void ProcessUrl(string url)
{
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("--headless=new");
chromeOptions.AddExcludedArgument("disable-popup-blocking");
ChromeDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl(url);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement colorChoiceElmt = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("group_4")));
SelectElement select = new SelectElement(colorChoiceElmt);
IList<IWebElement> optionList = select.Options;
string currentProductReference = null;
for (int index = 0; index < optionList.Count; index++)
{
if (index > 1)
{
wait.Until(ExpectedConditions.StalenessOf(colorChoiceElmt));
}
colorChoiceElmt = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("group_4")));
select = new SelectElement(colorChoiceElmt);
optionList = select.Options;
select.SelectByIndex(index);
IWebElement product = driver.FindElement(By.CssSelector(".product-info-row"));
IWebElement productName = product.FindElement(By.CssSelector("[itemprop=name]"));
IWebElement productPrice = product.FindElement(By.CssSelector(".product-price"));
IWebElement productDescription = driver.FindElements(By.CssSelector(".product-description p"))[4];
IWebElement productReference = product.FindElement(By.CssSelector("[itemprop=sku]"));
currentProductReference = productReference.Text;
IWebElement productReferer = product.FindElement(By.CssSelector(".product_header_container a"));
ProductReference pr = new()
{
DisplayName = productName.Text,
Price = productPrice.Text,
Description = productDescription.Text,
Referer = productReferer.Text,
Reference = productReference.Text,
AttributName = "Couleurs",
AttributValue = optionList[index].Text,
};
products.Add(pr);
Console.WriteLine(pr);
}
driver.Quit();
}
Solution
1st of all - don't use absolute selectors. Try to use unique and short selectors that point to needed element.
Then - after selecting dropdown option on 2+ try you should wait for previous dropdown element be re-rendered (it happens in your case), so when it happened - new product card info is shown. Then you just re-init dropdown element and get data from the next loop.
I added general code with described logic, you can adjust it and adopt to your script structure.
Waiting for element visbility, using 4.0+
WebDriverWait
would be something like
IWebElement colorChoiceElmt = wait.Until(webDriver =>
{
IWebElement target = driver.FindElement(By.Id("group_4"));
return target.Displayed ? target : null;
});
Waiting for element to be stale similar to
wait.Until(webDriver =>
{
try
{
IWebElement target = driver.FindElement(By.CssSelector("[itemprop=image]"));
return !target.Displayed
}
catch (Exception)
{
return true;
}
});
So, working example is:
using System;
using System.Collections.Generic;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
namespace TestProject1
{
[TestFixture]
public class Tests
{
[Test]
public void Test1()
{
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.AddExcludedArgument("disable-popup-blocking");
chromeOptions.AddArgument("--headless=new");
IWebDriver driver = new ChromeDriver(chromeOptions);
string url = "https://www.wrs.it/fr/bouchon-de-huile-moteur/200579-too02-bouchon-de-remplissage-d-huile-ducabike-ducati-diavel-2011.html";
driver.Navigate().GoToUrl(url);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement colorChoiceElmt = wait.Until(webDriver =>
{
IWebElement target = driver.FindElement(By.Id("group_4"));
return target.Displayed ? target : null;
});
SelectElement select = new SelectElement(colorChoiceElmt);
IList<IWebElement> optionList = select.Options;
List<Dictionary<string, string>> products = new List<Dictionary<string, string>>();
IWebElement product = driver.FindElement(By.CssSelector(".product-info-row"));
string imageHref = product.FindElement(By.CssSelector("[itemprop=image]")).GetDomProperty("href");
string referenceText = product.FindElement(By.CssSelector("[itemprop=sku]")).Text;
for (int index = 0; index < optionList.Count; index++)
{
select.SelectByIndex(index);
wait.Until(webDriver =>
{
try
{
IWebElement target = product.FindElement(By.CssSelector("[itemprop=image]"));
return !target.GetDomProperty("href").Equals(imageHref);
}
catch (Exception)
{
return true;
}
});
wait.Until(webDriver =>
{
try
{
IWebElement target = product.FindElement(By.CssSelector("[itemprop=sku]"));
return !target.Text.Equals(referenceText);
}
catch (Exception)
{
return true;
}
});
imageHref = product.FindElement(By.CssSelector("[itemprop=image]")).GetDomProperty("href");
product = driver.FindElement(By.CssSelector(".product-info-row"));
colorChoiceElmt = wait.Until(webDriver =>
{
IWebElement target = driver.FindElement(By.Id("group_4"));
return target.Displayed ? target : null;
});
select = new SelectElement(colorChoiceElmt);
optionList = select.Options;
string productName = product.FindElement(By.CssSelector("[itemprop=name]")).Text;
string productPrice = product.FindElement(By.CssSelector(".product-price")).Text;
string productDescription = driver.FindElements(By.CssSelector(".product-description p"))[4].Text;
referenceText = product.FindElement(By.CssSelector("[itemprop=sku]")).Text;
string productReferer = product.FindElement(By.CssSelector(".product_header_container a")).Text;
Dictionary<string, string> pr = new Dictionary<string, string>
{
{ "DisplayName", productName },
{ "Price", productPrice },
{ "Description", productDescription },
{ "Referer", productReferer },
{ "Reference", referenceText },
{ "AttributName", "Couleurs" },
{ "AttributValue", optionList[index].Text },
};
products.Add(pr);
}
driver.Quit();
}
}
}
Answered By - Yaroslavm
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.