Skip to content

Commit

Permalink
Chapter 3 - Page Object Model
Browse files Browse the repository at this point in the history
  • Loading branch information
ElSnoMan committed Oct 27, 2019
1 parent 4d0adef commit bfa0eeb
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 30 deletions.
5 changes: 5 additions & 0 deletions Framework/Framework.csproj
Expand Up @@ -4,4 +4,9 @@
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
</ItemGroup>

</Project>
44 changes: 44 additions & 0 deletions README.md
Expand Up @@ -92,3 +92,47 @@
- Rarity ("Common")

9. There's a lot of code in this one, so make sure to pause and replay as much as you need :)


## Chapter 3 - Page Object Model

Follow the video to for an explanation on the `Page Object Model` and `Page Map Pattern`.

1. Within the Royale project, create a `Pages` directory. This is where all of our Page objects will live.

2. Move the `Class1.cs` file into `Pages` and rename it to `HeaderNav.cs`

3. Within the file, rename `Class1` to `HeaderNav` and then make another class called `HeaderNavMap`

4. Use PackSharp to restructure our packages and dependencies so we leverage Framework and Royale projects
1. Move Selenium to the `Framework` project
- Open Command Palette > `PackSharp: Bootstrap Selenium` > select `Framework`
2. Remove Selenium from `Royale.Tests` project
- Open Command Palette > `PackSharp: Remove Package` > select `Royale.Tests` > select `Selenium.Support`
- Also remove `Selenium.WebDriver`

5. Framework is our base, so we want the projects to reference each other in a linear way.

Framework -> Royale -> Royale.Tests

`Royale.Tests` will reference `Royale` which references `Framework`

- Open Command Palette > `PackSharp: Add Project Reference` > select `Royale.Tests` > select `Royale`
- Open Command Palette > `PackSharp: Add Project Reference` > select `Royale` > select `Framework`

6. Now we can bring in `using OpenQA.Selenium` in our `HeaderNav.cs` file

> NOTE: The rest of this video is very "code-heavy", so make sure to follow along there
7. The naming convention for Pages and Page Maps is very simple. If you have a Home page, then you would do this:
- Page => `HomePage`
- Map => `HomePageMap`

8. In the video, there is a "jump" from `11:22` to `11:25` where I am able to use the `Map.Card()` immediately. At this point, you will have an error. All you need to do is:
- Add the `public readonly CardPageMap Map;` field at the top of the `CardsPage` class and the Constructor as well
- You will see the needed code at `11:43`. Sorry about that!

9. Card Details Page and Map
- Take a moment to pause the video and copy the code to move forward

10. At the end of the video, run your second test. It should fail! Your challenge is to solve this error so the test passes.
32 changes: 12 additions & 20 deletions Royale.Tests/CardTests.cs
Expand Up @@ -2,6 +2,7 @@
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using Royale.Pages;

namespace Tests
{
Expand All @@ -13,6 +14,7 @@ public class CardTests
public void BeforeEach()
{
driver = new ChromeDriver(Path.GetFullPath(@"../../../../" + "_drivers"));
driver.Url = "https://statsroyale.com";
}

[TearDown]
Expand All @@ -24,34 +26,24 @@ public void AfterEach()
[Test]
public void Ice_Spirit_is_on_Cards_Page()
{
// 1. go to statsroyale.com
driver.Url = "https://statsroyale.com";
// 2. click Cards link in header nav
driver.FindElement(By.CssSelector("a[href='/cards']")).Click();
// 3. Assert ice spirit is displayed
var iceSpirit = driver.FindElement(By.CssSelector("a[href*='Ice+Spirit']"));
var cardsPage = new CardsPage(driver);
var iceSpirit = cardsPage.Goto().GetCardByName("Ice Spirit");
Assert.That(iceSpirit.Displayed);
}

[Test]
public void Ice_Spirit_headers_are_correct_on_Card_Details_Page()
{
// 1. go to statsroyale.com
driver.Url = "https://statsroyale.com";
// 2. click Cards link in header nav
driver.FindElement(By.CssSelector("a[href='/cards']")).Click();
// 3. Go to Ice Spirit
driver.FindElement(By.CssSelector("a[href*='Ice+Spirit']")).Click();
// 4. Assert basic header stats
var cardName = driver.FindElement(By.CssSelector("[class*='cardName']")).Text;
var cardCategories = driver.FindElement(By.CssSelector(".card__rarity")).Text.Split(", ");
var cardType = cardCategories[0];
var cardArena = cardCategories[1];
var cardRarity = driver.FindElement(By.CssSelector(".card__common")).Text;
new CardsPage(driver).Goto().GetCardByName("Ice Spirit").Click();
var cardDetails = new CardDetailsPage(driver);

var (category, arena) = cardDetails.GetCardCategory();
var cardName = cardDetails.Map.CardName.Text;
var cardRarity = cardDetails.Map.CardRarity.Text;

Assert.AreEqual("Ice Spirit", cardName);
Assert.AreEqual("Troop", cardType);
Assert.AreEqual("Arena 8", cardArena);
Assert.AreEqual("Troop", category);
Assert.AreEqual("Arena 8", arena);
Assert.AreEqual("Common", cardRarity);
}
}
Expand Down
6 changes: 4 additions & 2 deletions Royale.Tests/Royale.Tests.csproj
Expand Up @@ -10,8 +10,10 @@
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Royale\Royale.csproj" />
</ItemGroup>

