Skip to content

Commit db30415

Browse files
authored
Feature/38 enhance element property getters logging (#54)
* Added logPageSource parameter to settings * Added logging of values for getAttribute() and getText() of Element * Enhanced LocalizationManager to get value from core if the key is missed in passed assembly * Added logging to ElementStateProviders' waiting functions
1 parent fc42830 commit db30415

26 files changed

+352
-52
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.aquality-automation</groupId>
88
<artifactId>aquality-selenium-core</artifactId>
9-
<version>1.1.0</version>
9+
<version>1.2.0</version>
1010

1111
<packaging>jar</packaging>
1212
<name>Aquality Selenium Core</name>

src/main/java/aquality/selenium/core/configurations/ILoggerConfiguration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ public interface ILoggerConfiguration {
1010
* @return language used for logging.
1111
*/
1212
String getLanguage();
13+
14+
/**
15+
* Perform page source logging in case of catastrophic failures or not.
16+
* @return true if enabled, false otherwise.
17+
*/
18+
boolean logPageSource();
1319
}

src/main/java/aquality/selenium/core/configurations/LoggerConfiguration.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@
66
public class LoggerConfiguration implements ILoggerConfiguration {
77

88
private static final String DEFAULT_LANGUAGE = "en";
9-
private final ISettingsFile settingsFile;
9+
private final String language;
10+
private final boolean doLogPageSource;
1011

1112
@Inject
1213
public LoggerConfiguration(ISettingsFile settingsFile){
13-
this.settingsFile = settingsFile;
14+
language = settingsFile.getValueOrDefault("/logger/language", DEFAULT_LANGUAGE).toString();
15+
doLogPageSource = Boolean.parseBoolean(
16+
settingsFile.getValueOrDefault("/logger/logPageSource", true).toString());
1417
}
1518

1619
@Override
1720
public String getLanguage() {
18-
return settingsFile.getValueOrDefault("/logger/language", DEFAULT_LANGUAGE).toString();
21+
return language;
22+
}
23+
24+
@Override
25+
public boolean logPageSource() {
26+
return doLogPageSource;
1927
}
2028
}

src/main/java/aquality/selenium/core/elements/CachedElementStateProvider.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package aquality.selenium.core.elements;
22

33
import aquality.selenium.core.elements.interfaces.IElementCacheHandler;
4-
import aquality.selenium.core.localization.ILocalizedLogger;
4+
import aquality.selenium.core.elements.interfaces.ILogElementState;
55
import aquality.selenium.core.waitings.IConditionalWait;
66
import org.openqa.selenium.By;
77
import org.openqa.selenium.NoSuchElementException;
@@ -24,13 +24,13 @@ public class CachedElementStateProvider extends ElementStateProvider {
2424
private final By locator;
2525
private final IConditionalWait conditionalWait;
2626
private final IElementCacheHandler elementCacheHandler;
27-
private final ILocalizedLogger localizedLogger;
2827

29-
public CachedElementStateProvider(By locator, IConditionalWait conditionalWait, IElementCacheHandler elementCacheHandler, ILocalizedLogger localizedLogger) {
28+
public CachedElementStateProvider(By locator, IConditionalWait conditionalWait,
29+
IElementCacheHandler elementCacheHandler, ILogElementState logger) {
30+
super(logger);
3031
this.locator = locator;
3132
this.conditionalWait = conditionalWait;
3233
this.elementCacheHandler = elementCacheHandler;
33-
this.localizedLogger = localizedLogger;
3434
}
3535

3636
protected List<Class<? extends Exception>> getHandledExceptions() {
@@ -52,11 +52,11 @@ protected boolean tryInvokeFunction(Predicate<WebElement> predicate, List<Class<
5252
}
5353
}
5454

55-
protected boolean waitForCondition(BooleanSupplier condition, String conditionName, Duration timeout) {
55+
protected boolean waitForCondition(BooleanSupplier condition, String conditionKeyPart, Duration timeout) {
56+
logElementState("loc.wait.for.state", conditionKeyPart);
5657
boolean result = conditionalWait.waitFor(condition, timeout);
5758
if (!result) {
58-
String timeoutString = timeout == null ? "" : String.format("%1$s s.", timeout.getSeconds());
59-
localizedLogger.warn("loc.element.not.in.state", locator, conditionName.toUpperCase(), timeoutString);
59+
logElementState("loc.wait.for.state.failed", conditionKeyPart);
6060
}
6161
return result;
6262
}
@@ -69,10 +69,12 @@ public boolean isClickable() {
6969
@Override
7070
public void waitForClickable(Duration timeout) {
7171
String errorMessage = String.format("Element %1$s has not become clickable after timeout.", locator);
72+
String conditionKeyPart = elementClickable().getStateName();
7273
try {
74+
logElementState("loc.wait.for.state", conditionKeyPart);
7375
conditionalWait.waitForTrue(this::isClickable, timeout, null, errorMessage);
7476
} catch (TimeoutException e) {
75-
localizedLogger.error("loc.element.not.in.state", elementClickable().getStateName(), ". ".concat(e.getMessage()));
77+
logElementState("loc.wait.for.state.failed", conditionKeyPart);
7678
throw new org.openqa.selenium.TimeoutException(e.getMessage(), e);
7779
}
7880
}
@@ -84,12 +86,12 @@ public boolean isDisplayed() {
8486

8587
@Override
8688
public boolean waitForDisplayed(Duration timeout) {
87-
return waitForCondition(() -> tryInvokeFunction(WebElement::isDisplayed), ElementState.DISPLAYED.toString(), timeout);
89+
return waitForCondition(() -> tryInvokeFunction(WebElement::isDisplayed), "displayed", timeout);
8890
}
8991

9092
@Override
9193
public boolean waitForNotDisplayed(Duration timeout) {
92-
return waitForCondition(() -> !isDisplayed(), "invisible or absent", timeout);
94+
return waitForCondition(() -> !isDisplayed(), "not.displayed", timeout);
9395
}
9496

9597
@Override
@@ -99,12 +101,12 @@ public boolean isExist() {
99101

100102
@Override
101103
public boolean waitForExist(Duration timeout) {
102-
return waitForCondition(() -> tryInvokeFunction(element -> true), ElementState.EXISTS_IN_ANY_STATE.toString(), timeout);
104+
return waitForCondition(() -> tryInvokeFunction(element -> true), "exist", timeout);
103105
}
104106

105107
@Override
106108
public boolean waitForNotExist(Duration timeout) {
107-
return waitForCondition(() -> !isExist(), "absent", timeout);
109+
return waitForCondition(() -> !isExist(), "not.exist", timeout);
108110
}
109111

110112
@Override

src/main/java/aquality/selenium/core/elements/DefaultElementStateProvider.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package aquality.selenium.core.elements;
22

33
import aquality.selenium.core.elements.interfaces.IElementFinder;
4+
import aquality.selenium.core.elements.interfaces.ILogElementState;
45
import aquality.selenium.core.waitings.IConditionalWait;
56
import org.openqa.selenium.By;
67

78
import java.time.Duration;
9+
import java.util.function.BooleanSupplier;
810

911
public class DefaultElementStateProvider extends ElementStateProvider {
1012

1113
private final By locator;
1214
private final IConditionalWait conditionalWait;
1315
private final IElementFinder elementFinder;
1416

15-
public DefaultElementStateProvider(By locator, IConditionalWait conditionalWait, IElementFinder elementFinder) {
17+
public DefaultElementStateProvider(By locator, IConditionalWait conditionalWait, IElementFinder elementFinder,
18+
ILogElementState logger) {
19+
super(logger);
1620
this.locator = locator;
1721
this.conditionalWait = conditionalWait;
1822
this.elementFinder = elementFinder;
@@ -25,7 +29,12 @@ public boolean isClickable() {
2529

2630
@Override
2731
public void waitForClickable(Duration timeout) {
28-
waitForIsClickable(timeout, false);
32+
try {
33+
waitForIsClickable(timeout, false);
34+
} catch (Exception e) {
35+
logElementState("loc.wait.for.state.failed", elementClickable().getStateName());
36+
throw e;
37+
}
2938
}
3039

3140
private boolean waitForIsClickable(Duration timeout, boolean catchTimeoutException) {
@@ -35,7 +44,10 @@ private boolean waitForIsClickable(Duration timeout, boolean catchTimeoutExcepti
3544
}
3645

3746
private boolean isElementInDesiredCondition(DesiredState elementStateCondition, Duration timeout) {
38-
return !elementFinder.findElements(locator, elementStateCondition, timeout).isEmpty();
47+
return doAndLogWaitForState(
48+
() -> !elementFinder.findElements(locator, elementStateCondition, timeout).isEmpty(),
49+
elementStateCondition.getStateName(),
50+
timeout);
3951
}
4052

4153
@Override
@@ -45,7 +57,10 @@ public boolean isDisplayed() {
4557

4658
@Override
4759
public boolean waitForDisplayed(Duration timeout) {
48-
return isAnyElementFound(timeout, ElementState.DISPLAYED);
60+
return doAndLogWaitForState(
61+
() -> isAnyElementFound(timeout, ElementState.DISPLAYED),
62+
"displayed",
63+
timeout);
4964
}
5065

5166
private boolean isAnyElementFound(Duration timeout, ElementState state) {
@@ -54,7 +69,10 @@ private boolean isAnyElementFound(Duration timeout, ElementState state) {
5469

5570
@Override
5671
public boolean waitForNotDisplayed(Duration timeout) {
57-
return conditionalWait.waitFor(() -> !isDisplayed(), timeout);
72+
return doAndLogWaitForState(
73+
() -> conditionalWait.waitFor(() -> !isDisplayed(), timeout),
74+
"not.displayed",
75+
timeout);
5876
}
5977

6078
@Override
@@ -64,12 +82,18 @@ public boolean isExist() {
6482

6583
@Override
6684
public boolean waitForExist(Duration timeout) {
67-
return isAnyElementFound(timeout, ElementState.EXISTS_IN_ANY_STATE);
85+
return doAndLogWaitForState(
86+
() -> isAnyElementFound(timeout, ElementState.EXISTS_IN_ANY_STATE),
87+
"exist",
88+
timeout);
6889
}
6990

7091
@Override
7192
public boolean waitForNotExist(Duration timeout) {
72-
return conditionalWait.waitFor(() -> !isExist(), timeout);
93+
return doAndLogWaitForState(
94+
() -> conditionalWait.waitFor(() -> !isExist(), timeout),
95+
"not.exist",
96+
timeout);
7397
}
7498

7599
@Override
@@ -86,4 +110,21 @@ public boolean waitForEnabled(Duration timeout) {
86110
public boolean waitForNotEnabled(Duration timeout) {
87111
return isElementInDesiredCondition(elementNotEnabled(), timeout);
88112
}
113+
114+
private boolean doAndLogWaitForState(BooleanSupplier waitingAction, String conditionKeyPart, Duration timeout)
115+
{
116+
if (Duration.ZERO.equals(timeout))
117+
{
118+
return waitingAction.getAsBoolean();
119+
}
120+
121+
logElementState("loc.wait.for.state", conditionKeyPart);
122+
boolean result = waitingAction.getAsBoolean();
123+
if (!result)
124+
{
125+
logElementState("loc.wait.for.state.failed", conditionKeyPart);
126+
}
127+
128+
return result;
129+
}
89130
}

src/main/java/aquality/selenium/core/elements/Element.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import aquality.selenium.core.applications.IApplication;
44
import aquality.selenium.core.configurations.IElementCacheConfiguration;
5+
import aquality.selenium.core.configurations.ILoggerConfiguration;
56
import aquality.selenium.core.elements.interfaces.*;
7+
import aquality.selenium.core.localization.ILocalizationManager;
68
import aquality.selenium.core.localization.ILocalizedLogger;
79
import aquality.selenium.core.logging.Logger;
810
import aquality.selenium.core.utilities.IElementActionRetrier;
@@ -41,6 +43,8 @@ protected Element(final By loc, final String name, final ElementState state) {
4143

4244
protected abstract ILocalizedLogger getLocalizedLogger();
4345

46+
protected abstract ILocalizationManager getLocalizationManager();
47+
4448
protected abstract IConditionalWait getConditionalWait();
4549

4650
protected abstract String getElementType();
@@ -53,10 +57,19 @@ protected IElementCacheHandler getCache() {
5357
return elementCacheHandler;
5458
}
5559

60+
protected ILoggerConfiguration getLoggerConfiguration() {
61+
return getLocalizedLogger().getConfiguration();
62+
}
63+
5664
protected Logger getLogger() {
5765
return Logger.getInstance();
5866
}
5967

68+
protected ILogElementState logElementState() {
69+
return ((messageKey, stateKey) -> getLocalizedLogger().infoElementAction(getElementType(), getName(), messageKey,
70+
getLocalizationManager().getLocalizedMessage(stateKey)));
71+
}
72+
6073
@Override
6174
public By getLocator() {
6275
return locator;
@@ -70,8 +83,8 @@ public String getName() {
7083
@Override
7184
public IElementStateProvider state() {
7285
return getElementCacheConfiguration().isEnabled()
73-
? new CachedElementStateProvider(locator, getConditionalWait(), getCache(), getLocalizedLogger())
74-
: new DefaultElementStateProvider(locator, getConditionalWait(), getElementFinder());
86+
? new CachedElementStateProvider(locator, getConditionalWait(), getCache(), logElementState())
87+
: new DefaultElementStateProvider(locator, getConditionalWait(), getElementFinder(), logElementState());
7588
}
7689

7790
@Override
@@ -81,7 +94,9 @@ public RemoteWebElement getElement(Duration timeout) {
8194
? getCache().getElement(timeout)
8295
: (RemoteWebElement) getElementFinder().findElement(locator, elementState, timeout);
8396
} catch (NoSuchElementException e) {
84-
logPageSource(e);
97+
if (getLoggerConfiguration().logPageSource()) {
98+
logPageSource(e);
99+
}
85100
throw e;
86101
}
87102
}
@@ -98,13 +113,17 @@ protected void logPageSource(WebDriverException exception) {
98113
@Override
99114
public String getText() {
100115
logElementAction("loc.get.text");
101-
return doWithRetry(() -> getElement().getText());
116+
String value = doWithRetry(() -> getElement().getText());
117+
logElementAction("loc.text.value", value);
118+
return value;
102119
}
103120

104121
@Override
105122
public String getAttribute(String attr) {
106123
logElementAction("loc.el.getattr", attr);
107-
return doWithRetry(() -> getElement().getAttribute(attr));
124+
String value = doWithRetry(() -> getElement().getAttribute(attr));
125+
logElementAction("loc.el.attr.value", attr, value);
126+
return value;
108127
}
109128

110129
@Override
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
11
package aquality.selenium.core.elements;
22

33
import aquality.selenium.core.elements.interfaces.IElementStateProvider;
4+
import aquality.selenium.core.elements.interfaces.ILogElementState;
45
import org.openqa.selenium.WebElement;
56

67
public abstract class ElementStateProvider implements IElementStateProvider {
78

9+
private final ILogElementState logger;
10+
11+
protected ElementStateProvider(ILogElementState logger) {
12+
this.logger = logger;
13+
}
14+
15+
protected void logElementState(String messageKey, String conditionKeyPart) {
16+
String conditionKey = "loc.el.state.".concat(conditionKeyPart);
17+
logger.logElementState(messageKey, conditionKey);
18+
}
19+
820
protected boolean isElementEnabled(WebElement element) {
921
return element.isEnabled();
1022
}
1123

1224
protected DesiredState elementEnabled() {
13-
return new DesiredState(this::isElementEnabled, "ENABLED")
25+
return new DesiredState(this::isElementEnabled, "enabled")
1426
.withCatchingTimeoutException()
1527
.withThrowingNoSuchElementException();
1628
}
1729

1830
protected DesiredState elementNotEnabled() {
19-
return new DesiredState(element -> !isElementEnabled(element), "NOT ENABLED")
31+
return new DesiredState(element -> !isElementEnabled(element), "not.enabled")
2032
.withCatchingTimeoutException()
2133
.withThrowingNoSuchElementException();
2234
}
2335

2436
protected DesiredState elementClickable() {
25-
return new DesiredState(webElement -> webElement.isDisplayed() && webElement.isEnabled(), "CLICKABLE");
37+
return new DesiredState(webElement -> webElement.isDisplayed() && webElement.isEnabled(), "clickable");
2638
}
2739
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package aquality.selenium.core.elements.interfaces;
2+
3+
/**
4+
* Describes interface that can log element state.
5+
*/
6+
public interface ILogElementState {
7+
/**
8+
* Logs element state.
9+
* @param messageKey key of localized message to log.
10+
* @param stateKey key of localized state to log.
11+
*/
12+
void logElementState(String messageKey, String stateKey);
13+
}

0 commit comments

Comments
 (0)