or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Sinon-Chai

1

2

Sinon-Chai provides a set of custom assertions for using the Sinon.JS spy, stub, and mocking framework with the Chai assertion library. It extends Chai with fluent, readable assertions for testing function calls, arguments, return values, and exceptions.

3

4

## Package Information

5

6

- **Package Name**: sinon-chai

7

- **Package Type**: npm

8

- **Language**: JavaScript (ES Modules)

9

- **Installation**: `npm install --save-dev sinon-chai`

10

11

## Core Imports

12

13

```javascript

14

import sinonChai from "sinon-chai";

15

import * as chai from "chai";

16

17

chai.use(sinonChai);

18

```

19

20

For CommonJS environments:

21

22

```javascript

23

const sinonChai = require("sinon-chai");

24

const chai = require("chai");

25

26

chai.use(sinonChai);

27

```

28

29

Note: The main export is a function that takes two parameters: the Chai constructor and Chai's utility functions.

30

31

## Basic Usage

32

33

```javascript

34

import * as chai from "chai";

35

import sinon from "sinon";

36

import sinonChai from "sinon-chai";

37

38

// Setup chai with sinon-chai plugin

39

chai.use(sinonChai);

40

41

// For should-style assertions

42

chai.should();

43

44

// For expect-style assertions

45

const { expect } = chai;

46

47

function hello(name, callback) {

48

callback("hello " + name);

49

}

50

51

describe("hello", function () {

52

it("should call callback with correct greeting", function () {

53

const callback = sinon.spy();

54

55

hello("world", callback);

56

57

// Using should syntax

58

callback.should.have.been.calledWith("hello world");

59

callback.should.have.been.calledOnce;

60

61

// Using expect syntax

62

expect(callback).to.have.been.calledWith("hello world");

63

expect(callback).to.have.been.calledOnce;

64

});

65

});

66

```

67

68

## Architecture

69

70

Sinon-Chai is built around the Chai plugin architecture and integrates with Sinon.JS spies, stubs, and mocks:

71

72

- **Plugin Registration**: The default export is a Chai plugin function that registers all assertion methods with Chai's prototype

73

- **Assertion Extension**: Extends Chai's `Assertion.prototype` with Sinon-specific methods and properties

74

- **Spy Detection**: Uses internal functions to detect valid Sinon spies and spy calls before applying assertions

75

- **Message Generation**: Leverages Sinon's built-in printf-style message formatting for clear assertion feedback

76

- **Always Modifier**: Implements a special `always` flag that changes assertion behavior to check all calls rather than any call

77

- **Method Types**: Supports three types of assertions:

78

- **Properties** (`called`, `calledOnce`, etc.) - Simple boolean checks

79

- **Boolean Methods** (`callCount(n)`) - Methods that take parameters for comparison

80

- **Spy Methods** (`calledWith`, `returned`, etc.) - Methods that delegate to Sinon's spy methods

81

82

## Capabilities

83

84

### Plugin Registration

85

86

The main export is a Chai plugin function that registers all Sinon-Chai assertions.

87

88

```javascript { .api }

89

/**

90

* Sinon-Chai plugin function for registering with Chai

91

* @param chai - The Chai constructor function

92

* @param utils - Chai's utility functions including addProperty and addMethod

93

*/

94

export default function sinonChai(

95

chai: ChaiStatic,

96

utils: ChaiUtils

97

): void;

98

99

interface ChaiStatic {

100

Assertion: ChaiAssertion;

101

}

102

103

interface ChaiUtils {

104

addProperty(ctx: any, name: string, getter: Function): void;

105

addMethod(ctx: any, name: string, method: Function): void;

106

flag(obj: any, key: string, value?: any): any;

107

inspect(obj: any): string;

108

}

109

```

110

111

### Call Detection Assertions

112

113

Assertions for detecting whether spies, stubs, or mocks have been called.

114

115

