Skip to content

Commit

Permalink
Fixed CachedElementStateProvider behaviour: IsEnabled and related fun…
Browse files Browse the repository at this point in the history
…ctions should throw NoSuchElementException (#77)

* Fixed CachedElementStateProvider behaviour:
IsEnabled and related functions should throw NoSuchElementException when the element is absent.
Fixes #57, #62
  • Loading branch information
mialeska authored Jun 24, 2020
1 parent e2adab1 commit b7d429a
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ public CachedElementStateProvider(By locator, IConditionalWait conditionalWait,

protected virtual IList<Type> HandledExceptions => new List<Type> { typeof(StaleElementReferenceException), typeof(NoSuchElementException) };

protected virtual bool TryInvokeFunction(Func<IWebElement, bool> func)
protected virtual bool TryInvokeFunction(Func<IWebElement, bool> func, IList<Type> exceptionsToHandle = null)
{
var handledExceptions = exceptionsToHandle ?? HandledExceptions;
try
{
return func(elementCacheHandler.GetElement(TimeSpan.Zero, ElementState.ExistsInAnyState));
}
catch (Exception e)
{
if (HandledExceptions.Any(type => type.IsAssignableFrom(e.GetType())))
if (handledExceptions.Any(type => type.IsAssignableFrom(e.GetType())))
{
return false;
}
Expand All @@ -46,7 +47,7 @@ protected virtual bool TryInvokeFunction(Func<IWebElement, bool> func)

public virtual bool IsClickable => TryInvokeFunction(element => element.Displayed && element.Enabled);

public virtual bool IsEnabled => TryInvokeFunction(element => element.Enabled);
public virtual bool IsEnabled => TryInvokeFunction(element => element.Enabled, new[] { typeof(StaleElementReferenceException) });

public virtual void WaitForClickable(TimeSpan? timeout = null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ private static readonly Func<IElementStateProvider, bool>[] StateFunctionsTrueWh
state => !state.WaitForNotEnabled(TimeSpan.Zero),
};

private static readonly Func<IElementStateProvider, bool>[] StateFunctionsThrowNoSuchElementException
= new Func<IElementStateProvider, bool>[]
{
state => state.IsEnabled,
state => state.WaitForEnabled(TimeSpan.Zero),
state => !state.WaitForNotEnabled(TimeSpan.Zero),
};

private IConditionalWait ConditionalWait => AqualityServices.ServiceProvider.GetRequiredService<IConditionalWait>();

[SetUp]
Expand Down Expand Up @@ -108,30 +116,35 @@ public void Should_RefreshElement_WhenItIsStale()
}

[Test]
[Ignore("Tests should be updated: find out more stable example")]
public void Should_ReturnCorrectState_False_WhenWindowIsRefreshed([ValueSource(nameof(StateFunctionsFalseWhenElementStale))] Func<IElementStateProvider, bool> stateCondition)
public void Should_ThrowNoSuchElementException_ForAbsentElement([ValueSource(nameof(StateFunctionsThrowNoSuchElementException))] Func<IElementStateProvider, bool> stateCondition)
{
var label = new Label(By.Name("Absent element"), "Absent element", ElementState.Displayed);
Assert.Throws<NoSuchElementException>(() => stateCondition.Invoke(label.State));
}

[Test]
public void Should_ReturnCorrectState_False_WhenWindowIsReopened([ValueSource(nameof(StateFunctionsFalseWhenElementStale))] Func<IElementStateProvider, bool> stateCondition)
{
AssertStateConditionAfterRefresh(stateCondition, expectedValue: false);
AssertStateConditionAfterReopen(stateCondition, expectedValue: false);
}

[Test]
[Ignore("Tests should be updated: find out more stable example")]
public void Should_ReturnCorrectState_True_WhenWindowIsRefreshed([ValueSource(nameof(StateFunctionsTrueWhenElementStaleWhichRetriveElement))] Func<IElementStateProvider, bool> stateCondition)
public void Should_ReturnCorrectState_True_WhenWindowIsReopened([ValueSource(nameof(StateFunctionsTrueWhenElementStaleWhichRetriveElement))] Func<IElementStateProvider, bool> stateCondition)
{
AssertStateConditionAfterRefresh(stateCondition, expectedValue: true);
AssertStateConditionAfterReopen(stateCondition, expectedValue: true);
}

private void AssertStateConditionAfterRefresh(Func<IElementStateProvider, bool> stateCondition, bool expectedValue)
private void AssertStateConditionAfterReopen(Func<IElementStateProvider, bool> stateCondition, bool expectedValue)
{
OpenDynamicContent();
var testElement = new Label(ContentLoc, "Example", ElementState.ExistsInAnyState);
testElement.State.WaitForClickable();
new Label(RemoveButtonLoc, "Remove", ElementState.Displayed).Click();
ConditionalWait.WaitForTrue(() => testElement.Cache.IsStale, message: "Element should be stale when it disappeared.");
AqualityServices.Application.Driver.Navigate().Refresh();
Assert.IsTrue(testElement.Cache.IsStale, "Element should remain stale after the page refresh.");
AqualityServices.Application.Quit();
StartLoading();
ConditionalWait.WaitForTrue(() => testElement.Cache.IsStale, message: "Element should be stale after page is closed.");
OpenDynamicContent();
Assert.AreEqual(expectedValue, stateCondition(testElement.State),
"Element state condition is not expected after refreshing the window");
"Element state condition is not expected after reopening the window");
}

[TearDown]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Aquality.Selenium.Core.Tests.Applications.WindowsApp.Locators;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using OpenQA.Selenium;
using System;

namespace Aquality.Selenium.Core.Tests.Applications.WindowsApp
Expand Down Expand Up @@ -33,6 +34,14 @@ private static readonly Func<IElementStateProvider, bool>[] StateFunctionsTrueWh
state => !state.WaitForNotEnabled(TimeSpan.Zero),
};

private static readonly Func<IElementStateProvider, bool>[] StateFunctionsThrowNoSuchElementException
= new Func<IElementStateProvider, bool>[]
{
state => state.IsEnabled,
state => state.WaitForEnabled(TimeSpan.Zero),
state => !state.WaitForNotEnabled(TimeSpan.Zero),
};

[SetUp]
public void SetUp()
{
Expand Down Expand Up @@ -85,6 +94,13 @@ public void Should_ReturnNewElement_WhenWindowIsReopened()
Assert.AreNotEqual(initialElement, resultElement, errorMessage);
}

[Test]
public void Should_ThrowNoSuchElementException_ForAbsentElement([ValueSource(nameof(StateFunctionsThrowNoSuchElementException))] Func<IElementStateProvider, bool> stateCondition)
{
var button = Factory.GetButton(CalculatorWindow.AbsentElement, "Absent element");
Assert.Throws<NoSuchElementException>(() => stateCondition.Invoke(button.State));
}

[Test]
public void Should_ReturnCorrectState_WhenWindowIsClosed([ValueSource(nameof(StateFunctionsFalseWhenElementStale))] Func<IElementStateProvider, bool> stateCondition)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ public static class CalculatorWindow
public static By ResultsLabel => MobileBy.AccessibilityId("48");

public static By EmptyButton => By.XPath("//*[@AutomationId='7']");

public static By AbsentElement => By.Name("Absent element");
}
}

0 comments on commit b7d429a

Please sign in to comment.