or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-handling.mdhooks.mdindex.mdparameter-transformation.mdruntime-context.mdstep-definitions.md

runtime-context.mddocs/

0

# Runtime Context

1

2

Access to scenario information, status, and reporting capabilities during test execution. The runtime context provides comprehensive access to scenario metadata, execution status, and powerful reporting features for enhanced test visibility and debugging.

3

4

## Capabilities

5

6

### Scenario Interface

7

8

Provides access to scenario information and reporting capabilities in hooks and step definitions.

9

10

```java { .api }

11

/**

12

* Main scenario interface for accessing test execution context

13

*/

14

public final class Scenario {

15

16

/**

17

* Get all tags associated with this scenario

18

* @return Collection of tag names including '@' prefix

19

*/

20

Collection<String> getSourceTagNames();

21

22

/**

23

* Get current execution status of the scenario

24

* @return Current status (most severe status of executed steps)

25

*/

26

Status getStatus();

27

28

/**

29

* Check if scenario has failed

30

* @return true if status is FAILED

31

*/

32

boolean isFailed();

33

34

/**

35

* Attach binary data to the test report

36

* @param data Binary data (e.g., screenshots, files)

37

* @param mediaType MIME type (e.g., "image/png", "application/json")

38

* @param name Human-readable name for the attachment

39

*/

40

void attach(byte[] data, String mediaType, String name);

41

42

/**

43

* Attach text data to the test report

44

* @param data Text content

45

* @param mediaType MIME type (e.g., "text/plain", "text/html")

46

* @param name Human-readable name for the attachment

47

*/

48

void attach(String data, String mediaType, String name);

49

50

/**

51

* Log text message to the test report

52

* @param text Message to log

53

*/

54

void log(String text);

55

56

/**

57

* Get scenario name from feature file

58

* @return Scenario name

59

*/

60

String getName();

61

62

/**

63

* Get unique identifier for this scenario execution

64

* @return Scenario ID (not stable across executions)

65

*/

66

String getId();

67

68

/**

69

* Get URI of the feature file containing this scenario

70

* @return Feature file URI

71

*/

72

URI getUri();

73

74

/**

75

* Get line number of scenario in feature file

76

* @return Line number (or example row line for scenario outlines)

77

*/

78

Integer getLine();

79

}

80

```

81

82

**Usage Examples:**

83

84

```java

85

import io.cucumber.java.After;

86

import io.cucumber.java.Before;

87

import io.cucumber.java.Scenario;

88

import java.util.Collection;

89

90

public class ScenarioContextExamples {

91

92

@Before

93

public void beforeScenario(Scenario scenario) {

94

// Log scenario start

95

scenario.log("Starting scenario: " + scenario.getName());

96

97

// Check scenario tags for setup decisions

98

Collection<String> tags = scenario.getSourceTagNames();

99

100

if (tags.contains("@database")) {

101

scenario.log("Initializing database for scenario");

102

initializeDatabase();

103

}

104

105

if (tags.contains("@web")) {

106

scenario.log("Starting web driver");

107

startWebDriver();

108

}

109

110

// Log scenario metadata

111

scenario.log("Feature file: " + scenario.getUri());

112

scenario.log("Line number: " + scenario.getLine());

113

scenario.log("Scenario ID: " + scenario.getId());

114

}

115

116

@After

117

public void afterScenario(Scenario scenario) {

118

// Log scenario completion

119

Status status = scenario.getStatus();

120

scenario.log("Scenario completed with status: " + status);

121

122

// Handle failed scenarios

123

if (scenario.isFailed()) {

124

scenario.log("❌ Scenario failed: " + scenario.getName());

125

126

// Take screenshot for web tests

127

if (scenario.getSourceTagNames().contains("@web")) {

128

byte[] screenshot = takeScreenshot();

129

scenario.attach(screenshot, "image/png", "Failure Screenshot");

130

}

131

132

// Attach error logs

133

String errorLog = getErrorLog();

134

scenario.attach(errorLog, "text/plain", "Error Log");

135

136

// Attach system state

137

String systemInfo = getSystemInfo();

138

scenario.attach(systemInfo, "application/json", "System State");

139

} else {

140

scenario.log("✅ Scenario passed successfully");

141

}

142

143

// Cleanup based on tags

144

Collection<String> tags = scenario.getSourceTagNames();

145

if (tags.contains("@cleanup")) {

146

scenario.log("Performing cleanup for @cleanup tag");

147

performCleanup();

148

}

149

}

150

}

151

```

