Skip to content

Instantly share code, notes, and snippets.

@crrobinson14
Last active July 12, 2016 14:56
Show Gist options
  • Save crrobinson14/2251a45045e90ee81cc34111bc00b811 to your computer and use it in GitHub Desktop.
Save crrobinson14/2251a45045e90ee81cc34111bc00b811 to your computer and use it in GitHub Desktop.
ActionHero testing support files
// Set NODE_ENV to test so AH creates api.specHelper for us
process.env.NODE_ENV = 'test';
process.env.ACTIONHERO_CONFIG = 'config,local-config';
// Get ActionHero ready to go
var actionheroPrototype = require('actionhero').actionheroPrototype,
actionhero = new actionheroPrototype(),
running = false;
global.api = null;
global.assert = require('assertthat');
global.bootstrap = {
init: function(done) {
actionhero.start(function(err, api) {
running = true;
if (err) {
throw err;
}
global.api = api;
// Set up anonymous and authenticated test user connections for calling API actions
api.resetConnection = function() {
api.testConnections = {};
api.testConnections.anonymous = new api.specHelper.connection();
api.testConnections.anonymous.rawConnection.req = { headers: {} };
Object.keys(api.session.testUsers).map(function(entry) {
api.testConnections[entry] = new api.specHelper.connection();
api.testConnections[entry].rawConnection.req = {
headers: {
authorization: 'Bearer ' + api.session.testUsers[entry].token
}
};
});
};
// Wait for an async message to be sent/broadcast to us
api.awaitMessage = function(connection, messageType, maxWait, callback) {
var maxTime = new Date().getTime() + maxWait,
cancel;
function check() {
if (new Date().getTime() > maxTime) {
clearInterval(cancel);
api.log('Timeout waiting for ' + messageType, 'info');
callback(null);
}
connection.messages.some(function(message) {
if (message.message && message.message.type && message.message.type === messageType) {
clearInterval(cancel);
callback(message);
return true;
}
});
}
cancel = setInterval(check, 100);
cancel.unref();
};
// Run an action but with a promise-style syntax. Note that we always resolve, so the test suite can deliberately evaluate
// errors as desired behavior.
api.specHelper.actionPromise = function(action, params) {
return new api.Promise(function(resolve, reject) {
api.specHelper.runAction(action, params, function(result) {
resolve(result);
});
});
};
// Pretend we've had a database failure
Object.keys(api.models).map(function(modelName) {
api.models[modelName].shouldFail = false;
api.models[modelName].beforeCreate(function(instance, options, callback) {
if (api.models[modelName].shouldFail) {
api.expectingOrmError = true;
callback(api.orm.queryError('Unable to process request.'));
} else {
callback();
}
});
api.models[modelName].beforeBulkCreate(function(instance, options, callback) {
if (api.models[modelName].shouldFail) {
api.expectingOrmError = true;
callback(api.orm.queryError('Unable to process request.'));
} else {
callback();
}
});
api.models[modelName].beforeFind(function(options, callback) {
if (api.models[modelName].shouldFail) {
api.expectingOrmError = true;
callback(api.orm.queryError('Unable to process request.'));
} else {
callback();
}
});
});
done();
});
},
teardown: function(done) {
if (running) {
actionhero.stop(function() {
delete global.api;
delete global.assert;
delete global.key;
});
}
done();
}
};
// Bootstrap functions before each test
before(bootstrap.init);
after(bootstrap.teardown);
// Reset from previous test runs
beforeEach(function(done) {
Object.keys(api.models).map(function(modelName) {
api.models[modelName].shouldFail = false;
});
api.resetConnection();
done();
});
describe('API: Core', function() {
it('should boot the test environment', function() {
assert.that(process.env.NODE_ENV).is.equalTo('test');
assert.that(api.env).is.equalTo('test');
assert.that(api.id).is.not.undefined();
});
});
describe('Action: createInterest', function() {
beforeEach(function() {
return api.models.interest.findAll({ where: { user_id: api.session.testUsers.duncanhines.id }}).then(function(interests) {
return api.Promise.map(interests || [], function(interest) {
return api.models.interest.destroy({ where: { id: interest.id } });
});
});
});
it('should reject anonymous calls', function() {
api.testConnections.anonymous.params = { name: 'Test' };
return api.specHelper.actionPromise('createInterest', api.testConnections.anonymous).then(function(response) {
assert.that(response.error.message).is.equalTo('Auth token required.');
});
});
it('should require a name field', function() {
api.testConnections.duncanhines.params = { avatar: 'Test' };
return api.specHelper.actionPromise('createInterest', api.testConnections.duncanhines).then(function(response) {
assert.that(response.error).is.equalTo('Error: name is a required parameter for this action');
});
});
it('should successfully create a proper interest', function() {
api.testConnections.duncanhines.params = { name: 'Test', newsAge: 5, tagline: 'Test interest' };
return api.specHelper.actionPromise('createInterest', api.testConnections.duncanhines).then(function(response) {
assert.that(response.interest.id).is.atLeast(1000);
return api.models.interest.findById(response.interest.id);
}).then(function(interest) {
assert.that(interest.name).is.equalTo('Test');
assert.that(interest.news_age).is.equalTo(5);
});
});
});
--recursive
--reporter spec
--timeout 15000
--ignore-leaks
--slow 3000
--globals api,assert
--require test/bootstrap
test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment