jbrumwell / mock-knex

A mock knex adapter for simulating a database during testing
MIT License
239 stars 71 forks source link

Sequence multiples without Step #72

Open timrichard opened 6 years ago

timrichard commented 6 years ago

Hi, thanks for a really useful library... I'm finding it really great for my current project.

I was looking at the docs, and managed to write some demo tests for multi queries on a sandbox project in order without the step argument. In ES6...

            const queryChain = [
                (query) => {
                    expect(query.method).to.equal('select');
                    query.response({'a': 'b'});
                },
                (query) => {
                    expect(query.method).to.equal('update');
                    query.response({'c': 'd'});
                },
                (query) => {
                    expect(query.method).to.equal('insert');
                    query.response({'e': 'f'});
                }
            ];

            tracker.on('query', (query) => {
                queryChain.shift().call(this, query);
            });

Which I guess could be in ES5 like this -

            var queryChain = [
                function (query) {
                    expect(query.method).to.equal('select');
                    query.response({'a': 'b'});
                },
                function (query) {
                    expect(query.method).to.equal('update');
                    query.response({'c': 'd'});
                },
                function (query) {
                    expect(query.method).to.equal('insert');
                    query.response({'e': 'f'});
                }
            ];

            tracker.on('query', function (query) {
                queryChain.shift().call(this, query);
            });
helloanoop commented 6 years ago

Thanks @timrichard

I think this is a much better and less ambiguous solution than the 'step' based approach.

I also think it would be good to have a 'registerQueryChain' api to be integrated into the tracker itself. So that a user could do this

const queryChain = [
                (query) => {
                    expect(query.method).to.equal('select');
                    query.response({'a': 'b'});
                },
                (query) => {
                    expect(query.method).to.equal('update');
                    query.response({'c': 'd'});
                },
        ]
        tracker.registerQueryChain(queryChain);
jbrumwell commented 6 years ago

@anoopmd @timrichard I agree I also found it annoying and wrote a helper class to deal with it, that works similar to your approach. But in the end this is still prone to errors.

I am open to suggestions but am currently looking into a similar approach to jest snapshots;

const chain = [
  {
    hash : <obj.sql hashed>
    query : <obj.sql>
    distance : 3,
    response : [],
  },  
]
tracker.install()
.chain(chain);

Internally on it would go step by step and perform;

(query) {
  const hashed = hashQuery(query.sql);
  const step = chain[ stepNumber ];
  const distance = step.acceptableDistance;

  if (step.hash !== hashed) {
    if (distance && new Levenshtein(obj.sql, step.query) > distance) {
       // fail here
    }
  }

  query.response(step.response);
}

This is still very rough draft and generating the chain file hasn't been thought out yet :) But it should automate the entire process of validating we have the correct query and returning the response. Another option could be validation of query.bindings as well. What are your thoughts on this approach?

fluxsauce commented 3 years ago

Here's an approach with step, but is a bit more readable and doesn't use shift. Did a little code golf with a coworker...

Super concise:

const steps = [];
steps[1] = query => query.response(countResults);
steps[2] = query => query.response(results);
tracker.on('query', (query, step) => steps[step](query);

Setting up both an expectation and response...

const steps = [];
step[1] = query => {
  expect(query.method).to.equal('select');
  query.response({'a': 'b'});
};
step[2] = query => {
  expect(query.method).to.equal('update');
  query.response({'c': 'd'});
}
tracker.on('query', (query, step) => steps[step](query);