or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdfakes.mdindex.mdmatchers.mdmocks.mdpromises.mdsandbox.mdspies.mdstubs.mdtimers.md

promises.mddocs/

0

# Promise Utilities

1

2

Sinon's promise utilities provide controllable Promise implementations for testing asynchronous code without relying on timing or external Promise resolution. These utilities allow you to manually control when Promises resolve or reject, making async tests deterministic and fast.

3

4

## Capabilities

5

6

### Creating Controllable Promises

7

8

Create Promise instances that can be manually resolved or rejected at any time during testing.

9

10

```javascript { .api }

11

/**

12

* Creates a controllable Promise for testing

13

* @param executor - Optional executor function (same as standard Promise)

14

* @returns Controllable promise with additional methods and properties

15

*/

16

function promise<T = any>(executor?: PromiseExecutor<T>): SinonPromise<T>;

17

18

interface SinonPromise<T> extends Promise<T> {

19

/** Current status of the promise */

20

status: "pending" | "resolved" | "rejected";

21

22

/** Value the promise resolved with (if resolved) */

23

resolvedValue?: T;

24

25

/** Reason the promise rejected with (if rejected) */

26

rejectedValue?: any;

27

28

/** Manually resolve the promise with a value */

29

resolve(value?: T): SinonPromise<T>;

30

31

/** Manually reject the promise with a reason */

32

reject(reason?: any): Promise<void>;

33

}

34

```

35

36

**Usage Examples:**

37

38

```javascript

39

import { promise } from "sinon";

40

41

// Create a controllable promise

42

const controllablePromise = promise();

43

44

// Check initial status

45

console.log(controllablePromise.status); // "pending"

46

47

// Set up promise handlers

48

controllablePromise.then(value => {

49

console.log("Resolved with:", value);

50

}).catch(error => {

51

console.log("Rejected with:", error);

52

});

53

54

// Manually resolve

55

controllablePromise.resolve("test data");

56

console.log(controllablePromise.status); // "resolved"

57

console.log(controllablePromise.resolvedValue); // "test data"

58

```

59

60

### Promise with Executor

61

62

Create controllable promises with initial executor logic.

63

64

```javascript { .api }

65

type PromiseExecutor<T> = (

66

resolve: (value: T | PromiseLike<T>) => void,

67

reject: (reason?: any) => void

68

) => void;

69

```

70

71

**Usage Examples:**

72

73

```javascript

74

import { promise } from "sinon";

75

76

// Promise with executor that doesn't resolve immediately

77

const delayedPromise = promise((resolve, reject) => {

78

// Executor runs but doesn't resolve yet

79

console.log("Promise created but not resolved");

80

});

81

82

// Later in test, manually control resolution

83

delayedPromise.resolve("manual resolution");

84

```

85

86

### Testing Async Functions

87

88

Use controllable promises to test functions that work with async operations.

89

90

**Usage Examples:**

91

92

```javascript

93

import sinon from "sinon";

94

95

// Function under test

96

async function processData(dataFetcher) {

97

try {

98

const data = await dataFetcher();

99

return { success: true, data };

100

} catch (error) {

101

return { success: false, error: error.message };

102

}

103

}

104

105

// Test with controllable promise

106

describe("processData", () => {

107

it("should handle successful data fetch", async () => {

108

const mockFetcher = sinon.stub();

109

const controllablePromise = sinon.promise();

110

111

mockFetcher.returns(controllablePromise);

112

113

// Start the async operation

114

const resultPromise = processData(mockFetcher);

115

116

// Verify promise is still pending

117

expect(controllablePromise.status).to.equal("pending");

118

119

// Manually resolve with test data

120

controllablePromise.resolve({ id: 1, name: "Test" });

121

122

// Await the result

123

const result = await resultPromise;

124

125

expect(result.success).to.be.true;

126

expect(result.data).to.deep.equal({ id: 1, name: "Test" });

127

expect(controllablePromise.status).to.equal("resolved");

128

});

129

130

it("should handle failed data fetch", async () => {

131

const mockFetcher = sinon.stub();

132

const controllablePromise = sinon.promise();

133

134

mockFetcher.returns(controllablePromise);

135

136

const resultPromise = processData(mockFetcher);

137

138

// Manually reject with test error

139

controllablePromise.reject(new Error("Network error"));

140

141

const result = await resultPromise;

142

143

expect(result.success).to.be.false;

144

expect(result.error).to.equal("Network error");

145

expect(controllablePromise.status).to.equal("rejected");

146

});

147

});

148

```

149

150

### Promise Status Inspection

151

152

Monitor promise state changes during testing for precise async behavior verification.

153

154

**Usage Examples:**

155

156

```javascript

157

import { promise } from "sinon";

158

159

const testPromise = promise();

160

161

// Initial state

162

assert.equal(testPromise.status, "pending");

163

assert.isUndefined(testPromise.resolvedValue);

164

assert.isUndefined(testPromise.rejectedValue);

165

166

// After resolution

167

testPromise.resolve("success");

168

assert.equal(testPromise.status, "resolved");

169

assert.equal(testPromise.resolvedValue, "success");

170

assert.isUndefined(testPromise.rejectedValue);

171

172

// Testing rejection

173

const rejectPromise = promise();

174

rejectPromise.reject("failure");

175

assert.equal(rejectPromise.status, "rejected");

176

assert.equal(rejectPromise.rejectedValue, "failure");

177

assert.isUndefined(rejectPromise.resolvedValue);

178

```

179

180

### Integration with Stubs

181

182

Combine controllable promises with stubs for comprehensive async testing.

183

184

**Usage Examples:**

185

186

```javascript

187

import sinon from "sinon";

188

189

class ApiClient {

190

async fetchUser(id) {

191

// Implementation that makes HTTP request

192

return fetch(`/api/users/${id}`).then(r => r.json());

193

}

194

}

195

196

describe("ApiClient", () => {

197

let client, fetchStub, controllablePromise;

198

199

beforeEach(() => {

200

client = new ApiClient();

201

controllablePromise = sinon.promise();

202

203

// Stub fetch to return controllable promise

204

fetchStub = sinon.stub(global, "fetch");

205

fetchStub.returns(controllablePromise);

206

});

207

208

afterEach(() => {

209

sinon.restore();

210

});

211

212

it("should fetch user data", async () => {

213

const userPromise = client.fetchUser(123);

214

215

// Verify fetch was called correctly

216

sinon.assert.calledOnce(fetchStub);

217

sinon.assert.calledWith(fetchStub, "/api/users/123");

218

219

// Simulate successful HTTP response

220

const mockResponse = {

221

json: sinon.stub().returns(Promise.resolve({ id: 123, name: "John" }))

222

};

223

224

controllablePromise.resolve(mockResponse);

225

226

const user = await userPromise;

227

expect(user).to.deep.equal({ id: 123, name: "John" });

228

});

229

});

230

```

231

232

## Types

233

234

```javascript { .api }

235

type PromiseExecutor<T> = (

236

resolve: (value: T | PromiseLike<T>) => void,

237

reject: (reason?: any) => void

238

) => void;

239

240

interface SinonPromise<T> extends Promise<T> {

241

status: "pending" | "resolved" | "rejected";

242

resolvedValue?: T;

243

rejectedValue?: any;

244

resolve(value?: T): SinonPromise<T>;

245

reject(reason?: any): Promise<void>;

246

}

247

```