152

153

### Status Enumeration

154

155

Represents the execution status of scenarios and steps.

156

157

```java { .api }

158

/**

159

* Execution status enumeration for scenarios and steps

160

*/

161

public enum Status {

162

163

/** Step/scenario executed successfully */

164

PASSED,

165

166

/** Step/scenario was skipped */

167

SKIPPED,

168

169

/** Step is marked as pending (not yet implemented) */

170

PENDING,

171

172

/** No matching step definition found */

173

UNDEFINED,

174

175

/** Multiple matching step definitions found */

176

AMBIGUOUS,

177

178

/** Step/scenario execution failed */

179

FAILED,

180

181

/** Step was not executed (unused) */

182

UNUSED

183

}

184

```

185

186

**Usage Examples:**

187

188

```java

189

import io.cucumber.java.After;

190

import io.cucumber.java.Status;

191

import io.cucumber.java.Scenario;

192

193

public class StatusHandlingExamples {

194

195

@After

196

public void handleScenarioStatus(Scenario scenario) {

197

Status status = scenario.getStatus();

198

199

switch (status) {

200

case PASSED:

201

scenario.log("✅ All steps passed successfully");

202

recordSuccessMetrics();

203

break;

204

205

case FAILED:

206

scenario.log("❌ One or more steps failed");

207

handleFailure(scenario);

208

break;

209

210

case SKIPPED:

211

scenario.log("⏭️ Scenario was skipped");

212

recordSkippedTest();

213

break;

214

215

case PENDING:

216

scenario.log("⏳ Scenario has pending steps");

217

reportPendingSteps();

218

break;

219

220

case UNDEFINED:

221

scenario.log("❓ Scenario has undefined steps");

222

reportUndefinedSteps();

223

break;

224

225

case AMBIGUOUS:

226

scenario.log("⚠️ Scenario has ambiguous step definitions");

227

reportAmbiguousSteps();

228

break;

229

230

case UNUSED:

231

scenario.log("⭕ Scenario was not executed");

232

break;

233

234

default:

235

scenario.log("❓ Unknown status: " + status);

236

}

237

}

238

239

private void handleFailure(Scenario scenario) {

240

// Specific failure handling

241

scenario.log("Failure details for: " + scenario.getName());

242

243

// Attach debug information

244

String debugInfo = gatherDebugInformation();

245

scenario.attach(debugInfo, "text/plain", "Debug Information");

246

247

// Send failure notification

248

sendFailureNotification(scenario.getName(), scenario.getUri().toString());

249

}

250

}

251

```

252

253

### Attachment and Logging

254

255

Comprehensive reporting capabilities for attaching files, screenshots, and logging information.

256

257

```java { .api }

258

/**

259

* Binary attachment with media type specification

260

*/

261

public void attach(byte[] data, String mediaType, String name);

262

263

/**

264

* Text attachment with media type specification

265

*/

266

public void attach(String data, String mediaType, String name);

267

268

/**

269

* Simple text logging

270

*/

271

public void log(String text);

272

```

273

274

**Usage Examples:**

275

276

