Selenide + Allure Integration: Complete Reference Guide
Master Selenide and Allure integration with step annotations, automatic screenshots, page source attachments, browser logs, and CI-ready reports. Java code, Maven, and Gradle examples included.
Introduction
Selenide gives you a concise UI automation API on top of Selenium, while Allure gives you a beautiful, navigable test report. When you combine them, every Selenide action becomes a self-documenting test step, every failure ships with a screenshot and the full HTML source, and every CI run becomes a shareable artifact that non-engineers can actually read.
This guide is a complete reference for wiring Selenide and Allure together in a real Java project. We'll cover the dependency setup in Maven and Gradle, the listeners and aspects you need, screenshot policies, page source attachments, custom step annotations, and how to publish the report from Jenkins or GitHub Actions.
By the end you'll have a configuration you can drop into any Selenide project, a clear mental model of how Allure intercepts Selenide calls, and patterns for keeping the report clean even when tests grow into the hundreds.
Why Allure for Selenide
Selenide already logs every action with great error messages. So why add Allure on top?
- Visual timeline. Allure shows each test as a tree of steps with durations. You can see at a glance which click took 4 seconds.
- Attachments per step. Screenshots, page source, network logs, and console output attach to the exact step that produced them.
- Test categorization.
@Epic,@Feature,@Story, and severity tags let product managers slice the report by area. - History and trends. Allure keeps a history of runs so flaky tests bubble up visually.
- CI-native. The report is static HTML that any web server can host, including GitHub Pages and S3.
Selenide ships with first-class Allure support via the selenide-allure integration module, so the wiring is minimal.
Dependency Setup
Maven
<properties>
<selenide.version>7.5.0</selenide.version>
<allure.version>2.27.0</allure.version>
<aspectj.version>1.9.22</aspectj.version>
<junit.version>5.11.0</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>selenide</artifactId>
<version>${selenide.version}</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-selenide</artifactId>
<version>${allure.version}</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<systemProperties>
<property>
<name>allure.results.directory</name>
<value>${project.build.directory}/allure-results</value>
</property>
</systemProperties>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.12.0</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
The AspectJ weaver is what lets Allure intercept @Step annotations at runtime. Without it, steps don't show up in the report.
Gradle
plugins {
id 'java'
id 'io.qameta.allure' version '2.12.0'
}
ext {
allureVersion = '2.27.0'
aspectjVersion = '1.9.22'
}
repositories { mavenCentral() }
dependencies {
testImplementation 'com.codeborne:selenide:7.5.0'
testImplementation "io.qameta.allure:allure-selenide:${allureVersion}"
testImplementation "io.qameta.allure:allure-junit5:${allureVersion}"
testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0'
testRuntimeOnly "org.aspectj:aspectjweaver:${aspectjVersion}"
}
test {
useJUnitPlatform()
def weaver = configurations.testRuntimeClasspath.find {
it.name.contains('aspectjweaver')
}
jvmArgs "-javaagent:${weaver}"
systemProperty 'allure.results.directory',
"${buildDir}/allure-results"
}
allure {
version = allureVersion
autoconfigure = true
aspectjweaver = true
useJUnit5 { version = allureVersion }
}
The io.qameta.allure plugin can manage the aspect weaver for you, but I always set -javaagent manually because it works the same locally and in CI.
Wiring the Selenide Allure Listener
Selenide's events fire through a public listener API. To pipe them into Allure, register the AllureSelenide listener once before tests run.
package com.example.tests;
import com.codeborne.selenide.logevents.SelenideLogger;
import io.qameta.allure.selenide.AllureSelenide;
import org.junit.jupiter.api.BeforeAll;
public abstract class BaseTest {
@BeforeAll
static void setUpAllure() {
SelenideLogger.addListener("AllureSelenide",
new AllureSelenide()
.screenshots(true)
.savePageSource(true)
.includeSelenideSteps(true));
}
}
The three switches matter:
screenshots(true)attaches a PNG to every failing step.savePageSource(true)attaches the live HTML at the moment of failure. This is gold for debugging hidden elements.includeSelenideSteps(true)turns every Selenide action (open,click,shouldHave) into its own Allure step.
Once that listener is registered, the report becomes self-documenting with zero per-test wiring.
A Real Test with Rich Steps
Here's a login flow that produces a clean Allure report:
package com.example.tests;
import io.qameta.allure.*;
import org.junit.jupiter.api.Test;
import static com.codeborne.selenide.Selenide.*;
import static com.codeborne.selenide.Selectors.*;
import static com.codeborne.selenide.Condition.*;
@Epic("Authentication")
@Feature("Login")
class LoginTest extends BaseTest {
@Test
@Story("Valid credentials succeed")
@Severity(SeverityLevel.CRITICAL)
@Description("User can log in with a verified email + password")
void userCanLogin() {
openLoginPage();
submitCredentials("alice@example.com", "SecurePass123!");
verifyWelcomeBanner("Alice");
}
@Step("Open the login page")
void openLoginPage() {
open("/login");
$("h1").shouldHave(text("Sign in"));
}
@Step("Submit credentials for {email}")
void submitCredentials(String email, String password) {
$("#email").setValue(email);
$("#password").setValue(password);
$(byAttribute("data-testid", "login-button")).click();
}
@Step("Verify welcome banner for {name}")
void verifyWelcomeBanner(String name) {
$(".welcome-message").shouldHave(text("Welcome, " + name));
}
}
In the Allure report this test renders as a 3-step tree with parameter values inline. Every $(...).click() becomes a sub-step. A failure on verifyWelcomeBanner attaches the screenshot + page source automatically.
Screenshot Strategy
By default AllureSelenide attaches screenshots on failure. You often want screenshots on key successful steps too.
import io.qameta.allure.Allure;
import com.codeborne.selenide.Screenshots;
@Step("Capture full-page screenshot")
public void attachScreenshot(String name) {
byte[] bytes = ((TakesScreenshot) WebDriverRunner.getWebDriver())
.getScreenshotAs(OutputType.BYTES);
Allure.addAttachment(name, "image/png",
new ByteArrayInputStream(bytes), "png");
}
For full-page captures across viewports, AShot integrates cleanly:
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.shooting.ShootingStrategies;
@Step("Capture scrolling screenshot")
public void attachFullPageScreenshot() {
BufferedImage image = new AShot()
.shootingStrategy(ShootingStrategies.viewportPasting(100))
.takeScreenshot(WebDriverRunner.getWebDriver())
.getImage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image, "png", out);
Allure.addAttachment("full-page", "image/png",
new ByteArrayInputStream(out.toByteArray()), "png");
}
Page Source on Failure
Selenide-Allure already saves page-source as text. To extend it with sanitized HTML or trimmed sections:
@Step("Attach sanitized page source")
public void attachSanitizedSource() {
String html = WebDriverRunner.source();
String stripped = html.replaceAll("(?s)<script.*?</script>", "");
Allure.addAttachment("page-source.html",
"text/html", stripped, "html");
}
Browser Logs and Network
Adding console and performance logs makes Allure useful for debugging client-side issues.
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogType;
@Step("Attach browser console logs")
public void attachConsoleLogs() {
LogEntries logs = WebDriverRunner.getWebDriver()
.manage().logs().get(LogType.BROWSER);
String body = logs.getAll().stream()
.map(e -> e.getLevel() + " " + e.getMessage())
.collect(Collectors.joining("\n"));
Allure.addAttachment("console.log",
"text/plain", body, "log");
}
Categorizing Tests
Add an allure-results/categories.json file in your resources to bucket failures:
[
{
"name": "Element not found",
"matchedStatuses": ["failed"],
"messageRegex": ".*ElementNotFound.*"
},
{
"name": "Timeout",
"matchedStatuses": ["failed", "broken"],
"messageRegex": ".*Timeout.*"
},
{
"name": "Assertion failed",
"matchedStatuses": ["failed"],
"messageRegex": ".*should have.*"
}
]
The report's Categories tab will group failures by these regexes.
Environment Metadata
Allure shows an Environment panel when you create allure-results/environment.properties. Build it dynamically in a @AfterAll:
@AfterAll
static void writeEnvironment() throws IOException {
Path file = Paths.get("target/allure-results/environment.properties");
Files.createDirectories(file.getParent());
Properties p = new Properties();
p.setProperty("Browser", Configuration.browser);
p.setProperty("BrowserVersion", Configuration.browserVersion);
p.setProperty("BaseUrl", Configuration.baseUrl);
p.setProperty("Headless", String.valueOf(Configuration.headless));
try (Writer w = Files.newBufferedWriter(file)) {
p.store(w, "Selenide environment");
}
}
Parametrized Tests and Parameters
Allure captures parameters automatically for JUnit 5 @ParameterizedTest:
@ParameterizedTest(name = "{0} can sign in")
@ValueSource(strings = {"alice", "bob", "charlie"})
@Story("Multiple users can sign in")
void usersCanLogin(String user) {
open("/login");
$("#email").setValue(user + "@example.com");
$("#password").setValue("SecurePass123!");
$("[type=submit]").click();
$(".welcome").shouldBe(visible);
}
Each parameter value shows up in the report tree.
Generating the Report Locally
After a Maven run:
mvn clean test
mvn allure:report # generates target/site/allure-maven-plugin
mvn allure:serve # opens a temporary HTTP server
Gradle:
./gradlew test
./gradlew allureReport
./gradlew allureServe
CI Publishing
GitHub Actions
- name: Run tests
run: mvn -B clean test
- name: Allure history
uses: actions/cache@v4
with:
path: target/allure-results/history
key: allure-history-${{ github.run_id }}
restore-keys: allure-history-
- name: Generate Allure report
uses: simple-elf/allure-report-action@v1
with:
allure_results: target/allure-results
allure_history: allure-history
- name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-history
Jenkins
Install the Allure Jenkins plugin and add a post-build step:
post {
always {
allure includeProperties: false,
jdk: '',
results: [[path: 'target/allure-results']]
}
}
Common Pitfalls
- Missing aspectj weaver. Symptoms:
@Stepmethods don't appear. Fix: confirm-javaagentis on the surefireargLine. - Listener registered too late. If the listener is added in
@BeforeEach, the first test misses some steps. Use@BeforeAll. - Multiple drivers.
AllureSelenidelistens to Selenide; raw Selenium calls won't appear. Stick to Selenide's API. - Big page source. On heavy SPAs, page source attachments can be megabytes. Trim or disable for stable tests.
Conclusion
Selenide and Allure are designed to coexist. With one listener registration, a working aspect weaver, and a small set of @Step annotations, you get a production-grade report that any teammate can read. Add screenshots, page source, environment metadata, and a categories file, and your report becomes the first place engineers look when CI turns red.
Once this baseline is in place, every new test you write inherits the reporting for free.