Fluent API
Fluent API
Stepwright uses a fluent (chainable) API pattern that makes scripts readable and self-documenting.
Creating a Script
Every script starts with Stepwright.create():
import { Stepwright } from '@korvol/stepwright';
const script = Stepwright.create('My Script Name');The script name is used for logging and reporting.
Method Chaining
All configuration methods return this, allowing you to chain them:
const script = Stepwright.create('E-commerce Checkout') .config({ headless: true }) .data({ cartId: 'abc123' }) .reporter(new JSONReporter()) .video(true) .checkpoint('Add to Cart') .step('Navigate', ...) .step('Click Add', ...) .endCheckpoint() .checkpoint('Checkout') .step('Go to cart', ...) .step('Enter details', ...) .step('Submit', ...) .endCheckpoint();Chain Order
The recommended order for method chaining is:
- Configuration -
config(),data(),video(),reporter() - Checkpoints and Steps -
checkpoint(),step(),endCheckpoint() - Execution -
run()
Stepwright.create('Script') // 1. Configuration .config({ ... }) .data({ ... }) .reporter(myReporter)
// 2. Steps .checkpoint('Phase 1') .step('Step 1', ...) .endCheckpoint()
// 3. Execute .run();Configuration Methods
.config(options)
Set execution options:
.config({ browser: 'chromium', // Browser type headless: true, // Headless mode defaultTimeout: 30000, // Default step timeout stopOnFailure: true, // Stop on first failure screenshotOnFailure: true, // Capture screenshots domOnFailure: true, // Capture DOM artifactDir: './artifacts', // Output directory verbose: true, // Enable verbose logging}).data(initialData)
Set initial shared data:
.data({ username: 'testuser', password: 'secret', baseUrl: 'https://app.example.com',}).video(config)
Enable video recording:
// Simple enable.video(true)
// With options.video({ enabled: true, dir: './videos', size: { width: 1280, height: 720 },}).reporter(reporter)
Add a reporter for output:
import { ConsoleReporter, JSONReporter } from '@korvol/stepwright';
.reporter(new ConsoleReporter({ colors: true })).reporter(new JSONReporter({ outputPath: './results.json' }))Step Definition Methods
.checkpoint(name, options?)
Start a new checkpoint:
.checkpoint('Login') // Simple.checkpoint('Login', { // With options required: true, maxRetries: 3,}).step(name, fn, options?)
Define a step:
.step('Navigate', async (ctx) => { await ctx.page.goto('https://example.com');})
.step('Fill Form', async (ctx) => { await ctx.page.fill('#email', ctx.data.email);}, { timeout: 10000, retry: { times: 2 },}).endCheckpoint()
Close the current checkpoint:
.checkpoint('Phase 1') .step('Step 1', ...) .step('Step 2', ...).endCheckpoint() // Close Phase 1
.checkpoint('Phase 2') .step('Step 3', ...).endCheckpoint() // Close Phase 2Background Task Methods
.background(name, task)
Add a background task that monitors for conditions:
.background('Handle Auth Popup', { trigger: { type: 'url', pattern: '**/login**' }, handler: async (ctx) => { await ctx.page.fill('#token', ctx.data.token); },})Execution Methods
.run(options?)
Execute the script:
// Run all stepsconst result = await script.run();
// Run until a specific stepconst result = await script.run({ untilStep: 'Submit Form' });
// Resume from a checkpointconst result = await script.run({ fromCheckpoint: 'Checkout' });Return Values
The run() method returns a StepwrightResult:
interface StepwrightResult<TData> { success: boolean; duration: number; stepsCompleted: number; totalSteps: number; steps: StepResult[]; checkpoints?: CheckpointResult[]; data: TData; failedStep?: { name: string; index: number; checkpoint?: string; error: Error; artifacts: StepArtifacts; }; video?: string;}Error Handling
Errors in steps are caught and reported:
const result = await script.run();
if (!result.success) { console.error('Failed step:', result.failedStep?.name); console.error('Error:', result.failedStep?.error.message); console.error('Screenshot:', result.failedStep?.artifacts.screenshot);}Immutability
// Don't do this - both share the same instanceconst base = Stepwright.create('Base');const withLogin = base.checkpoint('Login').step(...);const withoutLogin = base.checkpoint('Direct').step(...);
// Do this insteadfunction createScript(withLogin: boolean) { const script = Stepwright.create('Script'); if (withLogin) { script.checkpoint('Login').step(...).endCheckpoint(); } return script;}Next Steps
- Steps and Checkpoints - Deep dive into organizing scripts
- Data Management - Share data between steps
- Retries and Recovery - Handle failures gracefully