Skip to main content

Selenide

Use this path when you want a Selenide-based generator repository, or want to expose reusable Selenide flows from an existing Selenide/JUnit suite as Sixpack generators.

Requires Java 17+ and Maven. selenide-flows, selenide-sixpack-adapter, and the bundled FlowCli tool all target Java 17.

The fastest starting point is the sample repository:

git clone https://github.com/sixpack-dev/sixpack-sample-java-selenide.git
cd sixpack-sample-java-selenide

The sample contains:

  • a small local demo application (DemoApp, plain JDK HttpServer - no framework, no Node/npm needed)
  • Selenide flows in src/main/java/.../flows
  • direct JUnit/Selenide tests in src/test/java/.../CustomerFlowsTest.java
  • Sixpack generator wrappers in src/main/java/.../generators
  • a supplier entry point in src/main/java/.../supplier/SampleSupplier.java

Run the flow first

Run the tests before connecting the supplier to Sixpack:

mvn test

The sample starts the local demo app in-process automatically - no separate terminal/process needed, unlike frameworks where the app under test runs as its own process.

Run standalone, outside JUnit

A Sixpack supplier runs a flow outside the test runner, the same way a standalone CLI does - so verifying that path matters as much as the JUnit path. FlowCli ships inside selenide-flows itself (no separate dependency needed):

mvn -q compile exec:java -Dexec.mainClass=dev.sixpack.selenide.flows.cli.FlowCli -Dexec.args="list"
mvn -q compile exec:java -Dexec.mainClass=dev.sixpack.selenide.flows.cli.FlowCli -Dexec.args="inspect createApprovedCustomer --json"
mvn -q compile exec:java -Dexec.mainClass=dev.sixpack.selenide.flows.cli.FlowCli -Dexec.args="generate createApprovedCustomer"
  • list - discovers every @Flow on the classpath (name, shape, declaring class); no browser involved, just classpath scanning.
  • inspect <flow-name> - shows one flow's input/output types and contract validation issues; --json for machine-readable output.
  • generate <flow-name> - actually runs the flow (a real, headless browser session) and prints its result as JSON. Takes --input '{...}', --input-file <path>, or --set key=value (repeatable) for flat inputs.
  • validate - runs contract validation across every discovered flow without executing any of them; --strict fails on warnings too, not just errors.

Connect the sample as Sixpack generators

Create config/ files and a .env file from .env.example, then set:

  • SIXPACK_ORGANIZATION
  • SIXPACK_AUTH_TOKEN
  • SIXPACK_CLIENT_CERT_PATH
  • SIXPACK_CLIENT_KEY_PATH
  • SIXPACK_ENVIRONMENT
  • SIXPACK_URL

Start the supplier - it starts the demo app itself, then registers the generators with Sixpack:

set -a; source .env; set +a
mvn -q compile exec:java -Dexec.mainClass=dev.sixpack.sample.selenide.supplier.SampleSupplier

Add selenide-flows to your own project

Maven:

<dependency>
<groupId>dev.sixpack</groupId>
<artifactId>selenide-flows</artifactId>
<version>0.6.3</version>
</dependency>

Selenide itself is a provided dependency, not bundled - a consumer's own version wins, the same way @sixpack-dev/playwright-flows resolves the consumer's own Playwright as a peer dependency. You need to add your own com.codeborne:selenide dependency alongside it.

Gradle:

repositories {
mavenCentral()
}

dependencies {
implementation 'dev.sixpack:selenide-flows:0.6.3'
implementation 'com.codeborne:selenide:7.16.2' // required explicitly - not pulled in transitively
}

To bridge a flow into a Sixpack generator, also add selenide-sixpack-adapter:0.6.3.

Reusable flows

The simplest shape is a plain, @Flow-annotated static method using Selenide's static facade - no interface to implement:

@Flow
public static Output registerCustomer(CustomerAccount account) {
Selenide.open("/user");
Selenide.$("[data-testid=register-username-input]").setValue(account.username());
// ...
return new Output(account.username());
}

For a flow that genuinely needs more than one concurrent session (a customer and a risk operator both logged in at once), use Flows.define(FlowDefinition...) instead - a SelenideFlow taking an explicit FlowContext. Both shapes work identically from a direct test call, FlowCli/standalone execution, and a Sixpack generator.

Generator wiring

Wrap either flow shape with SelenideFlowGenerator (from selenide-sixpack-adapter):

@ItemMetadata(name = "Customer", description = "A registered customer")
public class RegisterCustomerGenerator
extends SelenideFlowGenerator<CustomerAccount, Output> {

public RegisterCustomerGenerator() {
super(YourFlowClass::registerCustomer);
}

public Output generate(CustomerAccount input) {
return runFlow(input);
}
}

runFlow maps two flow-thrown signals onto Sixpack's own retry model: FlowNotReadyException becomes an iterate-later request, and FlowNonRetryableException becomes a permanent failure - neither requires the flow itself to depend on the Sixpack SDK.

Reporting boundary: JUnit/Allure vs. standalone execution

Selenide's own JUnit5 extensions (ScreenShooterExtension, etc.) and Allure integrations (AllureSelenide, @Step/@Attachment) only capture anything when there is an active JUnit test case or Allure lifecycle to attach to. A flow dispatched as a bare Sixpack generator - through FlowRuntime, the same path a real supplier uses - has neither: no JUnit extension runs, and no Allure test case is active, so those integrations become silent no-ops rather than errors.

This means:

  • Screenshot/step reporting you rely on in tests will not appear when the same flow runs as a generator.
  • SelenideFlowExecutionException (thrown by SelenideFlowGenerator on failure) independently carries whatever screenshot/page-source Selenide itself already captured at the point of failure, regardless of whether Allure is wired up at all - this is the mechanism to rely on for generator-side failure diagnostics, not the JUnit/Allure integrations.
  • If you need step-level reporting specifically for generator runs, treat it as a separate concern from test reporting, since the two run in fundamentally different lifecycles.

Adapt the sample to your system

Keep the same project shape and replace the demo app-specific pieces:

  1. Point the page objects in pages/ at your application's own selectors.
  2. Replace the flows in flows/ with journeys that create your data.
  3. Keep each flow input and output flat unless the consumer contract truly needs nesting.
  4. Wrap the flows you want to expose in generators/.
  5. Add stock templates only after the generator contract is stable.
  6. Validate each important flow through direct JUnit tests, FlowCli generate, and live supplier execution - the same three-execution-mode discipline as any other Sixpack flow-based sample.