Giter Club home page Giter Club logo

deride's People

Contributors

cookie-bytes avatar jamesmorgan avatar jamlen avatar reaandrew avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

deride's Issues

Allow to stub an existing object

Allow to stub an existing object so that all the methods names are taken from the object to populate the stub. This is a convenience method.

Add constructedWith for expect

Look at adding the ability to assert against constructor args.

var Person = deride.construct(Person);
var bob = new Person('bob');
bob.expect.constructedWith('bob');

Support for setup x times and then something else

In needing to tests out some reconnection logic, I have the need to be able to do something like:

connectionFactory.setup.connect
  .toResolveWith(mockConnection)
  .twice()
  .and.then
  .toRejectWith(new Error('Boom')

Example tests

describe('multi', function() {
    it('only uses the stub x times', function() {
        bob.setup.greet
            .toReturn('alice')
            .twice()
            .and.then
            .toReturn('sally');
        bob.greet().should.eql('alice');
        bob.greet().should.eql('alice');
        bob.greet().should.eql('sally');
        bob.greet().should.eql('sally');
    });

    it('only uses the stub x times and then falls back', function() {
        var normalResult = bob.greet('alice');
        bob.setup.greet
            .toReturn('alice')
            .twice();
        bob.greet('alice').should.eql('alice');
        bob.greet('alice').should.eql('alice');
        should(bob.greet('alice')).eql(normalResult);
    });

    describe('also supports when specific arguments are provided', function() {
        it('only uses the stub X times when called with matching args', function() {
            var normalResult = bob.greet('talula');
            var normalSimon = bob.greet('simon');
            bob.setup.greet
                .when('simon')
                .toReturn('alice')
                .twice();
            // default Person behaviour
            should(bob.greet('talula')).eql(normalResult);
            // overridden behaviour
            bob.greet('simon').should.eql('alice');
            bob.greet('simon').should.eql('alice');
            // default Person behaviour
            should(bob.greet('simon')).eql(normalSimon);
        });

        it('falls back to default stub behaviour after X matching invocations', function() {
            bob = deride.wrap(bob);
            bob.setup.greet
                .toReturn('talula')
                .but.when('simon')
                .toReturn('alice')
                .times(2);
                        // default stubbed behaviour for non matching invocation
            bob.greet('alice').should.eql('talula');
                        // stubbed behaviour for 1st matching invocation
            bob.greet('simon').should.eql('alice');
                        // stubbed behaviour for 2nd matching invocation
            bob.greet('simon').should.eql('alice');
                        // falls back to default stubbed behaviour for other matching invocations
            bob.greet('simon').should.eql('talula');
                        // default stubbed behaviour for non matching invocation
            bob.greet('alice').should.eql('talula');
        });
    });
});

Allow a function as a predicate for setup.when

I would like to be able to provide a function to when which is invoked with the args at runtime and which is used to evaluate which overridden func to use.

It's the issue of wanting to setup a when and you have an object as the arg but you don't care about (or are unable to predict) all of the fields.

My usage is that I have a delegate which is invoked when a message is put onto the DLE queue in RabbitMQ.

Proposed usage:

dleConsumer.setup.when(function(msg){
  var content = JSON.parse(msg.content.toString());
  return content.resource === 'talula';
}).toDoThis(done);

The issue I have is that the dleConsumer will be invoked with any messages that end up on the DLE and I need to only care about ones which match my criteria.

Failing test:

it('can provide a predicate to when', function(done) {
    var func = deride.func();
    func.setup.when(function(msg) {
        var content = JSON.parse(msg.content.toString());
        return content.resource === 'talula';
    }).toDoThis(done);

    var msg = {
        //...
        //other properties that we do not know until runtime
        //...
        content: new Buffer(JSON.stringify({
                resource: 'talula'
        }))
    };
    func(msg);
});

Stubbing Event Emitters

Hi,

As requested by James.
Currently trying to test that we would handle the two different outcomes from restler correctly by using a deride stub.
However struggling to get the event emitters to work??

self.read = function(id, callback) {
    restler
        .get(url)
        .on('success', function(person) {
            console.log('sucess');                                                             
            return callback(null, person);
        })
        .on('fail', function(err) { 
            console.log('fail');
            return callback(err, null);                                                        
        });       

}

Add debug messages

Add debug output when stubbed methods are called.

Currently I do this often:

var mapper = deride.stub(['map']);
mapper.setup.map.toDoThis(function(a, b, cb) {
  debug('mapper.map', a, b);
  cb(); 
});

It would be good to just be able to use .toCallbackWith.

Issue with called.withArg or Args after 0.4.1

Using 0.4.0 the test sample below passes, but >=0.4.1 fails. Some issue with the upgrade of lodash to 4.5.1.

it('booooom', function() {
    var obj = deride.stub(['send']);
    obj.send(['a', 'b'], function() {});
    obj.expect.send.called.withArgs(['a', 'b']);
});

produces:

  Expectations
    1) booooom


  0 passing (14ms)
  1 failing

  1) Expectations booooom:

      AssertionError: Expected send to be called with: a,b
      + expected - actual

      -false
      +true

      at assertArgsWithEvaluator (lib/deride.js:118:9)
      at Object.withArgs (lib/deride.js:66:9)
      at Context.<anonymous> (test/test-deride.js:124:32)

Add option to override debug prefix

When #45 is complete, the debug output will be prefixed with something like:

  • deride:stub
  • deride:wrap
  • deride.func

Add the ability to override the debug prefix per stub.

For example:

var mapper = deride.stub(['map'], { prefix: 'mymodule:deride:mapper' });

Another issue in 1.2.0, JSON circular dependencies

