123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- const sinon = require('sinon');
- const EventEmitter = require('events');
- describe('Provider', function () {
- let fakes, Provider;
- beforeEach(function () {
- fakes = {
- Client: sinon.stub(),
- client: new EventEmitter(),
- };
- fakes.Client.returns(fakes.client);
- fakes.client.write = sinon.stub();
- fakes.client.shutdown = sinon.stub();
- Provider = require('../lib/provider')(fakes);
- });
- describe('constructor', function () {
- context('called without `new`', function () {
- it('returns a new instance', function () {
- expect(Provider()).to.be.an.instanceof(Provider);
- });
- });
- describe('Client instance', function () {
- it('is created', function () {
- Provider();
- expect(fakes.Client).to.be.calledOnce;
- expect(fakes.Client).to.be.calledWithNew;
- });
- it('is passed the options', function () {
- const options = { configKey: 'configValue' };
- Provider(options);
- expect(fakes.Client).to.be.calledWith(options);
- });
- });
- });
- describe('send', function () {
- describe('single notification behaviour', function () {
- let provider;
- context('transmission succeeds', function () {
- beforeEach(function () {
- provider = new Provider({ address: 'testapi' });
- fakes.client.write.onCall(0).returns(Promise.resolve({ device: 'abcd1234' }));
- });
- it('invokes the writer with correct `this`', function () {
- return provider.send(notificationDouble(), 'abcd1234').then(function () {
- expect(fakes.client.write).to.be.calledOn(fakes.client);
- });
- });
- it('writes the notification to the client once', function () {
- return provider.send(notificationDouble(), 'abcd1234').then(function () {
- const notification = notificationDouble();
- const builtNotification = {
- headers: notification.headers(),
- body: notification.compile(),
- };
- expect(fakes.client.write).to.be.calledOnce;
- expect(fakes.client.write).to.be.calledWith(builtNotification, 'abcd1234');
- });
- });
- it('does not pass the array index to writer', function () {
- return provider.send(notificationDouble(), 'abcd1234').then(function () {
- expect(fakes.client.write.firstCall.args[2]).to.be.undefined;
- });
- });
- it('resolves with the device token in the sent array', function () {
- return expect(provider.send(notificationDouble(), 'abcd1234')).to.become({
- sent: [{ device: 'abcd1234' }],
- failed: [],
- });
- });
- });
- context('error occurs', function () {
- let promise;
- beforeEach(function () {
- const provider = new Provider({ address: 'testapi' });
- fakes.client.write.onCall(0).returns(
- Promise.resolve({
- device: 'abcd1234',
- status: '400',
- response: { reason: 'BadDeviceToken' },
- })
- );
- promise = provider.send(notificationDouble(), 'abcd1234');
- });
- it('resolves with the device token, status code and response in the failed array', function () {
- return expect(promise).to.eventually.deep.equal({
- sent: [],
- failed: [{ device: 'abcd1234', status: '400', response: { reason: 'BadDeviceToken' } }],
- });
- });
- });
- });
- context('when multiple tokens are passed', function () {
- beforeEach(function () {
- fakes.resolutions = [
- { device: 'abcd1234' },
- { device: 'adfe5969', status: '400', response: { reason: 'MissingTopic' } },
- {
- device: 'abcd1335',
- status: '410',
- response: { reason: 'BadDeviceToken', timestamp: 123456789 },
- },
- { device: 'bcfe4433' },
- { device: 'aabbc788', status: '413', response: { reason: 'PayloadTooLarge' } },
- { device: 'fbcde238', error: new Error('connection failed') },
- ];
- });
- context('streams are always returned', function () {
- let promise;
- beforeEach(function () {
- const provider = new Provider({ address: 'testapi' });
- for (let i = 0; i < fakes.resolutions.length; i++) {
- fakes.client.write.onCall(i).returns(Promise.resolve(fakes.resolutions[i]));
- }
- promise = provider.send(
- notificationDouble(),
- fakes.resolutions.map(res => res.device)
- );
- return promise;
- });
- it('resolves with the sent notifications', function () {
- return promise.then(response => {
- expect(response.sent).to.deep.equal([{ device: 'abcd1234' }, { device: 'bcfe4433' }]);
- });
- });
- it('resolves with the device token, status code and response or error of the unsent notifications', function () {
- return promise.then(response => {
- expect(response.failed[3].error).to.be.an.instanceof(Error);
- response.failed[3].error = { message: response.failed[3].error.message };
- expect(response.failed).to.deep.equal(
- [
- { device: 'adfe5969', status: '400', response: { reason: 'MissingTopic' } },
- {
- device: 'abcd1335',
- status: '410',
- response: { reason: 'BadDeviceToken', timestamp: 123456789 },
- },
- { device: 'aabbc788', status: '413', response: { reason: 'PayloadTooLarge' } },
- { device: 'fbcde238', error: { message: 'connection failed' } },
- ],
- `Unexpected result: ${JSON.stringify(response.failed)}`
- );
- });
- });
- });
- });
- });
- describe('shutdown', function () {
- it('invokes shutdown on the client', function () {
- const callback = sinon.spy();
- const provider = new Provider({});
- provider.shutdown(callback);
- expect(fakes.client.shutdown).to.be.calledOnceWithExactly(callback);
- });
- });
- });
- function notificationDouble() {
- return {
- headers: sinon.stub().returns({}),
- payload: { aps: { badge: 1 } },
- compile: function () {
- return JSON.stringify(this.payload);
- },
- };
- }
|