Skip to content

Commit

Permalink
improved implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
IamRanjeetSingh committed Jul 15, 2024
1 parent e2d7697 commit b97d77a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 53 deletions.
95 changes: 43 additions & 52 deletions Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/POM/POMLearner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,8 @@ internal Task LearnElementsAsync(IList<ElementInfo> learnedElements)

private async Task LearnDocumentElementsAsync(HtmlDocument htmlDocument, IList<ElementInfo> learnedElements)
{
await LearnHtmlNodeChildElements(htmlDocument.DocumentNode, htmlNode =>
await LearnHtmlNodeChildElements(htmlDocument.DocumentNode, shouldLearnNode: htmlNode =>
{
if (!CheckStaticHtmlNodeExclusion(htmlNode))
{
return false;
}
eElementType type = GetElementType(htmlNode);
if (_pomSetting != null && !_pomSetting.filteredElementType.Contains(type))
{
Expand All @@ -83,64 +78,58 @@ await LearnHtmlNodeChildElements(htmlDocument.DocumentNode, htmlNode =>
}, learnedElements);
}

private async Task LearnHtmlNodeChildElements(HtmlNode htmlNode, Predicate<HtmlNode> shouldLearnElement, IList<ElementInfo> learnedElements)
private async Task LearnHtmlNodeChildElements(HtmlNode htmlNode, Predicate<HtmlNode> shouldLearnNode, IList<ElementInfo> learnedElements, IList<ElementInfo>? childElements = null)
{
//List<HTMLElementInfo> htmlElements = [];

foreach (HtmlNode childNode in htmlNode.ChildNodes)
{
eElementType childNodeType = GetElementType(childNode);
eElementType childNodeElementType = GetElementType(childNode);
IBrowserElement? browserElement = null;
HTMLElementInfo? childElement = null;
if (!shouldLearnElement(childNode))

if (IsNodeLearnable(childNode))
{
if (childNodeType == eElementType.Form)
{
//in case we have a Form element, then the POM filters don't apply anymore, then we use Form specific filter
await LearnHtmlNodeChildElements(childNode, FormChildrenElementFilter, learnedElements);
}
else
browserElement = await _browserElementProvider.GetElementAsync(eLocateBy.ByXPath, childNode.XPath);
if (browserElement != null)
{
await LearnHtmlNodeChildElements(childNode, shouldLearnElement, learnedElements);
childElement = await CreateHTMLElementInfoAsync(childNode, browserElement);
}

continue;
}

IBrowserElement? browserElement = await _browserElementProvider.GetElementAsync(eLocateBy.ByXPath, childNode.XPath);
if (browserElement == null || !await browserElement.IsVisibleAsync())
if (childElement != null && shouldLearnNode(childNode))
{
continue;
learnedElements.Add(childElement);
if (childElements != null)
{
childElements.Add(childElement);
}
}

childElement = await CreateHTMLElementInfoAsync(childNode, browserElement);

learnedElements.Add(childElement);

await LearnShadowDOMElementsAsync(childElement, learnedElements);
await LearnFrameElementsAsync(childElement, learnedElements);
//TODO: create suggested activities

IList<ElementInfo> grandChildElements = new List<ElementInfo>();
if (childNodeType == eElementType.Form)
if (childNodeElementType == eElementType.Form)
{
await LearnHtmlNodeChildElements(childNode, FormChildrenElementFilter, grandChildElements);
await LearnHtmlNodeChildElements(childNode, ShouldLearnFormChildNode, learnedElements, grandChildElements);
}
else
else if (!string.Equals(childNode.Name, "head", StringComparison.OrdinalIgnoreCase))
{
await LearnHtmlNodeChildElements(childNode, shouldLearnElement, grandChildElements);
await LearnHtmlNodeChildElements(childNode, shouldLearnNode, learnedElements, grandChildElements);
}
foreach (HTMLElementInfo grandChildElement in grandChildElements)

if (childElement != null)
{
grandChildElement.ParentElement = childElement;
foreach (ElementInfo grandChildElement in grandChildElements)
{
grandChildElement.ParentElement = childElement;
}
childElement.ChildElements.Clear();
childElement.ChildElements.AddRange(grandChildElements);

await LearnShadowDOMElementsAsync(childElement, learnedElements);
await LearnFrameElementsAsync(childElement, learnedElements);
}
childElement.ChildElements.Clear();
childElement.ChildElements.AddRange(grandChildElements.Cast<ElementInfo>());

learnedElements.AddRange(grandChildElements);
}
}

private static bool CheckStaticHtmlNodeExclusion(HtmlNode htmlNode)
private static bool IsNodeLearnable(HtmlNode htmlNode)
{
if (htmlNode.Name.StartsWith("#"))
{
Expand All @@ -161,13 +150,8 @@ private static bool CheckStaticHtmlNodeExclusion(HtmlNode htmlNode)
return true;
}

private static bool FormChildrenElementFilter(HtmlNode htmlNode)
private static bool ShouldLearnFormChildNode(HtmlNode htmlNode)
{
if (!CheckStaticHtmlNodeExclusion(htmlNode))
{
return false;
}

string tagName = htmlNode.Name ?? "";
if (tagName.StartsWith("input", StringComparison.OrdinalIgnoreCase) || tagName.StartsWith("button", StringComparison.OrdinalIgnoreCase))
{
Expand Down Expand Up @@ -195,7 +179,6 @@ private async Task<HTMLElementInfo> CreateHTMLElementInfoAsync(HtmlNode htmlNode
HTMLElementObject = htmlNode,
XPath = htmlNode.XPath,
IsAutoLearned = true,
ScreenShotImage = await GetElementScreenshotAsync(browserElement),
Locators = [],
Properties = [
new()
Expand All @@ -212,6 +195,7 @@ private async Task<HTMLElementInfo> CreateHTMLElementInfoAsync(HtmlNode htmlNode
}],
};
//LearnElementInfoDetails(htmlElementInfo); //check what properties of HTMLElementInfo are set in this method
htmlElementInfo.ScreenShotImage = await GetElementScreenshotAsync(browserElement);
htmlElementInfo.XPath = GenerateXPathFromHtmlElementInfo(htmlElementInfo);
htmlElementInfo.RelXpath = GenerateRelativeXPathFromHTMLElementInfo(htmlElementInfo, _xpathImpl, _pomSetting);
htmlElementInfo.Locators.AddRange(await GenerateLocatorsAsync(htmlElementInfo, _pomSetting));
Expand Down Expand Up @@ -750,7 +734,7 @@ internal static string GenerateRelativeXPathFromHTMLElementInfo(HTMLElementInfo
return xpathHelper.GetElementRelXPath(htmlElementInfo, pomSetting);
}

private async Task<string> GetElementScreenshotAsync(IBrowserElement? browserElement)
private async Task<string?> GetElementScreenshotAsync(IBrowserElement? browserElement)
{
if (_pomSetting == null ||
!_pomSetting.LearnScreenshotsOfElements ||
Expand All @@ -759,7 +743,14 @@ private async Task<string> GetElementScreenshotAsync(IBrowserElement? browserEle
return string.Empty;
}

return Convert.ToBase64String(await browserElement.ScreenshotAsync());
try
{
return Convert.ToBase64String(await browserElement.ScreenshotAsync().WaitAsync(timeout: TimeSpan.FromSeconds(3)));
}
catch(Exception)
{
return null;
}
}

private async Task LearnShadowDOMElementsAsync(HTMLElementInfo shadowHostElement, IList<ElementInfo> learnedElements)
Expand All @@ -768,7 +759,7 @@ private async Task LearnShadowDOMElementsAsync(HTMLElementInfo shadowHostElement
!_pomSetting.LearnShadowDomElements ||
shadowHostElement.ElementTypeEnum == eElementType.Iframe ||
shadowHostElement.ElementObject == null ||
await ((IBrowserElement)shadowHostElement.ElementObject).ShadowRootAsync() != null)
await ((IBrowserElement)shadowHostElement.ElementObject).ShadowRootAsync() == null)
{
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using GingerCore.Actions.VisualTesting;
using GingerCoreNET.SolutionRepositoryLib.RepositoryObjectsLib.PlatformsLib;
using amdocs.ginger.GingerCoreNET;
using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Web.Selenium;

#nullable enable
namespace Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Web.Playwright
Expand Down Expand Up @@ -620,6 +621,7 @@ public async Task<List<ElementInfo>> GetVisibleControls(PomSetting pomSetting, O
private sealed class PlaywrightBrowserElementProvider : POMLearner.IBrowserElementProvider
{
private readonly IBrowserTab _browserTab;
private int _shadowDOMDepth = 0;

internal PlaywrightBrowserElementProvider(IBrowserTab browserTab)
{
Expand All @@ -628,7 +630,19 @@ internal PlaywrightBrowserElementProvider(IBrowserTab browserTab)

public async Task<IBrowserElement?> GetElementAsync(eLocateBy locateBy, string locateValue)
{
return (await _browserTab.GetElementsAsync(locateBy, locateValue)).FirstOrDefault();
try
{
if (_shadowDOMDepth > 0 && locateBy == eLocateBy.ByXPath)
{
string cssLocateValue = new ShadowDOM().ConvertXPathToCssSelector(locateValue);
return (await _browserTab.GetElementsAsync(eLocateBy.ByCSS, cssLocateValue)).FirstOrDefault();
}
return (await _browserTab.GetElementsAsync(locateBy, locateValue)).FirstOrDefault();
}
catch(Exception)
{
return null;
}
}

public async Task OnFrameEnterAsync(HTMLElementInfo frameElement)
Expand All @@ -651,11 +665,13 @@ public Task OnFrameExitAsync(HTMLElementInfo frameElement)

public Task OnShadowDOMEnterAsync(HTMLElementInfo shadowHostElement)
{
_shadowDOMDepth++;
return Task.CompletedTask;
}

public Task OnShadowDOMExitAsync(HTMLElementInfo shadowHostElement)
{
_shadowDOMDepth--;
return Task.CompletedTask;
}
}
Expand Down

0 comments on commit b97d77a

Please sign in to comment.