Search code examples
javaseleniumaopaspectjpage-factory

AspectJ - pointcut to capture all WebElements annotated with @FindBy


My test framework uses selenium's PageFactory and Lambok. I want to write an aspect to capture all the web elements that a test flow comes across while running.

A typical page looks like:

@Slf4j
public class MyCustomPage {

    @Inject
    private IWebDriverSet driverSet;

    @Getter
    @FindBy(id = PAGE_ROOT)
    private WebElement root;

    @FindAll({
            @FindBy(css = FOOT_BAR),
            @FindBy(css = FOOT_BAR_B)
    })
    private WebElement navBar;
}

@FindBy determines the webelement that tests deal with. There are 50 of such pages.

The webElement fields are instantiated (assigned with a WebElement instance corresponding to the value in @FindBy) when the page is instantiated using the PageFactory.

I would like to capture these webElements that are annotated with @FindBy/@FindAll as soon as they are instantiated. I dont want to write a separate pointcut for every page class. How to do that?


Solution

  • Since value of a WebElement assigned via reflection you can't intercept that with set() pointcut designator. But you can track all calls to java.lang.reflect.Field.set

        @After("call(* java.lang.reflect.Field.set(..)) && args(obj, value) && target(target)")
        public void webelementInit(JoinPoint jp, Object obj, Object value, Field target) {
            //obj - instance of a class (page object) that declares current field
            //value - new field value (instantiated WebElement)
            //field - current field
            //you can filter calls to the fields you need by matching target.getDeclaringClass().getCanonicalName() with page object's package
            //for example:
            //if(target.getDeclaringClass().getCanonicalName().contains("com.example.pageobjects")) {
                //do stuff
            //}
        }
    

    In that case you need to define rt.jar in dependencies section in your pom.xml

    <dependencies>
            <dependency>
                <groupId>java</groupId>
                <artifactId>jre-runtime</artifactId>
                <version>1.8</version>
                <scope>system</scope>
                <systemPath>${java.home}/lib/rt.jar</systemPath>
            </dependency>
    ...
    </dependencies>
    

    and in weaveDependencies section of aspectj-maven-plugin

    <weaveDependencies>
        <weaveDependency>
            <groupId>java</groupId>
            <artifactId>jre-runtime</artifactId>
        </weaveDependency>
    ...
    </weaveDependencies>