```javascript { .api }

116

/**

117

* Assert that a spy has been called at least once

118

* Usage: spy.should.have.been.called

119

*/

120

interface CalledAssertion {

121

called: ChaiAssertion;

122

}

123

124

/**

125

* Assert that a spy has been called exactly n times

126

* Usage: spy.should.have.callCount(3)

127

*/

128

interface CallCountAssertion {

129

callCount(count: number): ChaiAssertion;

130

}

131

132

/**

133

* Assert that a spy has been called exactly once

134

* Usage: spy.should.have.been.calledOnce

135

*/

136

interface CalledOnceAssertion {

137

calledOnce: ChaiAssertion;

138

}

139

140

/**

141

* Assert that a spy has been called exactly twice

142

* Usage: spy.should.have.been.calledTwice

143

*/

144

interface CalledTwiceAssertion {

145

calledTwice: ChaiAssertion;

146

}

147

148

/**

149

* Assert that a spy has been called exactly thrice

150

* Usage: spy.should.have.been.calledThrice

151

*/

152

interface CalledThriceAssertion {

153

calledThrice: ChaiAssertion;

154

}

155

```

156

157

**Usage Examples:**

158

159

```javascript

160

const spy = sinon.spy();

161

162

spy();

163

spy();

164

165

spy.should.have.been.called;

166

spy.should.have.callCount(2);

167

spy.should.have.been.calledTwice;

168

169

// Negation

170

spy.should.not.have.been.calledOnce;

171

spy.should.not.have.been.calledThrice;

172

```

173

174

### Constructor Call Assertions

175

176

Assertions for detecting calls made with the `new` keyword.

177

178

```javascript { .api }

179

/**

180

* Assert that a spy was called with the new keyword

181

* Usage: spy.should.have.been.calledWithNew

182

* Always variant: spy.should.always.have.been.calledWithNew

183

*/

184

interface CalledWithNewAssertion {

185

calledWithNew: ChaiAssertion;

186

}

187

```

188

189

**Usage Examples:**

190

191

```javascript

192

const ConstructorSpy = sinon.spy();

193

194

new ConstructorSpy();

195

ConstructorSpy("without new");

196

197

ConstructorSpy.should.have.been.calledWithNew;

198

199

// For checking all calls

200

ConstructorSpy.should.always.have.been.calledWithNew; // Will fail

201

```

202

203

### Call Order Assertions

204

205

Assertions for verifying the order in which spies were called.

206

207

```javascript { .api }

208

/**

209

* Assert that spy1 was called before spy2

210

* Usage: spy1.should.have.been.calledBefore(spy2)

211

*/

212

interface CalledBeforeAssertion {

213

calledBefore(anotherSpy: SinonSpy): ChaiAssertion;

214

}

215

216

/**

217

* Assert that spy1 was called after spy2

218

* Usage: spy1.should.have.been.calledAfter(spy2)

219

*/

220

interface CalledAfterAssertion {

221

calledAfter(anotherSpy: SinonSpy): ChaiAssertion;

222

}

223

224

/**

225

* Assert that spy1 was called immediately before spy2

226

* Usage: spy1.should.have.been.calledImmediatelyBefore(spy2)

227

*/

228

interface CalledImmediatelyBeforeAssertion {

229

calledImmediatelyBefore(anotherSpy: SinonSpy): ChaiAssertion;

230

}

231

232

/**

233

* Assert that spy1 was called immediately after spy2

234

* Usage: spy1.should.have.been.calledImmediatelyAfter(spy2)

235

*/

236

interface CalledImmediatelyAfterAssertion {

237

calledImmediatelyAfter(anotherSpy: SinonSpy): ChaiAssertion;

238

}

239

```

240

241

**Usage Examples:**

242

243

```javascript

244

const spy1 = sinon.spy();

245

const spy2 = sinon.spy();

246

247

spy1();

248

spy2();

249

250

spy1.should.have.been.calledBefore(spy2);

251

spy2.should.have.been.calledAfter(spy1);

252

spy1.should.have.been.calledImmediatelyBefore(spy2);

253

spy2.should.have.been.calledImmediatelyAfter(spy1);

254

```

255

256

### Context (this) Assertions

257

