diff --git a/.gitignore b/.gitignore index ba5d491..e400015 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ src/obj/* src/logs/* src/Elmah/* publish/* +tests/Berufsschule_HAM.E2ETests/obj/* +tests/Berufsschule_HAM.E2ETests/bin/* diff --git a/src/Berufsschule_HAM.sln b/src/Berufsschule_HAM.sln index e54d82f..2228559 100644 --- a/src/Berufsschule_HAM.sln +++ b/src/Berufsschule_HAM.sln @@ -1,9 +1,11 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.2.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Berufsschule_HAM", "Berufsschule_HAM.csproj", "{93DF3CFA-1E88-78A3-FA37-F268564DC5FB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Berufsschule_HAM.E2ETests", "..\tests\Berufsschule_HAM.E2ETests\Berufsschule_HAM.E2ETests.csproj", "{26D89942-FBE0-4FCC-9DB5-CFEFC75C5222}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -14,6 +16,10 @@ Global {93DF3CFA-1E88-78A3-FA37-F268564DC5FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {93DF3CFA-1E88-78A3-FA37-F268564DC5FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {93DF3CFA-1E88-78A3-FA37-F268564DC5FB}.Release|Any CPU.Build.0 = Release|Any CPU + {26D89942-FBE0-4FCC-9DB5-CFEFC75C5222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26D89942-FBE0-4FCC-9DB5-CFEFC75C5222}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26D89942-FBE0-4FCC-9DB5-CFEFC75C5222}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26D89942-FBE0-4FCC-9DB5-CFEFC75C5222}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Controllers/AssetsController.cs b/src/Controllers/AssetsController.cs index afae388..f1d670a 100644 --- a/src/Controllers/AssetsController.cs +++ b/src/Controllers/AssetsController.cs @@ -173,10 +173,6 @@ public class AssetsController : Controller { await _ldap.UpdateAsset(cn, "l", requestModel.Location); } - else - { - await _ldap.DeleteAttribute(_ldap.AssetsBaseDn, "cn", cn, "l"); - } if (requestModel.Name is not null) { await _ldap.UpdateAsset(cn, "name", requestModel.Name); diff --git a/tests/Berufsschule_HAM.E2ETests/Berufsschule_HAM.E2ETests.csproj b/tests/Berufsschule_HAM.E2ETests/Berufsschule_HAM.E2ETests.csproj new file mode 100644 index 0000000..9c10485 --- /dev/null +++ b/tests/Berufsschule_HAM.E2ETests/Berufsschule_HAM.E2ETests.csproj @@ -0,0 +1,27 @@ + + + net8.0 + enable + enable + false + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + \ No newline at end of file diff --git a/tests/Berufsschule_HAM.E2ETests/Helper/AppHelper.cs b/tests/Berufsschule_HAM.E2ETests/Helper/AppHelper.cs new file mode 100644 index 0000000..a0d6563 --- /dev/null +++ b/tests/Berufsschule_HAM.E2ETests/Helper/AppHelper.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using System.Net; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; + +namespace Berufsschule_HAM.E2ETests.Helper; + +public static class AppHelper +{ + public const string ServerUrl = "http://localhost:5275"; + public static Uri ServerUri = new(ServerUrl); + public static async Task StartApp(string appUrl) + { + var startInfo = new ProcessStartInfo + { + FileName = "/snap/bin/dotnet", + Arguments = "run --project ../../../../../src/", + WorkingDirectory = AppContext.BaseDirectory, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + startInfo.EnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = "Development"; + + + var process = new Process { StartInfo = startInfo };// Process process = Process.Start("/snap/bin/dotnet", "run -e Development"); + process.Start(); + using var client = new HttpClient(); + for (int i = 0; i < 60; i++) + { + try + { + var response = await client.GetAsync(appUrl); + if (response.StatusCode == HttpStatusCode.OK) + { + return process; + } + else if (response.StatusCode != HttpStatusCode.RequestTimeout) + { + throw new Exception($"Server did not start properly? {response.StatusCode}"); + } + } + catch (Exception) { } + Thread.Sleep(1000); + } + throw new Exception("Server did not start within 60 seconds"); + } + + public static ChromeDriver GetChromeDriver() + { + var options = new ChromeOptions(); + //options.AddArgument("--headless"); + return new ChromeDriver(options); + + } + + public static void Login(ChromeDriver driver) + { + driver.Navigate().GoToUrl(ServerUrl); + IWebElement username = driver.FindElement(By.Id("username")); + username.SendKeys("admin"); + IWebElement password = driver.FindElement(By.Id("password")); + password.SendKeys("Test1234."); + IWebElement submit = driver.FindElement(By.CssSelector("button[type=\"submit\"]")); + submit.Click(); + Thread.Sleep(250); + } +} \ No newline at end of file diff --git a/tests/Berufsschule_HAM.E2ETests/HomePageTests.cs b/tests/Berufsschule_HAM.E2ETests/HomePageTests.cs new file mode 100644 index 0000000..6620a6c --- /dev/null +++ b/tests/Berufsschule_HAM.E2ETests/HomePageTests.cs @@ -0,0 +1,71 @@ +using Berufsschule_HAM.E2ETests.Helper; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using System.Diagnostics; + +namespace Berufsschule_HAM.E2ETests; + +public class HomePageTests : IDisposable +{ + private readonly ChromeDriver _driver; + public Uri serverUri; + public string serverUrl; + public Process serverProcess; + + public HomePageTests() + { + serverUrl = AppHelper.ServerUrl; + serverUri = AppHelper.ServerUri; + Task app = AppHelper.StartApp(serverUrl); + _driver = AppHelper.GetChromeDriver(); + serverProcess = app.Result; + } + + [Fact] + public void HomePage_ShouldShowLoginPage() + { + _driver.Navigate().GoToUrl(serverUrl); + IWebElement loginForm = _driver.FindElement(By.CssSelector("form[action=\"/Home/Login\"]")); + Assert.True(loginForm.Displayed); + } + + [Fact] + public void HomePage_ShouldSucceedLogin() + { + AppHelper.Login(_driver); + Assert.Contains("/Home/Index", _driver.Url); + } + + [Fact] + public void HomePage_ShouldSucceedLoginAndLogout() + { + AppHelper.Login(_driver); + Assert.Contains("/Home/Index", _driver.Url); + IWebElement userDropdown = _driver.FindElement(By.Id("userDropdown")); + userDropdown.Click(); + IWebElement logout = _driver.FindElement(By.CssSelector("a[href=\"/Home/Logout\"]")); + Assert.True(logout.Displayed); + logout.Click(); + Thread.Sleep(250); + Assert.Contains("/Home/Login", _driver.Url); + } + + [Fact] + public void HomePage_ShouldContainButtons() + { + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Index")); + AppHelper.Login(_driver); + + _driver.FindElement(By.CssSelector("a[href=\"/Home/Inventory\"]")); + _driver.FindElement(By.CssSelector("a[href=\"/Home/Assets\"]")); + _driver.FindElement(By.CssSelector("a[href=\"/Home/Locations\"]")); + _driver.FindElement(By.CssSelector("a[href=\"/Home/Users\"]")); + _driver.FindElement(By.CssSelector("a[href=\"/Home/Groups\"]")); + } + + public void Dispose() + { + _driver.Quit(); + serverProcess.Kill(); + } +} diff --git a/tests/Berufsschule_HAM.E2ETests/InventoryPageTests.cs b/tests/Berufsschule_HAM.E2ETests/InventoryPageTests.cs new file mode 100644 index 0000000..dbd1568 --- /dev/null +++ b/tests/Berufsschule_HAM.E2ETests/InventoryPageTests.cs @@ -0,0 +1,144 @@ +using Berufsschule_HAM.E2ETests.Helper; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using System.Diagnostics; + +namespace Berufsschule_HAM.E2ETests; + +public class InventoryPageTests : IDisposable +{ + private readonly ChromeDriver _driver; + public Uri serverUri; + public string serverUrl; + public Process serverProcess; + + public InventoryPageTests() + { + serverUrl = AppHelper.ServerUrl; + serverUri = AppHelper.ServerUri; + Task app = AppHelper.StartApp(serverUrl); + _driver = AppHelper.GetChromeDriver(); + serverProcess = app.Result; + } + + [Fact] + public void InventoryPage_ShouldShowButtons() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + _driver.FindElement(By.CssSelector("a[href=\"/Home/Assets?CreateModal=true\"]")); + _driver.FindElement(By.Id("barcodeInput")); + _driver.FindElement(By.Id("enterAssetIdManuallyButton")); + _driver.FindElement(By.Id("scanBarcodeButton")); + } + + [Fact] + public void InventoryPage_ShouldShowCompleteViewModal() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + IWebElement assetIdInputField = _driver.FindElement(By.Id("barcodeInput")); + assetIdInputField.SendKeys("1"); + IWebElement scanBarcode = _driver.FindElement(By.Id("enterAssetIdManuallyButton")); + scanBarcode.Click(); + Thread.Sleep(500); + IWebElement viewModal = _driver.FindElement(By.Id("viewAssetModal")); + Assert.True(viewModal.Displayed); + Assert.True(_driver.FindElement(By.CssSelector("svg[class=\"form-control\"]")).Displayed); + Thread.Sleep(500); + + Assert.NotEmpty(_driver.FindElement(By.Id("detailName")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailLocation")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailOwner")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailSerialNumber")).GetAttribute("value") ?? ""); + + Assert.NotEmpty(_driver.FindElement(By.Id("detailType")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailMake")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailModel")).GetAttribute("value") ?? ""); + + Assert.NotEmpty(_driver.FindElement(By.Id("detailPurchaseDate")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailPurchaseValue")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailPurchaseAt")).GetAttribute("value") ?? ""); + Assert.NotEmpty(_driver.FindElement(By.Id("detailPurchaseBy")).GetAttribute("value") ?? ""); + } + + [Fact] + public void InventoryPage_ShouldShowSuccessToastOnInformationCorrect() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + IWebElement assetIdInputField = _driver.FindElement(By.Id("barcodeInput")); + assetIdInputField.SendKeys("1"); + IWebElement scanBarcode = _driver.FindElement(By.Id("enterAssetIdManuallyButton")); + scanBarcode.Click(); + Thread.Sleep(500); + IWebElement viewModal = _driver.FindElement(By.Id("viewAssetModal")); + Assert.True(viewModal.Displayed); + IWebElement okButton = _driver.FindElement(By.CssSelector("#viewAssetModal button.btn.btn-primary[data-bs-dismiss=\"modal\"]")); + okButton.Click(); + Thread.Sleep(500); + IWebElement successToast = _driver.FindElement(By.CssSelector("#toastContainer div.bg-success")); + Assert.True(successToast.Displayed); + try + { + IWebElement failToast = _driver.FindElement(By.CssSelector("#toastContainer div.bg-danger")); + Assert.False(failToast.Displayed); + } catch (Exception) {} + } + + [Fact] + public void InventoryPage_ShouldShowSuccessToastOnInformationUpdate() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + IWebElement assetIdInputField = _driver.FindElement(By.Id("barcodeInput")); + assetIdInputField.SendKeys("1"); + IWebElement scanBarcode = _driver.FindElement(By.Id("enterAssetIdManuallyButton")); + scanBarcode.Click(); + Thread.Sleep(500); + IWebElement viewModal = _driver.FindElement(By.Id("viewAssetModal")); + Assert.True(viewModal.Displayed); + IWebElement updateButton = _driver.FindElement(By.CssSelector("#viewAssetModal button.btn.btn-warning[data-bs-dismiss=\"modal\"]")); + updateButton.Click(); + Thread.Sleep(1000); + IWebElement okButton = _driver.FindElement(By.CssSelector("#updateAssetModal button.btn.btn-warning[type=\"submit\"]")); + okButton.Click(); + Thread.Sleep(500); + IWebElement successToast = _driver.FindElement(By.CssSelector("#toastContainer div.bg-success")); + Assert.True(successToast.Displayed); + try + { + IWebElement failToast = _driver.FindElement(By.CssSelector("#toastContainer div.bg-danger")); + Assert.False(failToast.Displayed); + } catch (Exception) {} + } + + [Fact] + public void InventoryPage_ShouldLeadToAssetPage() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + IWebElement link = _driver.FindElement(By.CssSelector("a[href=\"/Home/Assets?CreateModal=true\"]")); + link.Click(); + Thread.Sleep(500); + Assert.Contains("/Home/Assets", _driver.Url); + } + + [Fact] + public void InventoryPage_ShouldShowPrintModal() + { + AppHelper.Login(_driver); + _driver.Navigate().GoToUrl(new Uri(serverUri, "/Home/Inventory")); + IWebElement openPrintModalButton = _driver.FindElement(By.Id("openPrintModal")); + openPrintModalButton.Click(); + Thread.Sleep(500); + IWebElement printModal = _driver.FindElement(By.Id("printModal")); + Assert.True(printModal.Displayed); + } + + public void Dispose() + { + _driver.Quit(); + serverProcess.Kill(); + } +}