Developing a team to request data from the database - part 4, completing

  • Tutorial

This is a continuation of the story that began here and continued here and here .


In the last part, I wrote an integration test that demonstrates the process of initializing and executing a complete set of handlers that retrieve data from the database. But since it may take too long for writing not only the handler, but also the setup rules for all necessary requests to the database, from writing this test, today I decided to implement its modular version, designed to configure and run single handler. This test looks like this:


describe('requestHandler', () => {
  const createStore = require('redux').createStore;
  const reducers = require('../../src/reducers.js');
  const DbMock = require('../mocks/DbMock');
  const db = new DbMock();
  const rules = require('../../src/rules');
  const dbRequest = require('../../src/storage/dbRequest');
  let request = null,
      store = null,
      context = null;
  beforeEach(() => {
    store = createStore(reducers);
    context = {
      db,
      store,
      rules
    };
    request = dbRequest.bind(context, [ 'user' ]);
    expect(store.getState().user).toBeNull();
    expect(store.getState().error).toEqual([]);
  });
  it('should get user from database', (done) => {
    const assert = checkUser.bind(context, [ done ]);
    store.subscribe(assert);
    store.dispatch({type: 'NOTE', note: { Id: 1, UserRecordId: 1 }});
    request();
  });
  functioncheckUser(args) {
    const state = store.getState();
    if(state.user === null)
      return;
    const user = state.user;
    expect(user.Id).toEqual(1);
    expect(user.Name).toEqual('Jack');
    const checkIsCompleted = args[0];
    checkIsCompleted();
  }
});

I run the tests and get a message that the module with the rules was not found. Once again, what will the handler need to extract from the rules?


  1. The name of the property key of the state container to which the record obtained from the database will be bound
  2. The name of the database table from which you want to extract the record
  3. The method that forms the request to be sent to the database in order to receive a response
  4. The dispatch method that sends the record received from the database to the state container storage.
  5. The dispatch method that sends an error, if one occurs, to the status container storage. I decided to first consolidate the errors in the state container, and then deal with them.

The set of rules appears to me as a dictionary ( Map), in which the key will be the name of the property of the state container and I will perhaps formulate the first unit test:


describe('rules', () => {
  const rules = require('../src/rules');
  it('should contain user rules', () => {
    const rule = rules.get('user');
    expect(rule.table).toEqual('users');
  });
});

I run the tests and Jasmineinforms me that I now have two non-performing tests. In order not to complicate the task, I will start with the simplest rule that tells me that in order to assign a value to the key of the userstatus container, my query should be contacted for data in a table users. It seems to be all logical. I will write as it seems to me a little code.


const makeRules = () => {
  const rules = newMap();
  rules.set('user', { table: 'users' });
  return rules;
};
module.exports = makeRules();

I run tests, and I see that only the test for my processor drops, although the error is different now. However, I will return to this test later when I have at least one complete rule in my dictionary ready.


I will modify the test of the rules dictionary a little. Add the code that checks for the presence of the dispatcher method that handles the error of the query to the database:


describe('rules', () => {
  const rules = require('../src/rules');
  it('should contain user rules', () => {
    const rule = rules.get('user');
    expect(rule.table).toEqual('users');
    expect(rule.onError.name).toEqual('dispatchError');
    expect(typeof rule.onError).toEqual('function');
  });
});

I perform tests, make sure that I have two faulty tests again, and come back to fine-tuning the code of the factory method to generate a dictionary of rules. I add a function to the literal object of the first rule:


const makeRules = () => {
  const rules = newMap();
  rules.set('user', { 
      table: 'users',
      onError: functiondispatchError(error, store) {
        const action = { type: 'ERROR', error };
        store.dispatch(action);        
      }
  });
  return rules;
};
module.exports = makeRules();

Run tests again. The new rule fragment successfully passes the test, so I decide to add checks for all remaining rules:


describe('rules', () => {
  const rules = require('../src/rules');
  it('should contain user rules', () => {
    const rule = rules.get('user');
    expect(rule.table).toEqual('users');
    expect(rule.onError.name).toEqual('dispatchError');
    expect(typeof rule.onError).toEqual('function');
    expect(rule.onSuccess.name).toEqual('dispatchUser');
    expect(typeof rule.onSuccess).toEqual('function');
    expect(rule.query.name).toEqual('getUserQuery');
    expect(typeof rule.query).toEqual('function');
  });
});

I run the tests. The test suite for the rules dictionary again gives an error. I am writing code:


const makeRules = () => {
  const rules = newMap();
  rules.set('user', { 
      table: 'users',
      onError: functiondispatchError(error, store) {        
        const action = { type: 'ERROR', error };
        store.dispatch(action);        
      },
      onSuccess: functiondispatchUser(user, store) {        
        const action = { type: 'USER', user };
        store.dispatch(action);
      },
      query: functiongetUserQuery(store) {
        const state = store.getState();
        if(state.note === null)
          returnnull;
        return { Id: state.note.UserRecordId };
      }
  });
  return rules;
};
module.exports = makeRules();

I run the tests. The test of the rule set is again successfully executed and it seems to me that I can now take up writing code for the new version of the data request from the database itself. This time I will not use the class syntax, because I do not see any advantage from its use. There will be a lot of code at once, because I will ruthlessly copy the tested part of it from the existing implementation of the query, adding it to the check, in case the record from the database has already been retrieved and placed in the state container. So the code:


functiondbRequest(args){
  const key = args[0];
  const getQuery = this.rules.get(key).query;
  const dispatchUser = this.rules.get(key).onSuccess;
  const dispatchError = this.rules.get(key).onError;
  const tableName = this.rules.get(key).table;
  const table = this.db.Model.extend({
    tableName: tableName
  });
  const state = this.store.getState();
  if(state[key] !== null)
    return;
  const query = getQuery(this.store);
  if(query === null)
    return;
  table.where(query).fetch().then((item) => {
      dispatchUser(item, this.store);
    }).catch((error) => {
      dispatchError(error, this.store);
    });
}
module.exports = dbRequest;

Running tests ... drumming! And I see a line of green dots. All tests completed successfully. And so I'll add to the set of another test that checks the correctness of the error handling, while I have not forgotten that to my psevdobazadannyh DbMockreturned an error, it is necessary to ask her account with Idequal 555 :



  it('should add error in store state', (done) => {
    const assert = checkErrorHasBeenAdded.bind(context, [ done ]);
    store.subscribe(assert);
    store.dispatch({type: 'NOTE', note: { Id: 1, UserRecordId: 555 }});
    request();
  });
  functioncheckErrorHasBeenAdded(args){
    const state = store.getState();
    if(state.error.length === 0)
      return;
    const error = state.error;
    expect(Array.isArray(error)).toBeTruthy();
    expect(error.length).toEqual(1);
    expect(error[0].message).toEqual('Something goes wrong!');
    const checkIsCompleted = args[0];
    checkIsCompleted();
  }

I run the tests again. Everything works as expected. We can assume that the correct prototype of the query command to the database is ready and go back to refactoring and developing the rules for configuring queries for it is already clear that the code for generating a set of rules will no longer be readable after adding just a couple more rules in the same format.


Also popular now: