Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion src/FlaUI.WebDriver/Controllers/FindElementsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ private async Task<ActionResult> FindElementFrom(Func<AutomationElement> startNo
{
element = await Wait.Until(() => startNode().FindFirstByXPath(findElementRequest.Value), element => element != null, session.ImplicitWaitTimeout);
}
else if (findElementRequest.Using == "css selector")
{
var (strategy, value) = ParseCssSelector(findElementRequest.Value);
var condition = _conditionParser.ParseCondition(session.Automation.ConditionFactory, strategy, value);
element = await Wait.Until(() => startNode().FindFirstDescendant(condition), element => element != null, session.ImplicitWaitTimeout);
}
else
{
var condition = _conditionParser.ParseCondition(session.Automation.ConditionFactory, findElementRequest.Using, findElementRequest.Value);
Expand All @@ -71,7 +77,7 @@ private async Task<ActionResult> FindElementFrom(Func<AutomationElement> startNo
return NoSuchElement(findElementRequest);
}

var knownElement = session.GetOrAddKnownElement(element);
var knownElement = session.GetOrAddKnownElement(element);
return await Task.FromResult(WebDriverResult.Success(new FindElementResponse
{
ElementReference = knownElement.ElementReference,
Expand All @@ -85,6 +91,12 @@ private async Task<ActionResult> FindElementsFrom(Func<AutomationElement> startN
{
elements = await Wait.Until(() => startNode().FindAllByXPath(findElementRequest.Value), elements => elements.Length > 0, session.ImplicitWaitTimeout);
}
else if (findElementRequest.Using == "css selector")
{
var (strategy, value) = ParseCssSelector(findElementRequest.Value);
var condition = _conditionParser.ParseCondition(session.Automation.ConditionFactory, strategy, value);
elements = await Wait.Until(() => startNode().FindAllDescendants(condition), elements => elements.Length > 0, session.ImplicitWaitTimeout);
}
else
{
var condition = _conditionParser.ParseCondition(session.Automation.ConditionFactory, findElementRequest.Using, findElementRequest.Value);
Expand Down Expand Up @@ -140,5 +152,53 @@ private Session GetSession(string sessionId)
session.SetLastCommandTimeToNow();
return session;
}

private (string strategy, string value) ParseCssSelector(string cssSelector)
{
var nameMatch = Regex.Match(cssSelector, @"^\*?\[name\s*=\s*""(.+?)""\]$", RegexOptions.IgnoreCase);
if (nameMatch.Success)
{
return ("name", UnescapeCssValue(nameMatch.Groups[1].Value));
}

var idMatch = Regex.Match(cssSelector, @"^#((?:[\w-]|\\[0-9a-fA-F]{1,6}\s?)+)$");
if (idMatch.Success)
{
return ("id", UnescapeCssValue(idMatch.Groups[1].Value));
}

var classMatch = Regex.Match(cssSelector, @"^\.((?:[\w-]|\\[0-9a-fA-F]{1,6}\s?)+)$");
if (classMatch.Success)
{
return ("class name", UnescapeCssValue(classMatch.Groups[1].Value));
}

var idAttrMatch = Regex.Match(cssSelector, @"^\*?\[id\s*=\s*""(.+?)""\]$", RegexOptions.IgnoreCase);
if (idAttrMatch.Success)
{
return ("id", UnescapeCssValue(idAttrMatch.Groups[1].Value));
}

var classAttrMatch = Regex.Match(cssSelector, @"^\*?\[class\s*=\s*""(.+?)""\]$", RegexOptions.IgnoreCase);
if (classAttrMatch.Success)
{
return ("class name", UnescapeCssValue(classAttrMatch.Groups[1].Value));
}

throw WebDriverResponseException.UnsupportedOperation(
$"CSS selector '{cssSelector}' is not supported. Only simple selectors are allowed: " +
"#id, .className, [name=\"value\"], [id=\"value\"], [class=\"value\"]"
);
}

private string UnescapeCssValue(string cssValue)
{
var result = Regex.Replace(cssValue, @"\\([0-9a-fA-F]{1,6})\s?", m =>
((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());

result = Regex.Replace(result, @"\\(.)", "$1");

return result;
}
}
}
1 change: 1 addition & 0 deletions src/FlaUI.WebDriver/Services/ConditionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public PropertyCondition ParseCondition(ConditionFactory conditionFactory, strin
{
switch (@using)
{
case "id":
case "accessibility id":
return conditionFactory.ByAutomationId(value);
case "name":
Expand Down
Loading