Skip to content

Commit 735c769

Browse files
FrankyBoyjimevans
authored andcommitted
Adding support for ByAll, finding elements matching all locators to .NET
Signed-off-by: Jim Evans <[email protected]>
1 parent a591496 commit 735c769

File tree

6 files changed

+284
-12
lines changed

6 files changed

+284
-12
lines changed
+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// <copyright file="ByAll.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.Collections.Generic;
18+
using System.Collections.ObjectModel;
19+
using System.Globalization;
20+
using System.Linq;
21+
using System.Text;
22+
23+
namespace OpenQA.Selenium.Support.PageObjects
24+
{
25+
/// <summary>
26+
/// Mechanism used to locate elements within a document using a series of lookups. This class will
27+
/// find all DOM elements that matches all of the locators in sequence, e.g.
28+
/// </summary>
29+
/// <example>
30+
/// The following code will find all elements that match by1 and then all elements that also match by2.
31+
/// <code>
32+
/// driver.findElements(new ByAll(by1, by2))
33+
/// </code>
34+
/// This means that the list of elements returned may not be in document order.
35+
/// </example>>
36+
public class ByAll : By
37+
{
38+
private readonly By[] bys;
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="ByAll"/> class with one or more <see cref="By"/> objects.
42+
/// </summary>
43+
/// <param name="bys">One or more <see cref="By"/> references</param>
44+
public ByAll(params By[] bys)
45+
{
46+
this.bys = bys;
47+
}
48+
49+
/// <summary>
50+
/// Find a single element.
51+
/// </summary>
52+
/// <param name="context">Context used to find the element.</param>
53+
/// <returns>The element that matches</returns>
54+
public override IWebElement FindElement(ISearchContext context)
55+
{
56+
var elements = this.FindElements(context);
57+
if (elements.Count == 0)
58+
{
59+
throw new NoSuchElementException("Cannot locate an element using " + this.ToString());
60+
}
61+
62+
return elements[0];
63+
}
64+
65+
/// <summary>
66+
/// Finds many elements
67+
/// </summary>
68+
/// <param name="context">Context used to find the element.</param>
69+
/// <returns>A readonly collection of elements that match.</returns>
70+
public override ReadOnlyCollection<IWebElement> FindElements(ISearchContext context)
71+
{
72+
if (this.bys.Length == 0)
73+
{
74+
return new List<IWebElement>().AsReadOnly();
75+
}
76+
77+
IEnumerable<IWebElement> elements = null;
78+
foreach (By by in this.bys)
79+
{
80+
ReadOnlyCollection<IWebElement> foundElements = by.FindElements(context);
81+
if (foundElements.Count == 0)
82+
{
83+
// Optimization: If at any time a find returns no elements, the
84+
// only possible result for find-all is an empty collection.
85+
return new List<IWebElement>().AsReadOnly();
86+
}
87+
88+
if (elements == null)
89+
{
90+
elements = foundElements;
91+
}
92+
else
93+
{
94+
elements = elements.Intersect(by.FindElements(context));
95+
}
96+
}
97+
98+
return elements.ToList().AsReadOnly();
99+
}
100+
101+
/// <summary>
102+
/// Writes out a comma separated list of the <see cref="By"/> objects used in the chain.
103+
/// </summary>
104+
/// <returns>Converts the value of this instance to a <see cref="System.String"/></returns>
105+
public override string ToString()
106+
{
107+
StringBuilder stringBuilder = new StringBuilder();
108+
foreach (By by in this.bys)
109+
{
110+
if (stringBuilder.Length > 0)
111+
{
112+
stringBuilder.Append(",");
113+
}
114+
115+
stringBuilder.Append(by);
116+
}
117+
118+
return string.Format(CultureInfo.InvariantCulture, "By.All([{0}])", stringBuilder.ToString());
119+
}
120+
}
121+
}