</Project>
8 changes: 0 additions & 8 deletions Royale/Class1.cs

This file was deleted.

36 changes: 36 additions & 0 deletions Royale/Pages/CardDetailsPage.cs
@@ -0,0 +1,36 @@
using OpenQA.Selenium;

namespace Royale.Pages
{
public class CardDetailsPage : PageBase
{
public readonly CardDetailsPageMap Map;

public CardDetailsPage(IWebDriver driver) : base(driver)
{
Map = new CardDetailsPageMap(driver);
}

public (string Category, string Arena) GetCardCategory()
{
var categories = Map.CardCategory.Text.Split(',');
return (categories[0].Trim(), categories[1].Trim());
}
}

public class CardDetailsPageMap
{
IWebDriver _driver;

public CardDetailsPageMap(IWebDriver driver)
{
_driver = driver;
}

public IWebElement CardName => _driver.FindElement(By.CssSelector("div[class*='cardName']"));

public IWebElement CardCategory => _driver.FindElement(By.CssSelector("div[class*='card__rarity']"));

public IWebElement CardRarity => _driver.FindElement(By.CssSelector("div[class*='rarityCaption']"));
}
}
43 changes: 43 additions & 0 deletions Royale/Pages/CardsPage.cs
@@ -0,0 +1,43 @@
using OpenQA.Selenium;

namespace Royale.Pages
{
public class CardsPage : PageBase
{
public readonly CardsPageMap Map;

public CardsPage(IWebDriver driver) : base(driver)
{
Map = new CardsPageMap(driver);
}

public CardsPage Goto()
{
HeaderNav.GotoCardsPage();
return this;
}

public IWebElement GetCardByName(string cardName)
{
// Given the cardName "Ice Spirit" => should turn into "Ice+Spirit" to work with our locator.
if (cardName.Contains(" "))
{
cardName = cardName.Replace(" ", "+");
}

return Map.Card(cardName);
}
}

public class CardsPageMap
{
IWebDriver _driver;

public CardsPageMap(IWebDriver driver)
{
_driver = driver;
}

public IWebElement Card(string name) => _driver.FindElement(By.CssSelector($"a[href*='{name}']"));
}
}
32 changes: 32 additions & 0 deletions Royale/Pages/HeaderNav.cs
@@ -0,0 +1,32 @@
using System;
using OpenQA.Selenium;

namespace Royale.Pages
{
public class HeaderNav
{
public readonly HeaderNavMap Map;

public HeaderNav(IWebDriver driver)
{
Map = new HeaderNavMap(driver);
}

public void GotoCardsPage()
{
Map.CardsTabLink.Click();
}
}

public class HeaderNavMap
{
IWebDriver _driver;

public HeaderNavMap(IWebDriver driver)
{
_driver = driver;
}

public IWebElement CardsTabLink => _driver.FindElement(By.CssSelector("a[href='/cards']"));
}
}
14 changes: 14 additions & 0 deletions Royale/Pages/PageBase.cs
@@ -0,0 +1,14 @@
using OpenQA.Selenium;

namespace Royale.Pages
{
public abstract class PageBase
{
public readonly HeaderNav HeaderNav;

public PageBase(IWebDriver driver)
{
HeaderNav = new HeaderNav(driver);
}
}
}
4 changes: 4 additions & 0 deletions Royale/Royale.csproj
@@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\Framework\Framework.csproj" />
</ItemGroup>

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
Expand Down

0 comments on commit bfa0eeb

Please sign in to comment.