Skip to content

Commit 7a933cc

Browse files
committed
Adding FindsByAllAttribute to .NET PageFactory implementation
This allows the user to specify that an element must match the criteria of all of the FindsBy attributes a property or field is marked with in order to be found by the PageFactory. Previously, a class member marked with multiple FindsBy attributes would find an element matching any of the attributes' criteria. Because of the nature of this change, you cannot use FindsBySequence and FindsByAll on the same class member. Attempting to do so will result in an exception when InitElements is called.
1 parent 735c769 commit 7a933cc

File tree

4 files changed

+99
-0
lines changed

4 files changed

+99
-0
lines changed
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// <copyright file="FindsByAllAttribute.cs" company="WebDriver Committers">
2+
// Copyright 2015 Software Freedom Conservancy
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
// </copyright>
16+
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Linq;
20+
using System.Text;
21+
22+
namespace OpenQA.Selenium.Support.PageObjects
23+
{
24+
/// <summary>
25+
/// Marks elements to indicate that found elements should match the criteria of
26+
/// all <see cref="FindsByAttribute"/> on the field or property.
27+
/// </summary>
28+
/// <remarks>
29+
/// <para>
30+
/// When used with a set of <see cref="FindsByAttribute"/>, all criteria must be
31+
/// matched to be returned. The criteria are used in sequence according to the
32+
/// Priority property. Note that the behavior when setting multiple
33+
/// <see cref="FindsByAttribute"/> Priority properties to the same value, or not
34+
/// specifying a Priority value, is undefined.
35+
/// </para>
36+
/// <para>
37+
/// <code>
38+
/// // Will find the element with the tag name "input" that also has an ID
39+
/// // attribute matching "elementId".
40+
/// [FindsByAll]
41+
/// [FindsBy(How = How.TagName, Using = "input", Priority = 0)]
42+
/// [FindsBy(How = How.Id, Using = "elementId", Priority = 1)]
43+
/// public IWebElement thisElement;
44+
/// </code>
45+
/// </para>
46+
/// </remarks>
47+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
48+
public sealed class FindsByAllAttribute : Attribute
49+
{
50+
}
51+
}

Diff for: dotnet/src/support/PageObjects/PageFactory.cs

+15
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,14 @@ private static List<By> CreateLocatorList(MemberInfo member)
189189
var useSequenceAttributes = Attribute.GetCustomAttributes(member, typeof(FindsBySequenceAttribute), true);
190190
bool useSequence = useSequenceAttributes.Length > 0;
191191

192+
var useAllAttributes = Attribute.GetCustomAttributes(member, typeof(FindsByAllAttribute), true);
193+
bool useAll = useAllAttributes.Length > 0;
194+
195+
if (useSequence && useAll)
196+
{
197+
throw new ArgumentException("Cannot specify FindsBySequence and FindsByAll on the same member");
198+
}
199+
192200
List<By> bys = new List<By>();
193201
var attributes = Attribute.GetCustomAttributes(member, typeof(FindsByAttribute), true);
194202
if (attributes.Length > 0)
@@ -211,6 +219,13 @@ private static List<By> CreateLocatorList(MemberInfo member)
211219
bys.Clear();
212220
bys.Add(chained);
213221
}
222+
223+
if (useAll)
224+
{
225+
ByAll all = new ByAll(bys.ToArray());
226+
bys.Clear();
227+
bys.Add(all);
228+
}
214229
}
215230

216231
return bys;

Diff for: dotnet/src/support/WebDriver.Support.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<Compile Include="PageObjects\ByFactory.cs" />
8383
<Compile Include="PageObjects\CacheLookupAttribute.cs" />
8484
<Compile Include="PageObjects\ByIdOrName.cs" />
85+
<Compile Include="PageObjects\FindsByAllAttribute.cs" />
8586
<Compile Include="PageObjects\RetryingElementLocatorFactory.cs" />
8687
<Compile Include="PageObjects\DefaultElementLocatorFactory.cs" />
8788
<Compile Include="PageObjects\FindsByAttribute.cs" />

Diff for: dotnet/test/support/PageObjects/PageFactoryBrowserTest.cs

+32
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ public void ShouldFindElementUsingSequence()
9999
Assert.AreEqual("I'm a child", page.NestedElement.Text.Trim());
100100
}
101101

102+
[Test]
103+
public void ShouldFindElementUsingAllFindBys()
104+
{
105+
driver.Url = xhtmlTestPage;
106+
var page = new PageFactoryBrowserTest.Page();
107+
PageFactory.InitElements(driver, page);
108+
Assert.True(page.ByAllElement.Displayed);
109+
}
110+
111+
[Test]
112+
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Cannot specify FindsBySequence and FindsByAll on the same member", MatchType = MessageMatch.Contains)]
113+
public void MixingFindBySequenceAndFindByAllShouldThrow()
114+
{
115+
driver.Url = xhtmlTestPage;
116+
var page = new PageFactoryBrowserTest.InvalidAttributeCombinationPage();
117+
PageFactory.InitElements(driver, page);
118+
}
119+
102120
#region Page classes for tests
103121
#pragma warning disable 649 //We set fields through reflection, so expect an always-null warning
104122

@@ -111,6 +129,11 @@ private class Page
111129
[FindsBy(How = How.Id, Using = "parent", Priority = 0)]
112130
[FindsBy(How = How.Id, Using = "child", Priority = 1)]
113131
public IWebElement NestedElement;
132+
133+
[FindsByAll]
134+
[FindsBy(How = How.TagName, Using = "form", Priority = 0)]
135+
[FindsBy(How = How.Name, Using = "someForm", Priority = 1)]
136+
public IWebElement ByAllElement;
114137
}
115138

116139
private class HoverPage
@@ -125,6 +148,15 @@ private class LinksPage
125148
public IList<IWebElement> AllLinks;
126149
}
127150

151+
private class InvalidAttributeCombinationPage
152+
{
153+
[FindsByAll]
154+
[FindsBySequence]
155+
[FindsBy(How = How.Id, Using = "parent", Priority = 0)]
156+
[FindsBy(How = How.Id, Using = "child", Priority = 1)]
157+
public IWebElement NotFound;
158+
}
159+
128160
#pragma warning restore 649
129161
#endregion
130162
}

0 commit comments

Comments
 (0)