or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

fixture-testing.mdglobal-management.mdindex.mdrecording-playback.mdrequest-interception.mdrequest-matching.mdresponse-definition.md

recording-playback.mddocs/

0

# Recording and Playback

1

2

This document covers nock's recording functionality, which captures real HTTP traffic and converts it into fixtures that can be replayed in tests.

3

4

## Recording Interface

5

6

The recorder provides methods to capture HTTP traffic and convert it to nock definitions.

7

8

```javascript { .api }

9

interface Recorder {

10

rec(options?: boolean | RecorderOptions): void;

11

clear(): void;

12

play(): string[] | Definition[];

13

}

14

15

const recorder: Recorder;

16

function restore(): void;

17

```

18

19

## Basic Recording

20

21

### Start Recording

22

23

```javascript { .api }

24

recorder.rec(options?: boolean | RecorderOptions): void;

25

```

26

27

Start recording HTTP traffic:

28

29

```javascript

30

const nock = require("nock");

31

32

// Start recording with default options

33

nock.recorder.rec();

34

35

// Make real HTTP requests - these will be recorded

36

const response = await fetch("https://api.example.com/users");

37

const data = await response.json();

38

39

// Stop recording and get the recorded fixtures

40

const fixtures = nock.recorder.play();

41

console.log(fixtures);

42

```

43

44

### Simple Boolean Options

45

46

```javascript

47

// Record with logging enabled

48

nock.recorder.rec(true);

49

50

// Record without logging

51

nock.recorder.rec(false);

52

```

53

54

## Recording Options

55

56

```javascript { .api }

57

interface RecorderOptions {

58

dont_print?: boolean;

59

output_objects?: boolean;

60

enable_reqheaders_recording?: boolean;

61

logging?: (content: string) => void;

62

use_separator?: boolean;

63

}

64

```

65

66

### Don't Print Option

67

68

Control whether recorded fixtures are automatically logged to console:

69

70

```javascript

71

// Don't print fixtures automatically (default: false)

72

nock.recorder.rec({ dont_print: true });

73

74

// Make requests...

75

const fixtures = nock.recorder.play(); // Get fixtures manually

76

```

77

78

### Output Objects Option

79

80

Control the format of recorded fixtures:

81

82

```javascript

83

// Output as JavaScript objects (default: false, outputs as strings)

84

nock.recorder.rec({ output_objects: true });

85

86

// Make requests...

87

const fixtures = nock.recorder.play();

88

// fixtures will be Definition[] instead of string[]

89

```

90

91

### Enable Request Headers Recording

92

93

Include request headers in recorded fixtures:

94

95

```javascript

96

nock.recorder.rec({ enable_reqheaders_recording: true });

97

98

// The recorded fixtures will include the headers sent in requests

99

```

100

101

Example output with headers:

102

103

```javascript

104

nock("https://api.example.com")

105

.get("/users")

106

.matchHeader("authorization", "Bearer token123")

107

.matchHeader("user-agent", "Node.js")

108

.reply(200, [{ id: 1, name: "Alice" }]);

109

```

110

111

### Custom Logging

112

113

Provide a custom logging function:

114

115

```javascript

116

const fs = require("fs");

117

118

nock.recorder.rec({

119

logging: (content) => {

120

// Write to file instead of console

121

fs.appendFileSync("./recorded-fixtures.js", content + "\n");

122

}

123

});

124

```

125

126

### Use Separator

127

128

Add separators between recorded fixtures:

129

130

```javascript

131

nock.recorder.rec({ use_separator: true });

132

133

// Output will include separator comments between fixtures:

134

// <<<<<<-- cut here -->>>>>>

135

```

136

137

## Managing Recordings

138

139

### Clear Recordings

140

141

```javascript { .api }

142

recorder.clear(): void;

143

```

144

145

Clear all recorded fixtures without stopping recording:

146

147

```javascript

148

nock.recorder.rec();

149

150

// Make some requests...

151

console.log(nock.recorder.play().length); // e.g., 3

152

153

// Clear recorded data

154

nock.recorder.clear();

155

console.log(nock.recorder.play().length); // 0

156

157

// Continue recording new requests...

158

```

