Skip to content

Commit

Permalink
Merge pull request #1 from meadow/ava
Browse files Browse the repository at this point in the history
Adds tests w/ ava
  • Loading branch information
rickharrison authored Jul 20, 2016
2 parents d4703b7 + e1ced80 commit 933ccbf
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
.nyc_output
coverage.lcov
11 changes: 11 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
machine:
node:
version: 6.3.0

test:
override:
- npm run cover
post:
- npm run lint
- ./node_modules/.bin/nyc report --reporter=text-lcov > coverage.lcov
- ./node_modules/.bin/codecov
15 changes: 6 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@
const assign = require('lodash.assign');
const aws = require('aws-sdk');

const DEFAULT_OPTS = {
region: 'us-standard',
accessKeyId: '',
secretAccessKey: '',
queue: ''
};

const Client = function Client (opts = DEFAULT_OPTS) {
const Client = function Client (opts = {}) {
if (!(this instanceof Client)) {
return new Client(opts);
}

const { region, accessKeyId, secretAccessKey, queue } = opts;
const { region = 'us-standard', accessKeyId, secretAccessKey, queue } = opts;

if (!accessKeyId || !secretAccessKey || !queue) {
throw new Error('Missing a required parameter: accessKeyId, secretAccessKey, or queue');
Expand All @@ -39,6 +32,10 @@ const Client = function Client (opts = DEFAULT_OPTS) {
*/

Client.prototype.sendMessage = function sendMessage (payload) {
if (!payload) {
throw new Error('Messages must have a payload.');
}

return new Promise((resolve, reject) => {
this.sqs.sendMessage({
MessageBody: JSON.stringify(payload)
Expand Down
19 changes: 17 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"description": "Client for Amazon SQS with built-in long polling.",
"main": "index.js",
"scripts": {
"cover": "nyc ava",
"lint": "eslint ./ --ext .js",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "ava"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -33,7 +34,21 @@
},
"devDependencies": {
"@meadow/eslint-config": "^2.0.0",
"ava": "^0.15.2",
"babel-eslint": "^6.1.2",
"eslint": "^3.1.1"
"codecov": "^1.0.1",
"eslint": "^3.1.1",
"nyc": "^7.0.0",
"sinon": "^1.17.4"
},
"ava": {
"files": [
"tests/**/*.js"
]
},
"nyc": {
"include": [
"index.js"
]
}
}
5 changes: 5 additions & 0 deletions tests/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"parserOptions": {
"sourceType": "module"
},
}
30 changes: 30 additions & 0 deletions tests/delete-message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import test from 'ava';
import sinon from 'sinon';

import sqs from '../index';

test.beforeEach((t) => {
t.context.client = sqs({ accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

sinon.stub(t.context.client.sqs, 'deleteMessage', function (params, callback) {
setImmediate(function () {
callback();
});
});
});

test.afterEach((t) => {
t.context.client.sqs.deleteMessage.restore();
});

test('returns a promise', (t) => {
const value = t.context.client.deleteMessage('foobar');

t.true(typeof value.then === 'function');
});

test('calls deleteMessage with the message body', async (t) => {
await t.context.client.deleteMessage('foobar');

t.true(t.context.client.sqs.deleteMessage.calledWith({ ReceiptHandle: 'foobar' }));
});
32 changes: 32 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import test from 'ava';

import sqs from '../index';

test('instantiantes a client when used without new', (t) => {
const client = sqs({ accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

t.truthy(client.sendMessage);
});

test('throws when missing required options', (t) => {
t.throws(() => {
sqs();
});
});

test('uses the default us-standard region', (t) => {
const client = sqs({ accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

t.is(client.sqs.config.region, 'us-standard');
});

test('creates amazon client with options', (t) => {
const client = sqs({ region: 'us-west-2', accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

t.truthy(client.sqs);
t.is(client.sqs.config.apiVersion, '2016-07-19');
t.is(client.sqs.config.region, 'us-west-2');
t.is(client.sqs.config.accessKeyId, 'foo');
t.is(client.sqs.config.secretAccessKey, 'bar');
t.is(client.sqs.config.params.QueueUrl, 'baz');
});
121 changes: 121 additions & 0 deletions tests/poll-queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import test from 'ava';
import sinon from 'sinon';

import sqs from '../index';

test.beforeEach((t) => {
t.context.client = sqs({ accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

sinon.stub(t.context.client.sqs, 'receiveMessage', function (params, callback) {
setImmediate(function () {
callback(null, t.context.data);
});
});

sinon.stub(t.context.client, 'deleteMessage', function () {
return Promise.resolve();
});
});

test.afterEach((t) => {
t.context.client.sqs.receiveMessage.restore();
t.context.client.deleteMessage.restore();
});

test('should use the default options', (t) => {
t.context.client.pollQueue({}, function () {

});

t.deepEqual(t.context.client.receiveOptions, {
AttributeNames: ['All'],
MessageAttributeNames: ['All'],
WaitTimeSeconds: 20
});
});

test('should extend the default options', (t) => {
t.context.client.pollQueue({ WaitTimeSeconds: 5, otherOption: 'foobar' }, function () {

});

t.deepEqual(t.context.client.receiveOptions, {
AttributeNames: ['All'],
MessageAttributeNames: ['All'],
WaitTimeSeconds: 5,
otherOption: 'foobar'
});
});

test.cb('should call the handler', (t) => {
t.plan(2);

t.context.data = {
Messages: [{ Body: '{ "foobar": "bazqux" }' }]
};

t.context.client.pollQueue({}, function (body) {
t.deepEqual(body, {
foobar: 'bazqux'
});
t.pass();
t.end();
});
});

test.cb('should call delete message', (t) => {
t.plan(1);

t.context.data = {
Messages: [{ Body: '{ "foobar": "bazqux" }' }]
};

t.context.client.pollQueue({}, function () {
const promise = Promise.resolve();

setImmediate(function () {
promise.then(function () {
t.is(t.context.client.deleteMessage.callCount, 1);
t.end();
});
});

return promise;
});
});

test.cb('should call poll queue multiple times', (t) => {
t.plan(1);

sinon.spy(t.context.client, 'pollQueue');

t.context.client.pollQueue({}, function () {

});

setTimeout(function () {
t.true(t.context.client.pollQueue.callCount > 1);
t.end();
}, 100);
});

test.cb('should call poll queue again even after errors', (t) => {
t.plan(1);

sinon.spy(t.context.client, 'pollQueue');

t.context.data = {
Messages: [{ Body: '{ "foobar": "bazqux" }' }]
};

t.context.client.pollQueue({}, function () {
return Promise.resolve().then(function () {
throw new Error();
});
});

setTimeout(function () {
t.true(t.context.client.pollQueue.callCount > 1);
t.end();
}, 100);
});
54 changes: 54 additions & 0 deletions tests/send-message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import test from 'ava';
import sinon from 'sinon';

import sqs from '../index';

test.beforeEach((t) => {
t.context.client = sqs({ accessKeyId: 'foo', secretAccessKey: 'bar', queue: 'baz' });

sinon.stub(t.context.client.sqs, 'sendMessage', function (params, callback) {
setImmediate(function () {
callback(null, { foo: 'bar' });
});
});
});

test.afterEach((t) => {
t.context.client.sqs.sendMessage.restore();
});

test('throws when a payload is not sent', (t) => {
t.throws(() => {
t.context.client.sendMessage();
});
});

test('returns a promise', (t) => {
const value = t.context.client.sendMessage({});

t.true(typeof value.then === 'function');
});

test('calls sendMessage with the message body', (t) => {
const message = { type: 'ACTION_TYPE', payload: 1337 };

t.context.client.sendMessage(message);

t.true(t.context.client.sqs.sendMessage.calledWith({ MessageBody: JSON.stringify(message) }));
});

test('returns the data from the promise', async (t) => {
const data = await t.context.client.sendMessage({ type: 'ACTION_TYPE', payload: 1337 });

t.deepEqual(data, { foo: 'bar' });
});

test('rejects the promise if sqs call fails', (t) => {
t.context.client.sqs.sendMessage.restore();

sinon.stub(t.context.client.sqs, 'sendMessage', function (params, callback) {
callback(new Error('foobar'), null);
});

t.throws(t.context.client.sendMessage({ type: 'ACTION_TYPE', payload: 1337 }));
});

0 comments on commit 933ccbf

Please sign in to comment.