or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfiguration.mdcore-auditing.mdindex.mdreport-generation.mduser-flows.md
tile.json

user-flows.mddocs/

0

# User Flow Testing

1

2

User flow testing enables comprehensive analysis of multi-step user journeys, measuring performance and user experience across complex interactions. This capability is essential for testing real-world user scenarios and identifying performance issues that occur during user interactions.

3

4

## Capabilities

5

6

### Start Flow Function

7

8

Creates a new UserFlow instance for multi-step user journey testing.

9

10

```javascript { .api }

11

/**

12

* Start a new user flow for multi-step testing

13

* @param page - Puppeteer page instance for testing

14

* @param options - Optional flow configuration and settings

15

* @returns Promise resolving to UserFlow instance

16

*/

17

function startFlow(

18

page: LH.Puppeteer.Page,

19

options?: LH.UserFlow.Options

20

): Promise<UserFlow>;

21

```

22

23

**Usage Examples:**

24

25

```javascript

26

import { startFlow } from 'lighthouse';

27

import puppeteer from 'puppeteer';

28

29

const browser = await puppeteer.launch();

30

const page = await browser.newPage();

31

32

// Start flow with custom name and configuration

33

const flow = await startFlow(page, {

34

name: 'E-commerce Checkout Flow',

35

config: {

36

settings: {

37

throttlingMethod: 'simulate',

38

throttling: {

39

rttMs: 40,

40

throughputKbps: 10240,

41

cpuSlowdownMultiplier: 1,

42

},

43

},

44

},

45

});

46

```

47

48

### UserFlow Class

49

50

The UserFlow class provides methods for different types of measurements within a user journey.

51

52

```javascript { .api }

53

class UserFlow {

54

/**

55

* Navigate to a URL and measure navigation performance

56

* @param requestor - URL string or navigation function

57

* @param stepFlags - Optional step configuration flags

58

* @returns Promise that resolves when navigation completes

59

*/

60

navigate(

61

requestor: LH.NavigationRequestor,

62

stepFlags?: LH.UserFlow.StepFlags

63

): Promise<void>;

64

65

/**

66

* Start measuring user interactions and dynamic changes

67

* @param stepFlags - Optional step configuration flags

68

* @returns Promise that resolves when timespan starts

69

*/

70

startTimespan(stepFlags?: LH.UserFlow.StepFlags): Promise<void>;

71

72

/**

73

* End timespan measurement

74

* @returns Promise that resolves when timespan ends

75

*/

76

endTimespan(): Promise<void>;

77

78

/**

79

* Take snapshot of current page state

80

* @param stepFlags - Optional step configuration flags

81

* @returns Promise that resolves when snapshot completes

82

*/

83

snapshot(stepFlags?: LH.UserFlow.StepFlags): Promise<void>;

84

85

/**

86

* Start a user-triggered navigation (alternative to navigate())

87

* @param stepFlags - Optional step configuration flags

88

* @returns Promise that resolves when navigation setup is complete

89

*/

90

startNavigation(stepFlags?: LH.UserFlow.StepFlags): Promise<void>;

91

92

/**

93

* End a user-triggered navigation started with startNavigation()

94

* @returns Promise that resolves when navigation completes

95

*/

96

endNavigation(): Promise<void>;

97

98

/**

99

* Create final flow result with all steps

100

* @returns Promise resolving to complete flow result

101

*/

102

createFlowResult(): Promise<LH.FlowResult>;

103

104

/**

105

* Generate flow report

106

* @returns Promise resolving to HTML report string

107

*/

108

generateReport(): Promise<string>;

109

110

/**

111

* Create artifacts JSON for the flow

112

* @returns Flow artifacts object

113

*/

114

createArtifactsJson(): LH.UserFlow.FlowArtifacts;

115

}

116

```

117

118

**Usage Examples:**

119

120

