Browse Source

Merge branch 'develop' into main

main
Jonathan McCaffrey 4 years ago
parent
commit
8224c9fcfb
  1. 8
      Components/Inputs/SearchButtonComponent.razor
  2. 37
      Components/Inputs/SearchIconButtonComponent.razor
  3. 21
      Components/Navigation/DesktopNavComponent.razor
  4. 8
      Components/Navigation/MobileNavComponent.razor
  5. 17
      Components/Navigation/TabletNavComponent.razor
  6. BIN
      IGP/Database.db
  7. 8
      IGP/Dialog/SearchDialogComponent.razor
  8. 34
      IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor
  9. 2
      IGP/Program.cs
  10. 2
      IGP/wwwroot/generated/AgileTaskModels.json
  11. 2
      IGP/wwwroot/generated/GitChangeModels.json
  12. 2
      IGP/wwwroot/generated/GitPatchModels.json
  13. 2
      IGP/wwwroot/generated/Variables.json
  14. 1
      Model/Chart/PointModel.cs
  15. 6
      Model/Entity/Data/DATA.cs
  16. 55
      TestAutomation/BaseTest.cs
  17. 8
      TestAutomation/Enums/WindowType.cs
  18. 11
      TestAutomation/Pages/BasePage.cs
  19. 11
      TestAutomation/Pages/DatabaseSinglePage.cs
  20. 73
      TestAutomation/Pages/HarassCalculatorPage.cs
  21. 13
      TestAutomation/Shared/BaseElement.cs
  22. 25
      TestAutomation/Shared/NavigationBar.cs
  23. 35
      TestAutomation/Shared/WebsiteSearchDialog.cs
  24. 2
      TestAutomation/TestAutomation.csproj
  25. 90
      TestAutomation/TestHarassCalculator.cs
  26. 35
      TestAutomation/TestSearchFeatures.cs
  27. 35
      TestAutomation/Tests.cs
  28. 3
      TestAutomation/Utils/Test.cs
  29. 6
      TestAutomation/Utils/TestMessage.cs
  30. 29
      TestAutomation/Utils/TestReport.cs
  31. 102
      TestAutomation/Utils/Website.cs

8
Components/Inputs/SearchButtonComponent.razor

@ -2,7 +2,7 @@
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
<button class="searchButtonContainer" @onclick="ButtonClicked">
<button id="@Id" class="searchButtonContainer" @onclick="ButtonClicked">
<div class="searchText">
Search...
</div>
@ -33,15 +33,15 @@
background-color: var(--info);
border: 2px solid var(--primary-border);
}
</style>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public string Id { get; set; } = default!;
private string userAgent = "";
string CommandKey => userAgent.Contains("Mac OS") ? "CMD" : "Ctrl";

37
Components/Inputs/SearchIconButtonComponent.razor

@ -0,0 +1,37 @@
@inject ISearchService SearchService
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
<button id="@Id" class="searchIconButtonContainer" @onclick="ButtonClicked">
<div class="searchText">
S
</div>
</button>
<style>
.searchIconButtonContainer {
background-color: var(--primary);
border: 2px solid var(--primary-border);
border-radius: 8px;
font-weight: 800;
width: 32px;
padding: 5px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public string Id { get; set; } = default!;
private void ButtonClicked(EventArgs eventArgs)
{
SearchService.Show();
}
}

21
Components/Navigation/DesktopNavComponent.razor

