WebDriver: explicitly wait doesn`t work by click to element - c#

My code with implicitly wait works well. But I read information about waits and understood, that I need using explicitly wait in my projects. That`s why I am trying implement my test project with it.
When step of my alhorithm equel click to button, I have error : http://joxi.ru/BA0GMyDhnY0n2y
Please, help me with it.
Base class:
using NUnit.Framework;
using System;
using LinkedinAddContacts.Pages;
using LinkedinAddContacts.TestData;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
namespace LinkedinAddContacts
{
[TestFixture]
public class TestClass
{
private IWebDriver webDriver;
private WebDriverWait waitDriver;
[SetUp]
public void InitializeBrowser()
{
webDriver = new ChromeDriver();
waitDriver = new WebDriverWait(webDriver, TimeSpan.FromSeconds(10));
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(30);
webDriver.Navigate().GoToUrl("https://www.linkedin.com/");
}
[Test]
public void TestMethod()
{
Authorization authorizationData = new Authorization();
StartPage objStartPage = new StartPage(waitDriver);
NetworkPage objNetworkPage = new NetworkPage(waitDriver);
objStartPage.EntrySystem(authorizationData);
objNetworkPage.ConnectPeople();
}
[TearDown]
public void CloseBrowser()
{
webDriver.Quit();
}
}
}
Secondary class:
using NUnit.Framework;
using LinkedinAddContacts.TestData;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
namespace LinkedinAddContacts.Pages
{
public class StartPage
{
// private IWebDriver webDriver;
private WebDriverWait waitDriver;
#region Objects
public StartPage(WebDriverWait waitDriver)
{
this.waitDriver = waitDriver;
}
private IWebElement EmailInput
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("session_key")));
//return webDriver.FindElement(By.Name("session_key"));
}
}
private IWebElement PasswordInput
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("session_password")));
// return webDriver.FindElement(By.Name("session_password"));
}
}
private IWebElement LoginButton
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("login-submit")));
//return webDriver.FindElement(By.Id("login-submit"));
}
}
private IWebElement RegistrationForm
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Id("regForm")));
// return webDriver.FindElement(By.Id("regForm"));
}
}
#endregion
#region Methods
public void CloseRegistrationForm()
{
IJavaScriptExecutor js = waitDriver as IJavaScriptExecutor;
js.ExecuteScript("document.getElementById('regForm').style.display = 'none';");
// ((IJavascriptExecutor)driver).executeScript("scroll(0,400)");
}
public void EntrySystem(Authorization authorizationData)
{
// CloseRegistrationForm();
EmailInput.SendKeys(authorizationData.Email);
PasswordInput.SendKeys(authorizationData.Password);
LoginButton.Click();
}
#endregion
}
}
Error there:
public void EntrySystem(Authorization authorizationData)
{
// CloseRegistrationForm();
EmailInput.SendKeys(authorizationData.Email);
PasswordInput.SendKeys(authorizationData.Password);
LoginButton.Click();
}

When I understand it properly your code crashes at this line:
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("login-submit")));
Now, taking a look at the startpage of linkedIn reveals that the login-submit button doesn't have a name attribute defined, but you can use it's id instead.
<input tabindex="1" id="login-submit" class="login submit-button" type="submit" value="Einloggen">
So you should be using By.id() instead of By.name().

It is important to notice which web driver you use.
First of all, As #Robert says, its better to find by Id whenever it is available to you.
Second, I think LoginButton.Click() does not work. I had such a problem with chrome driver. When page scale(zooming) is changed, the Click method does not work properly, or clicks elsewhere on the page.
I recommend you to use SendKeys for any click action.
Just like this:
LoginButton.SendKeys(Keys.Enter);// or Keys.Return
Never ever use Click method

Related

Unable to locate element -- OpenQA.Selenium.NoSuchElementException