```javascript

121

const flow = await startFlow(page, {name: 'Shopping Journey'});

122

123

// Step 1: Navigate to homepage

124

await flow.navigate('https://shop.example.com', {

125

stepName: 'Homepage Load',

126

});

127

128

// Step 2: Measure search interaction

129

await flow.startTimespan({stepName: 'Product Search'});

130

await page.type('.search-input', 'laptop');

131

await page.click('.search-button');

132

await page.waitForSelector('.search-results');

133

await flow.endTimespan();

134

135

// Step 3: Navigate to product page

136

await flow.navigate(async () => {

137

await page.click('.product-item:first-child a');

138

await page.waitForSelector('.product-details');

139

}, {stepName: 'Product Page Load'});

140

141

// Step 4: Take snapshot after adding to cart

142

await page.click('.add-to-cart');

143

await page.waitForSelector('.cart-confirmation');

144

await flow.snapshot({stepName: 'Added to Cart State'});

145

146

// Step 5: User-triggered navigation (alternative approach)

147

await flow.startNavigation({stepName: 'Checkout Page Load'});

148

await page.click('.checkout-button'); // This triggers navigation

149

await flow.endNavigation(); // Wait for navigation to complete

150

151

// Generate final flow result

152

const flowResult = await flow.createFlowResult();

153

```

154

155

### Flow Artifact Auditing

156

157

Audit pre-collected flow artifacts without running live tests.

158

159

```javascript { .api }

160

/**

161

* Audit collected flow artifacts

162

* @param flowArtifacts - Pre-collected flow artifacts and steps

163

* @param config - Optional Lighthouse configuration

164

* @returns Promise resolving to complete flow result

165

*/

166

function auditFlowArtifacts(

167

flowArtifacts: LH.UserFlow.FlowArtifacts,

168

config?: LH.Config

169

): Promise<LH.FlowResult>;

170

```

171

172

**Usage Examples:**

173

174

```javascript

175

import { auditFlowArtifacts } from 'lighthouse';

176

177

// Audit pre-collected artifacts (useful for CI/CD)

178

const flowResult = await auditFlowArtifacts(savedArtifacts, {

179

settings: {

180

onlyCategories: ['performance', 'accessibility'],

181

},

182

});

183

184

console.log('Flow steps:', flowResult.steps.length);

185

flowResult.steps.forEach((step, index) => {

186

console.log(`Step ${index + 1}: ${step.name}`);

187

console.log('Performance score:', step.lhr.categories.performance.score);

188

});

189

```

190

191

## Types and Interfaces

192

193

### UserFlow Options

194

195

```javascript { .api }

196

interface LH.UserFlow.Options {

197

name?: string; // Flow name for reporting

198

config?: LH.Config; // Lighthouse configuration

199

flags?: LH.Flags; // Runtime flags

200

}

201

```

202

203

### Step Flags

204

205

```javascript { .api }

206

interface LH.UserFlow.StepFlags {

207

stepName?: string; // Name of the step for reporting

208

config?: LH.Config; // Step-specific configuration

209

flags?: LH.Flags; // Step-specific flags

210

}

211

```

212

213

### Step Result

214

215

```javascript { .api }

216

interface LH.UserFlow.StepResult {

217

lhr: LH.LighthouseResult; // Lighthouse result for this step

218

name: string; // Step name

219

artifacts?: LH.Artifacts; // Raw artifacts collected

220

}

221

```

222

223

### Flow Result

224

225

```javascript { .api }

226

interface LH.FlowResult {

227

steps: LH.UserFlow.StepResult[]; // Array of all step results

228

name: string; // Flow name

229

}

230

```

231

232

### Flow Artifacts

233

234

```javascript { .api }

235

interface LH.UserFlow.FlowArtifacts {

236

gatherSteps: LH.UserFlow.GatherStep[]; // Collected gather steps

237

name: string; // Flow name

238

}

239

240

interface LH.UserFlow.GatherStep {

241

artifacts: LH.Artifacts; // Step artifacts

242

name: string; // Step name

243

config: LH.Config; // Step configuration

244

}

245

```

246

247

## Advanced Flow Patterns

248

249

### Multi-Page Flow

250

251