I cannot for the life of me get to the bottom of this one to give you a code sample which I appreciate doesn't help, but something has changed which is resulting in the serialize method throwing an error and I'm hoping you'll have an a-ha moment seeing the error.

Uncaught TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>:null:null)
    at serializeArgs (node_modules/deride/lib/deride.js:489:21)
    at Object.call (node_modules/deride/lib/deride.js:294:19)
    at Object.removeHandler (node_modules/deride/lib/deride.js:511:46)

Again, same test is fine on 1.1.0.

withArgs should evaluate equivalence

withArgs should evaluate equivalence. A further feature should be made called something like withExactArgs so that it uses strict equality on the actual object. The change for withArgs should simply be a strict equality of the JSON.stringify results of the expected and actual.

Add called.withMatch function

It would be useful to be able to assert that a method was called using a regex pattern to match on.

var bob = deride.stub(['greet']);
bob.setup.greet.toReturn('hello');

bob.greet('The inspiration for this was that my colleague was having a look at other mocking frameworks and mentioned to me that they do not work when using Object.freeze in the objects to enforce encapsulation. This library builds on composition to create a mocking library that can work with objects which are frozen.');

bob.expect.greet.called.withMatch(/^The inspiration for this was/);

Support ES6 classes

reported by @jamlen

Support ES6 classes

so given:

class Person {
  foo() { 
    console.log('foo');
  }
  greet(person) { 
    console.log('Howdy ' + person); 
  } 
}

this should work (but doesn’t):

let bob = new Person();
bob.greet('sam') // => Howd'y sam
bob = deride.wrap(bob);
bob.greet('sam') // => bob.greet is not a function

Add ability wrap an existing function

Currently you can only stub a function using deride.func() but I need to wrap an existing function to allow the execution to call the real method but be able to attach the expectations.

Expected usage:

var f = function (name) { return 'hello ' + name; };
var func = deride.func(f);
assert(func('bob'), 'hello bob');
func.expect.called.withArg('bob');

Add .withArg to expect

Currently there is withArgs but you need to know (and care) about all of the arguments passed. You might only be interested in a subset of these.

Therefore add a withArg function which you can select which argument (maybe by index, maybe by name if possible) to assert against.

When using expectations relating to `calledWithArgs` all arguments are not frozen and hence can be modified after the expectation

My use case is that I am using matchExactly() to test an expected call which is part of a large promise chain.

The promise chain then modifies further down the line the argument the first call was made with. I would expect deride to lock down and/or freeze the arguments for the initial expectation I setup if not mutated further down the line.

Sample failing test:

describe('copy by reference', function () {

    var bob;
    beforeEach(function testSetup() {
        bob = deride.stub(['greet']);
        bob.setup.greet.toResolve();
    });

    var mutatedObject = {
        test: 'abc'
    };

    beforeEach(function sampleInvocationMutatingObject(done) {
        bob.greet(mutatedObject)
            .then(function () {
                mutatedObject.test = '123';
                done();
            });
    });

    it('should not expect mutated object', function () {
        bob.expect.greet.called.matchExactly({
            test: 'abc' // this fails but only passes with { test: '123' }
        });
    });
});

Changing this function to cloneDeep fixes the problems - thoughts?

    function call() {
        calledWithArgs[timesCalled++] = _.cloneDeep(arguments);
    }

Thoughts?

toCallbackWith doesn't find the callback

If the method signature contains a function before the callback, then toCallbackWith will currently invoke that as the callback. This should be changed to expect the callback as the last argument which is a function.

For example:

bob.setup.greet.toCallbackWith([null, 'hello']);
bob.greet('sally', function(){
  done('this is not the callback');
}, function(err, msg) {
  msg.should.eql('hello');
  done();
});

Unexpected difference in behaviour between 1.1.0 and 1.2.0

Long time no speak folks.

I'm still using this library quite extensively and also have a few other teams at ThoughtWorks on it too. After upgrading one of my projects to 1.2.0 this morning I had some failing tests, upon investigation it appears that I can no longer override the behaviour of a given expect.

Take the following example:

'use strict';
const deride = require('deride');
const thing = deride.wrap({ example: () => {} });

thing.setup.example.toCallbackWith([null, 1]);
thing.setup.example.toCallbackWith([null, 2]);

thing.example((err, number) => {
  console.log(number);
});

On 1.1.x, the result is 2, on 1.2.0 the result is 1.

This causes us some issues because we have a whole bunch of tests that have an initial thing.setup.example, and then further down the line change the behaviour of thing.setup.example to do something else. An example is we have a generic stub API which we use across multiple tests, and in some of them we want to override the default behaviour that's configured as part of the stub to do something slightly different.

setup.toEmit

To allow a given method to emit an event when called. The original method will also be invoked and the response returned.

bob.setup.greet.toEmit('testing', 'arg1', {a: 1});
bob.on('testing', function(a1, a2) {
   a1.should.eql('arg1');
   a2.should.eql({a:1);
   done();
});
bob.greet('bob');

Ability to return both sync and async results

There are certain async methods that also return a sync result, for example:

var child = exec('ls -al', function(err, result) {
  console.log(result);
});

In this example, I need child.pid and result.

If I'm stubbing this method, I could do with being able to do both:

mockExec.setup.exec.toDoThis(function(command, callback) {                                    
  setTimeout(function() {                                                                     
    callback();                                                                             
  }, 100);                                                                                    
  return {                                                                                    
    pid: 12345                                                                              
  };                                                                                          
});                                                                                           

mockExec.setup.exec.toReturn({                                                            
  pid: 12345                                                                                
});   

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.