diff --git a/types/simple-mock/index.d.ts b/types/simple-mock/index.d.ts index dd95b6159f..fa934dd00f 100644 --- a/types/simple-mock/index.d.ts +++ b/types/simple-mock/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for simple-mock +// Type definitions for simple-mock v0.8.0 // Project: https://github.com/jupiter/simple-mock // Definitions by: Leon Yu // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped @@ -14,6 +14,11 @@ declare namespace Simple { */ restore(): void; + /** + * Use this if you need to restore only a single mock value or function on an object. + */ + restore(obj: any, key: string): void; + /** * Wraps fn in a spy and sets this on the obj, restorable with all mocks. */ @@ -101,7 +106,7 @@ declare namespace Simple { reset(): void; } - interface Action { + export interface Action { /** * arguments to call back with */ @@ -176,7 +181,23 @@ declare namespace Simple { rejectWith(val: V): Stub>; /** - * An array of behaviours, each having one of these properties: + * Configures this stub to use the specified array of actions. + */ + withActions(actions?: Action[]): Stub; + + /** + * Configures the stub to enable looping. + */ + withLoop(): Stub; + + /** + * Configures the stub to disable looping. + */ + noLoop(): Stub; + + /** + * An array of behaviours. + * Note: modifying this array directly is not supported, rather use stub.withActions(actions) if you need to add actions. */ actions: Action[]; diff --git a/types/simple-mock/simple-mock-tests.ts b/types/simple-mock/simple-mock-tests.ts index 05c900ee99..a441dbdc43 100644 --- a/types/simple-mock/simple-mock-tests.ts +++ b/types/simple-mock/simple-mock-tests.ts @@ -1,8 +1,9 @@ import Simple = require('simple-mock'); declare function describe(desc: string, action: () => void): void; declare function beforeEach(action: () => void): void; +declare function afterEach(action: () => void): void; declare function it(desc: string, action: (done: () => void) => void): void; -declare var assert: { +declare const assert: { (cond: any, message?: string): void; equal(a: T, b: T): void; deepEqual(a: T, b: T): void; @@ -556,13 +557,151 @@ describe('Simple', function() { }) }) + describe('for withActions configurations', function() { + let stubFn: Simple.Stub; + + it('performs all types of actions', function(done) { + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + const secondAction: Simple.Action = { cbArgs: [1, 2, 3], returnValue: undefined, throwError: undefined } + const thirdAction: Simple.Action = { cbArgs: [], returnValue: undefined, throwError: new Error('my message') } + stubFn = Simple.stub().withActions([firstAction, secondAction, thirdAction]) + let returned: string = stubFn() // Call 1 + stubFn('a', function() { // Call 2 + let call2Args = arguments + try { + stubFn() // Call 3 + } catch(e) { + + assert.equal(stubFn.callCount, 3) + + // Verify Call 1: return 'a' + assert(returned) + assert.equal(returned, 'a') + + // Verify Call 2: callback with 1,2,3 + assert(stubFn.called) + assert.equal(stubFn.calls[1].args[0], 'a') + assert.equal(call2Args.length, 3) + assert.equal(call2Args[0], 1) + assert.equal(call2Args[1], 2) + assert.equal(call2Args[2], 3) + + // Verify Call 3: error thrown + assert(e instanceof Error) + assert.equal(e.message, 'my message') + done() + } + }) + }) + + it('can return over multiple calls, looping per default', function() { + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + const secondAction: Simple.Action = { cbArgs: [], returnValue: 'b', throwError: undefined } + stubFn = Simple.stub().withActions([firstAction, secondAction]) + + let returned: string[] = [] + returned.push(stubFn()) + returned.push(stubFn()) + returned.push(stubFn()) + + assert.equal(returned.length, 3) + assert(stubFn.called) + assert.equal(stubFn.callCount, 3) + assert.equal(returned[0], 'a') + assert.equal(returned[1], 'b') + assert.equal(returned[2], 'a') + }) + + it('can return over multiple calls, looping turned off', function() { + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + const secondAction: Simple.Action = { cbArgs: [], returnValue: 'b', throwError: undefined } + stubFn = Simple.stub().withActions([firstAction, secondAction]) + stubFn.loop = false + + let returned: string[] = [] + returned.push(stubFn()) + returned.push(stubFn()) + returned.push(stubFn()) + + assert.equal(returned.length, 3) + assert(stubFn.called) + assert.equal(stubFn.callCount, 3) + assert.equal(returned[0], 'a') + assert.equal(returned[1], 'b') + assert.equal(returned[2], undefined) + }) + + it('preserves previously added configurations', function() { + const secondAction: Simple.Action = { cbArgs: [], returnValue: 'b', throwError: undefined } + const thirdAction: Simple.Action = { cbArgs: [], returnValue: 'c', throwError: undefined } + stubFn = Simple.stub().returnWith('a').withActions([secondAction, thirdAction]) + let returned: string[] = [] + returned.push(stubFn()) + returned.push(stubFn()) + returned.push(stubFn()) + + assert.equal(returned.length, 3) + assert(stubFn.called) + assert.equal(stubFn.callCount, 3) + assert.equal(returned[0], 'a') + assert.equal(returned[1], 'b') + assert.equal(returned[2], 'c') + }) + + it('is chainable and more configurations may be added after', function() { + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + const secondAction: Simple.Action = { cbArgs: [], returnValue: 'b', throwError: undefined } + stubFn = Simple.stub().withActions([firstAction, secondAction]).returnWith('c') + let returned: string[] = [] + returned.push(stubFn()) + returned.push(stubFn()) + returned.push(stubFn()) + + assert.equal(returned.length, 3) + assert(stubFn.called) + assert.equal(stubFn.callCount, 3) + assert.equal(returned[0], 'a') + assert.equal(returned[1], 'b') + assert.equal(returned[2], 'c') + }) + + it('allows setting actions array and then calling withActions', function() { + stubFn = Simple.stub() + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + stubFn.actions = [firstAction] + stubFn.withActions() + + let returned: string = stubFn() + + assert.equal(returned.length, 1) + assert(stubFn.called) + assert.equal(stubFn.callCount, 1) + assert.equal(returned, 'a') + }) + + it('allows calling withActions and then setting actions array', function() { + stubFn = Simple.stub() + stubFn.withActions() + const firstAction: Simple.Action = { cbArgs: [], returnValue: 'a', throwError: undefined } + stubFn.actions = [firstAction] + + let returned: string = stubFn() + + assert.equal(returned.length, 1) + assert(stubFn.called) + assert.equal(stubFn.callCount, 1) + assert.equal(returned, 'a') + }) + + }) + describe('for a specified function to call', function() { it('should be called with arguments and return', function() { let stubFn = Simple.stub().callFn(function() { return arguments }) - let returned = stubFn('z', 'x') + let returned: any = stubFn('z', 'x') assert.equal(stubFn.callCount, 1) assert.equal(returned[0], 'z') @@ -576,7 +715,7 @@ describe('Simple', function() { try { stubFn() - } catch (e) { + } catch(e) { assert(e instanceof Error) assert.equal(e.message, 'my message') } @@ -649,6 +788,10 @@ describe('Simple', function() { }) }) + afterEach(function() { + Simple.restore() + }) + describe('with a single resolving configuration', function() { let stubFn: Simple.Stub>; beforeEach(function() { @@ -768,6 +911,8 @@ describe('Simple', function() { }) }) + if (typeof Promise === 'undefined') return // Skip on unsupported platforms + describe('for native/conforming promises', function() { let fulfilledStub: Simple.Stub let rejectedStub: Simple.Stub @@ -895,6 +1040,82 @@ describe('Simple', function() { }) }) }) + + describe('#noLoop', function() { + + it('should disable looping', function() { + + let stub = Simple.stub().noLoop().returnWith('foo') + + assert.equal(stub(), 'foo') + assert.equal(stub(), undefined) + + }) + + }) + + describe('#withLoop', function() { + + it('should enable looping', function() { + + let stub = Simple.stub().withLoop().returnWith('foo') + + assert.equal(stub(), 'foo') + assert.equal(stub(), 'foo') + + }) + + }) + + }) + + describe('restore()', function() { + let objA: any + let objB: any + let originalValue: string + let mockedValue: string + + beforeEach(function() { + originalValue = 'a' + mockedValue = 'b' + + objA = { + name: 'objA', + valueMock: originalValue + } + + objB = { + name: 'objB', + valueMock: originalValue + } + + Simple.mock(objA, 'valueMock', mockedValue) + Simple.mock(objB, 'valueMock', mockedValue) + }) + + afterEach(function() { + Simple.restore() + }) + + it('can restore all mocks', function() { + Simple.restore() + assert.equal(objA.valueMock, originalValue) + assert.equal(objB.valueMock, originalValue) + }) + + it('can restore double-mocked values', function() { + Simple.mock(objA, 'valueMock', 'ac') + Simple.mock(objB, 'valueMock', 'bc') + Simple.restore() + assert.equal(objA.valueMock, originalValue) + assert.equal(objB.valueMock, originalValue) + }) + + it('can restore a single mock', function() { + Simple.restore(objA, 'valueMock') + assert.equal(objA.valueMock, originalValue) + assert.equal(objB.valueMock, mockedValue) + }) }) describe('mock()', function() {