Skip to content
Permalink
Browse files
feat(protractor): Photographer.whoWill(..) factory method to make ins…
…tantiation of the Photographer

#335
  • Loading branch information
jan-molak committed Sep 1, 2019
1 parent cb15f8b commit 288011696bd1825ee5ae61d00e265f5d1706a1c2
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 1 deletion.
@@ -3,17 +3,91 @@ import { ActivityFinished, ActivityStarts, DomainEvent } from '@serenity-js/core
import { Stage, StageCrewMember } from '@serenity-js/core/lib/stage';
import { PhotoTakingStrategy } from './strategies';

/**
* @desc
* The Photographer is a {@link @serenity-js/core/lib/stage~StageCrewMember} who takes screenshots
* of the web browser the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight is using.
*
* @example <caption>Assigning the Photographer to the Stage</caption>
*
* const { ArtifactArchiver } = require('@serenity-js/core');
* const { Photographer, TakePhotosOfFailures } = require('@serenity-js/protractor');
*
* exports.config = {
*
* serenity: {
* crew: [
* ArtifactArchiver.storingArtifactsAt('./target/site/serenity'),
* Photographer.whoWill(TakePhotosOfFailures),
* ]
* },
*
* // ... rest of the config omitted for brevity
* };
*
* @example <caption>Taking photos upon failures only</caption>
*
* const { Photographer, TakePhotosOfFailures } = require('@serenity-js/protractor');
*
* Photographer.whoWill(TakePhotosOfFailures)
*
* @example <caption>Taking photos of all the interactions</caption>
*
* const { Photographer, TakePhotosOfInteractions } = require('@serenity-js/protractor');
*
* Photographer.whoWill(TakePhotosOfInteractions)
*
* @example <caption>Taking photos before and after all the interactions</caption>
*
* const { Photographer, TakePhotosBeforeAndAfterInteractions } = require('@serenity-js/protractor');
*
* Photographer.whoWill(TakePhotosBeforeAndAfterInteractions)
*
* @see {@link @serenity-js/core/lib/stage~Stage}
*/
export class Photographer implements StageCrewMember {

/**
* @desc
* Instantiates a new {@link Photographer} configured to take photos (screenshots)
* as per the specified {@link PhotoTakingStrategy}.
*
* @param {Function} strategy - A no-arg constructor function that instantiates a {@link PhotoTakingStrategy}.
* @returns {StageCrewMember}
*/
static whoWill(strategy: new () => PhotoTakingStrategy): StageCrewMember {
return new Photographer(new strategy());
}

/**
* @param {PhotoTakingStrategy} photoTakingStrategy
* @param {Stage} stage
*/
constructor(
private readonly photoTakingStrategy: PhotoTakingStrategy,
private readonly stage: Stage = null,
) {
}

/**
* @desc
* Creates a new instance of this {@link StageCrewMember} and assigns it to a given {@link Stage}.
*
* @param {Stage} stage - An instance of a {@link Stage} this {@link StageCrewMember} will be assigned to
* @returns {StageCrewMember} - A new instance of this {@link StageCrewMember}
*/
assignedTo(stage: Stage): StageCrewMember {
return new Photographer(this.photoTakingStrategy, stage);
}

/**
* @desc
* Handles {@link DomainEvent} objects emitted by the {@link Stage}
* this {@link StageCrewMember} is assigned to.
*
* @param {DomainEvent} event
* @returns void
*/
notifyOf(event: DomainEvent): void {
if (! this.stage) {
throw new LogicError(`Photographer needs to be assigned to the Stage before it can be notified of any DomainEvents`);
@@ -11,8 +11,27 @@ import {
import { CorrelationId, Description, Name, Photo } from '@serenity-js/core/lib/model';
import { BrowseTheWeb } from '../../../screenplay';

/**
* @desc
* Configures the {@link Photographer} to take photos (a.k.a. screenshots)
* of the {@link @serenity-js/core/lib/screenplay~Activity} performed
* by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight
* under specific conditions.
*
* @abstract
*/
export abstract class PhotoTakingStrategy {

/**
* @desc
* Takes a photo of the web browser held by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight.
*
* @param {@serenity-js/core/lib/events~ActivityStarts | @serenity-js/core/lib/events~ActivityFinished} event
* @param {@serenity-js/core/lib/stage~Stage} stage - the Stage that holds reference to the Actor in the spotlight
* @returns void
*
* @see {@serenity-js/core/lib/stage~Stage#theActorInTheSpotlight}
*/
considerTakingPhoto(event: ActivityStarts | ActivityFinished, stage: Stage): void {
if (this.shouldTakeAPhotoOf(event)) {
const
@@ -1,7 +1,18 @@
import { DomainEvent, InteractionFinished, InteractionStarts } from '@serenity-js/core/lib/events';
import { ImplementationPending } from '@serenity-js/core/lib/model';
import { PhotoTakingStrategy } from './PhotoTakingStrategy';

/**
* @desc
* Configures the {@link Photographer} to take photos (a.k.a. screenshots) both before and after
* every single {@link @serenity-js/core/lib/screenplay~Interaction} performed
* by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight.
*
* *Please note* that this strategy will result in _a lot_ of screenshots being taken,
* which will seriously affect the performance of your tests.
* For this reason, it's best to use it only for debugging purposes.
*
* @implements {PhotoTakingStrategy}
*/
export class TakePhotosBeforeAndAfterInteractions extends PhotoTakingStrategy {
protected shouldTakeAPhotoOf(event: DomainEvent): boolean {
return event instanceof InteractionStarts
@@ -2,6 +2,17 @@ import { DomainEvent, InteractionFinished } from '@serenity-js/core/lib/events';
import { ImplementationPending } from '@serenity-js/core/lib/model';
import { PhotoTakingStrategy } from './PhotoTakingStrategy';

/**
* @desc
* Configures the {@link Photographer} to take photos (a.k.a. screenshots) when
* the {@link @serenity-js/core/lib/screenplay~Interaction} performed
* by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight results in an error.
*
* This strategy works best when you are interested in the screenshots only when
* the a fails.
*
* @implements {PhotoTakingStrategy}
*/
export class TakePhotosOfFailures extends PhotoTakingStrategy {
protected shouldTakeAPhotoOf(event: DomainEvent): boolean {
return event instanceof InteractionFinished
@@ -1,6 +1,19 @@
import { DomainEvent, InteractionFinished } from '@serenity-js/core/lib/events';
import { PhotoTakingStrategy } from './PhotoTakingStrategy';

/**
* @desc
* Configures the {@link Photographer} to take photos (a.k.a. screenshots) when
* the the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight
* performs any {@link @serenity-js/core/lib/screenplay~Interaction}.
*
* This strategy works best when you want the results of your automated tests
* to become comprehensive living documentation of your system.
*
* *Please note* that taking screenshots affects the performance of your tests.
*
* @implements {PhotoTakingStrategy}
*/
export class TakePhotosOfInteractions extends PhotoTakingStrategy {
protected shouldTakeAPhotoOf(event: DomainEvent): boolean {
return event instanceof InteractionFinished;

0 comments on commit 2880116

Please sign in to comment.