I am trying to automate a test case through Specflow, by using the Gherkin format, but I keep getting the error:
OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"xpath","selector":"./ancestor-or-self::form"}
The button that cannot be located is commented in the AddCart Page below.
The website that I am testing is: http://automationpractice.com/index.php
What I am trying to achieve is as seen below:
Feature: Adding products in the cart
Scenario Outline: Adding a product of the HomePage in the cart and continue shopping
Given That the user is on the HomePage
When User clicks the Add to cart button
And User clicks the Continue shopping button
Then The user will stay on the HomePage
The code of the Step Definition is:
namespace WebsiteTestingSpecflow.Steps
{
[Binding]
public sealed class AddingCartContinueStep
{
AddCartPage addcart = null;
[Given(#"That the user is on the HomePage")]
public void GivenThatTheUserIsOnTheHomePage()
{
IWebDriver webDriver = new ChromeDriver();
webDriver.Navigate().GoToUrl("http://automationpractice.com/index.php");
addcart = new AddCartPage(webDriver);
}
[When(#"User clicks the Add to cart button")]
public void WhenUserClicksTheAddToCartButton()
{
addcart.AddCart();
}
[When(#"User clicks the Continue shopping button")]
public void WhenUserClicksTheContinueShoppingButton()
{
addcart.ContinueShopping();
}
[Then(#"The user will stay on the HomePage")]
public void ThenTheUserWillStayOnTheHomePage()
{
addcart.Verifyelement();
}
}
}
The code of the AddCart Page is:
namespace WebsiteTestingSpecflow.Pages
{
public class AddCartPage
{
private readonly WebDriverWait wait;
public IWebDriver Webdriver { get; }
public AddCartPage(IWebDriver webDriver)
{
Webdriver = webDriver;
wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(30));
}
public IWebElement BtnAddCart => Webdriver.FindElement(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span"));
// This is the button that I keep getting error.
public IWebElement btnContinueCart => Webdriver.FindElement(By.CssSelector(".continue > span"));
public void AddCart() {
BtnAddCart.Submit();
}
public void ContinueShopping() {
wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector(".continue > span")));
btnContinueCart.Submit();
}
public void Verifyelement() => Webdriver.FindElement(By.CssSelector(".sfHover > .sf-with-ul"));
}
}
The CSS Selector of that button is as mentioned in the AddCart Page, but it still unable to locate the element.
May anyone know how can I fix this problem?
Thank you in advance.
Looks like you are trying to find element at the moment when it's not visible yet, because it will be visible only when you click to Add to cart and only then that element can be reached.
Try code below and also consider using Page Object model
public void ContinueShopping() {
IWebElement btnContinueCart => Webdriver.FindElement(By.CssSelector(".continue > span"));
wait.Until(ExpectedConditions.ElementToBeClickable(By.CssSelector(".continue > span")));
btnContinueCart.Submit();
}
You need to incorporate Actions into your code since this button is not visible unless you hover over it. Also add a wait condition around it
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
Actions action = new Actions(driver);
var btn = wait.Until(ExpectedConditions.ElementIsVisible(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span")));
action.MoveToElement(driver.FindElement(By.CssSelector("#homefeatured > .ajax_block_product:nth-child(1) .button:nth-child(1) > span"))).Build().Perform();
btn.Click();
Add the following to the top:
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;

Not able to Sign Up for a retail website by using Selenium Webdriver even though there is no error

Trying to sign up to Nordstrom site via Selenium with C#. The code executes correctly but for some reason the sign up does not happen. After sign up the Nordstrom site on the top right corner should say account instead of Login/Sign Up. There is no error whatsever but it just does not sign up. Is there something wrong with the way Create Account button is clicked?
Here's the code
using NordstromRack.UI_Elements;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;
using System;
using System.Threading;
namespace NordstromRack
{
class EntryPoint
{
static void Main(string[] args)
{
String parentHandle = Driver.driver.CurrentWindowHandle; // get the current window handle
EmailSignUp signup = new EmailSignUp();
Driver.driver.Navigate().GoToUrl("https://www.nordstromrack.com/");
Driver.driver.Manage().Window.Maximize();
Thread.Sleep(1000);
signup.SignUpLink.Click();
foreach (String winHandle in Driver.driver.WindowHandles)
{
Driver.driver.SwitchTo().Window(winHandle);
}
//WebDriverWait wait = new WebDriverWait(Driver.driver, TimeSpan.FromSeconds(1000));
//wait.Until(ExpectedConditions.ElementToBeClickable(signup.EmailInput));
signup.EmailInput.Click();
signup.EmailInput.SendKeys(Config.Credentials.Valid.BaseEmail);
Thread.Sleep(1000);
signup.Password.Click();
signup.Password.SendKeys(Config.Credentials.Valid.Password);
Thread.Sleep(1000);
Actions action = new Actions(Driver.driver);
action.MoveToElement(signup.CreateAccount).Click().Perform();
Console.WriteLine("Signup Successful");
Thread.Sleep(5000);
//Driver.driver.Quit();
}
}
}
Here's the class for identifying elements
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
namespace NordstromRack.UI_Elements
{
public class EmailSignUp
{
public EmailSignUp()
{
PageFactory.InitElements(Driver.driver, this);
}
[FindsBy(How = How.CssSelector, Using = "input.form-label__input.form-label__input--password")]
public IWebElement Password { get; set; }
[FindsBy(How = How.CssSelector, Using = "input.form-label__input.form-label__input--email")]
public IWebElement EmailInput { get; set; }
[FindsBy(How = How.ClassName, Using = "secondary-nav__link")]
public IWebElement SignUpLink { get; set; }
[FindsBy(How = How.CssSelector, Using = "button.cta-button.cta-button--nordstromrack")]
public IWebElement CreateAccount { get; set; }
}
}
Here is Driver Class
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace NordstromRack
{
public static class Driver
{
public static IWebDriver driver = new ChromeDriver();
}
}
Instead of all this
signup.Password.SendKeys(Config.Credentials.Valid.Password);
Thread.Sleep(1000);
Actions action = new Actions(Driver.driver);
action.MoveToElement(signup.CreateAccount).Click().Perform()
Try this.Not required to click on "Create Account" button.
signup.Password.SendKeys(Config.Credentials.Valid.Password);
signup.Password.Submit();
Did you try
signup.CreateAccount.SendKeys(Keys.Return);
In place of
Actions action = new Actions(Driver.driver);
action.MoveToElement(signup.CreateAccount).Click().Perform();
Note you will need to add Keys to your selenium imports.
?

Selenium Waits Logic

I am building a testing framework for my website
I want to fully separate the framework away from test
the issue is when I write a test sometimes the Assert needs time until it can be true, for example if I am on Upload file page and when the file is uploaded the website should display File uploaded successfully page but it will need to much time until the browser reaches this page
How should I force the Assert to wait sometime before it returns result?
some code that might explain my current way of work:
Upload Page Class
Public class UploadPage
{
[FindsBy(How = How.Name, Using = "upload-button")]
public IWebElement BtnUpload { get; set; }
public UploadPage()
{
PageFactory.InitElements(Driver, this);
}
public void UploadFile(string path)
{
//select file
BtnUpload.Click();
}
}
Successful Upload Page:
Public class UploadSuccessfulPage
{
[FindsBy(How = How.Name, Using = "success-message")]
public IWebElement LblSuccessMessage{ get; set; }
public UploadSuccessfulPage()
{
PageFactory.InitElements(Driver, this);
}
public bool IsAt()
{
Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(60))
return Driver.url==configurations.UploadSuccessfulPageURL;
}
}
Test Method:
public void TestUpload()
{
UploadPage uploadPage= new UploadPage ();
uploadPage.UploadFile(path);
UploadSuccessfulPage successPage= new UploadSuccessfulPage();
Assert.IsTrue(successPage.IsAt());
}
when I write my tests this way the assert do not wait despite that IsAt() contains implicit wait
P.S: I am not intending to use Thread.Sleep();
The method bool IsAt() should be implemented like:
public bool IsAt()
{
Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(60));
try {
return driver.FindElement(By.Name("success-message").Displayed;
} catch (WebDriverException e) {
return false;
}
}
Or using explicit wait:
public bool IsAt()
{
try {
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
wait.Until(ExpectedConditions.ElementIsVisible(By.Name("success-message")));
return true;
} catch (TimeoutException e){
return false;
}
}
Update:
If you want to verify by url, the bool IsAt() should look like:
public bool IsAt()
{
try {
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
wait.Until(ExpectedConditions.UrlToBe(configurations.UploadSuccessfulPageURL));
return true;
} catch (TimeoutException e){
return false;
}
}
Look at the class ExpectedConditions to find a condition suitable to your require

Get IWebDriver from setupfixture

First sorry about my English.
Here is my problem:
I make a test for mantisbt with many test cases(report issue), so i put the login in [SetUpFixture] and in [TestFixture] [Test, TestCaseSource("function")] I don't know how to get driver which i use for creating chrome browser to get elements.
Here is my code:
namespace testcailz
{
[SetUpFixture]
public class TestsSetupClass
{
public void login(IWebDriver driver)
{
IWebElement username = driver.FindElement(By.Name("username"));
username.SendKeys("1353049");
IWebElement password = driver.FindElement(By.Name("password"));
password.SendKeys("123456");
IWebElement login = driver.FindElement(By.XPath("//input[#value='Login'][#class='button']"));
login.Click();
}
[SetUp]
public void GlobalSetup()
{
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("http://www.cs.hcmus.edu.vn/mantisbt/login_page.php");
login(driver);
}
[TearDown]
public void GlobalTeardown()
{
// Do logout here
}
}
[TestFixture]
public class Class1
{
private static int[] data()
{
return new int[3] { 1, 2, 3 };
}
[Test, TestCaseSource("data")]
public void TestCaiLz(int i)
{
//wanna click to report new issue but how to get driver for Findelement
Assert.AreEqual(i, i);
}
}
}
As per java prospective, create driver object globally in class may be TestsSetupClass
public static WebDriver driver;
#BeforeSuite
public void startUp(){
driver=new FirefoxDriver();
driver.manage().window().maximize();
login(driver);
}
If you what to use this driver in another classes then extends this class. like below in java
public class Home extends Setup{ //...
}
Thank You,
Murali

Using webbackgrounder nuget in MVC to run background task for long time

I need to implement a task in background so what is my task? I have a table that stores the rent amount of each customers, so I need to calculate the rent price in each month after a specific datetimeackf so I googled it and I found a piece of code that (it is nuget called webbackgrounder) I added it to my solution and it gives me this part of code to handle my task:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace WebBackgrounder.DemoWeb
{
public class SampleJob : Job
{
public SampleJob(TimeSpan interval, TimeSpan timeout)
: base("Sample Job", interval, timeout)
{
}
public override Task Execute()
{
return new Task(() => Thread.Sleep(3000));
}
}
}
I want to know how can I program my task ?
More details : Here
I found this article but in fact I don't know can I use this method for longtime ??
Best regards .
any ideas will be appreciated.
You need to also add in a class to the App_Start folder of your application that will start the Job and manage it's lifetime. You can see an example here... https://github.com/NuGet/WebBackgrounder/tree/master/src/WebBackgrounder.DemoWeb
Here is the code from the demo app
using System;
using Elmah;
using WebBackgrounder.Jobs;
[assembly: WebActivator.PostApplicationStartMethod(typeof(WebBackgrounder.DemoWeb.App_Start.WebBackgrounderSetup), "Start")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(WebBackgrounder.DemoWeb.App_Start.WebBackgrounderSetup), "Shutdown")]
namespace WebBackgrounder.DemoWeb.App_Start
{
public static class WebBackgrounderSetup
{
static readonly JobManager _jobManager = CreateJobWorkersManager();
public static void Start()
{
_jobManager.Start();
}
public static void Shutdown()
{
_jobManager.Dispose();
}
private static JobManager CreateJobWorkersManager()
{
var jobs = new IJob[]
{
new SampleJob(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20)),
/* new ExceptionJob(TimeSpan.FromSeconds(15)), */
new WorkItemCleanupJob(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(5), new WorkItemsContext())
};
var coordinator = new WebFarmJobCoordinator(new EntityWorkItemRepository(() => new WorkItemsContext()));
var manager = new JobManager(jobs, coordinator);
manager.Fail(ex => Elmah.ErrorLog.GetDefault(null).Log(new Error(ex)));
return manager;
}
}
}
However I found it simpler to just use the parts of Webbackgrounder that I needed as follows. Place this class in the App_Start folder
using System;
using BombaySapphireCds.Jobs;
using Elmah;
[assembly: WebActivator.PostApplicationStartMethod(typeof(BombaySapphireCds.App_Start.PodMonitorConfig), "Start")]
[assembly: WebActivator.ApplicationShutdownMethod(typeof(BombaySapphireCds.App_Start.PodMonitorConfig), "Shutdown")]
namespace BombaySapphireCds.App_Start
{
public static class PodMonitorConfig
{
private static PodMonitorJob m_job;
public static void Start()
{
m_job = new PodMonitorJob(TimeSpan.FromSeconds(20));
}
public static void Shutdown()
{
m_job.Dispose();
}
}
}
and the class to do the actual work... (put this anywhere you like)
using System;
using System.Threading;
using System.Threading.Tasks;
namespace BombaySapphireCds.Jobs
{
public class PodMonitorJob : IDisposable
{
private CancellationTokenSource m_cancel;
private Task m_task;
private TimeSpan m_interval;
private bool m_running;
public PodMonitorJob(TimeSpan interval)
{
m_interval = interval;
m_running = true;
m_cancel = new CancellationTokenSource();
m_task = Task.Run(() => TaskLoop(), m_cancel.Token);
}
private void TaskLoop()
{
while (m_running)
{
//
// Do monitoring work here.
//
Thread.Sleep(m_interval);
}
}
public void Dispose()
{
m_running = false;
if (m_cancel != null)
{
try
{
m_cancel.Cancel();
m_cancel.Dispose();
}
catch
{
}
finally
{
m_cancel = null;
}
}
}
}
}
This has become the new standard for background task execution on the web. It's a NuGet package and it's called HangFire - https://github.com/HangfireIO/Hangfire. The tasks persist even beyond apppool recycling.

Categories