Provides lambda-based step definitions for Cucumber BDD testing framework with Java 8+ functional interfaces
—
Test execution context and utilities providing access to scenario metadata, status information, and reporting capabilities. Includes the Scenario class for runtime test information and PendingException for marking unimplemented steps.
Provides comprehensive access to test execution context, including scenario metadata, status information, and attachment/logging utilities for test reporting.
/**
* Scenario context providing test execution information and reporting utilities
* Available in hooks and accessible through test framework integration
*/
public final class Scenario {
/**
* Get all tags associated with this scenario
* @return Collection of tag names including '@' prefix (e.g., "@web", "@smoke")
*/
public Collection<String> getSourceTagNames() { ... }
/**
* Get current execution status of the scenario
* @return Current status (PASSED, FAILED, SKIPPED, etc.)
*/
public Status getStatus() { ... }
/**
* Check if the scenario has failed
* @return true if scenario status is FAILED, false otherwise
*/
public boolean isFailed() { ... }
/**
* Attach binary data to the test report
* @param data Binary data to attach
* @param mediaType MIME type of the data (e.g., "image/png", "application/json")
* @param name Descriptive name for the attachment
*/
public void attach(byte[] data, String mediaType, String name) { ... }
/**
* Attach text data to the test report
* @param data Text data to attach
* @param mediaType MIME type of the text (e.g., "text/plain", "application/json")
* @param name Descriptive name for the attachment
*/
public void attach(String data, String mediaType, String name) { ... }
/**
* Log text message to the test report
* @param text Message to log for debugging and reporting
*/
public void log(String text) { ... }
/**
* Get the scenario name as defined in the feature file
* @return Scenario name string
*/
public String getName() { ... }
/**
* Get unique identifier for this scenario
* @return Scenario ID string
*/
public String getId() { ... }
/**
* Get URI of the feature file containing this scenario
* @return URI of the feature file
*/
public URI getUri() { ... }
/**
* Get line number where scenario is defined in the feature file
* @return Line number (1-based) or null if not available
*/
public Integer getLine() { ... }
}Usage Examples:
import io.cucumber.java8.En;
import io.cucumber.java8.Scenario;
public class ScenarioContextSteps implements En {
public ScenarioContextSteps() {
Before((Scenario scenario) -> {
// Log scenario start with metadata
scenario.log("Starting scenario: " + scenario.getName());
scenario.log("Tags: " + scenario.getSourceTagNames());
scenario.log("Location: " + scenario.getUri() + ":" + scenario.getLine());
// Conditional setup based on tags
if (scenario.getSourceTagNames().contains("@database")) {
setupDatabaseConnection();
}
if (scenario.getSourceTagNames().contains("@web")) {
initializeWebDriver();
}
});
After((Scenario scenario) -> {
// Capture failure information
if (scenario.isFailed()) {
scenario.log("Scenario failed with status: " + scenario.getStatus());
// Attach screenshot for web tests
if (webDriver != null) {
byte[] screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", "failure-screenshot");
}
// Attach application logs
String logs = getApplicationLogs();
scenario.attach(logs, "text/plain", "application-logs");
// Attach database state for database tests
if (scenario.getSourceTagNames().contains("@database")) {
String dbState = getDatabaseState();
scenario.attach(dbState, "application/json", "database-state");
}
}
// Always attach performance metrics
String metrics = getPerformanceMetrics();
scenario.attach(metrics, "application/json", "performance-metrics");
});
// Step-level logging
AfterStep((Scenario scenario) -> {
long stepDuration = getLastStepDuration();
scenario.log("Step completed in " + stepDuration + "ms");
// Attach step-specific data for debugging
if (scenario.getSourceTagNames().contains("@debug")) {
String stepContext = getCurrentStepContext();
scenario.attach(stepContext, "application/json", "step-context");
}
});
}
}Enumeration of possible test execution states providing comprehensive status information.
/**
* Test execution status values
*/
public enum Status {
/** Test executed successfully without failures */
PASSED,
/** Test was skipped during execution */
SKIPPED,
/** Test step is marked as pending (not yet implemented) */
PENDING,
/** Test step has no matching step definition */
UNDEFINED,
/** Test step matches multiple step definitions ambiguously */
AMBIGUOUS,
/** Test execution failed due to assertion failure or exception */
FAILED,
/** Test step was not executed (unused in scenario) */
UNUSED
}Usage Examples:
public class StatusHandlingSteps implements En {
public StatusHandlingSteps() {
After((Scenario scenario) -> {
switch (scenario.getStatus()) {
case PASSED:
scenario.log("✅ Scenario completed successfully");
recordSuccessMetrics(scenario);
break;
case FAILED:
scenario.log("❌ Scenario failed - investigating...");
investigateFailure(scenario);
notifyFailureMonitoring(scenario);
break;
case SKIPPED:
scenario.log("⏭️ Scenario was skipped");
recordSkipReason(scenario);
break;
case PENDING:
scenario.log("⏳ Scenario has pending steps");
addToPendingBacklog(scenario);
break;
case UNDEFINED:
scenario.log("❓ Scenario has undefined steps");
generateStepDefinitionTemplates(scenario);
break;
case AMBIGUOUS:
scenario.log("🤔 Scenario has ambiguous step definitions");
analyzeStepDefinitionConflicts(scenario);
break;
case UNUSED:
scenario.log("🚫 Scenario step was not used");
break;
default:
scenario.log("Unknown status: " + scenario.getStatus());
}
});
}
}Exception class for marking test steps as not yet implemented, causing tests to be marked with PENDING status instead of failing.
/**
* Exception to mark steps as pending implementation
* Thrown from step definitions to indicate the step is not yet implemented
* Results in PENDING status rather than FAILED
*/
public final class PendingException extends RuntimeException {
/**
* Create pending exception with default message
* Default message: "TODO: implement me"
*/
public PendingException() { ... }
/**
* Create pending exception with custom message
* @param message Custom message describing what needs to be implemented
*/
public PendingException(String message) { ... }
}Usage Examples:
public class PendingStepDefinitions implements En {
public PendingStepDefinitions() {
// Step not yet implemented - default message
Given("a complex integration scenario", () -> {
throw new PendingException();
// Results in: "TODO: implement me"
});
// Step not yet implemented - custom message
When("I perform advanced data processing", () -> {
throw new PendingException("Waiting for data processing service API to be finalized");
});
// Conditional pending implementation
Then("the advanced analytics should be calculated", () -> {
if (!isAdvancedAnalyticsFeatureEnabled()) {
throw new PendingException("Advanced analytics feature not yet enabled in test environment");
}
// Normal implementation when feature is enabled
verifyAdvancedAnalytics();
});
// Partial implementation with pending parts
When("I configure the system with {string}", (String configType) -> {
switch (configType) {
case "basic":
configureBasicSettings();
break;
case "advanced":
throw new PendingException("Advanced configuration not yet implemented");
case "enterprise":
throw new PendingException("Enterprise configuration pending security review");
default:
throw new IllegalArgumentException("Unknown config type: " + configType);
}
});
// Pending with detailed task breakdown
Given("a complete e-commerce checkout flow", () -> {
throw new PendingException(
"E-commerce checkout implementation pending:\n" +
"- Payment gateway integration\n" +
"- Inventory reservation\n" +
"- Order confirmation email\n" +
"- Receipt generation"
);
});
}
}Comprehensive examples of using Scenario for test reporting, debugging, and evidence collection.
Binary Attachments:
public class AttachmentSteps implements En {
public AttachmentSteps() {
After((Scenario scenario) -> {
// Screenshot attachment
if (webDriver != null) {
byte[] screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", "final-screenshot");
}
// PDF report attachment
byte[] pdfReport = generateTestReport(scenario);
scenario.attach(pdfReport, "application/pdf", "test-report");
// Network capture attachment
if (scenario.getSourceTagNames().contains("@network")) {
byte[] networkLog = getNetworkCapture();
scenario.attach(networkLog, "application/json", "network-capture");
}
});
// Step-level binary attachments
When("I upload a file", () -> {
byte[] uploadedFile = performFileUpload();
scenario.attach(uploadedFile, "application/octet-stream", "uploaded-file");
});
}
}Text and Structured Data Attachments:
public class TextAttachmentSteps implements En {
public TextAttachmentSteps() {
After((Scenario scenario) -> {
// JSON data attachment
String apiResponses = collectApiResponses();
scenario.attach(apiResponses, "application/json", "api-responses");
// Plain text logs
String applicationLogs = getApplicationLogs();
scenario.attach(applicationLogs, "text/plain", "application-logs");
// CSV data attachment
String csvData = generateCsvReport();
scenario.attach(csvData, "text/csv", "test-data-report");
// XML configuration
String xmlConfig = getCurrentConfiguration();
scenario.attach(xmlConfig, "application/xml", "runtime-configuration");
// HTML summary
String htmlSummary = generateHtmlSummary(scenario);
scenario.attach(htmlSummary, "text/html", "test-summary");
});
}
}Conditional Logging and Attachments:
public class ConditionalReportingSteps implements En {
public ConditionalReportingSteps() {
After((Scenario scenario) -> {
// Tag-based conditional reporting
if (scenario.getSourceTagNames().contains("@performance")) {
String performanceMetrics = getPerformanceMetrics();
scenario.attach(performanceMetrics, "application/json", "performance-metrics");
scenario.log("Performance test completed - see attached metrics");
}
if (scenario.getSourceTagNames().contains("@security")) {
String securityAudit = getSecurityAuditResults();
scenario.attach(securityAudit, "application/json", "security-audit");
}
// Status-based conditional reporting
if (scenario.isFailed()) {
String debugInfo = collectDebugInformation();
scenario.attach(debugInfo, "text/plain", "debug-information");
String systemState = captureSystemState();
scenario.attach(systemState, "application/json", "system-state");
scenario.log("Failure occurred - debug information and system state captured");
}
// Scenario name-based conditional reporting
if (scenario.getName().contains("integration")) {
String integrationLogs = getIntegrationLogs();
scenario.attach(integrationLogs, "text/plain", "integration-logs");
}
});
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-cucumber--cucumber-java8