package net.thucydides.core.scheduling;
import net.thucydides.core.pages.PageObject;
import net.thucydides.core.steps.ExecutedStepDescription;
import net.thucydides.core.steps.StepEventBus;
import net.thucydides.core.steps.StepFailure;
import net.thucydides.core.util.MockEnvironmentVariables;
import net.thucydides.core.webdriver.Configuration;
import net.thucydides.core.webdriver.SystemPropertiesConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.Clock;
import org.openqa.selenium.support.ui.Duration;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.Sleeper;
import java.util.concurrent.TimeUnit;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.*;
public class WhenRunningPolledTests {
@Mock
WebDriver driver;
@Mock
Sleeper sleeper;
@Mock
StepFailure failure;
@Mock
WebDriver.Navigation navigation;
MockEnvironmentVariables environmentVariables;
Configuration configuration;
class Counter {
int counter = 0;
public int getCounter() {
return counter;
}
public void incrementCounter() {
counter++;
}
}
class ATestClass {
public void someTest() {}
}
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
environmentVariables = new MockEnvironmentVariables();
configuration = new SystemPropertiesConfiguration(environmentVariables);
when(driver.navigate()).thenReturn(navigation);
StepEventBus.getEventBus().clear();
StepEventBus.getEventBus().testSuiteStarted(ATestClass.class);
StepEventBus.getEventBus().testStarted("someTest");
}
class SlowPage extends PageObject {
public SlowPage(final WebDriver driver) {
super(driver);
}
}
private ExpectedCondition<Boolean> weHaveWaitedEnough(final Counter counter) {
return new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
counter.incrementCounter();
return counter.getCounter() > 3;
}
};
}
@Test
public void if_requested_page_should_be_refreshed_during_wait() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
page.waitForWithRefresh()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weHaveWaitedEnough(counter));
verify(navigation, times(3)).refresh();
}
@Test
public void wait_should_be_bypassed_if_a_previous_step_has_failed() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
StepEventBus.getEventBus().clear();
StepEventBus.getEventBus().testSuiteStarted(ATestClass.class);
StepEventBus.getEventBus().testStarted("someTest");
StepEventBus.getEventBus().stepStarted(ExecutedStepDescription.withTitle("a step"));
StepEventBus.getEventBus().stepFailed(failure);
page.waitForWithRefresh()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weHaveWaitedEnough(counter));
verify(navigation, times(0)).refresh();
}
@Test
public void normally_page_should_be_not_refreshed_during_wait() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
page.waitForCondition()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weHaveWaitedEnough(counter));
verify(navigation, never()).refresh();
}
@Test
public void page_should_pause_during_wait() throws InterruptedException {
Clock clock = new org.openqa.selenium.support.ui.SystemClock();
NormalFluentWait<WebDriver> waitFor = new NormalFluentWait(driver, clock, sleeper);
Counter counter = new Counter();
waitFor.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weHaveWaitedEnough(counter));
verify(sleeper, times(3)).sleep(new Duration(100, TimeUnit.MILLISECONDS));
}
private ExpectedCondition<Boolean> weSpitTheDummy(final Counter counter) {
return new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
counter.incrementCounter();
if (counter.getCounter() > 3) {
throw new AssertionError("Oh drat");
}
return false;
}
};
}
private ExpectedCondition<Boolean> weSpitTheDummyWithARuntimeException(final Counter counter) {
return new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
counter.incrementCounter();
if (counter.getCounter() < 3) {
throw new NullPointerException("Oh drat");
} else {
return true;
}
}
};
}
private ExpectedCondition<Boolean> weTakeTooLong() {
return new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
};
}
private ExpectedCondition<String> weDefineAnInvalidCondition() {
return new ExpectedCondition<String>() {
public String apply(WebDriver driver) {
return null;
}
};
}
@Test(expected = AssertionError.class)
public void should_propogate_exception_if_test_fails() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
page.waitForCondition()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weSpitTheDummy(counter));
}
@Test(expected = NullPointerException.class)
public void should_propogate_exception_if_test_fails_with_runtime_error() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
page.waitForCondition()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weSpitTheDummyWithARuntimeException(counter));
}
@Test
public void should_not_propogate_exception_if_test_fails_with_an_ignored_exception() {
SlowPage page = new SlowPage(driver);
Counter counter = new Counter();
page.waitForCondition()
.ignoring(NullPointerException.class)
.withTimeoutOf(5000).milliseconds()
.pollingEvery(100).milliseconds()
.until(weSpitTheDummyWithARuntimeException(counter));
}
@Test(expected = TimeoutException.class)
public void should_timeout_if_takes_too_long() {
SlowPage page = new SlowPage(driver);
page.waitForCondition()
.withTimeoutOf(1000).milliseconds()
.pollingEvery(25).milliseconds()
.until(weTakeTooLong());
}
@Test(expected = IllegalArgumentException.class)
public void should_check_that_condition_is_a_boolean_function() {
SlowPage page = new SlowPage(driver);
page.waitForCondition()
.withTimeoutOf(5000).milliseconds()
.pollingEvery(25).milliseconds()
.until(weDefineAnInvalidCondition());
}
private ExpectedBackendCondition<BackEnd, Boolean> weHaveWaitedAWhile() {
return new ExpectedBackendCondition<BackEnd, Boolean>() {
public Boolean apply(BackEnd backend) {
return backend.isBackendReady();
}
};
}
private class BackEnd {
int counter = 0;
public boolean isBackendReady() {
return (counter++ > 5);
}
public int getCounter() {
return counter;
}
}
@Test
public void should_be_able_to_wait_for_non_web_tests_too() throws InterruptedException {
BackEnd backEnd = new BackEnd();
NormalFluentWait<BackEnd> waitFor = new NormalFluentWait(backEnd);
waitFor.withTimeoutOf(5000).milliseconds()
.pollingEvery(10).milliseconds()
.until(weHaveWaitedAWhile());
assertThat(backEnd.getCounter()).isGreaterThan(5);
}
}