258

Assertions for verifying the context (this value) with which spies were called.

259

260

```javascript { .api }

261

/**

262

* Assert that a spy was called with the specified context (this value)

263

* Usage: spy.should.have.been.calledOn(context)

264

* Always variant: spy.should.always.have.been.calledOn(context)

265

*/

266

interface CalledOnAssertion {

267

calledOn(context: any): ChaiAssertion;

268

}

269

```

270

271

**Usage Examples:**

272

273

```javascript

274

const spy = sinon.spy();

275

const obj = { method: spy };

276

277

obj.method();

278

spy.call(obj);

279

spy.call({ other: true });

280

281

spy.should.have.been.calledOn(obj);

282

spy.should.not.always.have.been.calledOn(obj); // Because third call used different context

283

```

284

285

### Argument Assertions

286

287

Assertions for verifying the arguments passed to spies.

288

289

```javascript { .api }

290

/**

291

* Assert that a spy was called with the specified arguments (partial match)

292

* Usage: spy.should.have.been.calledWith(arg1, arg2)

293

* Always variant: spy.should.always.have.been.calledWith(arg1, arg2)

294

*/

295

interface CalledWithAssertion {

296

calledWith(...args: any[]): ChaiAssertion;

297

}

298

299

/**

300

* Assert that a spy was called exactly once with the specified arguments

301

* Usage: spy.should.have.been.calledOnceWith(arg1, arg2)

302

*/

303

interface CalledOnceWithAssertion {

304

calledOnceWith(...args: any[]): ChaiAssertion;

305

}

306

307

/**

308

* Assert that a spy was called with exactly the specified arguments (exact match)

309

* Usage: spy.should.have.been.calledWithExactly(arg1, arg2)

310

* Always variant: spy.should.always.have.been.calledWithExactly(arg1, arg2)

311

*/

312

interface CalledWithExactlyAssertion {

313

calledWithExactly(...args: any[]): ChaiAssertion;

314

}

315

316

/**

317

* Assert that a spy was called exactly once with exactly the specified arguments

318

* Usage: spy.should.have.been.calledOnceWithExactly(arg1, arg2)

319

*/

320

interface CalledOnceWithExactlyAssertion {

321

calledOnceWithExactly(...args: any[]): ChaiAssertion;

322

}

323

324

/**

325

* Assert that a spy was called with arguments matching the specified Sinon matchers

326

* Usage: spy.should.have.been.calledWithMatch(sinon.match.string, sinon.match.number)

327

* Always variant: spy.should.always.have.been.calledWithMatch(...matchers)

328

*/

329

interface CalledWithMatchAssertion {

330

calledWithMatch(...matchers: any[]): ChaiAssertion;

331

}

332

```

333

334

**Usage Examples:**

335

336

```javascript

337

const spy = sinon.spy();

338

339

spy("hello", "world", "extra");

340

spy("foo", "bar");

341

342

// Partial matching - passes because "hello", "world" are present

343

spy.should.have.been.calledWith("hello", "world");

344

345

// Exact matching - checks exact argument list

346

spy.should.have.been.calledWithExactly("hello", "world", "extra");

347

348

// Once variants - for single call verification

349

const onceSpy = sinon.spy();

350

onceSpy("single", "call");

351

onceSpy.should.have.been.calledOnceWith("single", "call");

352

onceSpy.should.have.been.calledOnceWithExactly("single", "call");

353

354

// Matcher-based assertions

355

spy.should.have.been.calledWithMatch(sinon.match.string, sinon.match.string);

356

```

357

358

### Return Value Assertions

359

360

Assertions for verifying values returned by spies.

361

362

```javascript { .api }

363

/**

364

* Assert that a spy returned the specified value

365

* Usage: spy.should.have.returned(value)

366

* Always variant: spy.should.have.always.returned(value)

367

*/

368

interface ReturnedAssertion {

369

returned(value: any): ChaiAssertion;

370

}

371

```

372

373

**Usage Examples:**

374

375

