tuxx
Version:
Framework built on React and Flux
360 lines (289 loc) • 14.8 kB
JavaScript
;
var moduleToTest = 'tuxx/src/TuxxActions.js';
jest.dontMock(moduleToTest);
describe('TuxxActions', function () {
var TuxxActions, tuxxActionCategory, mockStore, mockBody;
//action class to use for testing
var weirdCharAction = '\'{}/187&%__ .,.#""';
var actionCategory = {
category: 'tests',
source: 'test_source',
actions: ['get', 'set', 'test_action', weirdCharAction]
};
beforeEach(function () {
//reset TuxxActions and mocks before each test
TuxxActions = require(moduleToTest);
mockStore = {};
mockBody = {};
//create new action category for each test
tuxxActionCategory = TuxxActions.createActionCategory(actionCategory);
});
describe('createActionCategory', function () {
it('should return an action category with defined props', function () {
//category properties
expect(tuxxActionCategory.__category__).toBe('tests');
expect(tuxxActionCategory.__source__).toBe('test_source');
//individiual actions in category
expect(tuxxActionCategory.get).toEqual(jasmine.any(Function));
expect(tuxxActionCategory.get.type).toBe('tests_get');
expect(tuxxActionCategory.set).toEqual(jasmine.any(Function));
expect(tuxxActionCategory.set.type).toBe('tests_set');
expect(tuxxActionCategory.test_action).toEqual(jasmine.any(Function));
expect(tuxxActionCategory.test_action.type).toBe('tests_test_action');
expect(tuxxActionCategory[weirdCharAction]).toEqual(jasmine.any(Function));
expect(tuxxActionCategory[weirdCharAction].type).toBe('tests_' + weirdCharAction);
});
it('should assign the action category to TuxxActions at the key of the category string', function () {
expect(TuxxActions.tests).toBe(tuxxActionCategory);
});
it('should throw an error if the same category is created twice', function () {
expect(function () {
TuxxActions.createActionCategory(actionCategory);
}).toThrow(new Error('Invariant Violation: Action Category "tests" is already defined'));
});
describe('actionCategory', function () {
it('should dispatch an action when the associated action is invoked', function () {
var testBody = {};
tuxxActionCategory.get(testBody);
//method should invoke the dispatch method on the Dispatcher
var payload = TuxxActions.__Dispatcher__.dispatch.mock.calls[0][0];
expect(payload.source).toBe('test_source');
expect(payload.action.actionType).toBe('tests_get');
expect(payload.action.body).toBe(testBody);
var newTestBody = {};
tuxxActionCategory.set(newTestBody);
//method should invoke the dispatch method with a new set of parameters
payload = TuxxActions.__Dispatcher__.dispatch.mock.calls[1][0];
expect(payload.source).toBe('test_source');
expect(payload.action.actionType).toBe('tests_set');
expect(payload.action.body).toBe(newTestBody);
});
it('should register its own action category when register is invoked', function () {
//mocking out register method since actionCategory register is just a wrapper for Actions.register
TuxxActions.register = jest.genMockFunction();
var actionListeners = {
get: function(){},
set: function(){}
};
tuxxActionCategory.register(mockStore, actionListeners);
expect(TuxxActions.register.mock.calls[0][0]).toBe(mockStore);
//expecting to find actionListeners under the CATEGORY key
expect(TuxxActions.register.mock.calls[0][1].tests).toBe(actionListeners);
});
describe('before', function () {
it('should add a callback to be invoked before the corresponding action is dispatched and should receive the next callback to invoke and the current actionBody (passed in by original action method or previous callback) as inputs', function () {
//store a reference to the current get action and mock it out
var dispatchGetAction = tuxxActionCategory.get = jest.genMockFunction();
var mockBeforeAction = jest.genMockFunction();
tuxxActionCategory.before('get', mockBeforeAction);
//dispatch a get action with a mockActionBody
var mockActionBody = {};
tuxxActionCategory.get(mockActionBody);
//expect the mockBeforeAction to have been called with the dispatchGetAction callback and mockActionBody
expect(mockBeforeAction.mock.calls[0][0]).toBe(dispatchGetAction);
expect(mockBeforeAction.mock.calls[0][1]).toBe(mockActionBody);
//expect the dispatchGetAction not to have been called
expect(dispatchGetAction).not.toBeCalled();
});
it('should allow adding multiple callbacks and should invoke the last added callback when the action is invoked', function () {
//store reference to original get method for testing later on
var dispatchGetAction = tuxxActionCategory.get;
var mockBeforeAction = jest.genMockFunction();
tuxxActionCategory.before('get', mockBeforeAction);
//store a reference to the current get method as this method is not mockBeforeAction but is instead the output of calling .bind on mockBeforeAction
var mockBoundBeforeAction = tuxxActionCategory.get;
var mockNewBeforeAction = jest.genMockFunction();
tuxxActionCategory.before('get', mockNewBeforeAction);
//dispatch a get action with a mockActionBody
var mockActionBody = {};
tuxxActionCategory.get(mockActionBody);
//expect the mockNewBeforeAction to have been called with the mockBoundBeforeAction callback and mockActionBody
expect(mockNewBeforeAction.mock.calls[0][0]).toBe(mockBoundBeforeAction);
expect(mockNewBeforeAction.mock.calls[0][1]).toBe(mockActionBody);
//expect the mockBeforeAction not to be called
expect(mockBeforeAction).not.toBeCalled();
//invoke the first argument passed into the mockNewBeforeActio and pass in a newMockActionBody to it
var newMockActionBody = {};
mockNewBeforeAction.mock.calls[0][0](newMockActionBody);
//expect the mockBeforeAction to have been called with the dispatchGetAction callback and newMockActionBody
expect(mockBeforeAction.mock.calls[0][0]).toBe(dispatchGetAction);
expect(mockBeforeAction.mock.calls[0][1]).toBe(newMockActionBody);
});
it('should accept an array of action verbs and should add the callback to be invoked to each one of them', function () {
//store a reference to the current get and set actions
var dispatchGetAction = tuxxActionCategory.get = jest.genMockFunction();
var dispatchSetAction = tuxxActionCategory.set = jest.genMockFunction();
var mockBeforeAction = jest.genMockFunction();
tuxxActionCategory.before(['get', 'set'], mockBeforeAction);
//dispatch a get action with a mockActionBody
var mockActionBody = {};
tuxxActionCategory.get(mockActionBody);
//expect the mockBeforeAction to have been called with the dispatchGetAction callback and mockActionBody
expect(mockBeforeAction.mock.calls[0][0]).toBe(dispatchGetAction);
expect(mockBeforeAction.mock.calls[0][1]).toBe(mockActionBody);
//expect the dispatchGetAction not to have been called
expect(dispatchGetAction).not.toBeCalled();
//dispatch a set action with a mockActionBody
mockActionBody = {};
tuxxActionCategory.set(mockActionBody);
//expect the mockBeforeAction to have been called again with the dispatchSetAction callback and mockActionBody
expect(mockBeforeAction.mock.calls[1][0]).toBe(dispatchSetAction);
expect(mockBeforeAction.mock.calls[1][1]).toBe(mockActionBody);
//expect the dispatchSetAction not to have been called
expect(dispatchSetAction).not.toBeCalled();
});
it('should throw an error if the actionVerb string or one of the strings in the actionVerb array does not match an action in category', function () {
expect(function () {
tuxxActionCategory.before('not an action', function () {});
}).toThrow(new Error('Invariant Violation: could not find action: "not an action" within category: "tests" when attempting to register the before callback'));
expect(function () {
tuxxActionCategory.before(['get', 'not an action'], function () {});
}).toThrow(new Error('Invariant Violation: could not find action: "not an action" within category: "tests" when attempting to register the before callback'));
});
});
});
});
describe('register', function () {
var mockGet, mockGetTwo, mockWeird, mockWeirdTwo, categoriesToRegister;
//register mock category
beforeEach(function () {
//reinstantiate mock functions before each test
mockGet = jest.genMockFunction();
mockGetTwo = jest.genMockFunction();
mockWeird = jest.genMockFunction();
mockWeirdTwo = jest.genMockFunction();
//register listeners on actions within category object
categoriesToRegister = {
'tests': {
'get': mockGet
}
};
categoriesToRegister.tests[weirdCharAction] = mockWeird;
TuxxActions.register(mockStore, categoriesToRegister);
});
it('should attach the registration Id to the passed in store as the key of __registerId__', function () {
expect(mockStore.hasOwnProperty('__registerId__')).toBeTruthy();
});
it('should invoke the corresponding function when an action is passed in', function () {
//invoke dispatch
TuxxActions.tests.get(mockBody);
//pull dispatched payload out of dispatcher
var payload = TuxxActions.__Dispatcher__.dispatch.mock.calls[0][0];
//directly invoke registered cb with payload
TuxxActions.__Dispatcher__.register.mock.calls[0][0](payload);
//expect mocked function to have received payload body and payload
expect(mockGet.mock.calls[0][0]).toBe(mockBody);
expect(mockGet.mock.calls[0][1]).toBe(payload);
//make sure mockWeird was not called
expect(mockWeird.mock.calls.length).toBe(0);
//test weirdCharAction
TuxxActions.tests[weirdCharAction](mockBody);
payload = TuxxActions.__Dispatcher__.dispatch.mock.calls[1][0];
TuxxActions.__Dispatcher__.register.mock.calls[0][0](payload);
//expect mocked weird function to have received payload body and payload
expect(mockWeird.mock.calls[0][0]).toBe(mockBody);
expect(mockWeird.mock.calls[0][1]).toBe(payload);
//make sure mockGet was not called again
expect(mockGet.mock.calls.length).toBe(1);
});
it('should handle registering multiple categories at once', function () {
//create a new action class
TuxxActions.createActionCategory({
category: 'testsTwo',
source: 'testTwo_source',
actions: ['getTwo', 'setTwo', 'test_action', weirdCharAction]
});
//register both categories together
var categoriesToRegister = {
'tests': {
'get': mockGet
},
'testsTwo': {
'getTwo': mockGetTwo,
}
};
categoriesToRegister.tests[weirdCharAction] = mockWeird;
categoriesToRegister.testsTwo[weirdCharAction] = mockWeirdTwo;
TuxxActions.register(mockStore, categoriesToRegister);
//dispatch a get for tests
TuxxActions.__Dispatcher__.register.mock.calls[1][0]({
action: {
actionType: TuxxActions.tests.get.type
}
});
//expect only mockGet to have been called
expect(mockGet.mock.calls.length).toBe(1);
expect(mockWeird.mock.calls.length).toBe(0);
expect(mockGetTwo.mock.calls.length).toBe(0);
expect(mockWeirdTwo.mock.calls.length).toBe(0);
//dispatch a weird for tests
TuxxActions.__Dispatcher__.register.mock.calls[1][0]({
action: {
actionType: TuxxActions.tests[weirdCharAction].type
}
});
//expect only mockWeird to have been called
expect(mockGet.mock.calls.length).toBe(1);
expect(mockWeird.mock.calls.length).toBe(1);
expect(mockGetTwo.mock.calls.length).toBe(0);
expect(mockWeirdTwo.mock.calls.length).toBe(0);
//dispatch a getTwo for testsTwo
TuxxActions.__Dispatcher__.register.mock.calls[1][0]({
action: {
actionType: TuxxActions.testsTwo.getTwo.type
}
});
//expect only mockGetTwo to have been called
expect(mockGet.mock.calls.length).toBe(1);
expect(mockWeird.mock.calls.length).toBe(1);
expect(mockGetTwo.mock.calls.length).toBe(1);
expect(mockWeirdTwo.mock.calls.length).toBe(0);
//dispatch a weird for testsTwo
TuxxActions.__Dispatcher__.register.mock.calls[1][0]({
action: {
actionType: TuxxActions.testsTwo[weirdCharAction].type
}
});
//expect only mockGetTwo to have been called
expect(mockGet.mock.calls.length).toBe(1);
expect(mockWeird.mock.calls.length).toBe(1);
expect(mockGetTwo.mock.calls.length).toBe(1);
expect(mockWeirdTwo.mock.calls.length).toBe(1);
});
it('should invoke a waitFor if the store has a __tuxxArchitecture__ property', function () {
//add tuxxArchitecture property to store and register it
mockStore.__tuxxArchitecture__ = {};
TuxxActions.register(mockStore, {
'tests': {
get: function () {}
}
});
//invoke registered cb
TuxxActions.__Dispatcher__.register.mock.calls[1][0]({action: ''});
//expect waitFor to be called with the tuxxArchitecture
expect(TuxxActions.__Dispatcher__.waitFor.mock.calls[0][0]).toBe(mockStore.__tuxxArchitecture__);
});
it('should throw an error when the category does not have the desired action', function () {
expect(function () {
TuxxActions.register(mockStore, {
'tests': {
'get': function () {},
'doesntHave': function () {}
}
});
}).toThrow(new Error('Invariant Violation: "tests" category does not have action "doesntHave"'));
});
it('should throw an error when the action category does not exist', function () {
expect(function () {
TuxxActions.register(mockStore, {
'tests': {
'get': function () {}
},
'doesntHave': {
'get': function () {}
}
});
}).toThrow(new Error('Invariant Violation: "doesntHave" category has not been created yet'));
});
});
});