Table of Contents
Creating the Base Scenarios
Validating the Title of a Website
Creating the SpecFlow Scenario
- Open up the ‘BaseScenarios.feature’ file and add the following test scenario. We can also add a tag (e.g. ‘@Chrome’ for Chrome or ‘@HeadlessFirefox’ for Firefox in headless mode, either above the ‘Scenario’ (to apply to the specific scenario) or above the ‘Feature’ (to apply to all scenarios within the feature)…
@Chrome Feature: BaseScenarios These scenarios can be used in any project Scenario: 01. Validate the title of a website Given a DuckDuckGo user is on the base page Then they see the page title contains "DuckDuckGo"
The Given and Then steps are still undefined, so let’s add definitions for them now.
Creating the Undefined Step Definitions
- Copy the method below in BaseSteps class for the undefined Given step…
using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { [Given(@"a DuckDuckGo user is on the base page")] public void GivenIAmOnTheBasePage() { throw new PendingStepException(); } } }
- Because our base page is also the search page, let’s slightly tweak our undefined ‘Given’ step definition so that we can use RegEx to either use the word ‘base’ or ‘search’ when referring to the step and being on the page, without capturing the match and also accept either DuckDuckGo user or internet user(see https://agileforall.com/just-enough-regular-expressions-for-cucumber/ for more info…
using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { throw new PendingStepException(); } } }
- Next, copy the method for the undefined Then step definition to the BaseSteps class…
using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { throw new PendingStepException(); } [Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { throw new PendingStepException(); } } }
Creating the Test Methods
- Open up the ‘BasePage.cs’ class file in the ‘Pages’ namespace and add the following method to navigate to the Base URL (as defined in your ‘Settings.cs’ class file, with the whole thing looking similar to below…
using System; using OpenQA.Selenium; using ProductAutomation.Utils.Selenium; using static ProductAutomation.Utils.Selenium.Settings; namespace ProductAutomation.Pages { public class BasePage { protected IWebDriver driver = Driver.CurrentDriver; public void NavigateBaseUrl() { driver.Navigate().GoToUrl(baseUrl); driver.Manage().Window.Maximize(); Console.WriteLine(" :: The base URL is navigated to"); } } }
- Also add another method for asserting the page title contains the expected string…
public void ValidatePageTitle(string expectedTitle { var titleToValidate = GetTitle.Contains(expectedTitle); Assert.IsTrue(titleToValidate, " :: The actual page title is incorrect"); Console.WriteLine(" :: The title of the site is " + GetTitle); }
For the above to work, you will also need to add a GetTitle() method near the top of the class (near where Driver is declared), which returns Driver.GetTitle() …
public string GetTitle => Driver.CurrentDriver.Title;
The whole thing should look similar to below when done…
using System; using NUnit.Framework; using OpenQA.Selenium; using ProductAutomation.Utils.Selenium; using static ProductAutomation.Utils.Selenium.Settings; namespace ProductAutomation.Pages { public class BasePage { protected IWebDriver driver = Driver.CurrentDriver; public string GetTitle => Driver.CurrentDriver.Title; public void NavigateBaseUrl() { driver.Navigate().GoToUrl(baseUrl); driver.Manage().Window.Maximize(); Console.WriteLine(" :: The base URL is navigated to"); } } }
Connecting the Step Definitions to the Test Methods
We will now call the test methods from their appropriate step definitions. This whole POM approach is nice as we have suitable layers of abstraction, which helps the code be easier to read. It also allows the step definitions to simply contain one line of code when calling the test methods.
- Open up the ‘BaseSteps.cs’ step definition class file again, and refactor the class to look like below, noting how we initialise our basePage object at the top and how we keep assertions outside of our page classes…
using NUnit.Framework; using System; using ProductAutomation.Pages; using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { private BasePage basePage = new BasePage(); [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { basePage.NavigateBaseUrl(); } [Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { var titleToValidate = basePage.GetTitle.Contains(expectedTitle); Assert.IsTrue(titleToValidate, " :: The actual page title is incorrect"); Console.WriteLine(" :: The actual page title is " + titleToValidate); } } }
Validate the URL of the Website
Creating the SpecFlow scenario
- Open up the ‘BaseScenarios.feature’ file and add the following test scenario…
Scenario: 02. Validate the Url of a webpage Given a DuckDuckGo user is on the base page Then the page URL contains "https://start.duckduckgo.com"
Creating the Undefined Step Definition
- Next, let’s create the undefined step definition for the Then step…
[Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { throw new PendingStepException(); }
Creating the Test Method
We will now create the test method in C# for our undefined ‘Then’ step 😀
- Let’s add a GetUrl() property near the top of the BasePage class (near where Driver is declared), which returns Driver.GetUrl() …
public string GetUrl => Driver.CurrentDriver.Url;
Defining the Step Definition
- Open up the BaseSteps.cs class and add the assertions to the step definition, using the GetUrl property we just added to the BasePage…
[Then(@"the page URL contains ""(.*)""")] public void ThenISeeThePageUrlContains(string expectedUrl) { var urlToValidate = basePage.GetUrl.Contains(expectedUrl); Assert.IsTrue(urlToValidate, " :: The actual page Url is different"); Console.WriteLine(" :: The actual page URL is " + urlToValidate); }
The whole thing should look like below…
using System; using NUnit.Framework; using ProductAutomation.Pages; using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { private BasePage basePage = new BasePage(); [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { basePage.NavigateBaseUrl(); } [Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { var titleToValidate = basePage.GetTitle.Contains(expectedTitle); Assert.IsTrue(titleToValidate, " :: The actual page title is different"); Console.WriteLine(" :: The actual page title is " + titleToValidate); } [Then(@"the page URL contains ""(.*)""")] public void ThenISeeThePageUrlContains(string expectedUrl) { var urlToValidate = basePage.GetUrl.Contains(expectedUrl); Assert.IsTrue(urlToValidate, " :: The actual page Url is different"); Console.WriteLine(" :: The actual page URL is " + urlToValidate); } } }
Validate a PageSource String on the Website
Creating the SpecFlow Scenario
- Open up the ‘BaseScenarios.feature’ file and add the following test scenario…
Scenario: 03. Validate the PageSource string on a web page Given a DuckDuckGo user is on the base page Then they see "DuckDuckGo" in the PageSource
Creating the Undefined Step Definition
- Next, let’s create the method for the undefined step definition and add it to the BaseSteps class again…
-
[Then(@"they see ""(.*)"" in the PageSource")] public void ThenISeeInThePageSource(string expectedText) { throw new PendingStepException(); }
Creating the Test property
- Open up the BasePage class again and add a new property for the current page source
public string GetPageSource => Driver.CurrentDriver.PageSource;
Defining the Step Definition
- Open up the ‘BaseSteps.cs’ class file again, and add the assertion to the step definition…
[Then(@"they see ""(.*)"" in the PageSource")] public void ThenISeeInThePageSource(string expectedText) { var pageSourceTextToValidate = basePage.GetPageSource.Contains(expectedText); Assert.IsTrue(pageSourceTextToValidate, " :: The expected string is not present in the page source"); Console.WriteLine(" :: The page source does not contain " + expectedText); }
The whole thing should look like below…
using System; using NUnit.Framework; using ProductAutomation.Pages; using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { private BasePage basePage = new BasePage(); [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { basePage.NavigateBaseUrl(); } [Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { var titleToValidate = basePage.GetTitle.Contains(expectedTitle); Assert.IsTrue(titleToValidate, " :: The actual page title is different"); Console.WriteLine(" :: The actual page title is " + titleToValidate); } [Then(@"the page URL contains ""(.*)""")] public void ThenISeeThePageUrlContains(string expectedUrl) { var urlToValidate = basePage.GetUrl.Contains(expectedUrl); Assert.IsTrue(urlToValidate, " :: The actual page Url is different"); Console.WriteLine(" :: The actual page URL is " + urlToValidate); } [Then(@"they see ""(.*)"" in the PageSource")] public void ThenISeeInThePageSource(string expectedText) { var pageSourceTextToValidate = basePage.GetPageSource.Contains(expectedText); Assert.IsTrue(pageSourceTextToValidate, " :: The expected string is not present in the page source"); Console.WriteLine(" :: The page source does not contain " + expectedText); } } }
Validate Existence of Multiple Text in PageSource
Creating the SpecFlow Scenario
- Open up the ‘BaseScenarios.feature’ file and add the following test scenario…
Scenario: 04. Validate existence of multiple texts in PageSource Given a DuckDuckGo user is on the base page Then they see | expectedText | | DuckDuckGo | | search engine | | track you |
Creating the Undefined Step Definition
- Next, create the undefined step definition for the Then step in BaseSteps class and add a Table parameter, like below…
[Then(@"they see")] public void ThenISee(Table table) { throw new PendingStepException(); }
Defining the Step Definition
- Open up the ‘BaseSteps.cs’ class file again, and define the step by adding the assertion for each item in the table…
[Then(@"they see")] public void ThenISee(Table table) { foreach (var row in table.Rows) { var textToValidate = row["expectedText"]; Assert.IsTrue(basePage.GetPageSource.Contains(textToValidate), textToValidate + " is not in the PageSource!"); Console.WriteLine(":: The text " + textToValidate + " is in the PageSource "); } }
The whole thing should look like below now…
using System; using NUnit.Framework; using ProductAutomation.Pages; using TechTalk.SpecFlow; namespace ProductAutomation.Steps.BaseSteps { [Binding] public class BaseSteps { private BasePage basePage = new BasePage(); [Given(@"(?:a DuckDuckGo|an internet) user is on the (?:base|search) page")] public void GivenIAmOnTheBasePage() { basePage.NavigateBaseUrl(); } [Then(@"they see the page title contains ""(.*)""")] public void ThenIseeThePageTitleContains(string expectedTitle) { var titleToValidate = basePage.GetTitle.Contains(expectedTitle); Assert.IsTrue(titleToValidate, " :: The actual page title is different"); Console.WriteLine(" :: The actual page title is " + titleToValidate); } [Then(@"the page URL contains ""(.*)""")] public void ThenISeeThePageUrlContains(string expectedUrl) { var urlToValidate = basePage.GetUrl.Contains(expectedUrl); Assert.IsTrue(urlToValidate, " :: The actual page Url is different"); Console.WriteLine(" :: The actual page URL is " + urlToValidate); } [Then(@"they see ""(.*)"" in the PageSource")] public void ThenISeeInThePageSource(string expectedText) { var pageSourceTextToValidate = basePage.GetPageSource.Contains(expectedText); Assert.IsTrue(pageSourceTextToValidate, " :: The expected string is not present in the page source"); Console.WriteLine(" :: The page source does not contain " + expectedText); } [Then(@"they see")] public void ThenISee(Table table) { foreach (var row in table.Rows) { var textToValidate = row["expectedText"]; Assert.IsTrue(basePage.GetPageSource.Contains(textToValidate), textToValidate + " is not in the PageSource!"); Console.WriteLine(":: The text " + textToValidate + " is in the PageSource "); } } } }
SpecFlow Background Step
- If you look at the four base scenarios in your ‘BaseScenarios.feature’ file, you will see that every scenario shares the step of ‘Given I navigate to the base URL’. Because of this, we can clean up the Feature file a bit by declaring the ‘Given’ step once as a Background step, which will be applied at the beginning of every scenario in the Feature file (see https://github.com/cucumber/cucumber/wiki/Background for more information)…
@Chrome Feature: BaseScenarios These scenarios can be used in any project Background: DuckDuckGo user is already on the correct page Given a DuckDuckGo user is on the base page Scenario: 01. Validate the title of a website Then they see the page title contains "DuckDuckGo" Scenario: 02. Validate the URL of a web page Then the page URL contains "https://start.duckduckgo.com" Scenario: 03. Validate the PageSource string on a web page Then they see "DuckDuckGo" in the PageSource Scenario: 04. Validate the PageSource contains multiple text Then they see | expectedText | | DuckDuckGo | | search engine | | track you |
We have now successfully added our BaseScenarios. In the next part, we will actually add our first proper test of searching for something on Google and then clicking through on a search result 😀
