1

I'm trying to combine all these tools together. Here are the details and some screenshots of my project. I need post-compile time weave my source code.

Annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Click {}

Aspect:

@Aspect
public class ClickAspect {

  @Pointcut("@annotation(com.selenium.aspect.support.annotation.Click)")
  public void clickAnn() {}

  @Around("clickAnn()")
  public void clickOnAction(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("Clicking on a button");
      joinPoint.proceed();
  }
}

Page:

public class Page {

  @FindBy(id = "menu-item-40489")
  private WebElement search;

  public Page(WebDriver driver) {
      PageFactory.initElements(driver, this);
  }

  @Click
  public void clickOnSearch() {
      search.click();
  }
}

Test class:

public class SeleniumAspectSupportTest {

  private WebDriver driver;
  private Page page;

  @BeforeTest
  public void initDriver() {
      System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
      driver = new ChromeDriver();
      driver.manage().window().maximize();
      driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);
      driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);

      page = new Page(driver);
  }

  @AfterTest
  public void dropDriver() {
      driver.close();
  }

  @Test
  public void simpleTest() {
      driver.get("https://www.baeldung.com");
      page.clickOnSearch();
      System.out.println("DONE");
  }
}

pom.xml:

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.9.2</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.2</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjtools</artifactId>
        <version>1.9.2</version>
    </dependency>
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>7.4.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>3.141.59</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>11</source>
                <target>11</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.11</version>
            <configuration>
                <complianceLevel>11</complianceLevel>
                <source>11</source>
                <target>11</target>
            </configuration>
            <executions>
                <execution>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

aop.xml:

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
  <aspects>
    <aspect name="com.selenium.aspect.support.controller.ClickAspect"/>
  </aspects>
</aspectj>

The advise is not working, however the test passes. I've tried different aspectj library versions. What have I missed to make it work?