@ -1,9 +1,9 @@
@inherits LayoutComponentBase
@inject INavigationService navigationService
@inject INavigationService NavigationService
@implements IDisposable
@{
var visibleStyle = navigationService.GetNavigationSectionId() > 0 ? "clickOffVisible" : "";
var visibleStyle = NavigationService.GetNavigationSectionId() > 0 ? "clickOffVisible" : "";
}
<div onclick="@MenuClosed" class="clickOffBackground @visibleStyle">
@ -12,14 +12,14 @@
<div class="desktopNavContainer">
<div class="menuHeader">
<NavLink href="/" class="websiteTitle">
<NavLink id="desktop-homeLink" href="/" class="websiteTitle">
IGP Fan Reference
</NavLink>
<div class="sectionNavs">
@foreach (var webSection in WebSections)
{
var isSelected = navigationService.GetNavigationSectionId().Equals(webSection.Id);
var isSelected = NavigationService.GetNavigationSectionId().Equals(webSection.Id);
var sectionButtonStyle = "sectionButton";
if (isSelected)
{
@ -28,7 +28,6 @@
<div class="sectionNav">
<button onclick="@(() => { MenuClicked(webSection.Id); })" class="@sectionButtonStyle">@webSection.Name</button>
@if (isSelected)
{
<div class="navMenuPosition">
@ -41,7 +40,7 @@
}
</div>
<SearchButtonComponent/>
<SearchButtonComponent Id="desktop-searchButton"/>
</div>
</div>
@ -169,27 +168,27 @@
protected override void OnInitialized()
{
base.OnInitialized();
navigationService.Subscribe(StateHasChanged);
NavigationService.Subscribe(StateHasChanged);
}
void IDisposable.Dispose()
{
navigationService.Unsubscribe(StateHasChanged);
NavigationService.Unsubscribe(StateHasChanged);
}
void MenuClicked(int menuName)
{
navigationService.ChangeNavigationSectionId(menuName);
NavigationService.ChangeNavigationSectionId(menuName);
}
void MenuClosed()
{
navigationService.ChangeNavigationSectionId(-1);
NavigationService.ChangeNavigationSectionId(-1);
}
void HoverOut(MouseEventArgs mouseEventArgs)
{
navigationService.ChangeNavigationState(NavigationStateType.Default);
NavigationService.ChangeNavigationState(NavigationStateType.Default);
}
}

8
Components/Navigation/MobileNavComponent.razor

@ -1,4 +1,7 @@
<div class="mobileFooter">

<div class="mobileFooter">
<div class="mobileNavSectionsContainer">
@foreach (var webSection in WebSections)
{
@ -8,6 +11,7 @@
</div>
</div>
}
<SearchIconButtonComponent/>
</div>
<div class="fullPageButton @(selectedSection != null)" @onclick="OnPageClicked" @onclick:stopPropagation="false" @onclick:preventDefault="false">
@ -52,6 +56,8 @@
}
.mobileFooter {
position: fixed;
background-color: rgba(0,0,0,1);

17
Components/Navigation/TabletNavComponent.razor

@ -5,10 +5,13 @@
<div class="tabletTitle">
IGP Fan Reference
</div>
<div class="tabletButton">
<div class="tabletMenuTitle">
Menu
<div class="tabletButtons">
<SearchButtonComponent/>
<div class="tabletButton">
<div class="tabletMenuTitle">
Menu
</div>
</div>
</div>
</div>
@ -78,6 +81,12 @@
gap: 22px;
flex-direction: column;
}
.tabletButtons {
display: flex;
gap: 12px;
}
.tabletNavItem {
padding: 8px;

BIN
IGP/Database.db

Binary file not shown.

8
IGP/Dialog/SearchDialogComponent.razor

@ -8,7 +8,7 @@
@if (searchService.IsLoaded() && searchService.IsVisible)
{
<div class="searchBackground" onclick="@CloseDialog">
<div id="searchBackground" class="searchBackground" onclick="@CloseDialog">
<div class="searchContainer"
@onclick:preventDefault="true"
@onclick:stopPropagation="true">
@ -33,7 +33,11 @@
<div class="searchContents">
@foreach (var searchPoint in searchPoints)
{
<button class="searchLink @searchPoint.PointType.ToLower()" @onclick="() => OnSearch(searchPoint)">@searchPoint.Title</button>
<button class="searchLink @searchPoint.PointType.ToLower()"
label="@searchPoint.Title"
@onclick="() => OnSearch(searchPoint)">
@searchPoint.Title
</button>
}
</div>
</div>

34
IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor

@ -1,7 +1,7 @@
@inject IEconomyService economyService
@inject IBuildOrderService buildOrderService
@inject ITimingService timingService
@inject IJSRuntime jsRuntime;
@inject IEconomyService EconomyService
@inject IBuildOrderService BuildOrderService
@inject ITimingService TimingService
@inject IJSRuntime JsRuntime;
@implements IDisposable
@if (lastRequestedRefreshIndex != requestedRefreshIndex)
@ -13,10 +13,20 @@ else
<div class="chartsContainer">
@foreach (var chart in charts)
{
Dictionary<int, bool> takenPixels = new Dictionary<int, bool>();
<div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
<div style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
@foreach (var point in chart.Points)
{
var x = int.Parse(point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax));
if (takenPixels.ContainsKey(x)) continue;
takenPixels.Add(x, true);
<div style="position: absolute;
bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px;
left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px;
@ -82,8 +92,8 @@ else
protected override void OnInitialized()
{
base.OnInitialized();
buildOrderService.Subscribe(OnBuilderOrderChanged);
timingService.Subscribe(OnBuilderOrderChanged);
BuildOrderService.Subscribe(OnBuilderOrderChanged);
TimingService.Subscribe(OnBuilderOrderChanged);
ageTimer = new Timer(1000);
ageTimer.Elapsed += OnAge!;
@ -116,8 +126,8 @@ else
void IDisposable.Dispose()
{
buildOrderService.Unsubscribe(OnBuilderOrderChanged);
timingService.Unsubscribe(OnBuilderOrderChanged);
BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
TimingService.Unsubscribe(OnBuilderOrderChanged);
}
@ -133,7 +143,7 @@ else
protected override bool ShouldRender()
{
#if DEBUG
jsRuntime.InvokeVoidAsync("console.time", "ChartComponent");
JsRuntime.InvokeVoidAsync("console.time", "ChartComponent");
#endif
return true;
@ -142,13 +152,13 @@ else
protected override void OnAfterRender(bool firstRender)
{
#if DEBUG
jsRuntime.InvokeVoidAsync("console.timeEnd", "ChartComponent");
JsRuntime.InvokeVoidAsync("console.timeEnd", "ChartComponent");
#endif
}
void GenerateChart()
{
var economyOverTime = economyService.GetOverTime();
var economyOverTime = EconomyService.GetOverTime();
charts.Clear();
@ -189,7 +199,7 @@ else
for (var interval = 0; interval < economyOverTime.Count(); interval++)
{
var army = from unit in buildOrderService.GetCompletedBefore(interval)
var army = from unit in BuildOrderService.GetCompletedBefore(interval)
where unit.EntityType == EntityType.Army
select unit;

2
IGP/Program.cs

@ -44,7 +44,7 @@ builder.Services.AddBlazoredLocalStorageAsSingleton(config =>
#if DEBUG
builder.Services.AddGoogleAnalytics("G-S96LW7TVFY");
#else
builder.Services.AddGoogleAnalytics(builder.Configuration["GA-Tag"]);
builder.Services.AddGoogleAnalytics(builder.Configuration["GATag"]);
#endif
builder.Services.AddScoped<INavigationService, NavigationService>();

2
IGP/wwwroot/generated/AgileTaskModels.json

File diff suppressed because one or more lines are too long

2
IGP/wwwroot/generated/GitChangeModels.json

File diff suppressed because one or more lines are too long

2
IGP/wwwroot/generated/GitPatchModels.json

@ -1 +1 @@
[{"Id":1,"Name":"Database UX Patch","Date":"2022-03-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":2,"Name":"Thrum Stats Hotfix","Date":"2022-03-12T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":3,"Name":"Memory Tester Patch","Date":"2022-03-01T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":4,"Name":"Hide Pyre Hotfix","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":5,"Name":"Stream Patch 1","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":6,"Name":"Agile UI Hotfix","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":7,"Name":"Armor Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":8,"Name":"Home Page Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":9,"Name":"Mobile Menu Hotfix 2","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":10,"Name":"Mobile Menu Hotfix","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":11,"Name":"Mobile Menu Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":12,"Name":"0.0.6.8375a Patch","Date":"2022-02-18T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":13,"Name":"Google Tracking Hotfix","Date":"2022-02-18T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":14,"Name":"Privacy Policy Patch","Date":"2022-02-17T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":15,"Name":"Home Page Quick Hotfix","Date":"2022-02-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":16,"Name":"Early Agile Patch","Date":"2022-02-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":17,"Name":"Form Text Rendering Hotfix","Date":"2022-02-15T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":18,"Name":"Reducing Timing Interval Hotfix","Date":"2022-02-15T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":19,"Name":"Changelog Patch","Date":"2022-02-14T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":20,"Name":"SQL Patch","Date":"2022-03-26T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":21,"Name":"Stream Patch 2","Date":"2022-03-30T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":22,"Name":"0.0.6.8900a Patch","Date":"2022-03-30T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":23,"Name":"Database Links Patch","Date":"2022-04-01T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":24,"Name":"Open Source Patch","Date":"2022-04-03T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":25,"Name":"Stream Patch 3","Date":"2022-04-03T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":26,"Name":"Notes/Docs Patch","Date":"2022-04-10T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":27,"Name":"Stream Patch 4","Date":"2022-04-10T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":28,"Name":"Passive Patch","Date":"2022-04-12T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":29,"Name":"0.0.6.9121a Patch","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":30,"Name":"Stream Patch 5","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":31,"Name":"BuildCalc Hotfix","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":32,"Name":"Search Patch","Date":"2022-04-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":33,"Name":"Search Hotfix","Date":"2022-04-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":34,"Name":"Stream Patch 6","Date":"2022-04-17T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":35,"Name":"v0.0.6.9201a Patch","Date":"2022-04-18T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":36,"Name":"Build Calc Free Money Hotfix","Date":"2022-04-18T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":37,"Name":"BuildCalc Pyre Patch","Date":"2022-04-24T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":38,"Name":"Stream Patch 7","Date":"2022-04-24T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":39,"Name":"v0.0.6.9513a Patch","Date":"2022-04-29T00:00:00","GitChangeModels":[],"Important":"True"}]
[{"Id":1,"Name":"Database UX Patch","Date":"2022-03-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":2,"Name":"Thrum Stats Hotfix","Date":"2022-03-12T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":3,"Name":"Memory Tester Patch","Date":"2022-03-01T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":4,"Name":"Hide Pyre Hotfix","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":5,"Name":"Stream Patch 1","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":6,"Name":"Agile UI Hotfix","Date":"2022-02-20T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":7,"Name":"Armor Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":8,"Name":"Home Page Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":9,"Name":"Mobile Menu Hotfix 2","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":10,"Name":"Mobile Menu Hotfix","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":11,"Name":"Mobile Menu Patch","Date":"2022-02-19T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":12,"Name":"0.0.6.8375a Patch","Date":"2022-02-18T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":13,"Name":"Google Tracking Hotfix","Date":"2022-02-18T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":14,"Name":"Privacy Policy Patch","Date":"2022-02-17T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":15,"Name":"Home Page Quick Hotfix","Date":"2022-02-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":16,"Name":"Early Agile Patch","Date":"2022-02-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":17,"Name":"Form Text Rendering Hotfix","Date":"2022-02-15T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":18,"Name":"Reducing Timing Interval Hotfix","Date":"2022-02-15T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":19,"Name":"Changelog Patch","Date":"2022-02-14T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":20,"Name":"SQL Patch","Date":"2022-03-26T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":21,"Name":"Stream Patch 2","Date":"2022-03-30T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":22,"Name":"0.0.6.8900a Patch","Date":"2022-03-30T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":23,"Name":"Database Links Patch","Date":"2022-04-01T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":24,"Name":"Open Source Patch","Date":"2022-04-03T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":25,"Name":"Stream Patch 3","Date":"2022-04-03T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":26,"Name":"Notes/Docs Patch","Date":"2022-04-10T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":27,"Name":"Stream Patch 4","Date":"2022-04-10T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":28,"Name":"Passive Patch","Date":"2022-04-12T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":29,"Name":"0.0.6.9121a Patch","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":30,"Name":"Stream Patch 5","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":31,"Name":"BuildCalc Hotfix","Date":"2022-04-13T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":32,"Name":"Search Patch","Date":"2022-04-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":33,"Name":"Search Hotfix","Date":"2022-04-16T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":34,"Name":"Stream Patch 6","Date":"2022-04-17T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":35,"Name":"v0.0.6.9201a Patch","Date":"2022-04-18T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":36,"Name":"Build Calc Free Money Hotfix","Date":"2022-04-18T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":37,"Name":"BuildCalc Pyre Patch","Date":"2022-04-24T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":38,"Name":"Stream Patch 7","Date":"2022-04-24T00:00:00","GitChangeModels":[],"Important":"False"},{"Id":39,"Name":"v0.0.6.9513a Patch","Date":"2022-04-28T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":40,"Name":"v0.0.6.9553a Patch","Date":"2022-04-29T00:00:00","GitChangeModels":[],"Important":"True"},{"Id":41,"Name":"Stream Patch 8","Date":"2022-04-29T00:00:00","GitChangeModels":[],"Important":"False"}]

2
IGP/wwwroot/generated/Variables.json

@ -1 +1 @@
[{"Key":"GamePatch","Value":"v0.0.6.9513a"}]
[{"Key":"GamePatch","Value":"v0.0.6.9553a"}]

1
Model/Chart/PointModel.cs

@ -11,6 +11,7 @@ public class PointModel
var display = Interval / highestInterval * displayScale;
return ((int)display).ToString();
}
public string GetValue(float highestValue, float displayScale)
{

6
Model/Entity/Data/DATA.cs

@ -1136,7 +1136,7 @@ public class DATA
.AddPart(new EntityMovementModel { Speed = 378, Movement = MovementType.Ground })
.AddPart(new EntityWeaponModel
{
Damage = 15, MediumDamage = 20, HeavyDamage = 25, Range = 400, AttacksPerSecond = 0.56f,
Damage = 12, MediumDamage = 18, HeavyDamage = 24, Range = 400, AttacksPerSecond = 0.56f,
Targets = TargetType.Ground
})
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_XacalDamage })
@ -2616,7 +2616,7 @@ public class DATA
"Units that enter the target area suffer heavy damage over time. This damaging effect persists for a few seconds after leaving the plague area."
})
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "D" })
.AddPart(new EntityProductionModel { Energy = 75, Cooldown = 2 })
.AddPart(new EntityProductionModel { Energy = 75, Cooldown = 8 })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
},
{
@ -2670,7 +2670,7 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "D" })
.AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Mala })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Energy = 80, Cooldown = 2 })
.AddPart(new EntityProductionModel { Energy = 80, Cooldown = 8 })
},
{
DataType.ABILITY_SummonSiegeMaw,

55
TestAutomation/BaseTest.cs

@ -0,0 +1,55 @@
using TestAutomation.Utils;
namespace TestAutomation;
public enum DeploymentType
{
Dev,
Local
}
public class BaseTest
{
protected static readonly DeploymentType DeploymentType =
Environment.GetEnvironmentVariable("TEST_HOOK") != null
? DeploymentType.Dev
: DeploymentType.Local;
protected static readonly string WebsiteUrl =
DeploymentType.Equals(DeploymentType.Dev)
? "https://calm-mud-04916b210.1.azurestaticapps.net/"
: "https://localhost:7234";
protected static readonly TestReport TestReport = new();
protected static Website WebsiteInstance = default!;
protected static Website Website
{
get
{
if (WebsiteInstance == null)
{
var options = new FirefoxOptions();
options.AcceptInsecureCertificates = true;
if (DeploymentType.Equals(DeploymentType.Dev))
{
options.AddArgument("--headless");
}
options.AddArgument("--ignore-certificate-errors");
options.AddArgument("--start-maximized");
options.AddArgument("--test-type");
options.AddArgument("--allow-running-insecure-content");
IWebDriver webDriver = new FirefoxDriver(Environment.CurrentDirectory, options);
WebsiteInstance = new Website(webDriver);
}
return WebsiteInstance;
}
}
}

8
TestAutomation/Enums/WindowType.cs

@ -0,0 +1,8 @@
namespace TestAutomation.Enums;
public enum ScreenType
{
Desktop,
Tablet,
Mobile
}

11
TestAutomation/Pages/BasePage.cs

@ -1,11 +0,0 @@
using TestAutomation.Utils;
namespace TestAutomation.Pages;
public class BasePage {
public Website website;
public BasePage(Website website) {
this.website = website;
}
}

11
TestAutomation/Pages/DatabaseSinglePage.cs

@ -0,0 +1,11 @@
using TestAutomation.Shared;
using TestAutomation.Utils;
namespace TestAutomation.Pages;
public class DatabaseSinglePage : BaseElement
{
public DatabaseSinglePage(Website website) : base(website) { }
}

73
TestAutomation/Pages/HarassCalculatorPage.cs

@ -1,71 +1,86 @@
using TestAutomation.Utils;
using TestAutomation.Shared;
using TestAutomation.Utils;
namespace TestAutomation.Pages;
public class HarassCalculatorPage : BasePage {
public HarassCalculatorPage(Website website) : base(website) { }
private IWebElement NumberOfWorkersLostToHarass => website.Find("numberOfWorkersLostToHarass");
private IWebElement NumberOfTownHallsExisting => website.Find("numberOfTownHallsExisting");
private IList<IWebElement> OnTownHallTravelTimes => website.FindChildren("numberOfTownHallTravelTimes", "input");
private int TotalAlloyHarassment => website.FindInt("totalAlloyHarassment");
private int WorkerReplacementCost => website.FindInt("workerReplacementCost");
private int DelayedMiningCost => website.FindInt("delayedMiningCost");
private int AverageTravelTime => website.FindInt("getAverageTravelTime");
public class HarassCalculatorPage : BaseElement
{
public HarassCalculatorPage(Website website) : base(website)
{
}
private IWebElement NumberOfWorkersLostToHarass => Website.Find("numberOfWorkersLostToHarass");
private IWebElement NumberOfTownHallsExisting => Website.Find("numberOfTownHallsExisting");
private IList<IWebElement> OnTownHallTravelTimes => Website.FindChildren("numberOfTownHallTravelTimes", "input");
private int TotalAlloyHarassment => Website.FindInt("totalAlloyHarassment");
private int WorkerReplacementCost => Website.FindInt("workerReplacementCost");
private int DelayedMiningCost => Website.FindInt("delayedMiningCost");
private int AverageTravelTime => Website.FindInt("getAverageTravelTime");
private int ExampleTotalAlloyLoss => website.FindInt("exampleTotalAlloyLoss");
private int ExampleWorkerCost => website.FindInt("exampleWorkerCost");
private int ExampleMiningTimeCost => website.FindInt("exampleMiningTimeCost");
private int ExampleTotalAlloyLossDifference => website.FindInt("exampleTotalAlloyLossDifference");
private int ExampleTotalAlloyLossAccurate => website.FindInt("exampleTotalAlloyLossAccurate");
private int ExampleTotalAlloyLossAccurateDifference => website.FindInt("exampleTotalAlloyLossAccurateDifference");
private int ExampleTotalAlloyLoss => Website.FindInt("exampleTotalAlloyLoss");
private int ExampleWorkerCost => Website.FindInt("exampleWorkerCost");
private int ExampleMiningTimeCost => Website.FindInt("exampleMiningTimeCost");
private int ExampleTotalAlloyLossDifference => Website.FindInt("exampleTotalAlloyLossDifference");
private int ExampleTotalAlloyLossAccurate => Website.FindInt("exampleTotalAlloyLossAccurate");
private int ExampleTotalAlloyLossAccurateDifference => Website.FindInt("exampleTotalAlloyLossAccurateDifference");
public HarassCalculatorPage SetWorkersLostToHarass(int number) {
website.EnterInput(NumberOfWorkersLostToHarass, number);
public HarassCalculatorPage SetWorkersLostToHarass(int number)
{
Website.EnterInput(NumberOfWorkersLostToHarass, number);
return this;
}
public HarassCalculatorPage SetNumberOfTownHallsExisting(int number) {
website.EnterInput(NumberOfTownHallsExisting, number);
public HarassCalculatorPage SetNumberOfTownHallsExisting(int number)
{
Website.EnterInput(NumberOfTownHallsExisting, number);
return this;
}
public HarassCalculatorPage SetTownHallTravelTime(int forTownHall, int number) {
website.EnterInput(OnTownHallTravelTimes[forTownHall], number);
public HarassCalculatorPage SetTownHallTravelTime(int forTownHall, int number)
{
Website.EnterInput(OnTownHallTravelTimes[forTownHall], number);
return this;
}
public HarassCalculatorPage GetTotalAlloyHarassment(out int result) {
public HarassCalculatorPage GetTotalAlloyHarassment(out int result)
{
result = TotalAlloyHarassment;
return this;
}
public HarassCalculatorPage GetExampleTotalAlloyLoss(out int result) {
public HarassCalculatorPage GetExampleTotalAlloyLoss(out int result)
{
result = ExampleTotalAlloyLoss;
return this;
}
public HarassCalculatorPage GetExampleWorkerCost(out int result) {
public HarassCalculatorPage GetExampleWorkerCost(out int result)
{
result = ExampleWorkerCost;
return this;
}
public HarassCalculatorPage GetExampleMiningTimeCost(out int result) {
public HarassCalculatorPage GetExampleMiningTimeCost(out int result)
{
result = ExampleMiningTimeCost;
return this;
}
public HarassCalculatorPage GetExampleTotalAlloyLossAccurate(out int result) {
public HarassCalculatorPage GetExampleTotalAlloyLossAccurate(out int result)
{
result = ExampleTotalAlloyLossAccurate;
return this;
}
public HarassCalculatorPage GetExampleTotalAlloyLossDifference(out int result) {
public HarassCalculatorPage GetExampleTotalAlloyLossDifference(out int result)
{
result = ExampleTotalAlloyLossDifference;
return this;
}
public HarassCalculatorPage GetExampleTotalAlloyLossAccurateDifference(out int result) {
public HarassCalculatorPage GetExampleTotalAlloyLossAccurateDifference(out int result)
{
result = ExampleTotalAlloyLossAccurateDifference;
return this;
}

13
TestAutomation/Shared/BaseElement.cs

@ -0,0 +1,13 @@
using TestAutomation.Utils;
namespace TestAutomation.Shared;
public class BaseElement
{
protected readonly Website Website;
protected BaseElement(Website website)
{
Website = website;
}
}

25
TestAutomation/Shared/NavigationBar.cs

@ -0,0 +1,25 @@
using TestAutomation.Enums;
using TestAutomation.Utils;
namespace TestAutomation.Shared;
public class NavigationBar : BaseElement
{
public NavigationBar(Website website) : base(website) { }
private IWebElement HomeLink => Website.FindScreenSpecific("homeLink");
private IWebElement SearchButton => Website.FindScreenSpecific("searchButton");
public NavigationBar ClickHomeLink()
{
Website.Click(HomeLink);
return this;
}
public WebsiteSearchDialog ClickSearchButton()
{
Website.Click(SearchButton);
return Website.WebsiteSearchDialog;
}
}

35
TestAutomation/Shared/WebsiteSearchDialog.cs

@ -0,0 +1,35 @@
using Discord.Rest;
using TestAutomation.Utils;
namespace TestAutomation.Shared;
public class WebsiteSearchDialog : BaseElement
{
public WebsiteSearchDialog(Website website) : base(website)
{
}
public IWebElement SearchBackground => Website.Find("searchBackground");
public IWebElement SearchInput => Website.Find("searchInput");
public NavigationBar CloseDialog()
{
Website.ClickTopLeft();
return Website.NavigationBar;
}
public WebsiteSearchDialog Search(string throne)
{
Website.EnterInput(SearchInput, throne);
return this;
}
public void SelectSearchEntity(string throne)
{
Website.Click(Website.FindButtonWithLabel(throne));
//TODO Add DatabaseSinglePage
//return Website.DatabaseSinglePage;
}
}

2
TestAutomation/TestAutomation.csproj

@ -22,7 +22,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Pages\" />
<Folder Include="Pages\" />
</ItemGroup>
</Project>

90
TestAutomation/UnitTests.cs → TestAutomation/TestHarassCalculator.cs

@ -1,89 +1,45 @@
using System.Text;
using Newtonsoft.Json;
using TestAutomation.Utils;
namespace TestAutomation;
public class Tests {
private readonly IWebDriver _webDriver = default!;
private readonly string develop = "https://calm-mud-04916b210.1.azurestaticapps.net/";
private readonly HttpClient httpClient = new();
private readonly string localhost = "https://localhost:7234";
private readonly TestReport testReport = new();
public Tests() {
var options = new FirefoxOptions();
options.AcceptInsecureCertificates = true;
options.AddArgument("--headless");
options.AddArgument("--ignore-certificate-errors");
options.AddArgument("--start-maximized");
options.AddArgument("--test-type");
options.AddArgument("--allow-running-insecure-content");
_webDriver = new FirefoxDriver(Environment.CurrentDirectory, options);
Website = new Website(_webDriver);
}
private Website Website { get; }
[OneTimeSetUp]
public void Setup() {
_webDriver.Navigate().GoToUrl(develop);
_webDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(15);
}
[OneTimeTearDown]
public void TearDown() {
_webDriver.Quit();
var message = new {
content = "Test Report " + DateTime.Now.ToString("dd/MM/yyyy"),
embeds = testReport.GetMessages()
};
var content = new StringContent(JsonConvert.SerializeObject(message), Encoding.UTF8, "application/json");
httpClient.PostAsync(Environment.GetEnvironmentVariable("TEST_HOOK"), content).Wait();
}
[TestFixture]
public class TestHarassCalculator : BaseTest
{
[Test]
public void HarassCalculator() {
testReport.CreateTest();
public void CalculatorInput()
{
TestReport.CreateTest();
_webDriver.Navigate().GoToUrl(develop + "/harass-calculator");
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/harass-calculator");
var expectedTotalAlloyHarassment = 240;
try {
try
{
Website.HarassCalculatorPage
.SetWorkersLostToHarass(3)
.SetNumberOfTownHallsExisting(2)
.SetTownHallTravelTime(0, 30)
.GetTotalAlloyHarassment(out var foundTotalAlloyHarassment);
testReport.CheckPassed(expectedTotalAlloyHarassment.Equals(foundTotalAlloyHarassment),
TestReport.CheckPassed(expectedTotalAlloyHarassment.Equals(foundTotalAlloyHarassment),
TestMessage.CreateFailedMessage($"expectTotalAlloyHarassment of {expectedTotalAlloyHarassment} " +
"does not equal " +
$"foundTotalAlloyHarassment of {foundTotalAlloyHarassment} "));
}
catch (Exception e) {
testReport.CheckPassed(false,
catch (Exception e)
{
TestReport.CheckPassed(false,
TestMessage.CreateFailedMessage(e.StackTrace!));
}
}
[Test]
public void HarassCalculatorInformation() {
testReport.CreateTest();
public void CalculatedExampleInformation()
{
TestReport.CreateTest();
_webDriver.Navigate().GoToUrl(develop + "/harass-calculator");
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/harass-calculator");
var expectedExampleTotalAlloyLoss = 720;
var expectedExampleWorkerCost = 300;
@ -100,38 +56,38 @@ public class Tests {
.GetExampleTotalAlloyLossDifference(out var foundGetExampleTotalAlloyLossDifference)
.GetExampleTotalAlloyLossAccurateDifference(out var foundExampleTotalAlloyLossAccurateDifference);
testReport.CheckPassed(expectedExampleTotalAlloyLoss.Equals(foundTotalAlloyLoss),
TestReport.CheckPassed(expectedExampleTotalAlloyLoss.Equals(foundTotalAlloyLoss),
TestMessage.CreateFailedMessage($"expectedExampleTotalAlloyLoss of {expectedExampleTotalAlloyLoss} " +
"does not equal " +
$"foundTotalAlloyLoss of {foundTotalAlloyLoss} "));
testReport.CheckPassed(expectedExampleWorkerCost.Equals(foundExampleWorkerCost),
TestReport.CheckPassed(expectedExampleWorkerCost.Equals(foundExampleWorkerCost),
TestMessage.CreateFailedMessage($"expectedExampleWorkerCost of {expectedExampleWorkerCost} " +
"does not equal " +
$"foundExampleWorkerCost of {foundExampleWorkerCost} "));
testReport.CheckPassed(expectedExampleMiningTimeCost.Equals(foundExampleMiningTimeCost),
TestReport.CheckPassed(expectedExampleMiningTimeCost.Equals(foundExampleMiningTimeCost),
TestMessage.CreateFailedMessage($"expectedExampleMiningTimeCost of {expectedExampleMiningTimeCost} " +
"does not equal " +
$"foundExampleMiningTimeCost of {foundExampleMiningTimeCost} "));
testReport.CheckPassed(expectedExampleTotalAlloyLossAccurate.Equals(foundExampleTotalAlloyLossAccurate),
TestReport.CheckPassed(expectedExampleTotalAlloyLossAccurate.Equals(foundExampleTotalAlloyLossAccurate),
TestMessage.CreateFailedMessage(
$"expectedExampleTotalAlloyLossAccurate of {expectedExampleTotalAlloyLossAccurate} " +
"does not equal " +
$"foundExampleTotalAlloyLossAccurate of {foundExampleTotalAlloyLossAccurate} "));
testReport.CheckPassed(expectedExampleTotalAlloyLossDifference.Equals(foundGetExampleTotalAlloyLossDifference),
TestReport.CheckPassed(expectedExampleTotalAlloyLossDifference.Equals(foundGetExampleTotalAlloyLossDifference),
TestMessage.CreateFailedMessage(
$"expectedExampleTotalAlloyLossDifference of {expectedExampleTotalAlloyLossDifference} " +
"does not equal " +
$"foundGetExampleTotalAlloyLossDifference of {foundGetExampleTotalAlloyLossDifference} "));
testReport.CheckPassed(
TestReport.CheckPassed(
expectedExampleTotalAlloyLossAccurateDifference.Equals(foundExampleTotalAlloyLossAccurateDifference),
TestMessage.CreateFailedMessage(
$"expectedExampleTotalAlloyLossAccurateDifference of {expectedExampleTotalAlloyLossAccurateDifference} " +

35
TestAutomation/TestSearchFeatures.cs

@ -0,0 +1,35 @@
namespace TestAutomation;
[TestFixture]
public class TestSearchFeatures : BaseTest
{
[Test]
public void DesktopOpenCloseSearchDialog()
{
TestReport.CreateTest();
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/");
Website.NavigationBar
.ClickSearchButton()
.CloseDialog()
.ClickHomeLink();
}
[Test]
[Ignore("Not completed")]
public void DesktopSearchForThrone()
{
TestReport.CreateTest();
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/");
Website.NavigationBar
.ClickSearchButton()
.Search("Throne")
.SelectSearchEntity("Throne");
// .GetName(out var name);
// TestReport.CheckPassed(name.Equals("Throne"), "Couldn't find Throne via search.");
}
}

35
TestAutomation/Tests.cs

@ -0,0 +1,35 @@
using System.Text;
using Newtonsoft.Json;
namespace TestAutomation;
[SetUpFixture]
public class Tests : BaseTest
{
[OneTimeSetUp]
public void Setup()
{
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl);
Website.WebDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(15);
}
[OneTimeTearDown]
public void TearDown()
{
HttpClient HttpClient = new();
Website.WebDriver.Quit();
var message = new
{
content = "Test Report " + DateTime.Now.ToString("dd/MM/yyyy"),
embeds = TestReport.GetMessages()
};
var content = new StringContent(JsonConvert.SerializeObject(message), Encoding.UTF8, "application/json");
if (Environment.GetEnvironmentVariable("TEST_HOOK") == null) return;
HttpClient.PostAsync(Environment.GetEnvironmentVariable("TEST_HOOK"), content).Wait();
}
}

3
TestAutomation/Utils/Test.cs

@ -1,6 +1,7 @@
namespace TestAutomation.Utils;
public class Test {
public class Test
{
public string Name { get; set; } = "Name...";
public bool Result { get; set; } = true;
public IList<TestMessage> Messages { get; set; } = new List<TestMessage>();

6
TestAutomation/Utils/TestMessage.cs

@ -1,11 +1,13 @@
namespace TestAutomation.Utils;
public class TestMessage {
public class TestMessage
{
public string Title { get; set; } = "Name...";
public string Description { get; set; } = "";
public string Color { get; set; } = "FFFFFF";
public static TestMessage CreateFailedMessage(string description) {
public static TestMessage CreateFailedMessage(string description)
{
return new TestMessage { Title = "Check Failed", Description = description, Color = "FF0000" };
}
}

29
TestAutomation/Utils/TestReport.cs

@ -4,24 +4,31 @@ using System.Runtime.CompilerServices;
namespace TestAutomation.Utils;
public class TestReport {
public class TestReport
{
private List<Test> Tests { get; } = new();
[MethodImpl(MethodImplOptions.NoInlining)]
public Test CreateTest() {
public Test CreateTest()
{
var testName = new StackTrace().GetFrame(1)!.GetMethod()!.Name!;
Tests.Add(new Test { Name = testName });
return Tests.Last();
}
public void CheckPassed(bool passed, TestMessage message) {
public void CheckPassed(bool passed, TestMessage message)
{
if (passed) return;
Tests.Last().Result = false;
Tests.Last().Messages.Add(message);
throw new Exception(message.Description);
}
public bool DidTestsPass() {
foreach (var test in Tests) {
public bool DidTestsPass()
{
foreach (var test in Tests)
{
if (test.Result) continue;
return false;
@ -31,10 +38,13 @@ public class TestReport {
return true;
}
public List<object> GetMessages() {
public List<object> GetMessages()
{
if (DidTestsPass())
return new List<object> {
new {
return new List<object>
{
new
{
title = "Passed",
color = int.Parse("00FF00", NumberStyles.HexNumber),
description = $"All {Tests.Count} tests passed."
@ -45,7 +55,8 @@ public class TestReport {
foreach (var test in Tests)
foreach (var message in test.Messages)
messageList.Add(
new {
new
{
title = message.Title,
color = int.Parse(message.Color, NumberStyles.HexNumber),
description = message.Description

102
TestAutomation/Utils/Website.cs

@ -1,35 +1,113 @@
namespace TestAutomation.Utils;
using OpenQA.Selenium.Interactions;
using TestAutomation.Enums;
using TestAutomation.Shared;
public class Website {
public Website(IWebDriver webDriver) {
namespace TestAutomation.Utils;
public class Website
{
public readonly ScreenType ScreenType = ScreenType.Desktop;
public Website(IWebDriver webDriver)
{
WebDriver = webDriver;
HarassCalculatorPage = new HarassCalculatorPage(this);
NavigationBar = new NavigationBar(this);
WebsiteSearchDialog = new WebsiteSearchDialog(this);
}
public IWebDriver WebDriver { get; }
public HarassCalculatorPage HarassCalculatorPage { get; }
public NavigationBar NavigationBar { get; }
public WebsiteSearchDialog WebsiteSearchDialog { get; }
public IWebElement Find(string byId) {
return WebDriver.FindElement(By.Id(byId));
public IWebElement FindScreenSpecific(string byId)
{
var screenSpecificId = $"{ScreenType.ToString().ToLower()}-{byId}";
try
{
return WebDriver.FindElement(By.Id(screenSpecificId));
}
catch (Exception e)
{
throw new Exception($"Couldn't find {screenSpecificId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing.");
}
}
public IList<IWebElement> FindChildren(string ofId, string tagname) {
public IWebElement Find(string byId)
{
try
{
return WebDriver.FindElement(By.Id(byId));
}
catch (Exception e)
{
throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing.");
}
}
public IWebElement FindButtonWithLabel(string label)
{
try
{
return WebDriver.FindElement(By.XPath($"button[@label='{label}']"));
}
catch (Exception e)
{
throw new Exception($"Couldn't find with label: {label}. Element does not exist on current page. ");
}
}
//@FindBy(xpath = "//div[@label='First Name']")
public IList<IWebElement> FindChildren(string ofId, string tagname)
{
return WebDriver.FindElements(By.CssSelector($"#{ofId} {tagname}"));
}
public string FindText(string byId) {
public string FindText(string byId)
{
return WebDriver.FindElement(By.Id(byId)).Text;
}
public int FindInt(string byId) {
public int FindInt(string byId)
{
return int.Parse(WebDriver.FindElement(By.Id(byId)).Text);
}
public IWebElement EnterInput<T>(IWebElement element, T input) {
public void ClickTopLeft()
{
new Actions(WebDriver)
.MoveByOffset(32, 32)
.Click()
.Perform();
}
public IWebElement Click(IWebElement element)
{
try
{
element.Click();
}
catch
{
throw new Exception($"Couldn't click on {element.GetDomProperty("id")}. ");
}
return element;
}
public IWebElement EnterInput<T>(IWebElement element, T input)
{
element.Clear();
element.SendKeys(input!.ToString());
element.SendKeys(Keys.Enter);
@ -37,7 +115,8 @@ public class Website {
}
public IWebElement EnterInput<T>(string byId, T input) {
public IWebElement EnterInput<T>(string byId, T input)
{
var element = Find(byId);
element.Clear();
element.SendKeys(input!.ToString());
@ -45,7 +124,8 @@ public class Website {
return element;
}
public string GetLabel(string byId) {
public string GetLabel(string byId)
{
return Find(byId).Text;
}
}
Loading…
Cancel
Save