Skip to content

Commit c21c4cb

Browse files
committed
Add rejects() method
1 parent 51c3081 commit c21c4cb

File tree

5 files changed

+36
-25
lines changed

5 files changed

+36
-25
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,20 @@ console.log(calculator.add(1, 2)); //prints undefined
5555
```
5656

5757
## Working with promises
58-
When working with promises you can also use the method `resolves()` to return a promise.
58+
When working with promises you can also use `resolves()` and `rejects()` to return a promise.
5959

6060
```typescript
6161
calculator.heavyOperation(1, 2).resolves(4);
6262
//same as calculator.heavyOperation(1, 2).returns(Promise.resolve(4));
6363
console.log(await calculator.heavyOperation(1, 2)); //prints 4
6464
```
6565

66+
```typescript
67+
calculator.heavyOperation(1, 2).rejects(new Error());
68+
//same as calculator.heavyOperation(1, 2).returns(Promise.reject(new Error()));
69+
console.log(await calculator.heavyOperation(1, 2)); //throws Error
70+
```
71+
6672
## Verifying calls
6773
```typescript
6874
calculator.enabled = true;

spec/throws.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Substitute, Arg } from '../src/index'
55
interface Calculator {
66
add(a: number, b: number): number
77
divide(a: number, b: number): number
8+
heavyOperation(): Promise<number>
89
mode: boolean
910
fakeSetting: boolean
1011
}
@@ -16,6 +17,13 @@ test('throws on a method with arguments', t => {
1617
t.throws(() => calculator.divide(1, 0), { instanceOf: Error, message: 'Cannot divide by 0' })
1718
})
1819

20+
test('rejects on a method', async t => {
21+
const calculator = Substitute.for<Calculator>()
22+
calculator.heavyOperation().rejects(new Error('Error'))
23+
24+
await t.throwsAsync(calculator.heavyOperation, { instanceOf: Error, message: 'Error' })
25+
})
26+
1927
test('throws on a property being called', t => {
2028
const calculator = Substitute.for<Calculator>()
2129
calculator.mode.throws(new Error('Property not set'))

src/Transformations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ type MockObjectMixin<TArguments extends any[], TReturnType> = BaseMockObjectMixi
3333

3434
type NoArgumentMockObjectPromise<TReturnType> = NoArgumentMockObjectMixin<TReturnType> & {
3535
resolves: (...args: Unpacked<TReturnType>[]) => void;
36+
rejects: (exception: any) => void;
3637
}
3738

3839
type MockObjectPromise<TArguments extends any[], TReturnType> = MockObjectMixin<TArguments, TReturnType> & {
3940
resolves: (...args: Unpacked<TReturnType>[]) => void;
41+
rejects: (exception: any) => void;
4042
}
4143

4244
export type ObjectSubstitute<T extends Object, K extends Object = T> = ObjectSubstituteTransformation<T> & {

src/Utilities.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export enum SubstituteMethods {
1717
mimicks = 'mimicks',
1818
throws = 'throws',
1919
returns = 'returns',
20-
resolves = 'resolves'
20+
resolves = 'resolves',
21+
rejects = 'rejects'
2122
}
2223

2324
export const Nothing = Symbol();

src/states/FunctionState.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,27 @@ export class FunctionState implements ContextState {
130130
}
131131
}
132132

133-
if (property === SubstituteMethods.returns) {
133+
if (property === SubstituteMethods.returns
134+
|| property === SubstituteMethods.resolves
135+
|| property === SubstituteMethods.rejects
136+
) {
134137
return (...returns: any[]) => {
135138
if (!this._lastArgs) {
136139
throw SubstituteException.generic('Eh, there\'s a bug, no args recorded for this return :/')
137140
}
138-
this.returns.push({
139-
returnValues: returns,
140-
returnIndex: 0,
141-
args: this._lastArgs
142-
})
141+
const returnMock: Partial<ReturnMock> = { returnIndex: 0, args: this._lastArgs };
142+
switch (property) {
143+
case SubstituteMethods.returns:
144+
returnMock.returnValues = returns;
145+
break;
146+
case SubstituteMethods.resolves:
147+
returnMock.returnValues = returns.map(value => Promise.resolve(value));
148+
break;
149+
case SubstituteMethods.rejects:
150+
returnMock.returnValues = returns.map(value => Promise.reject(value));
151+
break;
152+
}
153+
this.returns.push(<ReturnMock>returnMock);
143154
this._calls.pop()
144155

145156
if (this.callCount === 0) {
@@ -156,23 +167,6 @@ export class FunctionState implements ContextState {
156167
};
157168
}
158169

159-
if (property === SubstituteMethods.resolves) {
160-
return (...returns: any[]) => {
161-
if (!this._lastArgs) {
162-
throw SubstituteException.generic('Eh, there\'s a bug, no args recorded for this return :/')
163-
}
164-
returns = returns.map(value => Promise.resolve(value))
165-
this.returns.push({
166-
returnValues: returns,
167-
returnIndex: 0,
168-
args: this._lastArgs
169-
})
170-
this._calls.pop()
171-
172-
context.state = context.initialState;
173-
};
174-
}
175-
176170
return context.proxy;
177171
}
178172
}

0 commit comments

Comments
 (0)