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 JDKHttpServer- 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@Flowon 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;--jsonfor 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;--strictfails 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_ORGANIZATIONSIXPACK_AUTH_TOKENSIXPACK_CLIENT_CERT_PATHSIXPACK_CLIENT_KEY_PATHSIXPACK_ENVIRONMENTSIXPACK_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 bySelenideFlowGeneratoron 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:
- Point the page objects in
pages/at your application's own selectors. - Replace the flows in
flows/with journeys that create your data. - Keep each flow input and output flat unless the consumer contract truly needs nesting.
- Wrap the flows you want to expose in
generators/. - Add stock templates only after the generator contract is stable.
- 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.