diff --git a/src/Atata/ScopeSearch/ComponentScopeLocateOptions.cs b/src/Atata/ScopeSearch/ComponentScopeLocateOptions.cs index d7c5cd6a..17e680cd 100644 --- a/src/Atata/ScopeSearch/ComponentScopeLocateOptions.cs +++ b/src/Atata/ScopeSearch/ComponentScopeLocateOptions.cs @@ -8,6 +8,8 @@ public class ComponentScopeLocateOptions : ICloneable public string[] Terms { get; set; } + public string OuterXPath { get; set; } + public string ElementXPath { get; set; } public int? Index { get; set; } diff --git a/src/Atata/ScopeSearch/ComponentScopeXPathBuilder.cs b/src/Atata/ScopeSearch/ComponentScopeXPathBuilder.cs index e27e68b6..a9c953fe 100644 --- a/src/Atata/ScopeSearch/ComponentScopeXPathBuilder.cs +++ b/src/Atata/ScopeSearch/ComponentScopeXPathBuilder.cs @@ -11,6 +11,11 @@ public ComponentScopeXPathBuilder(ComponentScopeLocateOptions options) public ComponentScopeLocateOptions Options { get; private set; } + public ComponentScopeXPathBuilder OuterXPath + { + get { return Options.OuterXPath != null ? _(Options.OuterXPath) : Descendant; } + } + public ComponentScopeXPathBuilder ComponentXPath { get { return _(Options.ElementXPath); } diff --git a/src/Atata/ScopeSearch/Strategies/FindByAttributeStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByAttributeStrategy.cs index d6a75265..861fe21e 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByAttributeStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByAttributeStrategy.cs @@ -12,7 +12,7 @@ public FindByAttributeStrategy(string attributeName) protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.TermsConditionOf(attributeName)]); + WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.TermsConditionOf(attributeName)]); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByChildContentStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByChildContentStrategy.cs index 909a58ea..a4a7b521 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByChildContentStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByChildContentStrategy.cs @@ -12,7 +12,7 @@ public FindByChildContentStrategy(int childIndex) protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.Any[childIndex + 1][z => z.TermsConditionOfContent]]); + WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.Any[childIndex + 1][z => z.TermsConditionOfContent]]); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByClassStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByClassStrategy.cs index 7025693e..75306050 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByClassStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByClassStrategy.cs @@ -9,7 +9,7 @@ protected override string Build(ComponentScopeXPathBuilder builder, ComponentSco string classCondition = GetClassCondition(options); return builder. - WrapWithIndex(x => x.Descendant.Any[classCondition]). + WrapWithIndex(x => x.OuterXPath.Any[classCondition]). DescendantOrSelf.ComponentXPath; } diff --git a/src/Atata/ScopeSearch/Strategies/FindByColumnIndexStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByColumnIndexStrategy.cs index b7278097..e56366ab 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByColumnIndexStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByColumnIndexStrategy.cs @@ -12,7 +12,7 @@ public FindByColumnIndexStrategy(int columnIndex) protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant._("td").WhereIndex(columnIndex).DescendantOrSelf.ComponentXPath); + WrapWithIndex(x => x.OuterXPath._("td").WhereIndex(columnIndex).DescendantOrSelf.ComponentXPath); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByContentOrValueStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByContentOrValueStrategy.cs index 0a02ba1a..1230fdbb 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByContentOrValueStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByContentOrValueStrategy.cs @@ -5,7 +5,7 @@ public class FindByContentOrValueStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.TermsConditionOfContent.Or.TermsConditionOf("value")]); + WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.TermsConditionOfContent.Or.TermsConditionOf("value")]); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByContentStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByContentStrategy.cs index 96cba306..e6c9ca27 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByContentStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByContentStrategy.cs @@ -5,7 +5,7 @@ public class FindByContentStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.TermsConditionOfContent]); + WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.TermsConditionOfContent]); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByCssStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByCssStrategy.cs index baf3d6f3..f8a0670c 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByCssStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByCssStrategy.cs @@ -1,5 +1,6 @@ using OpenQA.Selenium; - +using OpenQA.Selenium.Support.PageObjects; + namespace Atata { public class FindByCssStrategy : IComponentScopeLocateStrategy @@ -10,17 +11,20 @@ public ComponentScopeLocateResult Find(IWebElement scope, ComponentScopeLocateOp { By by = By.CssSelector(string.Join(",", options.Terms)); - if (options.Index.HasValue) - { - var elements = scope.GetAll(by.With(searchOptions)); - if (elements.Count <= options.Index.Value) - throw ExceptionFactory.CreateForNoSuchElement(by: by, searchContext: scope); - else - return new SequalComponentScopeLocateResult(elements[options.Index.Value], sequalStrategy); - } - else - { - return new SequalComponentScopeLocateResult(by, sequalStrategy); + if (options.OuterXPath != null) + by = new ByChained(By.XPath(options.OuterXPath + "*"), by); + + if (options.Index.HasValue) + { + var elements = scope.GetAll(by.With(searchOptions)); + if (elements.Count <= options.Index.Value) + throw ExceptionFactory.CreateForNoSuchElement(by: by, searchContext: scope); + else + return new SequalComponentScopeLocateResult(elements[options.Index.Value], sequalStrategy); + } + else + { + return new SequalComponentScopeLocateResult(by, sequalStrategy); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByDescriptionTermStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByDescriptionTermStrategy.cs index 666dcb43..a2dbb09b 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByDescriptionTermStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByDescriptionTermStrategy.cs @@ -5,7 +5,7 @@ public class FindByDescriptionTermStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant._("dl/dt")[y => y.TermsConditionOfContent]). + WrapWithIndex(x => x.OuterXPath._("dl/dt")[y => y.TermsConditionOfContent]). FollowingSibling._("dd").DescendantOrSelf.ComponentXPath; } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByFieldSetStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByFieldSetStrategy.cs index f9e0b6e7..9da98070 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByFieldSetStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByFieldSetStrategy.cs @@ -5,7 +5,7 @@ public class FindByFieldSetStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant._("fieldset")[y => y._("legend")[z => z.TermsConditionOfContent]]). + WrapWithIndex(x => x.OuterXPath._("fieldset")[y => y._("legend")[z => z.TermsConditionOfContent]]). DescendantOrSelf.ComponentXPath; } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByIdStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByIdStrategy.cs index ec83e304..ab7cfdf4 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByIdStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByIdStrategy.cs @@ -5,7 +5,7 @@ public class FindByIdStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.Any[y => y.TermsConditionOf("id")]). + WrapWithIndex(x => x.OuterXPath.Any[y => y.TermsConditionOf("id")]). DescendantOrSelf.ComponentXPath; } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByIndexStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByIndexStrategy.cs index b4651df9..e184dbfe 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByIndexStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByIndexStrategy.cs @@ -4,7 +4,7 @@ public class FindByIndexStrategy : XPathComponentScopeLocateStrategy { protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { - return builder.WrapWithIndex(options.Index.Value, x => x.Descendant.ComponentXPath); + return builder.WrapWithIndex(options.Index.Value, x => x.OuterXPath.ComponentXPath); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByInnerXPathStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByInnerXPathStrategy.cs index 5fc6026f..5d9e0964 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByInnerXPathStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByInnerXPathStrategy.cs @@ -10,7 +10,7 @@ protected override string Build(ComponentScopeXPathBuilder builder, ComponentSco ? options.Terms.Select(x => $"({x})").ToArray() : options.Terms; - return builder.WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.JoinOr(conditions)]); + return builder.WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.JoinOr(conditions)]); } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByLabelStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByLabelStrategy.cs index 145178b5..ea6e3fc4 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByLabelStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByLabelStrategy.cs @@ -7,7 +7,7 @@ public class FindByLabelStrategy : IComponentScopeLocateStrategy public ComponentScopeLocateResult Find(IWebElement scope, ComponentScopeLocateOptions options, SearchOptions searchOptions) { string labelXPath = new ComponentScopeXPathBuilder(options). - WrapWithIndex(x => x.Descendant._("label")[y => y.TermsConditionOfContent]); + WrapWithIndex(x => x.OuterXPath._("label")[y => y.TermsConditionOfContent]); IWebElement label = scope.Get(By.XPath(labelXPath).With(searchOptions).Label(options.GetTermsAsString())); diff --git a/src/Atata/ScopeSearch/Strategies/FindByNameStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByNameStrategy.cs index 13ecbcbd..1789d243 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByNameStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByNameStrategy.cs @@ -5,7 +5,7 @@ public class FindByNameStrategy : XPathComponentScopeLocateStrategy protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { return builder. - WrapWithIndex(x => x.Descendant.Any[y => y.TermsConditionOf("name")]). + WrapWithIndex(x => x.OuterXPath.Any[y => y.TermsConditionOf("name")]). DescendantOrSelf.ComponentXPath; } } diff --git a/src/Atata/ScopeSearch/Strategies/FindByXPathStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindByXPathStrategy.cs index 15dec426..40775841 100644 --- a/src/Atata/ScopeSearch/Strategies/FindByXPathStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindByXPathStrategy.cs @@ -24,22 +24,25 @@ protected override string Build(ComponentScopeXPathBuilder builder, ComponentSco } string conditionalXPath = conditionalXPathSelectors.Any() - ? builder.WrapWithIndex(x => x.Descendant.ComponentXPath[y => y.JoinOr(conditionalXPathSelectors)]) + ? builder.WrapWithIndex(x => x.OuterXPath.ComponentXPath[y => y.JoinOr(conditionalXPathSelectors)]) : null; - string[] outerXPathSelectors = builder.Options.Terms. + string[] completeXPathSelectors = builder.Options.Terms. Except(conditionalXPathTerms). - Select(x => acceptableXPathPrefixValues.Any(prefix => x.StartsWith(prefix)) ? x : ".//" + x). + Select(x => + acceptableXPathPrefixValues.Any(prefix => x.StartsWith(prefix)) + ? (options.OuterXPath?.Append(x) ?? x) + : ((options.OuterXPath ?? ".//") + x)). ToArray(); - string outerXPath = outerXPathSelectors.Any() - ? builder.WrapWithIndex(x => x._($"({string.Join(" | ", outerXPathSelectors)})")).DescendantOrSelf.ComponentXPath + string completeXPath = completeXPathSelectors.Any() + ? builder.WrapWithIndex(x => x._($"({string.Join(" | ", completeXPathSelectors)})")).DescendantOrSelf.ComponentXPath : null; - if (conditionalXPath != null && outerXPath != null) - return $"(({outerXPath}) | ({conditionalXPath}))"; + if (conditionalXPath != null && completeXPath != null) + return $"(({completeXPath}) | ({conditionalXPath}))"; else - return outerXPath ?? conditionalXPath; + return completeXPath ?? conditionalXPath; } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindFirstDescendantStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindFirstDescendantStrategy.cs index 816ac70b..ee6e57ea 100644 --- a/src/Atata/ScopeSearch/Strategies/FindFirstDescendantStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindFirstDescendantStrategy.cs @@ -4,7 +4,7 @@ public class FindFirstDescendantStrategy : XPathComponentScopeLocateStrategy { protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { - return builder.Descendant.ComponentXPath; + return builder.OuterXPath.ComponentXPath; } } } diff --git a/src/Atata/ScopeSearch/Strategies/FindLastDescendantStrategy.cs b/src/Atata/ScopeSearch/Strategies/FindLastDescendantStrategy.cs index b975579e..e128bf1c 100644 --- a/src/Atata/ScopeSearch/Strategies/FindLastDescendantStrategy.cs +++ b/src/Atata/ScopeSearch/Strategies/FindLastDescendantStrategy.cs @@ -4,7 +4,7 @@ public class FindLastDescendantStrategy : XPathComponentScopeLocateStrategy { protected override string Build(ComponentScopeXPathBuilder builder, ComponentScopeLocateOptions options) { - return builder.Wrap(x => x.Descendant.ComponentXPath)["last()"]; + return builder.Wrap(x => x.OuterXPath.ComponentXPath)["last()"]; } } }