159

160

### Play Recordings

161

162

```javascript { .api }

163

recorder.play(): string[] | Definition[];

164

```

165

166

Get recorded fixtures and optionally stop recording:

167

168

```javascript

169

// Get fixtures as strings (default)

170

const stringFixtures = nock.recorder.play();

171

console.log(stringFixtures[0]);

172

// Output: 'nock("https://api.example.com").get("/users").reply(200, [...]);'

173

174

// Get fixtures as objects

175

nock.recorder.rec({ output_objects: true });

176

// Make requests...

177

const objectFixtures = nock.recorder.play();

178

console.log(objectFixtures[0]);

179

// Output: { scope: "https://api.example.com", method: "GET", path: "/users", ... }

180

```

181

182

### Restore Original HTTP

183

184

```javascript { .api }

185

function restore(): void;

186

```

187

188

Stop recording and restore original HTTP behavior:

189

190

```javascript

191

nock.recorder.rec();

192

// Make requests...

193

194

// Stop recording and restore normal HTTP

195

nock.restore();

196

197

// HTTP requests will now behave normally (not recorded)

198

```

199

200

## Definition Objects

201

202

When using `output_objects: true`, recordings return Definition objects:

203

204

```javascript { .api }

205

interface Definition {

206

scope: string | RegExp;

207

path: string | RegExp;

208

port?: number | string;

209

method?: string;

210

status?: number;

211

body?: RequestBodyMatcher;

212

reqheaders?: Record<string, RequestHeaderMatcher>;

213

response?: ReplyBody;

214

headers?: ReplyHeaders;

215

options?: Options;

216

}

217

```

218

219

### Working with Definition Objects

220

221

```javascript

222

nock.recorder.rec({ output_objects: true });

223

224

// Make a request

225

await fetch("https://api.example.com/users", {

226

method: "POST",

227

headers: { "Content-Type": "application/json" },

228

body: JSON.stringify({ name: "Alice" })

229

});

230

231

const definitions = nock.recorder.play();

232

console.log(definitions[0]);

233

// Output:

234

// {

235

// scope: "https://api.example.com:443",

236

// method: "POST",

237

// path: "/users",

238

// body: '{"name":"Alice"}',

239

// status: 201,

240

// response: '{"id":1,"name":"Alice"}',

241

// headers: { "content-type": "application/json" }

242

// }

243

244

// Convert back to nock interceptors

245

const scopes = nock.define(definitions);

246

```

247

248

## Complete Recording Workflow

249

250

### Record and Generate Test Fixtures

251

252

```javascript

253

const nock = require("nock");

254

const fs = require("fs");

255

256

async function recordAPIInteractions() {

257

// Start recording with comprehensive options

258

nock.recorder.rec({

259

output_objects: true,

260

enable_reqheaders_recording: true,

261

dont_print: true

262

});

263

264

try {

265

// Make real API calls

266

const response1 = await fetch("https://api.example.com/users");

267

const users = await response1.json();

268

269

const response2 = await fetch("https://api.example.com/users/1");

270

const user = await response2.json();

271

272

const response3 = await fetch("https://api.example.com/users", {

273

method: "POST",

274

headers: { "Content-Type": "application/json" },

275

body: JSON.stringify({ name: "Bob" })

276

});

277

const newUser = await response3.json();

278

279

} finally {

280

// Get recorded fixtures

281

const definitions = nock.recorder.play();

282

283

// Save to file

284

const fixtures = JSON.stringify(definitions, null, 2);

285

fs.writeFileSync("./test/fixtures/api-fixtures.json", fixtures);

286

287

// Stop recording

288

nock.restore();

289

}

290

}

291

```

292

293

### Load and Use Recorded Fixtures

294

295

```javascript

296

const nock = require("nock");

297

const fixtures = require("./fixtures/api-fixtures.json");

298

299

describe("API Tests with Recorded Fixtures", () => {

300

beforeEach(() => {

301

// Load recorded fixtures

302

nock.define(fixtures);

303

});

304

305

afterEach(() => {

306

nock.cleanAll();

307

});

308

309

it("should get users list", async () => {

310

// This will use the recorded response

311

const response = await fetch("https://api.example.com/users");

312

const users = await response.json();

313

314

expect(Array.isArray(users)).toBe(true);

315

});

316

});

317

```

