简体   繁体   中英

Automated tests throwing error from code listed in setup despite it having already executed correctly in other tests

I am receiving a error from a group of tests where it seems to be looking for an element listed in the Setup Method despite the method already being executed, the error being thrown is:

Message: OpenQA.Selenium.NoSuchElementException : no such element: Unable to locate element: {"method":"xpath","selector":"//input[@id='txtCompany']"}
(Session info: chrome=71.0.3578.98)
(Driver info: chromedriver=2.45.615291
(ec3682e3c9061c10f26ea9e5cdcf3c53f3f74387),platform=Windows NT 10.0.17763 x86_64)"

I have tried replacing and commenting out code, I have also added in the extra step of returning to the Splash screen before clicking on the Reports drop down though this has not fixed the problem. Similar code works correctly outside of this class where a different test is taking place.

using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using NUnit.Framework;


[SetUp]
public void initalise()
    {   
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.Manage().Window.Maximize();

        //Navigates to the Test DB
        driver.Url = "https://TESTWEBSITE.co.uk";
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        //Find Company Text Box and send company name

driver.FindElement(By.XPath("//input[@id='txtCompany']")).SendKeys("COMPANY");

        //Find username Text Box and send username

driver.FindElement(By.XPath("//input[@id='txtUsername']")).SendKeys("6969_1");

        //Find password and send

driver.FindElement(By.XPath("//input[@id='txtPassword']")).SendKeys("PASSWORD");

        //Find Login button and click
        driver.FindElement(By.XPath("//input[@id='cmdLogin']")).Click();
    }

  [Test, Order(1)]
    public void reportsStandard()
    {
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.FindElement(By.XPath("//span[@class='rpOut']//span[@class='rpText'][contains(text(),'Reports')]")).Click();
        driver.FindElement(By.XPath("//span[contains(text(),'Standard Reports')]")).Click();

        IWebElement ReportType = driver.FindElement(By.XPath("//div[@id='ctl00_ContentPlaceHolder_lstReports']//ul[@class='rlbList']"));
        Assert.AreEqual(true, ReportType.Displayed);

    }
   [Test, Order(2)]
  public void reportsPandLCustomer()
    {

        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.FindElement(By.XPath("//span[contains(text(),'Home')]")).Click();
        driver.FindElement(By.XPath("//span[@class='rpOut']//span[@class='rpText'][contains(text(),'Reports')]")).Click();
        driver.FindElement(By.XPath("//span[contains(text(),'Profit and Loss by Customer')]")).Click();

        IWebElement AdvancedFiltering = driver.FindElement(By.XPath("//a[@id='ContentPlaceHolder_cmdAdvancedFiltering']"));
        Assert.AreEqual(true, AdvancedFiltering.Displayed);
    }

I would expect that the Tests execute as:

Setup (Launches Browser > Go to Website > Login)
Test Order 1 ( Click Reports Drop Down > Click Standard Report)
Test Order 2 ( Click Home Button > Click Reports Drop Down > ProfitAndLoss Button)

The actual result is:

Setup - Passes,
Test Order 1 - Passes,
Test Order 2 - Fails - Error is unable to locate an element which is only used during Setup Method.

So after playing around and some googling If I change the [Setup] Method to [OneTimeSetup] for the Class Then this works correctly. New Code will look like:

[OneTimeSetUp]
    public void initalise()
    {  //Maximise Window
        driver.Manage().Window.Maximize();

        //Navigates to the NG Test DB
        driver.Url = "https://TESTWEBSITE.co.uk";
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        //Find Company Text Box and send company name
        driver.FindElement(By.XPath("//input[@id='txtCompany']")).SendKeys("CompanyName");

        //Find username Text Box and send username
        driver.FindElement(By.XPath("//input[@id='txtUsername']")).SendKeys("6969_1");

        //Find password and send
        driver.FindElement(By.XPath("//input[@id='txtPassword']")).SendKeys("Password!");

        //Find Login button and click
        driver.FindElement(By.XPath("//input[@id='cmdLogin']")).Click();
    }
 [Test, Order(1)]
    public void reportsStandard()
    {
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.FindElement(By.XPath("//span[@class='rpOut']//span[@class='rpText'][contains(text(),'Reports')]")).Click();
        driver.FindElement(By.XPath("//span[contains(text(),'Standard Reports')]")).Click();
        IWebElement ReportType = driver.FindElement(By.XPath("//div[@id='ctl00_ContentPlaceHolder_lstReports']//ul[@class='rlbList']"));
//Assert.AreEqual(true, ReportType.Displayed);
    }
    [Test, Order(2)]
    public void reportsPandLCustomer()
    {

        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.FindElement(By.XPath("//span[contains(text(),'Home')]")).Click();
        driver.FindElement(By.XPath("//span[@class='rpOut']//span[@class='rpText'][contains(text(),'Reports')]")).Click();
        driver.FindElement(By.XPath("//span[contains(text(),'Profit and Loss by Customer')]")).Click();

        IWebElement AdvancedFiltering = driver.FindElement(By.XPath("//a[@id='ContentPlaceHolder_cmdAdvancedFiltering']"));
        Assert.AreEqual(true, AdvancedFiltering.Displayed);
    }
    [Test, Order(3)]
    public void reportsPandLPhone()
    {
        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        driver.FindElement(By.XPath("//span[contains(text(),'Home')]")).Click();
        driver.FindElement(By.XPath("//span[@class='rpOut']//span[@class='rpText'][contains(text(),'Reports')]")).Click();
        driver.FindElement(By.XPath("//span[contains(text(),'Profit and Loss by Phone Number')]")).Click();
        IWebElement ResetBTN = driver.FindElement(By.XPath("//span[@id='ctl00_FunctionBarPlaceHolder_cmdReset']"));
        Assert.AreEqual(true, ResetBTN.Displayed);
    }

The method tagged with [SetUp] is run before each test, see docs .

I think the problem is this:

  1. Setup runs, logging you in
  2. Test1 runs, passing
  3. Since Test1 has completed, Setup runs again but this time you are already logged in since you are reusing browser sessions (or at least appear to be given the code you have posted) so when the Setup method looks for the Company field it's not there.

Best practice is to use one browser session per test. It ensures that you have the cleanest run possible each time. You need to add launching the browser to your [SetUp] method and you need to add a [TearDown] method that quits the browser. This is how your tests should run:

  1. Setup runs, launches the browser and logs you in
  2. Test1 runs, passes
  3. TearDown runs and closes the browser
  4. Setup runs, launches the browser and logs you in
  5. Test2 runs, passes
  6. TearDown runs and closes the browser

Your TearDown method should be something like (see the docs linked above)

[TearDown]
public void Cleanup()
{
    driver.Quit();
}

Side note 1:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

This does not actually wait... it sets the wait time for the driver instance. It only needs to be set once ever and shouldn't be used again unless you want to change the timeout to a different value. You can remove all the instances of this except for the first one that should be in your Setup method.

Side note 2: Selenium contributors have stated to avoid using ImplicitWait . You should instead use WebDriverWait .

Side note 3: Your tests should not be run in a particular order. Each test should be independent of each other and should be able to run in any order.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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