or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdhttp-client.mdhttp-utilities.mdindex.mdrequest-response-mocking.mdtest-doubles.mdtest-sandbox.mdvalidation-helpers.md

request-response-mocking.mddocs/

0

# Request/Response Mocking

1

2

Shot-based HTTP request/response stubs for testing without running servers, including Express-specific context stubbing.

3

4

## Capabilities

5

6

### Shot Integration

7

8

Shot library integration for HTTP request/response injection and mocking.

9

10

```typescript { .api }

11

/**

12

* Shot injection function for simulating HTTP requests

13

* @param dispatchFunc - Function that handles the request

14

* @param options - Request configuration options

15

* @returns Promise resolving to response object

16

*/

17

function inject(

18

dispatchFunc: ShotListener,

19

options: ShotRequestOptions

20

): Promise<ResponseObject>;

21

22

/**

23

* Shot request options interface

24

*/

25

interface ShotRequestOptions {

26

url: string;

27

method?: string;

28

headers?: { [key: string]: string };

29

payload?: string | Buffer | object;

30

credentials?: any;

31

artifacts?: any;

32

app?: any;

33

plugins?: any;

34

validate?: boolean;

35

}

36

37

/**

38

* Shot listener function type

39

*/

40

type ShotListener = (req: IncomingMessage, res: ServerResponse) => void;

41

```

42

43

**Usage Examples:**

44

45

```typescript

46

import { inject } from "@loopback/testlab";

47

import { IncomingMessage, ServerResponse } from "http";

48

49

// Handler function to test

50

function handler(req: IncomingMessage, res: ServerResponse) {

51

res.writeHead(200, {"Content-Type": "application/json"});

52

res.end(JSON.stringify({url: req.url, method: req.method}));

53

}

54

55

// Inject request and get response

56

const response = await inject(handler, {

57

url: "/test",

58

method: "GET"

59

});

60

61

expect(response.statusCode).to.equal(200);

62

expect(JSON.parse(response.payload)).to.eql({

63

url: "/test",

64

method: "GET"

65

});

66

67

// POST request with payload

68

const postResponse = await inject(handler, {

69

url: "/users",

70

method: "POST",

71

payload: JSON.stringify({name: "Alice"}),

72

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

73

});

74

```

75

76

### Server Request Stubbing

77

78

Create stubbed HTTP server request objects for testing.

79

80

```typescript { .api }

81

/**

82

* Creates a stubbed HTTP server request object

83

* @param options - Request configuration options

84

* @returns IncomingMessage stub with request properties

85

*/

86

function stubServerRequest(options: ShotRequestOptions): IncomingMessage;

87

```

88

89

**Usage Examples:**

90

91

```typescript

92

import { stubServerRequest, expect } from "@loopback/testlab";

93

94

// Create stubbed request

95

const request = stubServerRequest({

96

url: "/api/users?limit=10",

97

method: "POST",

98

headers: {

99

"Content-Type": "application/json",

100

"Authorization": "Bearer token123"

101

},

102

payload: JSON.stringify({name: "Alice", email: "alice@example.com"})

103

});

104

105

// Test request properties

106

expect(request.url).to.equal("/api/users?limit=10");

107

expect(request.method).to.equal("POST");

108

expect(request.headers["content-type"]).to.equal("application/json");

109

expect(request.headers.authorization).to.equal("Bearer token123");

110

111

// Use in handler testing

112

function authMiddleware(req: IncomingMessage, res: ServerResponse, next: Function) {

113

if (!req.headers.authorization) {

114

res.writeHead(401);

115

res.end("Unauthorized");

116

return;

117

}

118

next();

119

}

120

121

// Test middleware with stubbed request

122

const mockRes = { writeHead: sinon.stub(), end: sinon.stub() };

123

const next = sinon.stub();

124

125

authMiddleware(request, mockRes as any, next);

126

expect(next).to.have.been.called();

127

```

128

129

### Server Response Stubbing

130

131

Create stubbed HTTP server response objects for testing.

132

133