318

319

## Advanced Recording Patterns

320

321

### Conditional Recording

322

323

```javascript

324

// Only record in development mode

325

if (process.env.NODE_ENV === "development") {

326

nock.recorder.rec({

327

output_objects: true,

328

logging: (content) => {

329

console.log("Recorded fixture:", content);

330

}

331

});

332

}

333

```

334

335

### Filtering Recorded Requests

336

337

```javascript

338

nock.recorder.rec({ output_objects: true });

339

340

// Make various requests...

341

342

const allDefinitions = nock.recorder.play();

343

344

// Filter to only record API calls to specific domain

345

const apiDefinitions = allDefinitions.filter(def =>

346

def.scope.includes("api.example.com")

347

);

348

349

// Save filtered definitions

350

nock.define(apiDefinitions);

351

```

352

353

### Recording with Custom Processing

354

355

```javascript

356

const processedFixtures = [];

357

358

nock.recorder.rec({

359

output_objects: true,

360

dont_print: true,

361

logging: (content) => {

362

// Process each fixture as it's recorded

363

try {

364

const definition = JSON.parse(content);

365

366

// Remove sensitive headers

367

if (definition.reqheaders) {

368

delete definition.reqheaders.authorization;

369

delete definition.reqheaders.cookie;

370

}

371

372

// Sanitize response data

373

if (definition.response && typeof definition.response === "string") {

374

const response = JSON.parse(definition.response);

375

if (response.email) {

376

response.email = "user@example.com"; // Sanitize email

377

}

378

definition.response = JSON.stringify(response);

379

}

380

381

processedFixtures.push(definition);

382

} catch (e) {

383

// Handle non-JSON fixtures

384

processedFixtures.push(content);

385

}

386

}

387

});

388

```

389

390

## Integration with Test Frameworks

391

392

### Jest Integration

393

394

```javascript

395

// jest.setup.js

396

const nock = require("nock");

397

398

// Global setup for recording

399

global.startRecording = (options = {}) => {

400

nock.recorder.rec({

401

output_objects: true,

402

dont_print: true,

403

...options

404

});

405

};

406

407

global.stopRecording = () => {

408

const fixtures = nock.recorder.play();

409

nock.restore();

410

return fixtures;

411

};

412

413

// jest.teardown.js

414

afterEach(() => {

415

if (nock.recorder.play().length > 0) {

416

nock.restore();

417

}

418

nock.cleanAll();

419

});

420

```

421

422

### Mocha Integration

423

424

```javascript

425

const nock = require("nock");

426

427

describe("API Tests", () => {

428

let recordedFixtures = [];

429

430

before(() => {

431

// Start recording for entire test suite

432

nock.recorder.rec({ output_objects: true });

433

});

434

435

after(() => {

436

// Save all recorded fixtures

437

recordedFixtures = nock.recorder.play();

438

nock.restore();

439

440

// Optionally save to file

441

if (process.env.SAVE_FIXTURES) {

442

const fs = require("fs");

443

fs.writeFileSync(

444

"./test/recorded-fixtures.json",

445

JSON.stringify(recordedFixtures, null, 2)

446

);

447

}

448

});

449

450

// Individual tests...

451

});

452

```

453

454

## Troubleshooting Recording

455

456

### Common Issues

457

458

1. **Headers not recorded**: Use `enable_reqheaders_recording: true`

459

2. **Binary data issues**: Ensure proper encoding for binary responses

460

3. **Too many fixtures**: Use `clear()` periodically or filter recordings

461

4. **Sensitive data**: Always sanitize recorded fixtures before saving

462

463

### Debugging Recording

464

465

```javascript

466

nock.recorder.rec({

467

logging: (content) => {

468

console.log("Recording:", content);

469

470

// Debug the structure

471

if (content.startsWith("{")) {

472

try {

473

const parsed = JSON.parse(content);

474

console.log("Parsed definition:", parsed);

475

} catch (e) {

476

console.log("Failed to parse:", e.message);

477

}

478

}

479

}

480

});

481

```