```javascript

376

const stub = sinon.stub();

377

stub.onFirstCall().returns("first");

378

stub.onSecondCall().returns("second");

379

380

stub();

381

stub();

382

383

stub.should.have.returned("first");

384

stub.should.have.returned("second");

385

stub.should.not.have.always.returned("first"); // Because second call returned different value

386

```

387

388

### Exception Assertions

389

390

Assertions for verifying exceptions thrown by spies.

391

392

```javascript { .api }

393

/**

394

* Assert that a spy threw an exception, optionally of a specific type

395

* Usage: spy.should.have.thrown()

396

* Usage: spy.should.have.thrown(Error)

397

* Usage: spy.should.have.thrown('TypeError')

398

* Always variant: spy.should.have.always.thrown(errorType)

399

*/

400

interface ThrownAssertion {

401

thrown(errorType?: any): ChaiAssertion;

402

}

403

```

404

405

**Usage Examples:**

406

407

```javascript

408

const stub = sinon.stub();

409

stub.onFirstCall().throws(new TypeError("Invalid argument"));

410

stub.onSecondCall().returns("success");

411

412

stub(); // Throws

413

stub(); // Returns

414

415

stub.should.have.thrown();

416

stub.should.have.thrown(TypeError);

417

stub.should.have.thrown("TypeError");

418

stub.should.not.have.always.thrown(); // Because second call didn't throw

419

```

420

421

### Always Modifier

422

423

The `always` modifier changes assertions to require that the condition holds for ALL calls to the spy.

424

425

```javascript { .api }

426

/**

427

* Modifier that requires assertions to hold for all calls to a spy

428

* Usage: spy.should.always.have.been.calledWith(arg)

429

*/

430

interface AlwaysModifier {

431

always: ChaiAssertion;

432

}

433

```

434

435

**Usage Examples:**

436

437

```javascript

438

const spy = sinon.spy();

439

440

spy("consistent");

441

spy("consistent");

442

spy("different");

443

444

// These will pass

445

spy.should.have.been.calledWith("consistent");

446

spy.should.have.been.calledWith("different");

447

448

// This will fail because not ALL calls used "consistent"

449

spy.should.not.always.have.been.calledWith("consistent");

450

```

451

452

## Types

453

454

```javascript { .api }

455

/**

456

* Sinon spy interface (simplified for type reference)

457

*/

458

interface SinonSpy {

459

(...args: any[]): any;

460

getCall(index: number): SinonSpyCall;

461

calledWith(...args: any[]): boolean;

462

calledWithExactly(...args: any[]): boolean;

463

called: boolean;

464

callCount: number;

465

calledOnce: boolean;

466

calledTwice: boolean;

467

calledThrice: boolean;

468

}

469

470

/**

471

* Sinon spy call interface (simplified for type reference)

472

*/

473

interface SinonSpyCall {

474

proxy: SinonSpy;

475

calledWith(...args: any[]): boolean;

476

calledWithExactly(...args: any[]): boolean;

477

}

478

479

/**

480

* Chai assertion interface (extended by Sinon-Chai)

481

*/

482

interface ChaiAssertion {

483

not: ChaiAssertion;

484

have: ChaiAssertion;

485

been: ChaiAssertion;

486

always: ChaiAssertion;

487

Assertion: Function;

488

}

489

```

490

491

## Error Handling

492

493

Sinon-Chai throws `TypeError` when assertions are used on objects that are not Sinon spies or spy calls:

494

495

```javascript

496

const notASpy = {};

497

498

// This will throw TypeError: [object Object] is not a spy or a call to a spy!

499

expect(() => {

500

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

501

}).to.throw(TypeError);

502

```

503

504

## Compatibility

505

506

- **Chai**: Requires Chai 5.x or 6.x

507

- **Sinon**: Requires Sinon 4.0.0 or higher

508

- **Node.js**: ES Module support required

509

- **Browsers**: Modern browsers with ES Module support

510

- **Assertion Styles**: Compatible with both Chai's `should` and `expect` interfaces

511

- **Negation**: All assertions support Chai's `.not` negation modifier