dotnet/src/support/WebDriver.Support.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
<Compile Include="Events\WebElementEventArgs.cs" />
7878
<Compile Include="Extensions\WebDriverExtensions.cs" />
7979
<Compile Include="GlobalSuppressions.cs" />
80+
<Compile Include="PageObjects\ByAll.cs" />
8081
<Compile Include="PageObjects\ByChained.cs" />
8182
<Compile Include="PageObjects\ByFactory.cs" />
8283
<Compile Include="PageObjects\CacheLookupAttribute.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
Copyright 2015 Software Freedom Conservancy
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
using System.Collections.Generic;
17+
using NMock2;
18+
using NUnit.Framework;
19+
using Is = NUnit.Framework.Is;
20+
21+
namespace OpenQA.Selenium.Support.PageObjects
22+
{
23+
[TestFixture]
24+
class ByAllTests
25+
{
26+
[Test]
27+
public void FindElementZeroBy()
28+
{
29+
var mock = new Mockery();
30+
var driver = mock.NewMock<IAllDriver>();
31+
32+
var by = new ByAll();
33+
34+
Assert.Throws<NoSuchElementException>(() => by.FindElement(driver));
35+
Assert.That(by.FindElements(driver), Is.EqualTo(new List<IWebElement>().AsReadOnly()));
36+
}
37+
38+
[Test]
39+
public void FindElementOneBy()
40+
{
41+
var mock = new Mockery();
42+
var driver = mock.NewMock<IAllDriver>();
43+
var elem1 = mock.NewMock<IAllElement>();
44+
var elem2 = mock.NewMock<IAllElement>();
45+
var elems12 = new List<IWebElement> { elem1, elem2 }.AsReadOnly();
46+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
47+
var by = new ByAll(By.Name("cheese"));
48+
49+
// findElement
50+
Assert.AreEqual(by.FindElement(driver), elem1);
51+
//findElements
52+
Assert.That(by.FindElements(driver), Is.EqualTo(elems12));
53+
54+
mock.VerifyAllExpectationsHaveBeenMet();
55+
}
56+
57+
[Test]
58+
public void FindElementOneByEmpty()
59+
{
60+
var mock = new Mockery();
61+
var driver = mock.NewMock<IAllDriver>();
62+
var empty = new List<IWebElement>().AsReadOnly();
63+
64+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(empty));
65+
66+
var by = new ByAll(By.Name("cheese"));
67+
68+
// one element
69+
Assert.Throws<NoSuchElementException>(() => by.FindElement(driver));
70+
Assert.That(by.FindElements(driver), Is.EqualTo(empty));
71+
72+
mock.VerifyAllExpectationsHaveBeenMet();
73+
}
74+
75+
[Test]
76+
public void FindElementTwoBy()
77+
{
78+
var mocks = new Mockery();
79+
var driver = mocks.NewMock<IAllDriver>();
80+
81+
var elem1 = mocks.NewMock<IAllElement>();
82+
var elem2 = mocks.NewMock<IAllElement>();
83+
var elem3 = mocks.NewMock<IAllElement>();
84+
var elems12 = new List<IWebElement> { elem1, elem2 }.AsReadOnly();
85+
var elems23 = new List<IWebElement> { elem2, elem3 }.AsReadOnly();
86+
87+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
88+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems23));
89+
90+
var by = new ByAll(By.Name("cheese"), By.Name("photo"));
91+
92+
// findElement
93+
Assert.That(by.FindElement(driver), Is.EqualTo(elem2));
94+
95+
//findElements
96+
var result = by.FindElements(driver);
97+
Assert.That(result.Count, Is.EqualTo(1));
98+
Assert.That(result[0], Is.EqualTo(elem2));
99+
100+
mocks.VerifyAllExpectationsHaveBeenMet();
101+
}
102+
103+
[Test]
104+
public void FindElementDisjunct()
105+
{
106+
var mocks = new Mockery();
107+
var driver = mocks.NewMock<IAllDriver>();
108+
109+
var elem1 = mocks.NewMock<IAllElement>();
110+
var elem2 = mocks.NewMock<IAllElement>();
111+
var elem3 = mocks.NewMock<IAllElement>();
112+
var elem4 = mocks.NewMock<IAllElement>();
113+
var elems12 = new List<IWebElement> { elem1, elem2 }.AsReadOnly();
114+
var elems34 = new List<IWebElement> { elem3, elem4 }.AsReadOnly();
115+
116+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
117+
Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems34));
118+
119+
var by = new ByAll(By.Name("cheese"), By.Name("photo"));
120+
121+
Assert.Throws<NoSuchElementException>(() => by.FindElement(driver));
122+
123+
var result = by.FindElements(driver);
124+
Assert.That(result.Count, Is.EqualTo(0));
125+
mocks.VerifyAllExpectationsHaveBeenMet();
126+
}
127+
128+
}
129+
}

dotnet/test/support/PageObjects/ByChainedTests.cs

-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Collections.Generic;
22
using NMock2;
33
using NUnit.Framework;
4-
using OpenQA.Selenium.Internal;
54
using Is = NUnit.Framework.Is;
65

76
namespace OpenQA.Selenium.Support.PageObjects
@@ -215,16 +214,5 @@ public void TestEquals()
215214
Assert.That(new ByChained(By.Id("cheese"), By.Name("photo")),
216215
Is.EqualTo(new ByChained(By.Id("cheese"), By.Name("photo"))));
217216
}
218-
219-
public interface IAllDriver :
220-
IFindsById, IFindsByLinkText, IFindsByName, IFindsByXPath, ISearchContext, IWebDriver
221-
{
222-
// Place holder
223-
}
224-
225-
public interface IAllElement : IWebElement
226-
{
227-
// Place holder
228-
}
229217
}
230218
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2015 Software Freedom Conservancy
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
using OpenQA.Selenium.Internal;
17+
18+
namespace OpenQA.Selenium.Support.PageObjects
19+
{
20+
public interface IAllDriver : IFindsById, IFindsByLinkText, IFindsByName, IFindsByXPath, IWebDriver
21+
{
22+
// Place holder
23+
}
24+
25+
public interface IAllElement : IWebElement
26+
{
27+
// Place holder
28+
}
29+
}

dotnet/test/support/WebDriver.Support.Tests.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,13 @@
7979
<ItemGroup>
8080
<Compile Include="Events\EventFiringWebDriverTest.cs" />
8181
<Compile Include="Extensions\ExecuteJavaScriptTest.cs" />
82+
<Compile Include="PageObjects\ByAllTests.cs" />
8283
<Compile Include="PageObjects\ByChainedBrowserTests.cs" />
8384
<Compile Include="PageObjects\ByChainedTests.cs" />
8485
<Compile Include="PageObjects\FindsByAttributeTests.cs" />
86+
<Compile Include="PageObjects\IAllDriver.cs">
87+
<SubType>Code</SubType>
88+
</Compile>
8589
<Compile Include="PageObjects\PageFactoryBrowserTest.cs" />
8690
<Compile Include="PageObjects\PageFactoryTest.cs" />
8791
<Compile Include="Properties\AssemblyInfo.cs" />

0 commit comments

Comments
 (0)