package org.fluentlenium.core.hook;
import org.assertj.core.api.Assertions;
import org.fluentlenium.adapter.FluentAdapter;
import org.fluentlenium.core.FluentControl;
import org.fluentlenium.core.components.ComponentInstantiator;
import org.fluentlenium.core.components.DefaultComponentInstantiator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class DefaultHookChainBuilderTest {
@Mock
private WebElement element;
@Mock
private ElementLocator locator;
@Mock
private WebDriver webDriver;
private ComponentInstantiator instantiator;
private HookChainBuilder hookChainBuilder;
private FluentAdapter fluentAdapter;
@Before
public void before() {
fluentAdapter = new FluentAdapter();
fluentAdapter.initFluent(webDriver);
instantiator = new DefaultComponentInstantiator(fluentAdapter);
hookChainBuilder = new DefaultHookChainBuilder(fluentAdapter, instantiator) {
@Override
protected FluentHook<?> newInstance(Class<? extends FluentHook<?>> hookClass, FluentControl fluentControl,
ComponentInstantiator instantiator, Supplier<WebElement> elementSupplier,
Supplier<ElementLocator> locatorSupplier, Supplier<String> toStringSupplier, Object options)
throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
return spy(super.newInstance(hookClass, fluentControl, instantiator, elementSupplier, locatorSupplier,
toStringSupplier, options));
}
};
}
@Test
public void testBuildHook() {
List<HookDefinition<?>> hookDefinitions = new ArrayList<>();
hookDefinitions.add(new HookDefinition<>(NanoHook.class));
hookDefinitions.add(new HookDefinition<>(NanoHook.class, new NanoHookOptions("option")));
hookDefinitions.add(new HookDefinition<>(NanoHook.class));
List<FluentHook> fluentHooks = hookChainBuilder.build(() -> element, () -> locator, () -> "toString", hookDefinitions);
Assertions.assertThat(fluentHooks).hasSize(hookDefinitions.size());
Assertions.assertThat(fluentHooks.get(0)).isInstanceOf(NanoHook.class);
Assertions.assertThat(fluentHooks.get(1)).isInstanceOf(NanoHook.class);
Assertions.assertThat(fluentHooks.get(2)).isInstanceOf(NanoHook.class);
fluentHooks.get(0).click();
verify(element).click();
verify(fluentHooks.get(0)).click();
verify(fluentHooks.get(1), never()).click();
verify(fluentHooks.get(2), never()).click();
reset(element);
reset(fluentHooks.toArray());
fluentHooks.get(2).click();
verify(element).click();
verify(fluentHooks.get(0)).click();
verify(fluentHooks.get(1)).click();
verify(fluentHooks.get(2)).click();
Assertions.assertThat(((NanoHook) fluentHooks.get(2)).getBeforeClickNano())
.isLessThanOrEqualTo(((NanoHook) fluentHooks.get(1)).getBeforeClickNano());
Assertions.assertThat(((NanoHook) fluentHooks.get(1)).getBeforeClickNano())
.isLessThanOrEqualTo(((NanoHook) fluentHooks.get(0)).getBeforeClickNano());
Assertions.assertThat(((NanoHook) fluentHooks.get(2)).getAfterClickNano())
.isGreaterThanOrEqualTo(((NanoHook) fluentHooks.get(1)).getAfterClickNano());
Assertions.assertThat(((NanoHook) fluentHooks.get(1)).getAfterClickNano())
.isGreaterThanOrEqualTo(((NanoHook) fluentHooks.get(0)).getAfterClickNano());
Assertions.assertThat(((NanoHook) fluentHooks.get(0)).getOptionValue()).isNull();
Assertions.assertThat(((NanoHook) fluentHooks.get(1)).getOptionValue()).isEqualTo("option");
Assertions.assertThat(((NanoHook) fluentHooks.get(2)).getOptionValue()).isNull();
}
private static class InvalidConstructorHook extends BaseHook<Object> {
InvalidConstructorHook() {
super(null, null, null, null, null, null);
}
}
@Test
public void testInvalidConstructorHook() {
List<HookDefinition<?>> hookDefinitions = new ArrayList<>();
hookDefinitions.add(new HookDefinition<>(InvalidConstructorHook.class));
Assertions
.assertThatThrownBy(() -> hookChainBuilder.build(() -> element, () -> locator, () -> "toString", hookDefinitions))
.isExactlyInstanceOf(HookException.class).hasMessage("An error has occurred with a defined hook.");
}
private static class FailingConstructorHook extends BaseHook<Object> {
FailingConstructorHook(FluentControl fluentControl, ComponentInstantiator instantiator,
Supplier<WebElement> elementSupplier, Supplier<ElementLocator> locatorSupplier, Supplier<String> toStringSupplier,
Object options) {
super(fluentControl, instantiator, elementSupplier, locatorSupplier, toStringSupplier, options);
throw new IllegalStateException();
}
}
@Test
public void testFailingConstructorHook() {
List<HookDefinition<?>> hookDefinitions = new ArrayList<>();
hookDefinitions.add(new HookDefinition<>(FailingConstructorHook.class));
Assertions
.assertThatThrownBy(() -> hookChainBuilder.build(() -> element, () -> locator, () -> "toString", hookDefinitions))
.isExactlyInstanceOf(HookException.class).hasMessage("An error has occurred with a defined hook.");
}
}