Serhii Kachan
  • 345
  • 4
  • 13
  • Welcome to SO. Please edit your question, using code blocks instead of screenshots. Nobody wants to use OCR in order to reproduce your problem in her local IDE. Thank you very much. Besides, Mojohaus AspectJ Maven Plugin 1.11 does not support more than Java 8. Either upgrade to 1.14.0 or use the more feature-rich and up-to-date [AspectJ.dev version](https://github.com/dev-aspectj/aspectj-maven-plugin). See also [here](https://stackoverflow.com/a/62213003/1082681) for an explanation. – kriegaex Oct 28 '21 at 07:38
  • Please also note that your around-advice will only be able to intercept `void` methods because it also has a `void` return type. If you ever annotate a non-void method with `@Click`, you need to adjust the advice method. But for now it should not be a problem. – kriegaex Oct 28 '21 at 07:43
  • Thanks for advices, edited my questions with code. I've tried both plugin adjustments however it didn't help. any other suggestions? – Serhii Kachan Oct 28 '21 at 08:45
  • I am a bit busy at the moment. If you need quick feedback, an [MCVE](https://stackoverflow.com/help/mcve) on GitHub which I can just clone and run would be helpful. Otherwise it might take a while before I have time to copy and paste all your code into a new project and add missing bits and pieces (such as a dummy HTML page to run the test against). – kriegaex Oct 28 '21 at 09:24
  • Another advantage would be that I could simply send you a PR with the fix. – kriegaex Oct 28 '21 at 09:30
  • OK, I see that there is no need to create a dummy HTML page, because you target baeldung.com. Fine, then it is easy to reproduce your problem. – kriegaex Oct 28 '21 at 10:26
  • OK, I see that there is no need to create a dummy HTML page, because you target baeldung.com. Fine, then it is easy to reproduce your problem. – kriegaex Oct 28 '21 at 10:26
  • https://github.com/SerhiiKachan/SeleniumAspectSupport I've shared the project here – Serhii Kachan Oct 28 '21 at 10:38
  • Sorry, I was already playing with your project before noticing that you published something on GH. – kriegaex Oct 28 '21 at 10:46

1 Answers1

1

There are several things which could be improved in your POM, aspect and test code. But the root cause of your problem is that the aspect is first woven into the test class by AspectJ Maven Plugin, but then overwritten by Maven Compiler Plugin due to a rather cumbersome Maven Compiler default configuration, causing it to recompile everything. Therefore, you need to add this to your Maven Compiler configuration:

<!-- IMPORTANT -->
<useIncrementalCompilation>false</useIncrementalCompilation>

You can find an explanation in my answer here.

Other things you should improve:

  • Upgrade to a more recent AspectJ Maven version supporting Java 11
  • Upgrade AspectJ dependencies to 1.9.7
  • Get rid of the aspectjweaver dependency and aop.xml, because you already use compile-time weaving and do not need a load-time weaving configuration on top of that. Either this or that, but not both.
  • Make aspectjtools a Maven Compiler dependency rather than a dependency for the Maven module itself. You only need the compiler inside the plugin, not during runtime. There, aspectjrt is enough.
  • Refine your pointcut to only include execution() joinpoints, because otherwise each aspect advice will be triggered twice, once for execution and once for call. You can see this on the console when running the test.
  • Activate <showWeaveInfo>true</showWeaveInfo> for AspectJ Maven. Then you can also see the previous problem, i.e. doubly woven advice, more clearly during compile time.
  • Enhance the test to also click away the cookie banner, which was necessary in my case in order to even be able to click the search button during the test. It also adds a second test case for @Click triggering the aspect.
  • In my case I had to quit the driver, not just close it. Otherwise, I would end up with dozens of chromedriver.exe background processes.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>SO_AJ_TestNGSelenium_69744638</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <aspectj.version>1.9.7</aspectj.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${aspectj.version}</version>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>7.4.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>11</source>
          <target>11</target>
          <!-- IMPORTANT -->
          <useIncrementalCompilation>false</useIncrementalCompilation>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.14.0</version>
        <configuration>
          <complianceLevel>11</complianceLevel>
          <source>11</source>
          <target>11</target>
          <showWeaveInfo>true</showWeaveInfo>
        </configuration>
        <executions>
          <execution>
            <phase>process-sources</phase>
            <goals>
              <goal>compile</goal>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

</project>
package com.selenium.aspect.support.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Click {}
package org.example;

import com.selenium.aspect.support.annotation.Click;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class Page {
  @FindBy(className = "css-47sehv")
  private WebElement cookiesAgree;

  @FindBy(id = "menu-item-40489")
  private WebElement search;

  public Page(WebDriver driver) {
    PageFactory.initElements(driver, this);
  }

  @Click
  public void clickOnCookiesAgree() {
    cookiesAgree.click();
  }

  @Click
  public void clickOnSearch() {
    search.click();
  }
}
package org.example;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ClickAspect {
  @Pointcut("@annotation(com.selenium.aspect.support.annotation.Click) && execution(* *(..))")
  public void clickAnn() {}

  @Around("clickAnn()")
  public void clickOnAction(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println(joinPoint + " -> Clicking on a button");
    joinPoint.proceed();
  }
}
package org.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;

public class SeleniumAspectSupportTest {

  private WebDriver driver;
  private Page page;

  @BeforeTest
  public void initDriver() {
    System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
    driver = new ChromeDriver();
    driver.manage().window().maximize();
    driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);
    driver.manage().timeouts().implicitlyWait(120, TimeUnit.SECONDS);
    page = new Page(driver);
  }

  @AfterTest
  public void dropDriver() {
    driver.close();
    driver.quit();
  }

  @Test
  public void simpleTest() {
    driver.get("https://www.baeldung.com");
    page.clickOnCookiesAgree();
    page.clickOnSearch();
    System.out.println("DONE");
  }
}

The console log should read:

execution(void org.example.Page.clickOnCookiesAgree()) -> Clicking on a button
execution(void org.example.Page.clickOnSearch()) -> Clicking on a button
kriegaex
  • 63,017
  • 15
  • 111
  • 202