Serenity-js: Performing similar type of actions.

Created on 27 Jul 2018  路  4Comments  路  Source: serenity-js/serenity-js

Hi @jan, firstly thank you so much for making code stuff so readable and giving us a chance to work on Serenity-JS. I was wondering, how can we perform similar type of actions in a single line instead using multiple clicks. Do we have loops in serenity?

Actor.attemptsTo(
Click.on(Test.proceed),
Click.on(Test.proceed),
Click.on(Test.proceed),
Click.on(Test.ok));

Is there any possibility in serenity to write it up something like,

Clicks.on(Test.proceed).while.isPresent() ,

Not sure for syntax,need your help ..

documentation question

All 4 comments

Hi @AbhineetSharmax! Thanks for your kind words, I'm glad that you find Serenity/JS useful!

If you wanted to execute a certain task several times, you could approach it as follows:

Create a "Repeater" task

Serenity/JS is all about composition, so I'd start with creating a "repeater" task that will execute the task I pass in a specified number of times:

import { Activity } from '@serenity-js/core/lib/screenplay';

export const Repeat = (times: number, activity: Activity) =>
    Task.where(`#actor repeats the activity to ${ activity } ${ times } times`,
        ...Array.from({ length: times }).map(() => activity)
    );

There's a little bit of array magic going on above, so let me walk you through that:

Array.from({ length: n })          // creates an array of n elements

Since we don't care about the values the array is populated with, just that it has n elements, we can then map that to an activity, therefore receiving an array of n activities:

Array.from({ length: times }).map(() => task)
// if times === 3, the result is:
// [ activity, activity, activity ] 

To make the above result compatible with Task.where(description: string, ...activities: Activity[]), I use the spread operator:

    Task.where(`#actor repeats the activity to ${ activity } ${ times } times`,
        ...Array.from({ length: times }).map(() => activity)
    );

Next, I wrap above construct in a function so that it can be configured at runtime:

export const Repeat = (times: number, activity: Activity) =>
    Task.where(`#actor repeats the task to ${ activity } ${ times } times`,
        ...Array.from({ length: times }).map(() => activity)
    );

Make the actor repeat the task of interest

With that in place, we can make the actor repeat a specific task several times:

actor.attemptsTo(
    Repeat(3, Click.on(Test.proceed))
);

Let me know if that helps!

Jan

Edit: Updated the code samples to make them compatible with both Task and Interaction interfaces as per the @AbhineetSharmax's suggestion.

@AbhineetSharmax thanks for writing me. I really appreciate the attention. :-)

Greetings, @jan-molak ..

There is a very small change, that i would like to mention in above implementation..

For the Repeater task, instead of taking a Task, we may switch to Activity.

So, for each Task Actor would performs some activity.

export const Repeat = (times: number, activity : Activity) =>
Task.where(#actor repeats the task to ${ activity } ${ times } times,
...Array.from({ length: times }).map(() => activity)
);

Above changes is done to resolve incompatibility issue. Argument 'Click' is not assignable to parameter of type 'Task'.

Once again, @jan-molak Thank you so much for the super quick solutions, you are really awesome :)

You're welcome! And you're right - the samples should've used the Activity interface instead. I've updated them now to incorporate your suggestion.

Was this page helpful?
0 / 5 - 0 ratings