From 7cc6bd9192a25158c3cdeb18dce5d178fc0a73f9 Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 10:07:55 +0100 Subject: [PATCH 1/6] E2E test CharacterDescription textarea --- ChatRPGTests/AuthorizedIndexE2ETests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ChatRPGTests/AuthorizedIndexE2ETests.cs b/ChatRPGTests/AuthorizedIndexE2ETests.cs index 32078d9..7d02cf1 100644 --- a/ChatRPGTests/AuthorizedIndexE2ETests.cs +++ b/ChatRPGTests/AuthorizedIndexE2ETests.cs @@ -424,6 +424,21 @@ public void Assert.True(characterNameAlert.Displayed && campaignTitleAlert.Displayed); } + [Fact] + public void AuthorizedIndexPage_CustomCampaign_CharacterDescriptionIsEmptyOnInitialization() + { + // Arrange + string expectedCharacterDescription = string.Empty; + + // Act + IWebElement? characterDescription = + _wait.Until(webDriver => webDriver.FindElement(By.Id("inputCharacterDescription"))); + string actualCharacterDescription = characterDescription.Text; + + // Assert + Assert.Equal(expectedCharacterDescription, actualCharacterDescription); + } + public void Dispose() { E2ETestUtility.Teardown(_driver); From ec618402e554da7f422cb8a2efed55a0ead36fd9 Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 11:40:32 +0100 Subject: [PATCH 2/6] Fix dynamic scalability problems in UI --- ChatRPG/wwwroot/css/site.css | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ChatRPG/wwwroot/css/site.css b/ChatRPG/wwwroot/css/site.css index 18dbc97..2aeb2cc 100644 --- a/ChatRPG/wwwroot/css/site.css +++ b/ChatRPG/wwwroot/css/site.css @@ -2,6 +2,7 @@ html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + height: 100%; } h1:focus { @@ -12,6 +13,10 @@ a, .btn-link { color: #0071c1; } +.page { + min-height: 100vh; +} + .btn-primary { background-color: #4eb758; color: black; @@ -180,7 +185,7 @@ a, .btn-link { .dashboard-wrapper { display: flex; flex-direction: column; - height: 100vh; + height: 100%; } .dashboard-container { @@ -189,8 +194,7 @@ a, .btn-link { flex-direction: column; align-items: center; justify-content: center; - overflow-y: auto; - margin-top: -120px; + margin-top: -50px; } .title-front { From a1d3834fd77e2e1a42573274fbeaf47368ad7091 Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 13:11:04 +0100 Subject: [PATCH 3/6] Add DeleteAsync method to EfPersisterService --- ChatRPG/Services/EfPersisterService.cs | 25 +++++++++++++++ ChatRPG/Services/IPersisterService.cs | 6 ++++ ChatRPGTests/CampaignE2ETests.cs | 42 ++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 ChatRPGTests/CampaignE2ETests.cs diff --git a/ChatRPG/Services/EfPersisterService.cs b/ChatRPG/Services/EfPersisterService.cs index 300c6a7..128719b 100644 --- a/ChatRPG/Services/EfPersisterService.cs +++ b/ChatRPG/Services/EfPersisterService.cs @@ -42,6 +42,31 @@ public async Task SaveAsync(Campaign campaign) } } + public async Task DeleteAsync(Campaign campaign) + { + if (!(await _dbContext.Campaigns.ContainsAsync(campaign))) + { + return; + } + + await using IDbContextTransaction transaction = await _dbContext.Database.BeginTransactionAsync(); + try + { + int campaignId = campaign.Id; + _dbContext.Campaigns.Remove(campaign); + + await _dbContext.SaveChangesAsync(); + await transaction.CommitAsync(); + _logger.LogInformation("Deleted campaign with id {Id} successfully", campaignId); + } + catch (Exception e) + { + _logger.LogError(e, "An error occurred while deleting"); + await transaction.RollbackAsync(); + throw; + } + } + /// public async Task LoadFromCampaignIdAsync(int campaignId) { diff --git a/ChatRPG/Services/IPersisterService.cs b/ChatRPG/Services/IPersisterService.cs index a67540e..dd2e080 100644 --- a/ChatRPG/Services/IPersisterService.cs +++ b/ChatRPG/Services/IPersisterService.cs @@ -14,6 +14,12 @@ public interface IPersisterService /// A task representing the asynchronous operation. Task SaveAsync(Campaign campaign); /// + /// Deletes the given and all its related entities. + /// + /// The campaign to delete. + /// A task representing the asynchronous operation. + Task DeleteAsync(Campaign campaign); + /// /// Loads the campaign with the given with all its related entities. /// /// Id of the campaign to load. diff --git a/ChatRPGTests/CampaignE2ETests.cs b/ChatRPGTests/CampaignE2ETests.cs new file mode 100644 index 0000000..8ae78cc --- /dev/null +++ b/ChatRPGTests/CampaignE2ETests.cs @@ -0,0 +1,42 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; + +namespace ChatRPGTests; + +[Collection("E2E collection")] +public class CampaignE2ETests : IDisposable +{ + private readonly ChatRPGFixture _fixture; + private readonly IWebDriver _driver; + private readonly WebDriverWait _wait; + private readonly string _testUsername = "test"; + private readonly string _testPassword = "test"; + + public CampaignE2ETests(ChatRPGFixture fixture) + { + _fixture = fixture; + _driver = E2ETestUtility.Setup("/"); + _wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10)); + + // Login and prepare to test Campaign page + Login(_testUsername, _testPassword); + } + + public void Dispose() + { + E2ETestUtility.Teardown(_driver); + _driver.Dispose(); + } + + private void Login(string username, string password) + { + Thread.Sleep(1000); // wait for Index title animation to finish + _wait.Until(webDriver => webDriver.FindElement(By.Id("login-button"))).Click(); + IWebElement? usernameForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("username-form"))); + usernameForm.SendKeys(username); + IWebElement? passwordForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("password-form"))); + passwordForm.SendKeys(password); + _wait.Until(webDriver => webDriver.FindElement(By.Id("login-submit"))).Submit(); + Thread.Sleep(500); // wait for page to load fully + } +} From 237e5e44197c70de14731b13ea0dc1408321310a Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 17:02:45 +0100 Subject: [PATCH 4/6] Add campaign deletion confirmation modal --- ChatRPG/App.razor | 26 ++++----- ChatRPG/ChatRPG.csproj | 1 + ChatRPG/Pages/ConfirmModal.razor | 58 +++++++++++++++++++++ ChatRPG/Pages/UserCampaignOverview.razor | 5 +- ChatRPG/Pages/UserCampaignOverview.razor.cs | 23 ++++++++ ChatRPG/Pages/_Host.cshtml | 1 + ChatRPG/Program.cs | 2 + ChatRPG/Services/EfPersisterService.cs | 1 + ChatRPG/_Imports.razor | 2 + ChatRPG/wwwroot/css/site.css | 14 ++++- 10 files changed, 119 insertions(+), 14 deletions(-) create mode 100644 ChatRPG/Pages/ConfirmModal.razor diff --git a/ChatRPG/App.razor b/ChatRPG/App.razor index 47e0fa8..51d9db5 100644 --- a/ChatRPG/App.razor +++ b/ChatRPG/App.razor @@ -1,14 +1,16 @@  - - - - - - - Not found - -

Sorry, there's nothing at this address.

-
-
-
+ + + + + + + + Not found + +

Sorry, there's nothing at this address.

+
+
+
+
diff --git a/ChatRPG/ChatRPG.csproj b/ChatRPG/ChatRPG.csproj index 40616a6..5e47a2a 100644 --- a/ChatRPG/ChatRPG.csproj +++ b/ChatRPG/ChatRPG.csproj @@ -8,6 +8,7 @@ + diff --git a/ChatRPG/Pages/ConfirmModal.razor b/ChatRPG/Pages/ConfirmModal.razor new file mode 100644 index 0000000..f6333c2 --- /dev/null +++ b/ChatRPG/Pages/ConfirmModal.razor @@ -0,0 +1,58 @@ +@using ChatRPG.Services +@using ChatRPG.Data.Models + + + +@code { + + [CascadingParameter] + BlazoredModalInstance Modal { get; set; } = default!; + + [Parameter] + [EditorRequired] + public Campaign? CampaignToDelete { get; set; } + + [Inject] + private IPersisterService? PersistService { get; set; } + + private async Task Confirm() + { + if (CampaignToDelete is null) + { + await Modal.CancelAsync(); + } + + await PersistService!.DeleteAsync(CampaignToDelete!); + await Modal.CloseAsync(ModalResult.Ok(true)); + } + + private async Task Close() => await Modal.CloseAsync(ModalResult.Ok(false)); + private async Task Cancel() => await Modal.CancelAsync(); + +} diff --git a/ChatRPG/Pages/UserCampaignOverview.razor b/ChatRPG/Pages/UserCampaignOverview.razor index eebee32..8a6ae28 100644 --- a/ChatRPG/Pages/UserCampaignOverview.razor +++ b/ChatRPG/Pages/UserCampaignOverview.razor @@ -15,7 +15,7 @@
@foreach (CampaignModel campaign in Campaigns) { - }
diff --git a/ChatRPG/Pages/UserCampaignOverview.razor.cs b/ChatRPG/Pages/UserCampaignOverview.razor.cs index 91f4f8f..8447afd 100644 --- a/ChatRPG/Pages/UserCampaignOverview.razor.cs +++ b/ChatRPG/Pages/UserCampaignOverview.razor.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Security.Authentication; +using Blazored.Modal; +using Blazored.Modal.Services; using ChatRPG.Data.Models; using ChatRPG.Services; using Microsoft.AspNetCore.Components; @@ -32,6 +34,8 @@ public partial class UserCampaignOverview : ComponentBase [Inject] private ICampaignMediatorService? CampaignMediatorService { get; set; } [Inject] private NavigationManager? NavMan { get; set; } + [CascadingParameter] public IModalService? ConfirmDeleteModal { get; set; } + protected override async Task OnInitializedAsync() { AuthenticationState authState = await AuthProvider!.GetAuthenticationStateAsync(); @@ -79,6 +83,25 @@ private void ApplyStartingScenario(string title, string scenario) StateHasChanged(); } + private async Task ShowCampaignDeleteModal(Campaign campaign) + { + IModalReference modal = ConfirmDeleteModal!.Show("Delete Campaign", + new ModalParameters().Add(nameof(ConfirmModal.CampaignToDelete), campaign)); + + ModalResult shouldDelete = await modal.Result; + if (shouldDelete.Confirmed) + { + await ModalClosed(); + } + } + + private async Task ModalClosed() + { + Campaigns = await PersisterService!.GetCampaignsForUser(User!); + Campaigns.Reverse(); // Reverse to display latest campaign first + StateHasChanged(); + } + private bool FieldIsEmpty() { if (string.IsNullOrWhiteSpace(CampaignTitle) && string.IsNullOrWhiteSpace(CharacterName)) diff --git a/ChatRPG/Pages/_Host.cshtml b/ChatRPG/Pages/_Host.cshtml index 4f203c7..f9eaa1e 100644 --- a/ChatRPG/Pages/_Host.cshtml +++ b/ChatRPG/Pages/_Host.cshtml @@ -10,6 +10,7 @@ + diff --git a/ChatRPG/Program.cs b/ChatRPG/Program.cs index a674565..5338a3e 100644 --- a/ChatRPG/Program.cs +++ b/ChatRPG/Program.cs @@ -1,3 +1,4 @@ +using Blazored.Modal; using ChatRPG.API; using ChatRPG.Areas.Identity; using ChatRPG.Data; @@ -22,6 +23,7 @@ .AddEntityFrameworkStores(); builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); +builder.Services.AddBlazoredModal(); HttpMessageHandlerFactory httpMessageHandlerFactory = new HttpMessageHandlerFactory(configuration); builder.Services.AddScoped>() diff --git a/ChatRPG/Services/EfPersisterService.cs b/ChatRPG/Services/EfPersisterService.cs index 128719b..473c681 100644 --- a/ChatRPG/Services/EfPersisterService.cs +++ b/ChatRPG/Services/EfPersisterService.cs @@ -42,6 +42,7 @@ public async Task SaveAsync(Campaign campaign) } } + /// public async Task DeleteAsync(Campaign campaign) { if (!(await _dbContext.Campaigns.ContainsAsync(campaign))) diff --git a/ChatRPG/_Imports.razor b/ChatRPG/_Imports.razor index 81bc3b1..ba7e22f 100644 --- a/ChatRPG/_Imports.razor +++ b/ChatRPG/_Imports.razor @@ -6,5 +6,7 @@ @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop +@using Blazored.Modal +@using Blazored.Modal.Services @using ChatRPG @using ChatRPG.Shared diff --git a/ChatRPG/wwwroot/css/site.css b/ChatRPG/wwwroot/css/site.css index 2aeb2cc..0400cc2 100644 --- a/ChatRPG/wwwroot/css/site.css +++ b/ChatRPG/wwwroot/css/site.css @@ -230,7 +230,6 @@ a, .btn-link { } .card-dim { - width: 18rem; background: #dcdcdc; } @@ -358,3 +357,16 @@ a, .btn-link { .dashboard-title-container { padding-bottom: 60px; } + +.campaign-button { + position: relative; +} + +.delete-campaign-button { + position: absolute; + bottom: 0; + right: 0; + margin-right: 5px; + margin-bottom: 5px; + background: #ececec; +} From c1ee7543d285d9251d8801e76e707f5502b2cc45 Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 20:37:23 +0100 Subject: [PATCH 5/6] E2E tests for campaign deletion modal --- ChatRPG/Pages/ConfirmModal.razor | 4 +- ChatRPG/wwwroot/css/site.css | 9 +- ChatRPGTests/AuthorizedIndexE2ETests.cs | 156 +++++++++++++++++++++--- ChatRPGTests/CampaignE2ETests.cs | 14 +-- ChatRPGTests/E2ETestUtility.cs | 38 ++++++ 5 files changed, 189 insertions(+), 32 deletions(-) diff --git a/ChatRPG/Pages/ConfirmModal.razor b/ChatRPG/Pages/ConfirmModal.razor index f6333c2..42985c3 100644 --- a/ChatRPG/Pages/ConfirmModal.razor +++ b/ChatRPG/Pages/ConfirmModal.razor @@ -22,8 +22,8 @@

diff --git a/ChatRPG/wwwroot/css/site.css b/ChatRPG/wwwroot/css/site.css index 0400cc2..9884cb2 100644 --- a/ChatRPG/wwwroot/css/site.css +++ b/ChatRPG/wwwroot/css/site.css @@ -368,5 +368,12 @@ a, .btn-link { right: 0; margin-right: 5px; margin-bottom: 5px; - background: #ececec; + background: none; + overflow: hidden; + outline:none; + border:solid 1px black; +} + +.delete-campaign-button:hover { + background: #eaeaea; } diff --git a/ChatRPGTests/AuthorizedIndexE2ETests.cs b/ChatRPGTests/AuthorizedIndexE2ETests.cs index 7d02cf1..8dbd783 100644 --- a/ChatRPGTests/AuthorizedIndexE2ETests.cs +++ b/ChatRPGTests/AuthorizedIndexE2ETests.cs @@ -21,7 +21,7 @@ public AuthorizedIndexE2ETests(ChatRPGFixture fixture) _wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10)); // Login and prepare to test Authorized Index - Login(_testUsername, _testPassword); + E2ETestUtility.Login(_wait, _testUsername, _testPassword); } [Fact] @@ -116,14 +116,14 @@ public void AuthorizedIndexPage_YourCampaigns_ContainsSameAmountOfCampaignsAsDis // Arranged IWebElement? campaignsContainer = _wait.Until(webDriver => webDriver.FindElement(By.Id("your-campaigns"))); ReadOnlyCollection? campaigns = campaignsContainer.FindElements(By.ClassName("card")); - string expectedAmountOfScenarios = campaigns.Count.ToString(); + string expectedAmountOfCampaigns = campaigns.Count.ToString(); // Act IWebElement? campaignsCounter = _wait.Until(webDriver => webDriver.FindElement(By.Id("campaigns-count"))); - string actualAmountOfScenarios = Regex.Match(campaignsCounter.Text, @"\d+").Value; + string actualAmountOfCampaigns = Regex.Match(campaignsCounter.Text, @"\d+").Value; // Assert - Assert.Equal(expectedAmountOfScenarios, actualAmountOfScenarios); + Assert.Equal(expectedAmountOfCampaigns, actualAmountOfCampaigns); } [Fact] @@ -439,22 +439,146 @@ public void AuthorizedIndexPage_CustomCampaign_CharacterDescriptionIsEmptyOnInit Assert.Equal(expectedCharacterDescription, actualCharacterDescription); } - public void Dispose() + [Fact] + public void AuthorizedIndexPage_YourCampaigns_DisplaysRemoveCampaignButtonWhenEarlierCampaignExists() { - E2ETestUtility.Teardown(_driver); - _driver.Dispose(); + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + + // Act + IWebElement? firstRemoveCampaignButton = _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0]; + + // Assert + Assert.True(firstRemoveCampaignButton.Displayed); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_ModalIsDisplayedAfterRemoveCampaignButtonIsClicked() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + + // Act + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + IWebElement? modal = _wait.Until(webDriver => webDriver.FindElement(By.ClassName("modal"))); + + // Assert + Assert.True(modal.Displayed); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_ModalCloseButtonIsDisplayedWhenModalIsActivated() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + + // Act + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + IWebElement? modalCloseButton = _wait.Until(webDriver => webDriver.FindElement(By.Id("modal-close"))); + + // Assert + Assert.True(modalCloseButton.Displayed); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); } - private void Login(string username, string password) + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_ModalConfirmButtonIsDisplayedWhenModalIsActivated() { - Thread.Sleep(1000); // wait for Index title animation to finish - _wait.Until(webDriver => webDriver.FindElement(By.Id("login-button"))).Click(); - IWebElement? usernameForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("username-form"))); - usernameForm.SendKeys(username); - IWebElement? passwordForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("password-form"))); - passwordForm.SendKeys(password); - _wait.Until(webDriver => webDriver.FindElement(By.Id("login-submit"))).Submit(); - Thread.Sleep(500); // wait for page to load fully + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + + // Act + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + IWebElement? modalConfirmButton = _wait.Until(webDriver => webDriver.FindElement(By.Id("modal-confirm"))); + + // Assert + Assert.True(modalConfirmButton.Displayed); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_ModalBodyContainsCorrectCampaignTitle() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + string expectedCampaignTitleString = "Campaign title: Test Title"; + + // Act + IWebElement? modalBody = _wait.Until(webDriver => webDriver.FindElement(By.ClassName("modal-body"))); + + // Assert + Assert.Contains(expectedCampaignTitleString, modalBody.Text); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_ModalBodyContainsCorrectCharacterName() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + string expectedCharacterName = "Character name: Test Name"; + + // Act + IWebElement? modalBody = _wait.Until(webDriver => webDriver.FindElement(By.ClassName("modal-body"))); + + // Assert + Assert.Contains(expectedCharacterName, modalBody.Text); + E2ETestUtility.RemoveTestCampaign(_driver, _wait); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_CampaignIsDeletedAndRemovedFromCampaignListWhenModalIsConfirmed() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + IWebElement? campaignsCounterBefore = _wait.Until(webDriver => webDriver.FindElement(By.Id("campaigns-count"))); + int expectedAmountOfCampaigns = int.Parse(Regex.Match(campaignsCounterBefore.Text, @"\d+").Value) - 1; + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + + // Act + _wait.Until(webDriver => webDriver.FindElement(By.Id("modal-confirm"))).Click(); + Thread.Sleep(500); // Wait for page to update + IWebElement? campaignsCounterAfter = _wait.Until(webDriver => webDriver.FindElement(By.Id("campaigns-count"))); + int actualAmountOfCampaigns = int.Parse(Regex.Match(campaignsCounterAfter.Text, @"\d+").Value); + + // Assert + Assert.Equal(expectedAmountOfCampaigns, actualAmountOfCampaigns); + } + + [Fact] + public void AuthorizedIndexPage_DeleteCampaignModal_CampaignIsPreservedInCampaignListWhenModalIsClosed() + { + // Arrange + E2ETestUtility.CreateTestCampaign(_driver, _wait); + IWebElement? campaignsCounterBefore = _wait.Until(webDriver => webDriver.FindElement(By.Id("campaigns-count"))); + int expectedAmountOfCampaigns = int.Parse(Regex.Match(campaignsCounterBefore.Text, @"\d+").Value); + _wait.Until(webDriver => webDriver.FindElements(By.ClassName("delete-campaign-button")))[0].Click(); + Thread.Sleep(200); // wait for modal to load + + // Act + _wait.Until(webDriver => webDriver.FindElement(By.Id("modal-close"))).Click(); + Thread.Sleep(500); // Wait for page to update + IWebElement? campaignsCounterAfter = _wait.Until(webDriver => webDriver.FindElement(By.Id("campaigns-count"))); + int actualAmountOfCampaigns = int.Parse(Regex.Match(campaignsCounterAfter.Text, @"\d+").Value); + + // Assert + Assert.Equal(expectedAmountOfCampaigns, actualAmountOfCampaigns); + } + + public void Dispose() + { + E2ETestUtility.Teardown(_driver); + _driver.Dispose(); } public static IEnumerable StartScenarioTitles => new List diff --git a/ChatRPGTests/CampaignE2ETests.cs b/ChatRPGTests/CampaignE2ETests.cs index 8ae78cc..af09378 100644 --- a/ChatRPGTests/CampaignE2ETests.cs +++ b/ChatRPGTests/CampaignE2ETests.cs @@ -19,7 +19,7 @@ public CampaignE2ETests(ChatRPGFixture fixture) _wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10)); // Login and prepare to test Campaign page - Login(_testUsername, _testPassword); + E2ETestUtility.Login(_wait, _testUsername, _testPassword); } public void Dispose() @@ -27,16 +27,4 @@ public void Dispose() E2ETestUtility.Teardown(_driver); _driver.Dispose(); } - - private void Login(string username, string password) - { - Thread.Sleep(1000); // wait for Index title animation to finish - _wait.Until(webDriver => webDriver.FindElement(By.Id("login-button"))).Click(); - IWebElement? usernameForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("username-form"))); - usernameForm.SendKeys(username); - IWebElement? passwordForm = _wait.Until(webDriver => webDriver.FindElement(By.Id("password-form"))); - passwordForm.SendKeys(password); - _wait.Until(webDriver => webDriver.FindElement(By.Id("login-submit"))).Submit(); - Thread.Sleep(500); // wait for page to load fully - } } diff --git a/ChatRPGTests/E2ETestUtility.cs b/ChatRPGTests/E2ETestUtility.cs index a05bc09..c579ac6 100644 --- a/ChatRPGTests/E2ETestUtility.cs +++ b/ChatRPGTests/E2ETestUtility.cs @@ -1,5 +1,7 @@ +using System.Collections.ObjectModel; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; +using OpenQA.Selenium.Support.UI; namespace ChatRPGTests; @@ -31,4 +33,40 @@ public static void Teardown(IWebDriver driver) driver.Close(); driver.Quit(); } + + public static void Login(WebDriverWait wait, string username, string password) + { + Thread.Sleep(1000); // wait for Index title animation to finish + wait.Until(webDriver => webDriver.FindElement(By.Id("login-button"))).Click(); + wait.Until(webDriver => webDriver.FindElement(By.Id("username-form"))).SendKeys(username); + wait.Until(webDriver => webDriver.FindElement(By.Id("password-form"))).SendKeys(password); + wait.Until(webDriver => webDriver.FindElement(By.Id("login-submit"))).Submit(); + Thread.Sleep(500); // wait for page to load fully + } + + public static void CreateTestCampaign(IWebDriver driver, WebDriverWait wait) + { + driver.Navigate().GoToUrl("http://localhost:5111/"); + Thread.Sleep(500); + wait.Until(webDriver => webDriver.FindElement(By.Id("inputCampaignTitle"))).SendKeys("Test Title"); + wait.Until(webDriver => webDriver.FindElement(By.Id("inputCharacterName"))).SendKeys("Test Name"); + wait.Until(webDriver => webDriver.FindElement(By.Id("inputCharacterDescription"))).SendKeys("Test Description"); + wait.Until(webDriver => webDriver.FindElement(By.Id("inputCustomStartScenario"))).SendKeys("Test Scenario"); + wait.Until(webDriver => webDriver.FindElement(By.Id("create-campaign-button"))).Click(); + Thread.Sleep(200); // Wait for page to load + driver.Navigate().GoToUrl("http://localhost:5111/"); + Thread.Sleep(500); + } + + public static void RemoveTestCampaign(IWebDriver driver, WebDriverWait wait) + { + driver.Navigate().GoToUrl("http://localhost:5111/"); + Thread.Sleep(500); // Wait for page to load + IWebElement? yourCampaignsContainer = + wait.Until(webDriver => webDriver.FindElement(By.Id("your-campaigns"))); + ReadOnlyCollection? removeButtons = yourCampaignsContainer.FindElements(By.ClassName("delete-campaign-button")); + removeButtons[0].Click(); // Remove latest campaign + wait.Until(webDriver => webDriver.FindElement(By.Id("modal-confirm"))).Click(); + Thread.Sleep(200); + } } From 493787e901c4616c348e7451249213ebb16e1571 Mon Sep 17 00:00:00 2001 From: KarmaKamikaze Date: Mon, 20 Nov 2023 20:49:24 +0100 Subject: [PATCH 6/6] Setup E2E tests for Campaign page --- ChatRPGTests/CampaignE2ETests.cs | 4 +++- ChatRPGTests/E2ETestUtility.cs | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChatRPGTests/CampaignE2ETests.cs b/ChatRPGTests/CampaignE2ETests.cs index af09378..4c907ac 100644 --- a/ChatRPGTests/CampaignE2ETests.cs +++ b/ChatRPGTests/CampaignE2ETests.cs @@ -18,12 +18,14 @@ public CampaignE2ETests(ChatRPGFixture fixture) _driver = E2ETestUtility.Setup("/"); _wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10)); - // Login and prepare to test Campaign page + // Login, create test campaign and prepare to test Campaign page E2ETestUtility.Login(_wait, _testUsername, _testPassword); + E2ETestUtility.CreateTestCampaign(_driver, _wait, true); } public void Dispose() { + E2ETestUtility.RemoveTestCampaign(_driver, _wait); E2ETestUtility.Teardown(_driver); _driver.Dispose(); } diff --git a/ChatRPGTests/E2ETestUtility.cs b/ChatRPGTests/E2ETestUtility.cs index c579ac6..4d4b867 100644 --- a/ChatRPGTests/E2ETestUtility.cs +++ b/ChatRPGTests/E2ETestUtility.cs @@ -44,7 +44,7 @@ public static void Login(WebDriverWait wait, string username, string password) Thread.Sleep(500); // wait for page to load fully } - public static void CreateTestCampaign(IWebDriver driver, WebDriverWait wait) + public static void CreateTestCampaign(IWebDriver driver, WebDriverWait wait, bool goToCampaign = false) { driver.Navigate().GoToUrl("http://localhost:5111/"); Thread.Sleep(500); @@ -54,8 +54,11 @@ public static void CreateTestCampaign(IWebDriver driver, WebDriverWait wait) wait.Until(webDriver => webDriver.FindElement(By.Id("inputCustomStartScenario"))).SendKeys("Test Scenario"); wait.Until(webDriver => webDriver.FindElement(By.Id("create-campaign-button"))).Click(); Thread.Sleep(200); // Wait for page to load - driver.Navigate().GoToUrl("http://localhost:5111/"); - Thread.Sleep(500); + if (!goToCampaign) + { + driver.Navigate().GoToUrl("http://localhost:5111/"); + Thread.Sleep(500); + } } public static void RemoveTestCampaign(IWebDriver driver, WebDriverWait wait)