diff --git a/dotnet/src/support/PageObjects/ByAll.cs b/dotnet/src/support/PageObjects/ByAll.cs
new file mode 100644
index 0000000000000..c985a80b6c573
--- /dev/null
+++ b/dotnet/src/support/PageObjects/ByAll.cs
@@ -0,0 +1,79 @@
+/*
+Copyright 2015 Software Freedom Conservancy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+
+namespace OpenQA.Selenium.Support.PageObjects
+{
+ /// Mechanism used to locate elements within a document using a series of lookups. This class will
+ /// find all DOM elements that matches all of the locators in sequence, e.g.
+ /// driver.findElements(new ByAll(by1, by2))
+ /// will find all elements that match by1 and then all elements that match by2.
+ /// This means that the list of elements returned may not be in document order.>
+ public class ByAll : By
+ {
+ private readonly By[] _bys;
+
+ public ByAll(params By[] bys)
+ {
+ _bys = bys;
+ }
+
+ public override IWebElement FindElement(ISearchContext context)
+ {
+ var elements = FindElements(context);
+ if (elements.Count == 0)
+ {
+ throw new NoSuchElementException("Cannot locate an element using " + ToString());
+ }
+ return elements[0];
+ }
+
+ public override ReadOnlyCollection FindElements(ISearchContext context)
+ {
+ if (_bys.Length == 0)
+ return new List().AsReadOnly();
+
+ ReadOnlyCollection elems = _bys[0].FindElements(context);
+ // skipping first elem
+ for (int index = 1; index < _bys.Length; index++)
+ {
+ var @by = _bys[index];
+ elems = @by.FindElements(context).Where(el => elems.Contains(el)).ToList().AsReadOnly();
+ }
+
+ return elems.ToList().AsReadOnly();
+ }
+
+ public override string ToString()
+ {
+ var stringBuilder = new StringBuilder("By.all(");
+ stringBuilder.Append("{");
+
+ var first = true;
+ foreach (var by in _bys)
+ {
+ stringBuilder.Append((first ? "" : ",")).Append(by);
+ first = false;
+ }
+ stringBuilder.Append("})");
+ return stringBuilder.ToString();
+ }
+
+ }
+}
diff --git a/dotnet/src/support/PageObjects/ByAny.cs b/dotnet/src/support/PageObjects/ByAny.cs
new file mode 100644
index 0000000000000..91d65e3abd103
--- /dev/null
+++ b/dotnet/src/support/PageObjects/ByAny.cs
@@ -0,0 +1,77 @@
+/*
+Copyright 2015 Software Freedom Conservancy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+
+namespace OpenQA.Selenium.Support.PageObjects
+{
+ /// Mechanism used to locate elements within a document using a series of lookups. This class will
+ /// find all DOM elements that matches any of the locators in sequence, e.g.
+ /// driver.findElements(new ByAny(by1, by2))
+ /// will find all elements that match by1 and then all elements that match by2.
+ /// This means that the list of elements returned may not be in document order.>
+ public class ByAny : By
+ {
+ private readonly By[] _bys;
+
+ public ByAny(params By[] bys)
+ {
+ _bys = bys;
+ }
+
+ public override IWebElement FindElement(ISearchContext context)
+ {
+ foreach (var @by in _bys)
+ {
+ var elems = @by.FindElements(context);
+ if (elems.Any())
+ {
+ return elems[0];
+ }
+ }
+ throw new NoSuchElementException("Cannot locate an element using " + ToString());
+ }
+
+ public override ReadOnlyCollection FindElements(ISearchContext context)
+ {
+ var elems = new List();
+ foreach (var @by in _bys)
+ {
+ elems.AddRange(@by.FindElements(context));
+ }
+
+ return elems.Distinct().ToList().AsReadOnly();
+ }
+
+ public override string ToString()
+ {
+ var stringBuilder = new StringBuilder("By.all(");
+ stringBuilder.Append("{");
+
+ var first = true;
+ foreach (var by in _bys)
+ {
+ stringBuilder.Append((first ? "" : ",")).Append(by);
+ first = false;
+ }
+ stringBuilder.Append("})");
+ return stringBuilder.ToString();
+ }
+
+ }
+}
diff --git a/dotnet/src/support/WebDriver.Support.csproj b/dotnet/src/support/WebDriver.Support.csproj
index 98bdadb6ae277..4ec582fd80011 100644
--- a/dotnet/src/support/WebDriver.Support.csproj
+++ b/dotnet/src/support/WebDriver.Support.csproj
@@ -77,6 +77,8 @@
+
+
diff --git a/dotnet/test/support/PageObjects/ByAllTests.cs b/dotnet/test/support/PageObjects/ByAllTests.cs
new file mode 100644
index 0000000000000..532c48903e17b
--- /dev/null
+++ b/dotnet/test/support/PageObjects/ByAllTests.cs
@@ -0,0 +1,129 @@
+/*
+Copyright 2015 Software Freedom Conservancy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+using System.Collections.Generic;
+using NMock2;
+using NUnit.Framework;
+using Is = NUnit.Framework.Is;
+
+namespace OpenQA.Selenium.Support.PageObjects
+{
+ [TestFixture]
+ class ByAllTests
+ {
+ [Test]
+ public void FindElementZeroBy()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+
+ var by = new ByAll();
+
+ Assert.Throws(() => by.FindElement(driver));
+ Assert.That(by.FindElements(driver), Is.EqualTo(new List().AsReadOnly()));
+ }
+
+ [Test]
+ public void FindElementOneBy()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+ var elem1 = mock.NewMock();
+ var elem2 = mock.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ var by = new ByAll(By.Name("cheese"));
+
+ // findElement
+ Assert.AreEqual(by.FindElement(driver), elem1);
+ //findElements
+ Assert.That(by.FindElements(driver), Is.EqualTo(elems12));
+
+ mock.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementOneByEmpty()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+ var empty = new List().AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(empty));
+
+ var by = new ByAll(By.Name("cheese"));
+
+ // one element
+ Assert.Throws(() => by.FindElement(driver));
+ Assert.That(by.FindElements(driver), Is.EqualTo(empty));
+
+ mock.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementTwoBy()
+ {
+ var mocks = new Mockery();
+ var driver = mocks.NewMock();
+
+ var elem1 = mocks.NewMock();
+ var elem2 = mocks.NewMock();
+ var elem3 = mocks.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ var elems23 = new List { elem2, elem3 }.AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems23));
+
+ var by = new ByAll(By.Name("cheese"), By.Name("photo"));
+
+ // findElement
+ Assert.That(by.FindElement(driver), Is.EqualTo(elem2));
+
+ //findElements
+ var result = by.FindElements(driver);
+ Assert.That(result.Count, Is.EqualTo(1));
+ Assert.That(result[0], Is.EqualTo(elem2));
+
+ mocks.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementDisjunct()
+ {
+ var mocks = new Mockery();
+ var driver = mocks.NewMock();
+
+ var elem1 = mocks.NewMock();
+ var elem2 = mocks.NewMock();
+ var elem3 = mocks.NewMock();
+ var elem4 = mocks.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ var elems34 = new List { elem3, elem4 }.AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems34));
+
+ var by = new ByAll(By.Name("cheese"), By.Name("photo"));
+
+ Assert.Throws(() => by.FindElement(driver));
+
+ var result = by.FindElements(driver);
+ Assert.That(result.Count, Is.EqualTo(0));
+ mocks.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ }
+}
diff --git a/dotnet/test/support/PageObjects/ByAnyTests.cs b/dotnet/test/support/PageObjects/ByAnyTests.cs
new file mode 100644
index 0000000000000..e441f242f9716
--- /dev/null
+++ b/dotnet/test/support/PageObjects/ByAnyTests.cs
@@ -0,0 +1,130 @@
+/*
+Copyright 2015 Software Freedom Conservancy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+using System.Collections.Generic;
+using NMock2;
+using NUnit.Framework;
+using Is = NUnit.Framework.Is;
+
+namespace OpenQA.Selenium.Support.PageObjects
+{
+ [TestFixture]
+ public class ByAnyTests
+ {
+ [Test]
+ public void FindElementZeroBy()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+
+ var by = new ByAny();
+
+ Assert.Throws(() => by.FindElement(driver));
+ Assert.That(by.FindElements(driver), Is.EqualTo(new List().AsReadOnly()));
+ }
+
+ [Test]
+ public void FindElementOneBy()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+ var elem1 = mock.NewMock();
+ var elem2 = mock.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ var by = new ByAny(By.Name("cheese"));
+
+ // findElement
+ Assert.AreEqual(by.FindElement(driver), elem1);
+ //findElements
+ Assert.That(by.FindElements(driver), Is.EqualTo(elems12));
+
+ mock.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementOneByEmpty()
+ {
+ var mock = new Mockery();
+ var driver = mock.NewMock();
+ var empty = new List().AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(empty));
+
+ var by = new ByAny(By.Name("cheese"));
+
+ // one element
+ Assert.Throws(() => by.FindElement(driver));
+ Assert.That(by.FindElements(driver), Is.EqualTo(empty));
+
+ mock.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementTwoBy()
+ {
+ var mocks = new Mockery();
+ var driver = mocks.NewMock();
+
+ var elem1 = mocks.NewMock();
+ var elem2 = mocks.NewMock();
+ var elem3 = mocks.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ var elems23 = new List { elem2, elem3 }.AsReadOnly();
+ var expected = new List { elem1, elem2, elem3 }.AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems23));
+
+ var by = new ByAny(By.Name("cheese"), By.Name("photo"));
+
+ // findElement
+ Assert.That(by.FindElement(driver), Is.EqualTo(elem1));
+
+ //findElements
+ var result = by.FindElements(driver);
+ Assert.That(result, Is.EqualTo(expected));
+
+ mocks.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ [Test]
+ public void FindElementDisjunct()
+ {
+ var mocks = new Mockery();
+ var driver = mocks.NewMock();
+
+ var elem1 = mocks.NewMock();
+ var elem2 = mocks.NewMock();
+ var elem3 = mocks.NewMock();
+ var elem4 = mocks.NewMock();
+ var elems12 = new List { elem1, elem2 }.AsReadOnly();
+ var elems34 = new List { elem3, elem4 }.AsReadOnly();
+ var expected = new List {elem1, elem2, elem3, elem4}.AsReadOnly();
+
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("cheese").Will(Return.Value(elems12));
+ Expect.AtLeastOnce.On(driver).Method("FindElementsByName").With("photo").Will(Return.Value(elems34));
+
+ var by = new ByAny(By.Name("cheese"), By.Name("photo"));
+
+ Assert.That(by.FindElement(driver), Is.EqualTo(elem1));
+
+ var result = by.FindElements(driver);
+ Assert.That(result, Is.EqualTo(expected));
+ mocks.VerifyAllExpectationsHaveBeenMet();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/dotnet/test/support/PageObjects/ByChainedTests.cs b/dotnet/test/support/PageObjects/ByChainedTests.cs
index 92ededc5283ae..0da8befcb9453 100644
--- a/dotnet/test/support/PageObjects/ByChainedTests.cs
+++ b/dotnet/test/support/PageObjects/ByChainedTests.cs
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using NMock2;
using NUnit.Framework;
-using OpenQA.Selenium.Internal;
using Is = NUnit.Framework.Is;
namespace OpenQA.Selenium.Support.PageObjects
@@ -215,16 +214,5 @@ public void TestEquals()
Assert.That(new ByChained(By.Id("cheese"), By.Name("photo")),
Is.EqualTo(new ByChained(By.Id("cheese"), By.Name("photo"))));
}
-
- public interface IAllDriver :
- IFindsById, IFindsByLinkText, IFindsByName, IFindsByXPath, ISearchContext, IWebDriver
- {
- // Place holder
- }
-
- public interface IAllElement : IWebElement
- {
- // Place holder
- }
}
}
diff --git a/dotnet/test/support/PageObjects/IAllDriver.cs b/dotnet/test/support/PageObjects/IAllDriver.cs
new file mode 100644
index 0000000000000..fb77ad6307e86
--- /dev/null
+++ b/dotnet/test/support/PageObjects/IAllDriver.cs
@@ -0,0 +1,29 @@
+/*
+Copyright 2015 Software Freedom Conservancy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+using OpenQA.Selenium.Internal;
+
+namespace OpenQA.Selenium.Support.PageObjects
+{
+ public interface IAllDriver : IFindsById, IFindsByLinkText, IFindsByName, IFindsByXPath, IWebDriver
+ {
+ // Place holder
+ }
+
+ public interface IAllElement : IWebElement
+ {
+ // Place holder
+ }
+}
diff --git a/dotnet/test/support/WebDriver.Support.Tests.csproj b/dotnet/test/support/WebDriver.Support.Tests.csproj
index 1a52f7af7cb28..065ec7c84b577 100644
--- a/dotnet/test/support/WebDriver.Support.Tests.csproj
+++ b/dotnet/test/support/WebDriver.Support.Tests.csproj
@@ -78,9 +78,12 @@
+
+
+