net.serenitybdd.screenplay.Actor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of serenity-journey Show documentation
Show all versions of serenity-journey Show documentation
Support for the User Journey pattern in Serenity
package net.serenitybdd.screenplay;
import com.google.common.base.Optional;
import net.serenitybdd.core.PendingStepException;
import net.serenitybdd.core.Serenity;
import net.serenitybdd.core.SkipNested;
import net.serenitybdd.core.eventbus.Broadcaster;
import net.serenitybdd.screenplay.events.*;
import net.serenitybdd.screenplay.exceptions.IgnoreStepException;
import net.serenitybdd.screenplay.formatting.FormattedTitle;
import net.thucydides.core.annotations.Pending;
import net.thucydides.core.steps.StepEventBus;
import java.lang.reflect.Method;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
public class Actor implements PerformsTasks, SkipNested {
private final String name;
private final PerformedTaskTally taskTally = new PerformedTaskTally();
private EventBusInterface eventBusInterface = new EventBusInterface();
private ConsequenceListener consequenceListener = new ConsequenceListener(eventBusInterface);
private Map notepad = newHashMap();
private Map abilities = newHashMap();
public Actor(String name) {
this.name = name;
}
public String toString() {
return name;
}
public static Actor named(String name) {
return new Actor(name);
}
public String getName() {
return name;
}
public Actor can(T doSomething) {
doSomething.asActor(this);
abilities.put(doSomething.getClass(), doSomething);
return this;
}
@SuppressWarnings("unchecked")
public T abilityTo(Class extends T> doSomething) {
return (T) abilities.get(doSomething);
}
public final void has(Performable... todos) {
attemptsTo(todos);
}
/**
* A tense-neutral synonyme for has() for use with given() clauses
*/
public final void wasAbleTo(Performable... todos) {
attemptsTo(todos);
}
public final void attemptsTo(Performable... tasks) {
beginPerformance();
for (Performable task : tasks) {
perform(task);
}
endPerformance();
}
public ANSWER asksFor(Question question) {
return question.answeredBy(this);
}
private void perform(T todo) {
if (isPending(todo)) {
StepEventBus.getEventBus().stepPending();
}
try {
notifyPerformanceOf(todo);
taskTally.newTask();
todo.performAs(this);
if (anOutOfStepErrorOccurred()) {
eventBusInterface.mergePreviousStep();
}
} catch (Throwable exception) {
if (!pendingOrIgnore(exception)) {
eventBusInterface.reportStepFailureFor(todo, exception);
}
if (Serenity.shouldThrowErrorsImmediately() || isAnAssumptionFailure(exception)) {
throw exception;
}
} finally {
eventBusInterface.updateOverallResult();
}
}
private void notifyPerformanceOf(T todo) {
Broadcaster.getEventBus().post(new ActorPerforms(todo));
}
private boolean isPending(T todo) {
Method performAs = getPerformAsForClass(todo.getClass().getSuperclass()).
or(getPerformAsForClass(todo.getClass()).orNull());
return (performAs != null) && (performAs.getAnnotation(Pending.class) != null);
}
private Optional getPerformAsForClass(Class taskClass) {
try {
return Optional.of(taskClass.getMethod("performAs", Actor.class));
} catch (NoSuchMethodException e) {
return Optional.absent();
}
}
private void logSkippedTask() {
StepEventBus.getEventBus().testSkipped();
}
private boolean pendingOrIgnore(Throwable exception) {
return exception instanceof IgnoreStepException ||
exception instanceof PendingStepException;
}
private boolean isAnAssumptionFailure(Throwable e) {
return e.getClass().getSimpleName().contains("Assumption");
}
public final void can(Consequence... consequences) {
should(consequences);
}
public final void should(Consequence... consequences) {
ErrorTally errorTally = new ErrorTally(eventBusInterface);
startConsequenceCheck();
for (Consequence consequence : consequences) {
check(consequence, errorTally);
}
endConsequenceCheck();
errorTally.reportAnyErrors();
}
private boolean anOutOfStepErrorOccurred() {
return eventBusInterface.aStepHasFailed()
&& eventBusInterface.getStepCount() > taskTally.getPerformedTaskCount();
}
private void check(Consequence consequence, ErrorTally errorTally) {
try {
eventBusInterface.reportNewStepWithTitle(FormattedTitle.ofConsequence(consequence));
if (eventBusInterface.shouldIgnoreConsequences()) {
StepEventBus.getEventBus().stepIgnored();
} else {
consequence.evaluateFor(this);
}
eventBusInterface.reportStepFinished();
} catch (IgnoreStepException e) {
eventBusInterface.reportStepIgnored();
} catch (Throwable e) {
errorTally.recordError(consequence, e);
}
}
public void remember(String key, Question question) {
ANSWER answer = this.asksFor(question);
notepad.put(key, answer);
}
public void remember(String key, Object value) {
notepad.put(key, value);
}
@SuppressWarnings("unchecked")
public T recall(String key) {
return (T) notepad.get(key);
}
public T sawAsThe(String key) {
return recall(key);
}
public T gaveAsThe(String key) {
return recall(key);
}
private void beginPerformance() {
Broadcaster.getEventBus().post(new ActorBeginsPerformanceEvent(name));
}
private void endPerformance() {
Broadcaster.getEventBus().post(new ActorEndsPerformanceEvent(name));
}
private void startConsequenceCheck() {
consequenceListener.beginConsequenceCheck();
Broadcaster.getEventBus().post(new ActorBeginsConsequenceCheckEvent(name));
}
private void endConsequenceCheck() {
consequenceListener.endConsequenceCheck();
Broadcaster.getEventBus().post(new ActorEndsConsequenceCheckEvent(name));
}
}