```javascript

252

const flow = await startFlow(page, {name: 'Multi-Page Journey'});

253

254

// Navigate through multiple pages

255

await flow.navigate('https://example.com', {stepName: 'Homepage'});

256

await flow.navigate('https://example.com/products', {stepName: 'Products Page'});

257

await flow.navigate('https://example.com/about', {stepName: 'About Page'});

258

259

const result = await flow.createFlowResult();

260

```

261

262

### Complex Interaction Flow

263

264

```javascript

265

const flow = await startFlow(page, {name: 'Form Submission Flow'});

266

267

// Initial page load

268

await flow.navigate('https://example.com/contact', {stepName: 'Contact Page Load'});

269

270

// Measure form interaction performance

271

await flow.startTimespan({stepName: 'Form Filling'});

272

await page.type('#name', 'John Doe');

273

await page.type('#email', 'john@example.com');

274

await page.type('#message', 'Hello world');

275

await flow.endTimespan();

276

277

// Measure form submission

278

await flow.startTimespan({stepName: 'Form Submission'});

279

await page.click('#submit-button');

280

await page.waitForSelector('.success-message');

281

await flow.endTimespan();

282

283

// Final state snapshot

284

await flow.snapshot({stepName: 'Success State'});

285

286

const result = await flow.createFlowResult();

287

```

288

289

### Conditional Flow Steps

290

291

```javascript

292

const flow = await startFlow(page, {name: 'Conditional User Flow'});

293

294

await flow.navigate('https://example.com/login', {stepName: 'Login Page'});

295

296

// Check if already logged in

297

const isLoggedIn = await page.$('.user-menu') !== null;

298

299

if (!isLoggedIn) {

300

await flow.startTimespan({stepName: 'Login Process'});

301

await page.type('#username', 'testuser');

302

await page.type('#password', 'password');

303

await page.click('#login-button');

304

await page.waitForSelector('.user-menu');

305

await flow.endTimespan();

306

}

307

308

await flow.navigate('https://example.com/dashboard', {stepName: 'Dashboard Load'});

309

const result = await flow.createFlowResult();

310

```

311

312

## Performance Considerations

313

314

### Flow Configuration

315

316

```javascript

317

// Optimize flow for CI/CD environments

318

const flow = await startFlow(page, {

319

name: 'CI Performance Test',

320

config: {

321

settings: {

322

// Faster execution for CI

323

throttlingMethod: 'provided',

324

screenEmulation: {disabled: true},

325

// Focus on key metrics

326

onlyCategories: ['performance'],

327

onlyAudits: [

328

'first-contentful-paint',

329

'largest-contentful-paint',

330

'cumulative-layout-shift',

331

],

332

},

333

},

334

});

335

```

336

337

### Memory Management

338

339

```javascript

340

// Clean up resources after flow completion

341

try {

342

const flow = await startFlow(page, {name: 'Resource-Intensive Flow'});

343

344

// Run your flow steps...

345

await flow.navigate('https://example.com');

346

const result = await flow.createFlowResult();

347

348

return result;

349

} finally {

350

// Ensure browser cleanup

351

await browser.close();

352

}

353

```

354

355

## Error Handling

356

357

```javascript

358

const flow = await startFlow(page, {name: 'Error-Handled Flow'});

359

360

try {

361

await flow.navigate('https://example.com', {stepName: 'Homepage'});

362

363

await flow.startTimespan({stepName: 'User Interaction'});

364

// ... user interactions

365

await flow.endTimespan();

366

367

const result = await flow.createFlowResult();

368

369

// Check for step-level errors

370

result.steps.forEach((step, index) => {

371

if (step.lhr.runtimeError) {

372

console.error(`Step ${index + 1} error:`, step.lhr.runtimeError);

373

}

374

if (step.lhr.runWarnings.length > 0) {

375

console.warn(`Step ${index + 1} warnings:`, step.lhr.runWarnings);

376

}

377

});

378

379

} catch (error) {

380

console.error('Flow execution error:', error.message);

381

throw error;

382

}

383

```