From f9772c307d2ba336fbf2d55706a53b6aed3be940 Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 19 Nov 2017 15:20:21 +1300 Subject: [PATCH 1/5] Initial commit --- .../AgeRangerWebUi/AgeRangerWebUi.csproj | 104 +++++++++++ .../AgeRangerWebUi/App.config | 11 ++ .../AgeRangerWebUi/Driver/Driver.cs | 23 +++ .../Features/AddNewPerson.feature | 25 +++ .../Features/AddNewPerson.feature.cs | 125 +++++++++++++ .../Features/DeletePerson.feature | 9 + .../Features/DeletePerson.feature.cs | 89 +++++++++ .../Features/EditPerson.feature | 10 ++ .../Features/EditPerson.feature.cs | 91 ++++++++++ .../PageObjects/AgeRangerMainPage.cs | 64 +++++++ .../AgeRangerWebUi/Properties/AssemblyInfo.cs | 36 ++++ .../AgeRangerWebUi/Steps/PersonSteps.cs | 169 ++++++++++++++++++ .../AgeRangerWebUi/packages.config | 8 + AgeRanger_Automation/AgeRanger_Automation.sln | 25 +++ 14 files changed, 789 insertions(+) create mode 100644 AgeRanger_Automation/AgeRangerWebUi/AgeRangerWebUi.csproj create mode 100644 AgeRanger_Automation/AgeRangerWebUi/App.config create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Driver/Driver.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/PageObjects/AgeRangerMainPage.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Properties/AssemblyInfo.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/Steps/PersonSteps.cs create mode 100644 AgeRanger_Automation/AgeRangerWebUi/packages.config create mode 100644 AgeRanger_Automation/AgeRanger_Automation.sln diff --git a/AgeRanger_Automation/AgeRangerWebUi/AgeRangerWebUi.csproj b/AgeRanger_Automation/AgeRangerWebUi/AgeRangerWebUi.csproj new file mode 100644 index 0000000..f886e93 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/AgeRangerWebUi.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C} + Library + AgeRangerWebUi + AgeRangerWebUi + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll + + + + + + + + + + + + ..\packages\SpecFlow.2.2.1\lib\net45\TechTalk.SpecFlow.dll + + + ..\packages\Selenium.WebDriver.3.7.0\lib\net45\WebDriver.dll + + + ..\packages\Selenium.Support.3.7.0\lib\net45\WebDriver.Support.dll + + + + + + AddNewPerson.feature + True + True + + + DeletePerson.feature + True + True + + + EditPerson.feature + True + True + + + + + + + + + SpecFlowSingleFileGenerator + AddNewPerson.feature.cs + + + SpecFlowSingleFileGenerator + DeletePerson.feature.cs + + + SpecFlowSingleFileGenerator + EditPerson.feature.cs + + + + + + + + \ No newline at end of file diff --git a/AgeRanger_Automation/AgeRangerWebUi/App.config b/AgeRanger_Automation/AgeRangerWebUi/App.config new file mode 100644 index 0000000..fde1b9b --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/App.config @@ -0,0 +1,11 @@ + + + +
+ + + + + + + \ No newline at end of file diff --git a/AgeRanger_Automation/AgeRangerWebUi/Driver/Driver.cs b/AgeRanger_Automation/AgeRangerWebUi/Driver/Driver.cs new file mode 100644 index 0000000..4340ec9 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Driver/Driver.cs @@ -0,0 +1,23 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Remote; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AgeRangerWebUi.Driver +{ + public class Driver + { + public IWebDriver GetRemoteDriver() + { + var capabilities = new DesiredCapabilities(); + capabilities.SetCapability("browserName", "Chrome"); + capabilities.SetCapability("platform", "Windows 10"); + capabilities.SetCapability("version", "62.0"); + return new RemoteWebDriver(new Uri("http://localhost:4444/wd/hub"), capabilities, + TimeSpan.FromSeconds(60)); + } + } +} diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature b/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature new file mode 100644 index 0000000..685d1b1 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature @@ -0,0 +1,25 @@ +Feature: Add New Person + This feature will cover the different tests for Adding a New Person to the system + +@basicFlow +Scenario Outline: AddNewPersonComplete + Given I navigate to http://ageranger.azurewebsites.net + When I click on the AddPerson button + And I add a new person with as a FirstName, as a LastName and as Age + Then I can see a new person the Landing page with ,, and + + Examples: + | FirstName | LastName | Age | AgeRange | + | MyName | MyLastName | 40 | Very adult | + +@exceptionFlow +Scenario Outline: AddNewPersonFail + Given I navigate to http://ageranger.azurewebsites.net + And I click on the AddPerson button + When I type in the First Name field + And I clear the First Name field + Then I can see an inline error with message + + Examples: + | something | FirstNameInlineError | + | something | First name is required." | \ No newline at end of file diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature.cs b/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature.cs new file mode 100644 index 0000000..dd1fa29 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/AddNewPerson.feature.cs @@ -0,0 +1,125 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (http://www.specflow.org/). +// SpecFlow Version:2.2.0.0 +// SpecFlow Generator Version:2.2.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace AgeRangerWebUi.Features +{ + using TechTalk.SpecFlow; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.2.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [NUnit.Framework.TestFixtureAttribute()] + [NUnit.Framework.DescriptionAttribute("Add New Person")] + public partial class AddNewPersonFeature + { + + private TechTalk.SpecFlow.ITestRunner testRunner; + +#line 1 "AddNewPerson.feature" +#line hidden + + [NUnit.Framework.OneTimeSetUpAttribute()] + public virtual void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Add New Person", "\tThis feature will cover the different tests for Adding a New Person to the syste" + + "m", ProgrammingLanguage.CSharp, ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + [NUnit.Framework.OneTimeTearDownAttribute()] + public virtual void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + [NUnit.Framework.SetUpAttribute()] + public virtual void TestInitialize() + { + } + + [NUnit.Framework.TearDownAttribute()] + public virtual void ScenarioTearDown() + { + testRunner.OnScenarioEnd(); + } + + public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioStart(scenarioInfo); + } + + public virtual void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("AddNewPersonComplete")] + [NUnit.Framework.CategoryAttribute("basicFlow")] + [NUnit.Framework.TestCaseAttribute("MyName", "MyLastName", "40", "Very adult", null)] + public virtual void AddNewPersonComplete(string firstName, string lastName, string age, string ageRange, string[] exampleTags) + { + string[] @__tags = new string[] { + "basicFlow"}; + if ((exampleTags != null)) + { + @__tags = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Concat(@__tags, exampleTags)); + } + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("AddNewPersonComplete", @__tags); +#line 5 +this.ScenarioSetup(scenarioInfo); +#line 6 + testRunner.Given("I navigate to http://ageranger.azurewebsites.net", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line 7 + testRunner.When("I click on the AddPerson button", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 8 + testRunner.And(string.Format("I add a new person with {0} as a FirstName, {1} as a LastName and {2} as Age", firstName, lastName, age), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 9 + testRunner.Then(string.Format("I can see a new person the Landing page with {0},{1},{2} and {3}", firstName, lastName, age, ageRange), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + this.ScenarioCleanup(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("AddNewPersonFail")] + [NUnit.Framework.CategoryAttribute("exceptionFlow")] + [NUnit.Framework.TestCaseAttribute("something", "First name is required.\"", null)] + public virtual void AddNewPersonFail(string something, string firstNameInlineError, string[] exampleTags) + { + string[] @__tags = new string[] { + "exceptionFlow"}; + if ((exampleTags != null)) + { + @__tags = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Concat(@__tags, exampleTags)); + } + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("AddNewPersonFail", @__tags); +#line 16 +this.ScenarioSetup(scenarioInfo); +#line 17 + testRunner.Given("I navigate to http://ageranger.azurewebsites.net", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line 18 + testRunner.And("I click on the AddPerson button", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 19 + testRunner.When(string.Format("I type {0} in the First Name field", something), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 20 + testRunner.And("I clear the First Name field", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 21 + testRunner.Then(string.Format("I can see an inline error with message {0}", firstNameInlineError), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + this.ScenarioCleanup(); + } + } +} +#pragma warning restore +#endregion diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature b/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature new file mode 100644 index 0000000..cb774f4 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature @@ -0,0 +1,9 @@ +Feature: DeletePerson + This feature will cover the different tests for Deleting a Person to the system + +@basicFlow +Scenario: DeletePersonComplete + Given I navigate to http://ageranger.azurewebsites.net + When I delete the first Person in the list + And I click on Confirm + Then the count of people should decrease by one diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature.cs b/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature.cs new file mode 100644 index 0000000..cf43335 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/DeletePerson.feature.cs @@ -0,0 +1,89 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (http://www.specflow.org/). +// SpecFlow Version:2.2.0.0 +// SpecFlow Generator Version:2.2.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace AgeRangerWebUi.Features +{ + using TechTalk.SpecFlow; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.2.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [NUnit.Framework.TestFixtureAttribute()] + [NUnit.Framework.DescriptionAttribute("DeletePerson")] + public partial class DeletePersonFeature + { + + private TechTalk.SpecFlow.ITestRunner testRunner; + +#line 1 "DeletePerson.feature" +#line hidden + + [NUnit.Framework.OneTimeSetUpAttribute()] + public virtual void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "DeletePerson", "\tThis feature will cover the different tests for Deleting a Person to the system", ProgrammingLanguage.CSharp, ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + [NUnit.Framework.OneTimeTearDownAttribute()] + public virtual void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + [NUnit.Framework.SetUpAttribute()] + public virtual void TestInitialize() + { + } + + [NUnit.Framework.TearDownAttribute()] + public virtual void ScenarioTearDown() + { + testRunner.OnScenarioEnd(); + } + + public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioStart(scenarioInfo); + } + + public virtual void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("DeletePersonComplete")] + [NUnit.Framework.CategoryAttribute("basicFlow")] + public virtual void DeletePersonComplete() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("DeletePersonComplete", new string[] { + "basicFlow"}); +#line 5 +this.ScenarioSetup(scenarioInfo); +#line 6 + testRunner.Given("I navigate to http://ageranger.azurewebsites.net", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line 7 + testRunner.When("I delete the first Person in the list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 8 + testRunner.And("I click on Confirm", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 9 + testRunner.Then("the count of people should decrease by one", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + this.ScenarioCleanup(); + } + } +} +#pragma warning restore +#endregion diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature b/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature new file mode 100644 index 0000000..66d20b8 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature @@ -0,0 +1,10 @@ +Feature: EditPerson + This feature will cover the different tests for Editing a Person to the system + +@basicFlow +Scenario: EditPersonComplete + Given I navigate to http://ageranger.azurewebsites.net + And I edit the first Person in the list + When I change the Age for that Person to a higher value + And I click on Confirm + Then the age of the first person will have changed diff --git a/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature.cs b/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature.cs new file mode 100644 index 0000000..1fdbc92 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Features/EditPerson.feature.cs @@ -0,0 +1,91 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (http://www.specflow.org/). +// SpecFlow Version:2.2.0.0 +// SpecFlow Generator Version:2.2.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace AgeRangerWebUi.Features +{ + using TechTalk.SpecFlow; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.2.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [NUnit.Framework.TestFixtureAttribute()] + [NUnit.Framework.DescriptionAttribute("EditPerson")] + public partial class EditPersonFeature + { + + private TechTalk.SpecFlow.ITestRunner testRunner; + +#line 1 "EditPerson.feature" +#line hidden + + [NUnit.Framework.OneTimeSetUpAttribute()] + public virtual void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "EditPerson", "\tThis feature will cover the different tests for Editing a Person to the system", ProgrammingLanguage.CSharp, ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + [NUnit.Framework.OneTimeTearDownAttribute()] + public virtual void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + [NUnit.Framework.SetUpAttribute()] + public virtual void TestInitialize() + { + } + + [NUnit.Framework.TearDownAttribute()] + public virtual void ScenarioTearDown() + { + testRunner.OnScenarioEnd(); + } + + public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioStart(scenarioInfo); + } + + public virtual void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + [NUnit.Framework.TestAttribute()] + [NUnit.Framework.DescriptionAttribute("EditPersonComplete")] + [NUnit.Framework.CategoryAttribute("basicFlow")] + public virtual void EditPersonComplete() + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("EditPersonComplete", new string[] { + "basicFlow"}); +#line 5 +this.ScenarioSetup(scenarioInfo); +#line 6 + testRunner.Given("I navigate to http://ageranger.azurewebsites.net", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line 7 + testRunner.And("I edit the first Person in the list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 8 + testRunner.When("I change the Age for that Person to a higher value", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 9 + testRunner.And("I click on Confirm", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 10 + testRunner.Then("the age of the first person will have changed", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + this.ScenarioCleanup(); + } + } +} +#pragma warning restore +#endregion diff --git a/AgeRanger_Automation/AgeRangerWebUi/PageObjects/AgeRangerMainPage.cs b/AgeRanger_Automation/AgeRangerWebUi/PageObjects/AgeRangerMainPage.cs new file mode 100644 index 0000000..ba262a8 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/PageObjects/AgeRangerMainPage.cs @@ -0,0 +1,64 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Support.PageObjects; +using System.Collections.Generic; +using System.Threading; + +namespace AgeRangerWebUi.PageObjects +{ + public class AgeRangerMainPage + + { + public AgeRangerMainPage(IWebDriver driver) + { + PageFactory.InitElements(driver, this); + } + + [FindsBy(How = How.XPath, Using = "//input[@id='searchText']")] + public IWebElement SearchTextField { get; set; } + + [FindsBy(How = How.XPath, Using = "//table")] + public IWebElement PeopleTable { get; set; } + + [FindsBy(How = How.XPath, Using = "//td[@class='col-md-7 ng-binding']")] + public IList ExistingUserName { get; set; } + + [FindsBy(How = How.XPath, Using = "//td[@class='col-md-2 ng-binding']")] + public IList ExistingUserAge { get; set; } + + [FindsBy(How = How.XPath, Using = "//a[@ng-click='openEditForm(person)']")] + public IWebElement EditPerson { get; set; } + + [FindsBy(How = How.XPath, Using = "//a[@ng-click='delete(person)']")] + public IWebElement DeletePerson { get; set; } + + [FindsBy(How = How.XPath, Using = "//a[@ng-click='openNewPersonForm()']")] + public IWebElement AddPerson { get; set; } + + [FindsBy(How = How.XPath, Using = "//input[@name='FirstName']")] + public IWebElement FirstName { get; set; } + + [FindsBy(How = How.XPath, Using = "//p[@class='help-block']")] + public IWebElement FirstNameInlineError { get; set; } + + [FindsBy(How = How.XPath, Using = "//input[@name='LastName']")] + public IWebElement LastName { get; set; } + + [FindsBy(How = How.XPath, Using = "//input[@name='Age']")] + public IWebElement Age { get; set; } + + [FindsBy(How = How.XPath, Using = "//button[@ng-click='submit()']")] + public IWebElement SubmitButton { get; set; } + + [FindsBy(How = How.XPath, Using = "//button[@ng-click='close()']")] + public IWebElement CloseButton { get; set; } + + [FindsBy(How = How.XPath, Using = "//button[@data-bb-handler='confirm']")] + public IWebElement OkButton { get; set; } + + [FindsBy(How = How.XPath, Using = "//button[@data-bb-handler='cancel']")] + public IWebElement CancelButton { get; set; } + + [FindsBy(How = How.XPath, Using = "//button[@class='bootbox-close-button close']")] + public IWebElement CrossButton { get; set; } + } +} diff --git a/AgeRanger_Automation/AgeRangerWebUi/Properties/AssemblyInfo.cs b/AgeRanger_Automation/AgeRangerWebUi/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0f24134 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AgeRangerWebUi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AgeRangerWebUi")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e82adcc4-bd7a-4659-8b5f-7a79b0c4b25c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AgeRanger_Automation/AgeRangerWebUi/Steps/PersonSteps.cs b/AgeRanger_Automation/AgeRangerWebUi/Steps/PersonSteps.cs new file mode 100644 index 0000000..a4ea98f --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/Steps/PersonSteps.cs @@ -0,0 +1,169 @@ +using AgeRangerWebUi.Driver; +using AgeRangerWebUi.PageObjects; +using NUnit.Framework; +using OpenQA.Selenium; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using TechTalk.SpecFlow; +using TechTalk.SpecFlow.Assist; + +namespace AgeRangerWebUi.Steps +{ + [Binding] + public sealed class PersonSteps + { + + private AgeRangerMainPage mainPage; + public PersonSteps() + { + var driverFactory = new Driver.Driver(); + Driver = driverFactory.GetRemoteDriver(); + mainPage = new AgeRangerMainPage(Driver); + } + + public static IWebDriver Driver { get; set; } + + [AfterScenario] + public void AfterScenario() + { + Driver.Quit(); + Driver = null; + } + + [StepDefinition(@"I navigate to (.*)")] + public void GivenINavigateTo(string url) + { + Driver.Navigate().GoToUrl(url); + Thread.Sleep(2000); + } + + [StepDefinition(@"I click on the AddPerson button")] + public void WhenIClickOnTheAddPersonButton() + { + var pageObject = new AgeRangerMainPage(Driver); + pageObject.AddPerson.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"I add a new person with (.*) as a FirstName, (.*) as a LastName and (.*) as Age")] + public void GivenIAddANewPersonWithAsAFirstNameAsALastNameAndAsAge(string firstName, string lastName, int age) + { + var pageObject = new AgeRangerMainPage(Driver); + pageObject.FirstName.SendKeys(firstName); + pageObject.LastName.SendKeys(lastName); + pageObject.Age.SendKeys(age.ToString()); + pageObject.SubmitButton.Click(); + Thread.Sleep(1000); + pageObject.OkButton.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"I can see a new person the Landing page with (.*),(.*),(.*) and (.*)")] + public void ThenICanSeeANewPersonTheLandingPageWithMyNameMyLastNameAndVeryAdult(string firstName, string lastName, int age, string ageRange) + { + var pageObject = new AgeRangerMainPage(Driver); + string firstLastName = (firstName + ' ' + lastName); + string userFound = "false"; + IList tableRow = pageObject.PeopleTable.FindElements(By.TagName("tr")); + foreach (IWebElement row in tableRow) + { + if (row.Text.Contains(firstLastName) && row.Text.Contains(age.ToString()) && row.Text.Contains(ageRange)) + { + userFound = "true"; + break; + } + } + Assert.AreEqual("true", userFound, "User was not Found."); + } + + [StepDefinition(@"I type (.*) in the First Name field")] + public void WhenITypeInTheFirstNameField(string firstName) + { + var pageObject = new AgeRangerMainPage(Driver); + pageObject.FirstName.SendKeys(firstName); + } + + [StepDefinition(@"I clear the First Name field")] + public void WhenIClearTheFirstNameField() + { + var pageObject = new AgeRangerMainPage(Driver); + pageObject.FirstName.Clear(); + } + + [StepDefinition(@"I can see an inline error with message (.*).")] + public void ThenICanSeeAnInlineErrorWithMessageFirstNameIsRequired_(string FirstNameInlineError) + { + var pageObject = new AgeRangerMainPage(Driver); + string errorMessage = pageObject.FirstNameInlineError.Text; + Assert.AreEqual(FirstNameInlineError, errorMessage, "Inline Error is not displayed or not matching."); + } + + [StepDefinition(@"I delete the first Person in the list")] + public void WhenIDeleteTheFirstPersonInTheList() + { + var pageObject = new AgeRangerMainPage(Driver); + int countBeforeDelete = pageObject.ExistingUserName.Count; + ScenarioContext.Current.Add("countBeforeDelete", countBeforeDelete); + pageObject.DeletePerson.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"I click on Confirm")] + public void WhenIClickOnConfirm() + { + var pageObject = new AgeRangerMainPage(Driver); + pageObject.OkButton.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"the count of people should decrease by one")] + public void ThenTheCountOfPeopleShouldDecreaseByOne() + { + var pageObject = new AgeRangerMainPage(Driver); + int countAfterDelete = pageObject.ExistingUserName.Count; + int countBeforeDelete = ScenarioContext.Current.Get("countBeforeDelete"); + if (countAfterDelete != null) + { + Assert.AreEqual(countAfterDelete, (countBeforeDelete - 1)); + } + else + Console.WriteLine("No Results left to Delete."); + + } + + [StepDefinition(@"I edit the first Person in the list")] + public void GivenIEditTheFirstPersonInTheList() + { + var pageObject = new AgeRangerMainPage(Driver); + int ageBeforeEdit = Int32.Parse(pageObject.ExistingUserAge.First().Text); + ScenarioContext.Current.Add("ageBeforeEdit", ageBeforeEdit); + pageObject.EditPerson.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"I change the Age for that Person to a higher value")] + public void WhenIChangeTheAgeForThatPersonTo() + { + var pageObject = new AgeRangerMainPage(Driver); + int newAge = ScenarioContext.Current.Get("ageBeforeEdit"); + newAge = ++newAge; + pageObject.Age.Clear(); + pageObject.Age.SendKeys(newAge.ToString()); + pageObject.SubmitButton.Click(); + Thread.Sleep(1000); + } + + [StepDefinition(@"the age of the first person will have changed")] + public void ThenTheAgeOfTheFirstPersonWillHaveChanged() + { + var pageObject = new AgeRangerMainPage(Driver); + int ageAfterEdit = Int32.Parse(pageObject.ExistingUserAge.First().Text); + int ageBeforeEdit = ScenarioContext.Current.Get("ageBeforeEdit"); + Assert.AreNotEqual(ageBeforeEdit, ageAfterEdit, "Age is still the same."); + } + + } +} \ No newline at end of file diff --git a/AgeRanger_Automation/AgeRangerWebUi/packages.config b/AgeRanger_Automation/AgeRangerWebUi/packages.config new file mode 100644 index 0000000..dbc9472 --- /dev/null +++ b/AgeRanger_Automation/AgeRangerWebUi/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/AgeRanger_Automation/AgeRanger_Automation.sln b/AgeRanger_Automation/AgeRanger_Automation.sln new file mode 100644 index 0000000..25fef16 --- /dev/null +++ b/AgeRanger_Automation/AgeRanger_Automation.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2009 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AgeRangerWebUi", "AgeRangerWebUi\AgeRangerWebUi.csproj", "{E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E82ADCC4-BD7A-4659-8B5F-7A79B0C4B25C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B5261534-D330-41DE-894F-1FB189C09E64} + EndGlobalSection +EndGlobal From c18e77fcb03b0368416530c17b8ccaad0a177ca6 Mon Sep 17 00:00:00 2001 From: Santiago Date: Sun, 19 Nov 2017 15:26:46 +1300 Subject: [PATCH 2/5] Added ReadMe --- AgeRanger_Automation/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 AgeRanger_Automation/README.md diff --git a/AgeRanger_Automation/README.md b/AgeRanger_Automation/README.md new file mode 100644 index 0000000..fc4a8a2 --- /dev/null +++ b/AgeRanger_Automation/README.md @@ -0,0 +1,14 @@ +Running this project. + +- Prerequisites: +-- Node.js is installed +-- Webdriver-manager is installed and configured (npm install webdriver-manager -g) +--- dependency on JDK being installed +-- Chrome version 62 is installed + +- How to: +1. Open solution in Visual Studio +2. Open a powershell command prompt windows +2.a. Run the following command: webdriver-manager start +3. Build solution +4. Execute Tests from Test Explorer in VS \ No newline at end of file From 2ddc9ee5a44aeea4dc2432ceb01881f2274b79a9 Mon Sep 17 00:00:00 2001 From: Santiago Fraga Vazquez <33674227+sfraga72@users.noreply.github.com> Date: Sun, 19 Nov 2017 15:27:53 +1300 Subject: [PATCH 3/5] amended readme --- AgeRanger_Automation/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AgeRanger_Automation/README.md b/AgeRanger_Automation/README.md index fc4a8a2..bbf5177 100644 --- a/AgeRanger_Automation/README.md +++ b/AgeRanger_Automation/README.md @@ -8,7 +8,6 @@ Running this project. - How to: 1. Open solution in Visual Studio -2. Open a powershell command prompt windows -2.a. Run the following command: webdriver-manager start +2. Open a powershell command prompt windows and run the following command: webdriver-manager start 3. Build solution -4. Execute Tests from Test Explorer in VS \ No newline at end of file +4. Execute Tests from Test Explorer in VS From bb72831d2dd53d3a2558c854d3a43c8edc637ce7 Mon Sep 17 00:00:00 2001 From: Santiago Fraga Vazquez <33674227+sfraga72@users.noreply.github.com> Date: Sun, 19 Nov 2017 15:32:49 +1300 Subject: [PATCH 4/5] fixing formatting of readme --- AgeRanger_Automation/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/AgeRanger_Automation/README.md b/AgeRanger_Automation/README.md index bbf5177..ff8a022 100644 --- a/AgeRanger_Automation/README.md +++ b/AgeRanger_Automation/README.md @@ -1,13 +1,14 @@ Running this project. -- Prerequisites: --- Node.js is installed --- Webdriver-manager is installed and configured (npm install webdriver-manager -g) ---- dependency on JDK being installed --- Chrome version 62 is installed +* Prerequisites: + * Node.js is installed + * Webdriver-manager is installed and configured (npm install webdriver-manager -g) + * dependency on JDK being installed + * Chrome version 62 is installed -- How to: +* How to: 1. Open solution in Visual Studio -2. Open a powershell command prompt windows and run the following command: webdriver-manager start +2. Open a powershell command prompt windows + 1. Run the following command: webdriver-manager start 3. Build solution 4. Execute Tests from Test Explorer in VS From 5bf583bffabcb3093262886a93ad4051eedd4030 Mon Sep 17 00:00:00 2001 From: Santiago Fraga Vazquez <33674227+sfraga72@users.noreply.github.com> Date: Sun, 19 Nov 2017 15:34:39 +1300 Subject: [PATCH 5/5] Added Manual Test Plan --- AgeRanger_Automation/AgeRanger_TestPlan.xls | Bin 0 -> 20480 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 AgeRanger_Automation/AgeRanger_TestPlan.xls diff --git a/AgeRanger_Automation/AgeRanger_TestPlan.xls b/AgeRanger_Automation/AgeRanger_TestPlan.xls new file mode 100644 index 0000000000000000000000000000000000000000..8a5753ffb5a6c42d7e184e25974b92a6cb236e99 GIT binary patch literal 20480 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 literal 0 HcmV?d00001