```typescript { .api }

134

/**

135

* Creates a stubbed HTTP server response object

136

* @param request - Associated request object

137

* @param onEnd - Callback called when response ends

138

* @returns ServerResponse stub

139

*/

140

function stubServerResponse(

141

request: IncomingMessage,

142

onEnd: ShotCallback

143

): ServerResponse;

144

145

/**

146

* Callback function for Shot response completion

147

*/

148

type ShotCallback = (response: ResponseObject) => void;

149

150

/**

151

* Shot response constructor type

152

*/

153

type ShotResponseCtor = new (

154

request: IncomingMessage,

155

onEnd: ShotCallback

156

) => ServerResponse;

157

158

/**

159

* Observed response type (alias for ResponseObject)

160

*/

161

type ObservedResponse = ResponseObject;

162

```

163

164

**Usage Examples:**

165

166

```typescript

167

import { stubServerRequest, stubServerResponse, expect } from "@loopback/testlab";

168

169

// Create request and response stubs

170

const request = stubServerRequest({url: "/test"});

171

let capturedResponse: any;

172

173

const response = stubServerResponse(request, (res) => {

174

capturedResponse = res;

175

});

176

177

// Test response operations

178

response.writeHead(200, {"Content-Type": "application/json"});

179

response.write(JSON.stringify({message: "Hello"}));

180

response.end();

181

182

// Verify captured response

183

expect(capturedResponse.statusCode).to.equal(200);

184

expect(capturedResponse.headers["content-type"]).to.equal("application/json");

185

expect(JSON.parse(capturedResponse.payload)).to.eql({message: "Hello"});

186

```

187

188

### Handler Context Stubbing

189

190

Create complete handler context stubs with request, response, and result promise.

191

192

```typescript { .api }

193

/**

194

* Creates a stubbed handler context for testing

195

* @param requestOptions - Optional request configuration

196

* @returns Handler context stub with request, response, and result promise

197

*/

198

function stubHandlerContext(

199

requestOptions?: ShotRequestOptions

200

): HandlerContextStub;

201

202

/**

203

* Handler context stub interface

204

*/

205

interface HandlerContextStub {

206

request: IncomingMessage;

207

response: ServerResponse;

208

result: Promise<ObservedResponse>;

209

}

210

```

211

212

**Usage Examples:**

213

214

```typescript

215

import { stubHandlerContext, expect } from "@loopback/testlab";

216

217

// Create handler context

218

const context = stubHandlerContext({

219

url: "/api/test",

220

method: "GET"

221

});

222

223

// Use in handler

224

function testHandler(req: IncomingMessage, res: ServerResponse) {

225

res.writeHead(200, {"Content-Type": "text/plain"});

226

res.end("Hello World");

227

}

228

229

// Execute handler

230

testHandler(context.request, context.response);

231

232

// Wait for result

233

const result = await context.result;

234

expect(result.statusCode).to.equal(200);

235

expect(result.payload).to.equal("Hello World");

236

expect(result.headers["content-type"]).to.equal("text/plain");

237

238

// Test async handler

239

async function asyncHandler(req: IncomingMessage, res: ServerResponse) {

240

// Simulate async operation

241

await new Promise(resolve => setTimeout(resolve, 10));

242

res.writeHead(200);

243

res.end("Async response");

244

}

245

246

const asyncContext = stubHandlerContext();

247

asyncHandler(asyncContext.request, asyncContext.response);

248

const asyncResult = await asyncContext.result;

249

expect(asyncResult.payload).to.equal("Async response");

250

```

251

252

### Express Context Stubbing

253

254

Create Express-specific context stubs with full Express request/response API.

255

256

```typescript { .api }

257

/**

258

* Creates a stubbed Express context for testing Express applications

259

* @param requestOptions - Optional request configuration

260

* @returns Express context stub with app, request, response, and result

261

*/

262

function stubExpressContext(

263

requestOptions?: ShotRequestOptions

264

): ExpressContextStub;

265

266

/**

267

* Express context stub interface

268

*/

269

interface ExpressContextStub extends HandlerContextStub {

270

app: express.Application;

271

request: express.Request;

272

response: express.Response;

273

result: Promise<ObservedResponse>;

274

}

275

```

276

277

**Usage Examples:**

278

279

