Skip to content

Commit 165b71b

Browse files
committed
Implementing FindsBySequence attribute for .NET PageFactory
Allows the user to mark a field or property in a page object such that any FindsBy attributes set on the member are used in sequence, as specified by the Priority property. Note that when not specifying a Priority value, or specifying multiple FindsBy attributes with the same Priority value, the behavior is undefined.
1 parent b9042c8 commit 165b71b

File tree

4 files changed

+77
-0
lines changed

4 files changed

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

dotnet/src/support/PageObjects/PageFactory.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public static void InitElements(ISearchContext driver, object page)
136136

137137
private static List<By> CreateLocatorList(MemberInfo member)
138138
{
139+
var useSequenceAttributes = Attribute.GetCustomAttributes(member, typeof(FindsBySequenceAttribute), true);
140+
bool useSequence = useSequenceAttributes.Length > 0;
141+
139142
List<By> bys = new List<By>();
140143
var attributes = Attribute.GetCustomAttributes(member, typeof(FindsByAttribute), true);
141144
if (attributes.Length > 0)
@@ -151,6 +154,13 @@ private static List<By> CreateLocatorList(MemberInfo member)
151154

152155
bys.Add(castedAttribute.Finder);
153156
}
157+
158+
if (useSequence)
159+
{
160+
ByChained chained = new ByChained(bys.ToArray());
161+
bys.Clear();
162+
bys.Add(chained);
163+
}
154164
}
155165

156166
return bys;

dotnet/src/support/WebDriver.Support.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
<Compile Include="PageObjects\ByFactory.cs" />
8282
<Compile Include="PageObjects\CacheLookupAttribute.cs" />
8383
<Compile Include="PageObjects\FindsByAttribute.cs" />
84+
<Compile Include="PageObjects\FindsBySequenceAttribute.cs" />
8485
<Compile Include="PageObjects\How.cs" />
8586
<Compile Include="PageObjects\PageFactory.cs" />
8687
<Compile Include="PageObjects\WebElementListProxy.cs" />

dotnet/test/support/PageObjects/PageFactoryBrowserTest.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,27 @@ public void ShouldFindMultipleElements()
9090
Assert.AreEqual("Open new window", page.AllLinks[0].Text.Trim());
9191
}
9292

93+
[Test]
94+
public void ShouldFindElementUsingSequence()
95+
{
96+
driver.Url = xhtmlTestPage;
97+
var page = new PageFactoryBrowserTest.Page();
98+
PageFactory.InitElements(driver, page);
99+
Assert.AreEqual("I'm a child", page.NestedElement.Text.Trim());
100+
}
101+
93102
#region Page classes for tests
94103
#pragma warning disable 649 //We set fields through reflection, so expect an always-null warning
95104

96105
private class Page
97106
{
98107
[FindsBy(How = How.Name, Using = "someForm")]
99108
public IWebElement formElement;
109+
110+
[FindsBySequence]
111+
[FindsBy(How = How.Id, Using = "parent", Priority = 0)]
112+
[FindsBy(How = How.Id, Using = "child", Priority = 1)]
113+
public IWebElement NestedElement;
100114
}
101115

102116
private class HoverPage

0 commit comments

Comments
 (0)