Search code examples
web-testingserenity-bddcucumber-serenity

Serenity Screenplay - List of targets


I am using Serenity screenplay with Java. I have a dropdown list with some options and I want to assert that the options dropdown list has X number of options. I have been using the Target class to find elements and assert they contain the correct text etc, but each of my Targets is for a single element. I would like to get a list of Targets and then assert that the list has X elements in it.

I found a class in the Serenity/JS libraries called TargetElements (https://serenity-js.org/modules/protractor/class/src/screenplay/questions/targets/TargetElements.ts~TargetElements.html) which looks like exactly what I need, but it is not available in the Java version of Serenity.

Here's an example of a typical Target that I use:

    public static final Target OPTIONS_LIST_FIELD = Target.the("options field")
                        .located(By.cssSelector("div[data-testid='option_field']"));

And I want to do something like this:

    public static final List<Target> OPTIONS_LIST = Target.all("options")
                        .located(By.cssSelector("div[data-testid='option']"));

    assertThat(OPTIONS_LIST.size(), equalTo(6))

Solution

  • Target is an abstract class and it's intended usage is to be able to locate and resolve an element on web page. This would give you an instance of either ByTarget or XPathOrCssTarget.

    At the core, the objective should be to get a list of WebElements(WebElementFacade in Serenity) on which an action can be performed or can be resolved to assert data.

    The following fulfills most of the requirements:

    List<String> webElementsValues = Target.the("options field").located(By.cssSelector("div[data-testid='option_field']")).resolveForAll(new Actor("Stack")).texts();
    
    List<WebElementFacade> webElements = Target.the("options field").located(By.cssSelector("div[data-testid='option_field']")).resolveForAll(new Actor("Stack"));
    

    But if you still want a List<Target> elements one can take the following approach which might require some tweak based on your application.

    public static List<Target> getListOfTargetElements() {
    
    int sizeOfOptions = Target.the("Parent Element").locatedBy("//..locate your element here").resolveAllFor(new Actor("byteish")).size();
        List<Target> listOfTarget = null;
        for (int i = 0; i<sizeOfOptions;i++){
            listOfTarget.add(Target.the("element:"+i).locatedBy("div/eleme["+i+"]"));
        }
    
        return listOfTarget;
    }