A few methods to make Cucumber testing with SpecFlow and Selenium easier.
Install the PageObjection
Nuget Package, along with TechTalk.SpecFlow
and NUnit3
.
Make your steps inherit from PageFactory
:
using PageObjection;
using NUnit.Framework;
using TechTalk.SpecFlow;
using SFAndSelenium.Pages;
namespace SFAndSelenium.Steps
{
[Binding]
public class BasicSteps : PageFactory
{
// ...
}
}
Make your page objects inherit from PageObject
:
using PageObjection;
namespace SFAndSelenium.Pages
{
public class ContactPage : PageObject
{
public override string Url => "http://awful-valentine.com/contact-us/";
// ...
}
}
In your step files, you'll have a few helper methods available to you including On<YourPage>
and Visit<YourPage>
.
These methods can be used to create instances of your page objects, which you can then use to automate the page:
using PageObjection;
using NUnit.Framework;
using TechTalk.SpecFlow;
using SFAndSelenium.Pages;
namespace SFAndSelenium.Steps
{
[Binding]
public class BasicSteps : PageFactory
{
[Given(@"I am browsing for an awful valentine")]
public void GivenIAmBrowsingForAnAwfulValentine()
{
Visit<HomePage>();
}
[When(@"I choose to contact someone")]
public void WhenIChooseToContactSomeone()
{
On<HomePage>().ContactUs();
}
[Then(@"I see a contact form")]
public void ThenISeeAContactForm()
{
Assert.True(On<ContactPage>().IsLoaded);
}
[When(@"I enter my name as ""(.*)""")]
public void WhenIEnterMyNameAs(string name)
{
On<ContactPage>().Name = name;
}
[Then(@"my name is ""(.*)""")]
public void ThenMyNameIs(string expected)
{
Assert.That(On<ContactPage>().Name, Is.EqualTo(expected));
}
// ...
}
}
As you can see, On
and Visit
return an instance of the specified PageObject that's ready to use.
If you need to do multiple things with the page, rather than a single action, you can pass an Action function into both On
and Visit
like so:
[When(@"I enter my information:")]
public void WhenIEnterMyInformation(Table table)
{
var details = table.Rows[0];
On<ContactPage>((page) =>
{
page.Name = details["Name"];
page.Email = details["Email"];
page.Subject = details["Subject"];
page.Message = details["Message"];
});
}
Waiting for something to happen can be achieved using the WaitUntil
function like so:
// Step Definition:
[When(@"I submit the following contact request:")]
public void WhenISubmitTheFollowingContactRequest(Table table)
{
var details = table.Rows[0];
Visit<ContactPage>((page) =>
{
page.Name = details["Name"];
page.Email = details["Email"];
page.Subject = details["Subject"];
page.Message = details["Message"];
page.Send();
WaitUntil(() => { return page.IsWorking() == false; });
});
}
// Page Object:
public class ContactPage : PageObject
{
// ...
public bool IsWorking()
{
return Browser.FindElementByClassName("ajax-loader").Displayed;
}
}
Rather than writing Browser.FindElementByCssSelector()
you can use the inherited QuerySelector
and QuerySelectorAll
methods within your PageObjects:
public class ContactPage : PageObject
{
// ...
public bool IsWorking()
{
return QuerySelector(".ajax-loader").Displayed;
}
}