```typescript

280

import { stubExpressContext, expect } from "@loopback/testlab";

281

import express from "express";

282

283

// Create Express context

284

const context = stubExpressContext({

285

url: "/users/123?include=profile",

286

method: "GET",

287

headers: {"Accept": "application/json"}

288

});

289

290

// Test Express request properties

291

expect(context.request.params).to.be.an.Object();

292

expect(context.request.query).to.eql({include: "profile"});

293

expect(context.request.get("Accept")).to.equal("application/json");

294

expect(context.app).to.be.an.instanceOf(express.application.constructor);

295

296

// Use with Express middleware

297

function parseUserId(req: express.Request, res: express.Response, next: express.NextFunction) {

298

const userId = req.url.match(/\/users\/(\d+)/)?.[1];

299

if (userId) {

300

(req as any).userId = userId;

301

next();

302

} else {

303

res.status(400).json({error: "Invalid user ID"});

304

}

305

}

306

307

// Test middleware

308

const next = sinon.stub();

309

parseUserId(context.request, context.response, next);

310

expect((context.request as any).userId).to.equal("123");

311

expect(next).to.have.been.called();

312

313

// Use with Express route handler

314

function getUserHandler(req: express.Request, res: express.Response) {

315

const userId = (req as any).userId;

316

const includeProfile = req.query.include === "profile";

317

318

res.json({

319

id: userId,

320

name: "Alice",

321

...(includeProfile && {profile: {age: 30}})

322

});

323

}

324

325

getUserHandler(context.request, context.response);

326

327

const result = await context.result;

328

expect(result.statusCode).to.equal(200);

329

expect(JSON.parse(result.payload)).to.eql({

330

id: "123",

331

name: "Alice",

332

profile: {age: 30}

333

});

334

```

335

336

### Advanced Usage Patterns

337

338

Complex testing scenarios and patterns.

339

340

**Usage Examples:**

341

342

```typescript

343

import {

344

stubExpressContext,

345

stubHandlerContext,

346

inject,

347

expect,

348

sinon

349

} from "@loopback/testlab";

350

351

// Testing middleware chains

352

async function testMiddlewareChain() {

353

const context = stubExpressContext({

354

url: "/protected",

355

headers: {"Authorization": "Bearer valid-token"}

356

});

357

358

const middlewares = [authMiddleware, validateToken, handler];

359

360

// Simulate middleware chain

361

for (const middleware of middlewares) {

362

await new Promise((resolve) => {

363

middleware(context.request, context.response, resolve);

364

});

365

}

366

367

const result = await context.result;

368

expect(result.statusCode).to.equal(200);

369

}

370

371

// Testing error handling

372

async function testErrorHandling() {

373

const context = stubHandlerContext();

374

375

function errorHandler(req: IncomingMessage, res: ServerResponse) {

376

try {

377

throw new Error("Something went wrong");

378

} catch (error) {

379

res.writeHead(500);

380

res.end(JSON.stringify({error: error.message}));

381

}

382

}

383

384

errorHandler(context.request, context.response);

385

386

const result = await context.result;

387

expect(result.statusCode).to.equal(500);

388

expect(JSON.parse(result.payload)).to.eql({

389

error: "Something went wrong"

390

});

391

}

392

393

// Testing with POST data

394

async function testPostData() {

395

const postData = {name: "Bob", email: "bob@example.com"};

396

const context = stubExpressContext({

397

url: "/users",

398

method: "POST",

399

payload: JSON.stringify(postData),

400

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

401

});

402

403

function createUserHandler(req: express.Request, res: express.Response) {

404

// In real Express app, body would be parsed by body-parser middleware

405

// For testing, we can access the raw payload

406

const body = JSON.parse((req as any).payload || "{}");

407

408

res.status(201).json({

409

id: Math.random().toString(36),

410

...body,

411

createdAt: new Date().toISOString()

412

});

413

}

414

415

createUserHandler(context.request, context.response);

416

417

const result = await context.result;

418

expect(result.statusCode).to.equal(201);

419

const responseBody = JSON.parse(result.payload);

420

expect(responseBody).to.have.property("id");

421

expect(responseBody.name).to.equal("Bob");

422

expect(responseBody.email).to.equal("bob@example.com");

423

}

424

```