2

I'm sure this is a simple one but I have not been able to find the cause of this error let alone the solution.

I am using selenium page objects which has been running perfectly up until now when I have added a new page to my tests.

Here is my main code

class RunTest
{
   static IWebDriver driver;

   [Test]
   public void Login()
   {
      var options = new ChromeOptions();
      options.AddArguments("chrome.switches", "--disable-extensions --disable-extensions-file-access-check --disable-extensions-http-throttling --disable-infobars --enable-automation ");
      options.AddUserProfilePreference("credentials_enable_service", false);
      options.AddUserProfilePreference("profile.password_manager_enabled", false);
      driver = new ChromeDriver(options);

      driver.Url = ConfigurationManager.AppSettings["URL"];

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

      var loginPage = new LoginPage(driver);
      loginPage.LoginToApplication("Test1");

      IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
      var element = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='content']/div/div/div/div/ul/li[4]/div[1]/div[2]/div/button[1]")));

      var setenv = new SetEnvironment(driver);
      setenv.SetEnvQA();
}

[Test]
public void AddBatchTest()
{
   var AddBatch = new Batch(driver);
   AddBatch.AddNewBatch("Test1");
}

[Test]
public void Test1()
{
   var NewCli = new AddNewClient(driver);
   NewCli.Addanewclient("Test1");
}

The Login and Test1 tests (Along with the others) run perfectly however the Batch test falls over with

System.ArgumentException : The SearchContext of the locator object cannot be null Parameter name: locator

The code in the batch class and AddNewClient class are identical so I cant see what the problem is

Batch:

namespace OnlineStore.PageObjects
{
    class Batch
    {
        IWebDriver driver;

        //Admin link in left hand otions
        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_NavigationPanel_navigationpanel1_hlAdmin']")]
        public IWebElement AdminScreen { get; set; }

        //Add new batch link
        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_HyperLink38']")]
        public IWebElement AddNewBatchLnk { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_DatepickerReceived_txtDate']")]
        public IWebElement DateReceived { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='aspnetForm']/div[3]/div/div[2]/div[3]/table[3]/tbody/tr/td/table/tbody/tr[7]/td]")]
        public IWebElement SelectToday { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_txtTotal']")]
        public IWebElement BatchTotal { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_ucCurrency_ddlCurrency']")]
        public IWebElement Currency { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_cboAgency']")]
        public IWebElement Provider { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_txtNote']")]
        public IWebElement BatchNotes { get; set; }

        public Batch(IWebDriver driver)
        {
            this.driver = driver;
            PageFactory.InitElements(driver, this); 
        }

        public void AddNewBatch(string testName)
        {
            var userData = ExcelDataAccess.GetTestData(testName);

            IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30.00));

            AdminScreen.Click();
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='ctl00_MainBody_HyperLink38']")));

            AddNewBatchLnk.Click();
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='ctl00_MainBody_DatepickerReceived_txtDate']")));

            DateReceived.SendKeys("22/05/2017");
            //SelectToday.Click();
            BatchTotal.SendKeys("1000");
            Currency.SendKeys("USD");
            Provider.SendKeys("Client");
            BatchNotes.SendKeys("Some Batchg notes here please");

        }
    }
}

AddNewClient:

public AddNewClient(IWebDriver driver)
{
   this.driver = driver;
   PageFactory.InitElements(driver, this);
}

public void Addanewclient(string testName)
{ 
   //Code here
}

Any ideas?

Update: I tried moving the AddBatchTest code into the Login code script and it ran fine but when I pushed it back out to its own test it errored again.

Full stack trace as requested in the comments.

Result StackTrace:  
at OpenQA.Selenium.Support.PageObjects.PageFactory.InitElements(Object page, IElementLocator locator, IPageObjectMemberDecorator decorator)
   at OpenQA.Selenium.Support.PageObjects.PageFactory.InitElements(ISearchContext driver, Object page)
   at OnlineStore.PageObjects.Batch..ctor(IWebDriver driver) in C:\Users\andrew.logan-smith\documents\visual studio 2015\Projects\OnlineStore\OnlineStore\PageObjects\Batch.cs:line 54
   at OnlineStore.TestCases.RunTest.AddBatchTest() in C:\Users\andrew.logan-smith\documents\visual studio 2015\Projects\OnlineStore\OnlineStore\TestCases\RunTest.cs:line 52
