Skip to content

Commit 0d51fbe

Browse files
authored
Implement IElement (#29)
* Implement IElement to resolve #9 * #9 Change namespaces for Actions * #9 rename parameter * #9 Fix comments after review * #9 Change access modifiers for constants * #9 rename IElementWithState interface method
1 parent bc5dd7e commit 0d51fbe

File tree

15 files changed

+199
-152
lines changed

15 files changed

+199
-152
lines changed

Aquality.Selenium/src/Aquality.Selenium/Browsers/JavaScript.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static class JavaScriptExtensions
3535
{
3636
private const string JavaScriptResourcePath = "Resources.JavaScripts";
3737
private const string JavaScriptFileExtension = "js";
38-
38+
3939
public static string GetScript(this JavaScript javaScript)
4040
{
4141
return javaScript.GetResourcePath().GetScript();

Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/JsActions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using Aquality.Selenium.Elements.Interfaces;
2-
using System;
1+
using System;
2+
using Aquality.Selenium.Elements.Interfaces;
33

44
namespace Aquality.Selenium.Elements.Actions
55
{

Aquality.Selenium/src/Aquality.Selenium/Elements/Actions/MouseActions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using Aquality.Selenium.Elements.Interfaces;
2-
using System;
1+
using System;
2+
using Aquality.Selenium.Elements.Interfaces;
33

44
namespace Aquality.Selenium.Elements.Actions
55
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Aquality.Selenium.Elements
2+
{
3+
internal class PopularClassNames
4+
{
5+
private PopularClassNames()
6+
{
7+
}
8+
9+
public const string Disabled = "disabled";
10+
}
11+
12+
internal class Attributes
13+
{
14+
private Attributes()
15+
{
16+
}
17+
18+
public const string Class = "class";
19+
}
20+
}
Lines changed: 79 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
1-
using Aquality.Selenium.Elements.Actions;
2-
using Aquality.Selenium.Elements.Interfaces;
1+
using System;
32
using OpenQA.Selenium;
43
using OpenQA.Selenium.Remote;
5-
using System;
4+
using Aquality.Selenium.Browsers;
5+
using Aquality.Selenium.Elements.Actions;
6+
using Aquality.Selenium.Elements.Interfaces;
7+
using Aquality.Selenium.Logging;
8+
using Aquality.Selenium.Waitings;
69

710
namespace Aquality.Selenium.Elements
811
{
912
public abstract class Element : IElement
1013
{
14+
private readonly Logger logger = Logger.Instance;
15+
1116
protected Element(By locator, string name, ElementState state)
1217
{
1318
Locator = locator;
1419
Name = name;
20+
ElementState = state;
1521
}
1622

1723
public By Locator { get; }
1824

1925
public string Name { get; }
2026

27+
public ElementState ElementState { get; }
28+
2129
protected abstract string ElementType { get; }
2230

2331
public JsActions JsActions => new JsActions(this, ElementType);
@@ -26,79 +34,121 @@ protected Element(By locator, string name, ElementState state)
2634

2735
public IElementStateProvider State => new ElementStateProvider(Locator);
2836

37+
private Browser Browser => BrowserManager.Browser;
38+
39+
private IElementFinder Finder => ElementFinder.Instance;
40+
41+
private IElementFactory ElementFactory => new ElementFactory();
42+
2943
public bool IsEnabled(TimeSpan? timeout = null)
3044
{
31-
throw new NotImplementedException();
45+
bool isElementEnabled(IWebElement element) => element.Enabled && !element.GetAttribute(Attributes.Class).Contains(PopularClassNames.Disabled);
46+
return Finder.FindElements(Locator, isElementEnabled, timeout).Count != 0;
3247
}
3348

3449
public RemoteWebElement GetElement(TimeSpan? timeout = null)
3550
{
36-
throw new NotImplementedException();
51+
try
52+
{
53+
return (RemoteWebElement)Finder.FindElement(Locator, ElementState, timeout);
54+
}
55+
catch (NoSuchElementException ex)
56+
{
57+
logger.Debug($"Page source:{Environment.NewLine}{Browser.Driver.PageSource}");
58+
throw ex;
59+
}
3760
}
3861

39-
public void Click()
62+
public void ClickAndWait()
4063
{
41-
throw new NotImplementedException();
64+
Click();
65+
Browser.WaitForPageToLoad();
4266
}
4367

44-
public void ClickAndWait()
68+
public void WaitAndClick()
4569
{
46-
throw new NotImplementedException();
70+
WaitForElementIsClickable();
71+
Click();
4772
}
4873

49-
public void RightClick()
74+
public void Click()
5075
{
51-
throw new NotImplementedException();
76+
logger.InfoLoc("loc.clicking");
77+
JsActions.HighlightElement();
78+
ConditionalWait.WaitFor(driver =>
79+
{
80+
GetElement().Click();
81+
return true;
82+
});
5283
}
5384

54-
public void WaitAndClick()
85+
public void RightClick()
5586
{
56-
throw new NotImplementedException();
87+
logger.InfoLoc("loc.clicking.right");
88+
ConditionalWait.WaitFor(driver =>
89+
{
90+
var element = GetElement();
91+
new OpenQA.Selenium.Interactions.Actions(driver).MoveToElement(element).ContextClick(element).Build().Perform();
92+
return true;
93+
});
5794
}
5895

5996
public void Focus()
6097
{
61-
throw new NotImplementedException();
98+
JsActions.SetFocus();
6299
}
63100

64101
public string GetAttribute(string attr, HighlightState highlightState = HighlightState.NotHighlight, TimeSpan? timeout = null)
65102
{
66-
throw new NotImplementedException();
103+
logger.InfoLoc("loc.el.getattr", attr);
104+
HighlightElement(highlightState);
105+
return ConditionalWait.WaitFor(driver => GetElement(timeout).GetAttribute(attr), timeout);
67106
}
68107

69108
public string GetText(HighlightState highlightState = HighlightState.NotHighlight)
70109
{
71-
throw new NotImplementedException();
110+
logger.InfoLoc("loc.get.text");
111+
HighlightElement(highlightState);
112+
return ConditionalWait.WaitFor(driver => GetElement().Text);
72113
}
73114

74-
public void SendKeys(string key)
115+
private void HighlightElement(HighlightState highlightState)
75116
{
76-
throw new NotImplementedException();
117+
if (highlightState.Equals(HighlightState.Highlight))
118+
{
119+
JsActions.HighlightElement();
120+
}
77121
}
78122

79-
public void SetInnerHtml(string value)
123+
public void SendKeys(string key)
80124
{
81-
throw new NotImplementedException();
125+
ConditionalWait.WaitFor(driver =>
126+
{
127+
GetElement().SendKeys(key);
128+
return true;
129+
});
82130
}
83131

84-
public void WaitForElementIsClickable(TimeSpan? timeout = null)
132+
public void SetInnerHtml(string value)
85133
{
86-
throw new NotImplementedException();
134+
Click();
135+
logger.InfoLoc("loc.send.text", value);
136+
Browser.ExecuteScript(JavaScript.SetInnerHTML, GetElement(), value);
87137
}
88138

89-
public T FindChildElement<T>(By childLocator, ElementState state = ElementState.Displayed) where T : IElement
139+
public void WaitForElementIsClickable(TimeSpan? timeout = null)
90140
{
91-
throw new NotImplementedException();
141+
Finder.FindElements(Locator, element => element.Displayed && element.Enabled, timeout);
92142
}
93-
94-
public T FindChildElement<T>(By childLocator, ElementSupplier<T> supplier, ElementState state = ElementState.Displayed) where T : IElement
143+
144+
public T FindChildElement<T>(By childLocator, ElementSupplier<T> supplier = null, ElementState state = ElementState.Displayed) where T : IElement
95145
{
96-
throw new NotImplementedException();
146+
return ElementFactory.FindChildElement(this, childLocator, supplier, state);
97147
}
98148

99-
public bool HasState(PopularClassNames className)
149+
public bool ContainsClassAttribute(string className)
100150
{
101-
throw new NotImplementedException();
151+
return GetAttribute(Attributes.Class).Contains(className.ToLower());
102152
}
103153
}
104154
}

Aquality.Selenium/src/Aquality.Selenium/Elements/ElementFactory.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class ElementFactory : IElementFactory
1616
{
1717
private static readonly string ByXpathIdentifier = "By.XPath";
1818

19+
private Browser Browser => BrowserManager.Browser;
20+
1921
public IButton GetButton(By locator, string name, ElementState state = ElementState.Displayed)
2022
{
2123
return new Button(locator, name, state);
@@ -76,7 +78,7 @@ public IList<T> FindElements<T>(By locator, ElementSupplier<T> supplier = null,
7678
throw new ArgumentOutOfRangeException($"No such expected value: {expectedCount}");
7779
}
7880

79-
var webElements = GetBrowser().Driver.FindElements(locator);
81+
var webElements = Browser.Driver.FindElements(locator);
8082
IEnumerable<T> elements = webElements.Select((webElement, index) =>
8183
{
8284
var elementIndex = index + 1;
@@ -90,18 +92,13 @@ private By GenerateXpathLocator(By baseLocator, IWebElement webElement, int elem
9092
var strBaseLocator = baseLocator.ToString();
9193
var elementLocator = strBaseLocator.Contains(ByXpathIdentifier)
9294
? $"({strBaseLocator.Split(':')[1].Trim()})[{elementIndex}]"
93-
: GetBrowser().ExecuteScript<string>(JavaScript.GetElementXPath, webElement);
95+
: Browser.ExecuteScript<string>(JavaScript.GetElementXPath, webElement);
9496
return By.XPath(elementLocator);
9597
}
9698

9799
private ElementSupplier<T> ResolveSupplier<T>(ElementSupplier<T> supplier) where T : IElement
98100
{
99101
return supplier ?? ((locator, name, state) => (T)Activator.CreateInstance(typeof(T), locator, name, state));
100102
}
101-
102-
private Browser GetBrowser()
103-
{
104-
return BrowserManager.Browser;
105-
}
106103
}
107104
}

Aquality.Selenium/src/Aquality.Selenium/Elements/ElementFinder.cs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,73 +27,66 @@ public static ElementFinder Instance
2727
{
2828
InstanceHolder.Value = new ElementFinder();
2929
}
30-
3130
return InstanceHolder.Value;
3231
}
3332
}
3433

3534
private ITimeoutConfiguration TimeoutConfiguration => Configuration.Instance.TimeoutConfiguration;
3635

37-
private TimeSpan DefaultTimeout => TimeoutConfiguration.Condition;
38-
3936
private Browser Browser => BrowserManager.Browser;
4037

41-
public IWebElement FindElement(By locator, TimeSpan? timeout = null, ElementState state = ElementState.ExistsInAnyState)
38+
public IWebElement FindElement(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
4239
{
43-
var clearTimeout = timeout ?? DefaultTimeout;
44-
var elements = FindElements(locator, clearTimeout, state);
40+
var elementStateCondition = ResolveState(state);
41+
return FindElement(locator, elementStateCondition, timeout);
42+
}
43+
44+
public IWebElement FindElement(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
45+
{
46+
var clearTimeout = timeout ?? TimeoutConfiguration.Condition;
47+
var elements = FindElements(locator, elementStateCondition, clearTimeout);
4548
if (elements.Any())
4649
{
4750
return elements.First();
4851
}
49-
50-
throw new NoSuchElementException($"Element was not found in {clearTimeout.Seconds} seconds in state {state} by locator {locator}");
52+
throw new NoSuchElementException($"Element was not found in desired state in {clearTimeout.Seconds} seconds by locator {locator}");
5153
}
5254

53-
public IWebElement FindElement(By by)
55+
public ReadOnlyCollection<IWebElement> FindElements(By locator, ElementState state = ElementState.ExistsInAnyState, TimeSpan? timeout = null)
5456
{
55-
return FindElement(by, timeout: null);
57+
var elementStateCondition = ResolveState(state);
58+
return FindElements(locator, elementStateCondition, timeout);
5659
}
5760

58-
public ReadOnlyCollection<IWebElement> FindElements(By locator, TimeSpan? timeout = null, ElementState state = ElementState.ExistsInAnyState)
61+
public ReadOnlyCollection<IWebElement> FindElements(By locator, Func<IWebElement, bool> elementStateCondition, TimeSpan? timeout = null)
5962
{
60-
var resultElements = new List<IWebElement>();
6163
Browser.ImplicitWaitTimeout = TimeSpan.Zero;
64+
var resultElements = new List<IWebElement>();
6265
ConditionalWait.WaitForTrue(driver =>
6366
{
64-
var foundElements = driver.FindElements(locator);
65-
var filteredElements = FilterByState(foundElements, state);
66-
resultElements.AddRange(filteredElements);
67-
return filteredElements.Any();
68-
}, timeout ?? DefaultTimeout);
67+
var elements = driver.FindElements(locator).Where(elementStateCondition);
68+
resultElements.AddRange(elements);
69+
return elements.Any();
70+
}, timeout);
6971
Browser.ImplicitWaitTimeout = TimeoutConfiguration.Implicit;
70-
return resultElements.ToList().AsReadOnly();
72+
return resultElements.AsReadOnly();
7173
}
7274

73-
private IList<IWebElement> FilterByState(IList<IWebElement> foundElements, ElementState state)
75+
private Func<IWebElement, bool> ResolveState(ElementState state)
7476
{
75-
var filteredElements = new List<IWebElement>();
76-
if (foundElements.Any())
77+
Func<IWebElement, bool> elementStateCondition;
78+
switch (state)
7779
{
78-
switch (state)
79-
{
80-
case ElementState.Displayed:
81-
filteredElements.AddRange(foundElements.Where(element => element.Displayed));
82-
break;
83-
case ElementState.ExistsInAnyState:
84-
filteredElements.AddRange(foundElements);
85-
break;
86-
default:
87-
throw new InvalidOperationException($"{state} state is not recognized");
88-
}
80+
case ElementState.Displayed:
81+
elementStateCondition = element => element.Displayed;
82+
break;
83+
case ElementState.ExistsInAnyState:
84+
elementStateCondition = element => true;
85+
break;
86+
default:
87+
throw new InvalidOperationException($"{state} state is not recognized");
8988
}
90-
91-
return filteredElements;
92-
}
93-
94-
public ReadOnlyCollection<IWebElement> FindElements(By by)
95-
{
96-
return FindElements(by, timeout: null);
89+
return elementStateCondition;
9790
}
9891
}
9992
}

Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/IComboBox.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using Aquality.Selenium.Elements.Actions;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using Aquality.Selenium.Elements.Actions;
33

44
namespace Aquality.Selenium.Elements.Interfaces
55
{

Aquality.Selenium/src/Aquality.Selenium/Elements/Interfaces/IElement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using Aquality.Selenium.Elements.Actions;
1+
using System;
22
using OpenQA.Selenium;
33
using OpenQA.Selenium.Remote;
4-
using System;
4+
using Aquality.Selenium.Elements.Actions;
55

66
namespace Aquality.Selenium.Elements.Interfaces
77
{

0 commit comments

Comments
 (0)