```java

277

import io.cucumber.java.After;

278

import io.cucumber.java.AfterStep;

279

import io.cucumber.java.Before;

280

import io.cucumber.java.Scenario;

281

import java.io.File;

282

import java.nio.file.Files;

283

284

public class AttachmentExamples {

285

286

@Before("@web")

287

public void beforeWebScenario(Scenario scenario) {

288

scenario.log("🌐 Starting web scenario: " + scenario.getName());

289

290

// Attach browser configuration

291

String browserConfig = getBrowserConfiguration();

292

scenario.attach(browserConfig, "application/json", "Browser Configuration");

293

}

294

295

@AfterStep("@screenshot")

296

public void takeScreenshotAfterStep(Scenario scenario) {

297

// Take screenshot after each step for visual tests

298

byte[] screenshot = takeScreenshot();

299

scenario.attach(screenshot, "image/png", "Step Screenshot");

300

301

scenario.log("📸 Screenshot captured after step");

302

}

303

304

@After

305

public void attachTestResults(Scenario scenario) {

306

// Always attach test execution log

307

String executionLog = getExecutionLog();

308

scenario.attach(executionLog, "text/plain", "Execution Log");

309

310

if (scenario.isFailed()) {

311

// Attach comprehensive failure information

312

attachFailureDetails(scenario);

313

}

314

315

// Attach performance metrics

316

String performanceData = getPerformanceMetrics();

317

scenario.attach(performanceData, "application/json", "Performance Metrics");

318

}

319

320

private void attachFailureDetails(Scenario scenario) {

321

scenario.log("🔍 Collecting failure details...");

322

323

// Screenshot for UI tests

324

if (scenario.getSourceTagNames().contains("@web")) {

325

byte[] screenshot = takeScreenshot();

326

scenario.attach(screenshot, "image/png", "Failure Screenshot");

327

scenario.log("📸 Failure screenshot captured");

328

}

329

330

// Browser logs for web tests

331

if (scenario.getSourceTagNames().contains("@web")) {

332

String browserLogs = getBrowserLogs();

333

scenario.attach(browserLogs, "text/plain", "Browser Console Logs");

334

}

335

336

// Database state for data tests

337

if (scenario.getSourceTagNames().contains("@database")) {

338

String dbState = getDatabaseState();

339

scenario.attach(dbState, "application/json", "Database State");

340

}

341

342

// API response for integration tests

343

if (scenario.getSourceTagNames().contains("@api")) {

344

String lastResponse = getLastApiResponse();

345

scenario.attach(lastResponse, "application/json", "Last API Response");

346

}

347

348

// System logs

349

String systemLogs = getSystemLogs();

350

scenario.attach(systemLogs, "text/plain", "System Logs");

351

352

// Stack trace

353

String stackTrace = getStackTrace();

354

scenario.attach(stackTrace, "text/plain", "Stack Trace");

355

356

scenario.log("🔍 Failure details collection complete");

357

}

358

359

// Example of attaching various file types

360

public void attachVariousFileTypes(Scenario scenario) {

361

try {

362

// HTML report

363

String htmlReport = generateHtmlReport();

364

scenario.attach(htmlReport, "text/html", "Test Report");

365

366

// JSON data

367

String jsonData = getTestData();

368

scenario.attach(jsonData, "application/json", "Test Data");

369

370

// XML configuration

371

String xmlConfig = getXmlConfiguration();

372

scenario.attach(xmlConfig, "application/xml", "Configuration");

373

374

// CSV data

375

String csvData = getCsvData();

376

scenario.attach(csvData, "text/csv", "Data Export");

377

378

// Binary file

379

File logFile = new File("application.log");

380

if (logFile.exists()) {

381

byte[] logContent = Files.readAllBytes(logFile.toPath());

382

scenario.attach(logContent, "application/octet-stream", "Application Log");

383

}

384

385

// PDF report

386

byte[] pdfReport = generatePdfReport();

387

scenario.attach(pdfReport, "application/pdf", "PDF Report");

388

389

} catch (Exception e) {

390

scenario.log("⚠️ Error attaching files: " + e.getMessage());

391

}

392

}

393

}

394

```

395

396

### Scenario Metadata Access

397

398

Access detailed scenario metadata for conditional logic and reporting.

399

400