Result Message: 
System.ArgumentException : The SearchContext of the locator object cannot be null
Parameter name: locator
Brian
  • 5,069
  • 7
  • 37
  • 47
Smithy7876
  • 316
  • 4
  • 13
  • *The code in the batch class and AddNewClient class are identical so I cant see what the problem is* Well, obviously there is a problem. You need to add the full stack trace as well as **all** the relevant code. – Guy May 22 '17 at 10:32
  • I concur there is definitely a problem some where. I've added the stack trace. I believe I have already got all of the **relevant** code. The remaining is just the elements and selenium commands – Smithy7876 May 22 '17 at 10:46
  • `InitElements` failed on the elements initialization, the elements **are relevant**. And posting just the methods signatures will probably never be useful. – Guy May 22 '17 at 11:00
  • I have already put everything from my RunTest class (Apart from the closing }) So do you think the issue is somewhere in my batch class? I only ask as it works fine if I put the call to it into the Login test. Hence my complete confusion! Happy to put up all of my element sets if you think it will help though (Im quite worried that im going to make this into a huge question!) – Smithy7876 May 22 '17 at 11:06
  • The elements are in `Batch` class and you can see in the stack trace that the exception is thrown from `Batch` class constructor, then yes, this class is relevant.You should add all of it. – Guy May 22 '17 at 11:11
  • There isn't any problem in the amount of code as long as it relevant. – Guy May 22 '17 at 11:12
  • Ok i've added the entire batch class to my question – Smithy7876 May 22 '17 at 11:17

1 Answers1

3

The order of the Test methods in RunTest class is not necessarily the ecxution order. In your case the order is probably AddBatchTest() -> Login() -> Test1(). That cause the driver to be null when calling Batch constructor and PageFactory.InitElements receives null as the driver argument i.e. the SearchContext, hence the error

The SearchContext of the locator object cannot be null

InitElements method from github

public static void InitElements(ISearchContext driver, object page)
{
    InitElements(page, new DefaultElementLocator(driver));
}

I suggest you move the Login() under [SetUp] annotation and add [TearDown]. It will run before and after each test and provide you "clean slate"

public class RunTest
{
    private IWebDriver driver = null;

    [SetUp]
    public void Login()
    {
        driver = new ChromeDriver(options);
        //...
    }

    [Test]
    public void AddBatchTest()
    {
        var AddBatch = new Batch(driver);
        AddBatch.AddNewBatch("Test1");
    }

    [Test]
    public void Test1()
    {
        var NewCli = new AddNewClient(driver);
        NewCli.Addanewclient("Test1");
    }

    [TearDown]
    public void TearDown()
    {
        if (Driver != null)
        {
            Driver.Quit();
        }
    }
}

Edit

If you want to run SetUp and TearDown one time for all the tests you can use [TestFixtureSetUp] and [TestFixtureTearDown] annotations. You also need to add [TestFixture] to the class

[TestFixture]
public class RunTest
{
    [TestFixtureSetUp]
    public void SetUp()
    {
    }

    [Test]
    public void AddBatchTest()
    {
    }

    [Test]
    public void Test1()
    {
    }

    [TestFixtureTearDown]
    public void TearDown()
    {
    }
}

*This is for NUnit 2, for NUnit 3 use [OneTimeSetUp] and [OneTimeTearDown].

Guy
  • 46,488
  • 10
  • 44
  • 88
  • Thanks for this. It does work and solve the initial issue and I guess this is best practice approach. Any way I can write this without redoing it for every test? Unfortunately due to the way the website is written (Which I have no control over) the login script takes 30 seconds every time (Its 2 button clicks and the normal username and password!) so naturally calling it for every test is going to slow down the process an awful lot. – Smithy7876 May 22 '17 at 13:02