using ESuite.UI.E2E.Helpers;
using ESuite.UI.E2E.Models;
using ESuite.UI.E2E.Pages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
namespace ESuite.UI.E2E.StepDefinitions
{
[Binding]
public class AuditLogsStepDefinitions
{
private readonly ScenarioContext _scenarioContext;
private readonly AutomationTestManagerHelper automationTestManagerHelper;
private readonly ConfigHelper configHelper;
public AuditLogsStepDefinitions(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
automationTestManagerHelper = new(_scenarioContext);
configHelper = new();
}
///
/// Step definition for checking Audit logs of a specific object type.
///
/// The type of object for which Audit logs are being checked.
/// Example: "Forms", "Sequence, "Glossary", "Custom Fields", "Domains", "Users"
/// A table containing the expected Audit log entries.
/// Example: If in column "EntityDisplayName" will be "scenarioDataInstance"
/// we will use data from current scenario instance.
[Then(@"I check (.*) Audit logs")]
public void ThenICheckAuditLogs(string objectType, Table dataTable)
{
RetryHelper.Retry(() =>
{
string objectName;
string? objectTypeCF = null;
var logs = dataTable.CreateSet();
foreach (var log in logs)
{
switch (log.Type)
{
case "Create":
switch (objectType)
{
case "Forms":
objectName = _scenarioContext["FormName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
break;
case "Sequence":
objectName = _scenarioContext["SequenceName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SequenceCreated"].ToString()!, true);
break;
case "Glossaries":
objectName = _scenarioContext["GlossaryName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type!, objectType, objectName,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
case "Glossary Item":
objectName = _scenarioContext["GlossaryItemName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type!, objectType, objectName,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
case "Glossary Custom Field Value":
objectName = _scenarioContext["GlossaryName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type);
CheckPartialExistingAuditLogs(log.Type!, objectType, objectName,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
case "Custom Field":
objectName = _scenarioContext["CustomFieldName"].ToString()!;
objectTypeCF = objectType + " " + _scenarioContext["CustomFieldType"].ToString()!;
CheckCustomFieldsAudits(objectTypeCF, objectName, _scenarioContext["CustomFieldType"].ToString()!, log);
break;
case "Client Domains":
objectName = _scenarioContext["DomainName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainCreated"].ToString()!);
break;
case "Users":
objectName = _scenarioContext["UserName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
//To Do to change from CheckPartialExistingAuditLogsForCustomFields to CheckAuditLogs
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["UserCreated"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
case "Sso Manager":
objectName = _scenarioContext["SSOProviderName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SSOProviderCreated"].ToString()!);
break;
case "Organisation":
objectName = _scenarioContext["OrganisationName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["OrganisationCreated"].ToString()!);
break;
case "Site":
objectName = _scenarioContext["SiteName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SiteCreated"].ToString()!);
break;
case "Role":
objectName = _scenarioContext["DomainRoleName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["RoleCreated"].ToString()!, true);
break;
case "UserRoles":
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type);
CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!, true);
break;
case "Role Access":
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type);
CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!, true);
break;
case "Mail Template":
objectName = "";
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["DomainMailTemplateCreated"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLog(log.Type)],
() => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable());
break;
case "Specification":
objectName = _scenarioContext["SpecificationName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["Specification"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLog(log.Type)],
() => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable());
break;
case "Form Field Instance":
objectName = _scenarioContext["FormFieldInstance"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type);
CheckPartialExistingAuditLogs(log.Type!, objectType, objectName,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
default:
throw new NoSuchElementException($"This type of Log: {objectType} doesn't exist!");
}
break;
case "Update":
switch (objectType)
{
case "Forms":
//it's for checking version logs registered as create for each version
log.Type = "";
objectName = _scenarioContext["FormName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckEditedForm(objectName);
break;
case "Sequence":
objectName = _scenarioContext["SequenceName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SequenceEdited"].ToString()!);
break;
case "Glossary":
objectName = _scenarioContext["GlossaryName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
break;
case "Custom Field":
objectName = _scenarioContext["CustomFieldName"].ToString()!;
objectTypeCF = objectType + " " + _scenarioContext["CustomFieldType"].ToString()!;
CheckCustomFieldsAudits(objectType, objectName, _scenarioContext["CustomFieldType"].ToString()!, log);
break;
case "Client Domains":
objectName = _scenarioContext["DomainName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainEdited"].ToString()!);
break;
case "Users":
objectName = _scenarioContext["UserName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
//To Do to change from CheckPartialExistingAuditLogsForCustomFields to CheckPartialExistingAuditLogs
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["UserNameEdited"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLog(log.Type)],
() => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable());
break;
case "Sso Manager":
objectName = _scenarioContext["SSOProviderName"].ToString()!;
CheckAuditOnEntity(objectType, objectName, log);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SSOProviderEdited"].ToString()!);
break;
case "Organisation":
objectName = _scenarioContext["OrganisationName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["OrganisationEdited"].ToString()!);
break;
case "Site":
objectName = _scenarioContext["SiteName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["SiteEdited"].ToString()!);
break;
case "Role":
objectName = _scenarioContext["DomainRoleName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckAuditLogs(log.Type, objectType, _scenarioContext["DomainRoleName"].ToString()!);
break;
case "Mail Template":
objectName = "";
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["DomainMailTemplateUpdated"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLog(log.Type)],
() => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable());
break;
case "Specification":
objectName = _scenarioContext!["SpecificationName"].ToString()!;
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
CheckPartialExistingAuditLogs(log.Type, objectType, _scenarioContext["SpecificationEdited"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLog(log.Type)],
() => I.GetTextsFromElements(AuditPage.EntityDisplayName).AsEnumerable());
break;
case "Form Field Instance":
objectName = _scenarioContext["FormFieldInstance"].ToString()!;
NavigateToAuditLog();
I.FillField(AuditPage.TypeSearchInputField, log.Type);
I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
CheckPartialExistingAuditLogs(log.Type!, objectType, objectName,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
break;
default:
throw new NoSuchElementException($"This type of entity: {objectType} doesn't exist!");
}
break;
case "Delete":
CheckDeletedAuditLog(objectType, GetObjectNameFromScenarioContext(objectType), log);
break;
case "Purge":
CheckPurgedAuditLog(objectType, GetObjectNameFromScenarioContext(objectType), log);
break;
default:
throw new NoSuchElementException($"This type of Log: {log.Type} doesn't exist!");
}
}
});
}
private string GetObjectNameFromScenarioContext(string objectType)
{
return objectType switch
{
"Forms" => _scenarioContext["FormName"].ToString()!,
"Form Template" => _scenarioContext["FormName"].ToString()!,
"Sequence" => _scenarioContext["SequenceName"].ToString()!,
"Glossary" => _scenarioContext["GlossaryName"].ToString()!,
"Custom Field" => _scenarioContext["CustomFieldName"].ToString()!,
"Client Domains" => _scenarioContext["DomainName"].ToString()!,
"Users" => _scenarioContext["UserName"].ToString()!,
"Sso Manager" => _scenarioContext["SSOProviderName"].ToString()!,
"Organisation" => _scenarioContext["OrganisationName"].ToString()!,
"Site" => _scenarioContext["SiteName"].ToString()!,
"Role" => _scenarioContext["DomainRoleName"].ToString()!,
"Specification" => _scenarioContext["SpecificationName"].ToString()!,
"UserRoles" => _scenarioContext["RoleUserCreated"].ToString()!,
"Custom Field Text" => _scenarioContext["CustomFieldName"].ToString()!,
_ => throw new NoSuchElementException($"This type of entity: {objectType} doesn't exist!")
};
}
private void CheckDeletedAuditLog(string objectType, string objectName, AuditData log)
{
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type, objectName);
var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay);
var expectedTiming = _scenarioContext["Timing"].ToString();
var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity);
var actualEntityDisplayName = I.GetTextFromElement(AuditPage.EntityDisplayName);
var expectedEntityDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[objectType];
Assert.AreEqual(log.Type, actualLogType, $"Expected log type: {log.Type}, but found: {actualLogType}");
Assert.AreEqual(expectedEntityDisplayName, actualEntityDisplayName, $"Expected Entity Display Name: {expectedEntityDisplayName}, but found: {actualEntityDisplayName}");
Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}");
Assert.IsTrue(I.IsVisibleNumberOfElements(AuditPage.LogLines, 1), "Number of visible log lines doesn't match: 1");
}
private void CheckPurgedAuditLog(string objectType, string objectName, AuditData log)
{
NavigateToAuditLog();
FillAuditLogSearchFields(log.Type);
CheckAuditLogs(log.Type!, objectType, objectName, true);
}
private static void NavigateToAuditLog()
{
BasicPage.ClickOnDropdownMenuItem("Audit Log", "Support");
I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField);
}
private void FillAuditLogSearchFields(string? logType = null, string? objectName = null)
{
if (string.IsNullOrEmpty(objectName))
{
objectName = "";
}
if (string.IsNullOrEmpty(logType))
{
logType = "";
}
I.FillField(AuditPage.DisplayNameSearchInputField, objectName);
Console.WriteLine($"Filling audit log search fields: LogType='{logType}', ObjectName='{objectName ?? ""}'");
I.FillField(AuditPage.TypeSearchInputField, logType);
I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
}
public void CheckEditedForm(string objectName)
{
RetryHelper.Retry(() =>
{
NavigateToAuditLog();
I.FillField(AuditPage.DisplayNameSearchInputField, objectName);
int numberOfParentLogs = 1;
int numberOfAllRelatedLogs = (int)_scenarioContext["FormVersion"]!;
int expectedNumberOfAllLogLines = (int)_scenarioContext["FormVersion"]! + numberOfParentLogs;
Assert.IsTrue(
I.IsVisibleNumberOfElements(AuditPage.LogLines, expectedNumberOfAllLogLines),
$"Number of all existing Logs: {numberOfParentLogs} doesn't match number of visible Logs");
I.Click(AuditPage.ParentLogButton);
I.WaitTillInvisible(BasicPage.LoadingMessage);
Assert.IsTrue(
I.IsVisibleNumberOfElements(AuditPage.LogLines, numberOfParentLogs),
$"Number of Parent Logs: {numberOfParentLogs} doesn't match number of visible Logs");
I.Click(AuditPage.AllRelatedLogsButton);
I.WaitTillInvisible(BasicPage.LoadingMessage);
Assert.IsTrue(
I.IsVisibleNumberOfElements(AuditPage.LogLines, numberOfAllRelatedLogs),
$"Number of all related Logs: {numberOfAllRelatedLogs} doesn't match number of visible Logs");
});
}
public void CheckCustomFieldsAudits(string objectType, string objectName, string? customFieldType, AuditData log)
{
BasicPage.ClickOnDropdownMenuItem("Custom Fields");
BasicPage.SearchObjectNameInTableViaSearchInputField(objectName);
I.Click(BasicPage.AuditObjectButton(objectName));
I.WaitTillInvisible(BasicPage.AuditObjectButton(objectName));
I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField);
I.FillField(AuditPage.TypeSearchInputField, log.Type!);
I.WaitTillInvisible(BasicPage.LoadingMessage);
I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
string auditEntity = customFieldType!.Replace(" ", string.Empty);
if (!string.IsNullOrEmpty(auditEntity) && !auditEntity.Equals("FormTemplate") && !auditEntity.Equals("Domain"))
{
CheckPartialExistingAuditLogs(log.Type!, objectType, _scenarioContext["CustomField"].ToString()!,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
CheckPartialExistingAuditLogs(log.Type!, objectType, auditEntity,
() => [.. AuditPage.GetTextFromAuditLogOnCustomFields(log.Type!)],
() => I.GetTextsFromElements(AuditPage.CustomFieldsEntityDisplayName).AsEnumerable());
}
}
public void CheckCustomFieldsAudits(string objectType, string objectName, AuditData log)
{
CheckCustomFieldsAudits(objectType, objectName, null, log);
}
public void CheckAuditOnEntity(string objectType, string objectName, AuditData log)
{
NavigateToEntityMenu(objectType);
SearchAuditEntity(objectType, objectName);
OpenAuditLogOnEntity(objectName);
FillAuditLogSearchFields(log.Type, log.DisplayName == "scenarioDataInstance" ? objectName : log.DisplayName);
ValidateAuditLogDetails(log);
}
private static void NavigateToEntityMenu(string objectType)
{
BasicPage.ClickOnDropdownMenuItem(objectType);
}
public void CheckAuditLogs(string logType, string entityDisplayName, string auditEntity, bool allowPartialMatch = false)
{
string[] createdData = auditEntity.Split(", ");
string[] auditData = [.. AuditPage.GetTextFromAuditLog(logType)];
var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity);
var actualEntityDisplayName = I.GetTextFromElement(AuditPage.EntityDisplayName);
var expectedEntityDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[entityDisplayName];
var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay);
var expectedTiming = _scenarioContext["Timing"].ToString()!;
Assert.AreEqual(logType, actualLogType, $"Expected log type: {logType}, but found: {actualLogType}");
Assert.AreEqual(expectedEntityDisplayName, actualEntityDisplayName, $"Expected Entity Display Name: {expectedEntityDisplayName}, but found: {actualEntityDisplayName}");
Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}");
if (allowPartialMatch)
{
foreach (string data in createdData)
{
Assert.IsTrue(auditData.Contains(data), $"Expected audit data does not contain: {data}");
}
}
else
{
Assert.AreEqual(createdData.Length, auditData.Length, $"Expected {createdData.Length} audit entries, but found {auditData.Length}");
for (int i = 0; i < createdData.Length; i++)
{
Assert.AreEqual(createdData[i], auditData[i], $"Expected audit data was: '{createdData[i]}', but found '{auditData[i]}'");
}
}
}
public void CheckPartialExistingAuditLogs(string logType, string entityDisplayName, string auditEntity, Func getAuditLogFunc, Func> getEntityDisplayNamesFunc)
{
string[] createdData = auditEntity.Split(", ");
string[] auditData = getAuditLogFunc();
var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity);
var actualDisplayNames = getEntityDisplayNamesFunc();
var expectedDisplayName = AutomationTestManagerHelper.AuditEntityDisplayName[entityDisplayName];
var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay);
var expectedTiming = _scenarioContext["Timing"].ToString()!;
Assert.AreEqual(logType, actualLogType, $"Expected log type: {logType}, but found: {actualLogType}");
Assert.IsTrue(actualDisplayNames.Any(name => name.Equals(expectedDisplayName)), $"Expected Entity Display Name: {expectedDisplayName}, but found: {string.Join(", ", actualDisplayNames)}");
Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}");
foreach (string data in createdData)
{
Assert.IsTrue(auditData.Any(x => x.Contains(data)), $"Expected audit data does not contain: {data}");
}
}
private void SearchAuditEntity(string objectType, string objectName)
{
if (objectType.Equals("Users", StringComparison.OrdinalIgnoreCase))
{
automationTestManagerHelper.SaveDataFromCreatedUser();
I.WaitForElementVisibleAndClickable(BasicPage.SearchUsersInput);
BasicPage.SearchObjectNameInTableViaSearchInputField(objectName, BasicPage.SearchUsersInput);
I.WaitForVisible(BasicPage.ObjectNameInTable(objectName));
}
else
{
I.WaitForElementVisibleAndClickable(BasicPage.SearchInput);
BasicPage.SearchObjectNameInTableViaSearchInputField(objectName);
}
}
private static void OpenAuditLogOnEntity(string objectName)
{
I.Click(BasicPage.AuditObjectButton(objectName));
I.WaitTillInvisible(BasicPage.AuditObjectButton(objectName));
I.WaitForElementVisibleAndClickable(AuditPage.TypeSearchInputField);
}
private void ValidateAuditLogDetails(AuditData log)
{
I.Click(AuditPage.ParentLogButton);
I.WaitTillInvisible(BasicPage.LoadingMessage);
I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
var actualTiming = I.GetTextFromElement(AuditPage.TimingDisplay);
var expectedTiming = _scenarioContext["Timing"].ToString()!;
var actualLogType = I.GetTextFromElement(AuditPage.AuditLogTypeOfEntity);
if (log.Type!.Equals("Create", StringComparison.OrdinalIgnoreCase))
{
Assert.IsTrue(
I.IsVisibleNumberOfElements(AuditPage.LogLines, 1),
"Number of the Log Lines wasn't equal to 1"
);
Assert.AreEqual(log.Type!, actualLogType, $"Expected log type: {log.Type!}, but found: {actualLogType}");
}
Assert.AreEqual(expectedTiming, actualTiming, $"Expected Timing was: {expectedTiming}, but found: {actualTiming}");
}
}
}