```java

401

public class ScenarioMetadataExamples {

402

403

@Before

404

public void analyzeScenario(Scenario scenario) {

405

// Basic metadata

406

String name = scenario.getName();

407

String uri = scenario.getUri().toString();

408

Integer line = scenario.getLine();

409

String id = scenario.getId();

410

411

scenario.log("📋 Scenario Analysis:");

412

scenario.log(" Name: " + name);

413

scenario.log(" File: " + uri);

414

scenario.log(" Line: " + line);

415

scenario.log(" ID: " + id);

416

417

// Tag analysis

418

Collection<String> tags = scenario.getSourceTagNames();

419

scenario.log(" Tags: " + String.join(", ", tags));

420

421

// Conditional setup based on metadata

422

if (name.toLowerCase().contains("slow")) {

423

scenario.log("⏰ Slow test detected - increasing timeouts");

424

increaseTimeouts();

425

}

426

427

if (uri.contains("critical")) {

428

scenario.log("🚨 Critical test - enabling detailed logging");

429

enableDetailedLogging();

430

}

431

432

// Tag-based configuration

433

configureBasedOnTags(scenario, tags);

434

}

435

436

private void configureBasedOnTags(Scenario scenario, Collection<String> tags) {

437

if (tags.contains("@performance")) {

438

scenario.log("⚡ Performance test - starting profiler");

439

startProfiler();

440

}

441

442

if (tags.contains("@security")) {

443

scenario.log("🔒 Security test - enabling security monitoring");

444

enableSecurityMonitoring();

445

}

446

447

if (tags.contains("@integration")) {

448

scenario.log("🔗 Integration test - checking external services");

449

checkExternalServices();

450

}

451

452

if (tags.contains("@smoke")) {

453

scenario.log("💨 Smoke test - using minimal setup");

454

useMinimalSetup();

455

}

456

457

// Environment-specific tags

458

if (tags.contains("@dev-only") && !isDevEnvironment()) {

459

scenario.log("⏭️ Dev-only test in non-dev environment - will skip");

460

}

461

462

if (tags.contains("@prod-safe") && isProdEnvironment()) {

463

scenario.log("✅ Production-safe test in prod environment");

464

}

465

}

466

467

@After

468

public void reportScenarioMetrics(Scenario scenario) {

469

// Create detailed scenario report

470

String report = String.format(

471

"Scenario Execution Report:\n" +

472

" Name: %s\n" +

473

" Status: %s\n" +

474

" File: %s (line %d)\n" +

475

" Tags: %s\n" +

476

" Duration: %d ms\n" +

477

" Steps: %d\n",

478

scenario.getName(),

479

scenario.getStatus(),

480

scenario.getUri(),

481

scenario.getLine(),

482

String.join(", ", scenario.getSourceTagNames()),

483

getExecutionDuration(scenario.getId()),

484

getStepCount(scenario.getId())

485

);

486

487

scenario.attach(report, "text/plain", "Execution Report");

488

scenario.log("📊 Execution report generated");

489

}

490

}

491

```

492

493

### PendingException

494

495

Exception class for marking steps as not yet implemented, commonly used during BDD development.

496

497

```java { .api }

498

/**

499

* Exception to mark steps as pending (not yet implemented)

500

*/

501

public final class PendingException extends RuntimeException {

502

503

/**

504

* Create pending exception with default message "TODO: implement me"

505

*/

506

public PendingException();

507

508

/**

509

* Create pending exception with custom message

510

* @param message Custom message describing what needs to be implemented

511

*/

512

public PendingException(String message);

513

}

514

```

515

516

**Usage Examples:**

517

518

```java

519

import io.cucumber.java.PendingException;

520

import io.cucumber.java.en.*;

521

522

public class PendingStepExamples {

523

524

@Given("the user is logged in")

525

public void the_user_is_logged_in() {

526

// TODO: Implement user login logic

527

throw new PendingException("User login not yet implemented");

528

}

529

530

@When("I perform a complex calculation")

531

public void i_perform_complex_calculation() {

532

// TODO: Implement calculation logic

533

throw new PendingException("Complex calculation algorithm pending");

534

}

535

536

@Then("the result should be accurate")

537

public void the_result_should_be_accurate() {

538

// Placeholder for result validation

539

throw new PendingException();

540

}

541

542

@Given("the external API is available")

543

public void external_api_available() {

544

// TODO: Check API availability

545

throw new PendingException("API availability check not implemented - requires API client setup");

546

}

547

548

// Pattern: Implement step gradually

549

@When("I submit the payment form")

550

public void submit_payment_form() {

551

// Step 1: Form validation (implemented)

552

validatePaymentForm();

553

554

// Step 2: Payment processing (pending)

555

throw new PendingException("Payment processing integration pending - waiting for payment gateway setup");

556

557

// Step 3: Result handling (not reached)

558

// handlePaymentResult();

559

}

560

561

// Pattern: Feature flag for incomplete features

562

@Then("the new feature should be visible")

563

public void new_feature_visible() {

564

if (!isFeatureFlagEnabled("NEW_FEATURE")) {

565

throw new PendingException("New feature behind feature flag - implementation complete but not enabled");

566

}

567

568

// Feature implementation here when enabled

569

validateNewFeature();

570

}

571

}

572

```