UNPKG

opbeat-ionic

Version:

The unofficial Opbeat client for Ionic

354 lines (309 loc) 11.3 kB
'use strict'; var fs = require('fs'); var os = require('os'); var zlib = require('zlib'); var util = require('util'); var test = require('tape'); var nock = require('nock'); var common = require('common'); var afterAll = require('after-all'); var helpers = require('./_helpers'); var request = require('../lib/request'); var opbeat = require('../'); var options = { organizationId: 'some-org-id', appId: 'some-app-id', secretToken: 'secret', captureExceptions: false }; var optionFixtures = [ ['appId', 'APP_ID'], ['organizationId', 'ORGANIZATION_ID'], ['secretToken', 'SECRET_TOKEN'], ['clientLogLevel', 'CLIENT_LOG_LEVEL', 'info'], ['hostname', 'HOSTNAME', os.hostname()], ['stackTraceLimit', 'STACK_TRACE_LIMIT', Infinity], ['captureExceptions', 'CAPTURE_EXCEPTIONS', true], ['exceptionLogLevel', 'EXCEPTION_LOG_LEVEL', 'fatal'] ]; var falsyValues = [false, 0, '', '0', 'false', 'no', 'off', 'disabled']; var truthyValues = [true, 1, '1', 'true', 'yes', 'on', 'enabled']; var skipBody = function () { return '*'; }; var uncaughtExceptionListeners = process._events.uncaughtException; var setup = function () { clean(); uncaughtExceptionListeners = process._events.uncaughtException; process.removeAllListeners('uncaughtException'); helpers.mockLogger(); }; var clean = function () { process._events.uncaughtException = uncaughtExceptionListeners; helpers.restoreLogger(); }; optionFixtures.forEach(function (fixture) { test('should be configurable by envrionment variable OPBEAT_' + fixture[1], function (t) { setup(); var bool = typeof fixture[2] === 'boolean'; var value = bool ? (fixture[2] ? '0' : '1') : 'custom-value'; process.env['OPBEAT_' + fixture[1]] = value; var client = opbeat(); t.equal(client[fixture[0]], bool ? value != false : value); delete process.env['OPBEAT_' + fixture[1]]; t.end(); }); test('should overwrite OPBEAT_' + fixture[1] + ' by option property ' + fixture[0], function (t) { setup(); var options = {}; var bool = typeof fixture[2] === 'boolean'; var value1 = bool ? (fixture[2] ? '0' : '1') : 'overwriting-value'; var value2 = bool ? (fixture[2] ? '1' : '0') : 'custom-value'; options[fixture[0]] = value1; process.env['OPBEAT_' + fixture[1]] = value2; var client = opbeat(options); t.equal(client[fixture[0]], bool ? value1 != false : value1); delete process.env['OPBEAT_' + fixture[1]]; t.end(); }); test('should default ' + fixture[0] + ' to ' + fixture[2], function (t) { setup(); var client = opbeat(); t.equal(client[fixture[0]], fixture[2]); t.end(); }); }); falsyValues.forEach(function (val) { test('should be disabled by envrionment variable OPBEAT_ACTIVE set to: ' + util.inspect(val), function (t) { setup(); process.env.OPBEAT_ACTIVE = val; var client = opbeat({ appId: 'foo', organizationId: 'bar', secretToken: 'baz' }); t.equal(client.active, false); delete process.env.OPBEAT_ACTIVE; t.end(); }); }); truthyValues.forEach(function (val) { test('should be enabled by envrionment variable OPBEAT_ACTIVE set to: ' + util.inspect(val), function (t) { setup(); process.env.OPBEAT_ACTIVE = val; var client = opbeat({ appId: 'foo', organizationId: 'bar', secretToken: 'baz' }); t.equal(client.active, true); delete process.env.OPBEAT_ACTIVE; t.end(); }); }); test('should overwrite OPBEAT_ACTIVE by option property active', function (t) { setup(); var options = { appId: 'foo', organizationId: 'bar', secretToken: 'baz', active: false }; process.env.OPBEAT_ACTIVE = '1'; var client = opbeat(options); t.equal(client.active, false); delete process.env.OPBEAT_ACTIVE; t.end(); }); test('should default active to true if required options have been specified', function (t) { setup(); var client = opbeat({ appId: 'foo', organizationId: 'bar', secretToken: 'baz' }); t.equal(client.active, true); t.end(); }); test('should default active to false if required options have not been specified', function (t) { setup(); var client = opbeat(); t.equal(client.active, false); t.end(); }); test('should force active to false if required options have not been specified', function (t) { setup(); var client = opbeat({ active: true }); t.equal(client.active, false); t.end(); }); test('#captureError()', function (t) { t.test('should send a plain text message to Opbeat server', function (t) { setup(); var client = opbeat(options); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .defaultReplyHeaders({'Location': 'foo'}) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(200); client.on('logged', function (result) { scope.done(); t.equal(result, 'foo'); t.end(); }); client.captureError('Hey!'); }); t.test('should emit error when request returns non 200', function (t) { setup(); var client = opbeat(options); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(500, { error: 'Oops!' }); client.on('error', function () { scope.done(); t.end(); }); client.captureError('Hey!'); }); t.test('shouldn\'t shit it\'s pants when error is emitted without a listener', function (t) { setup(); var client = opbeat(options); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(500, { error: 'Oops!' }); client.captureError('Hey!'); setTimeout(function () { t.end(); }, 25); }); t.test('should attach an Error object when emitting error', function (t) { setup(); var client = opbeat(options); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(500, { error: 'Oops!' }); client.on('error', function (err) { scope.done(); t.equal(err.message, 'Opbeat error (500): {"error":"Oops!"}'); t.end(); }); client.captureError('Hey!'); }); t.test('should use `param_message` as well as `message` if given an object as 1st argument', function (t) { setup(); var client = opbeat(options); var oldErrorFn = request.error; request.error = function (client, options, callback) { t.ok('message' in options); t.ok('param_message' in options); t.equal(options.message, 'Hello World'); t.equal(options.param_message, 'Hello %s'); request.error = oldErrorFn; t.end(); }; client.captureError({ message: 'Hello %s', params: ['World'] }); }); t.test('should send an Error to Opbeat server', function (t) { setup(); var client = opbeat(options); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .defaultReplyHeaders({'Location': 'foo'}) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(200); client.on('logged', function (result) { scope.done(); t.equal(result, 'foo'); t.end(); }); client.captureError(new Error('wtf?')); }); }); test('#handleUncaughtExceptions()', function (t) { t.test('should add itself to the uncaughtException event list', function (t) { setup(); t.equal(process._events.uncaughtException, undefined); var client = opbeat(options); client.handleUncaughtExceptions(); t.equal(process._events.uncaughtException.length, 1); t.end(); }); t.test('should not add more than one listener for the uncaughtException event', function (t) { setup(); var client = opbeat(options); client.handleUncaughtExceptions(); var before = process._events.uncaughtException.length; client.handleUncaughtExceptions(); t.equal(process._events.uncaughtException.length, before); t.end(); }); t.test('should send an uncaughtException to Opbeat server', function (t) { setup(); var scope = nock('https://opbeat.com') .filteringRequestBody(skipBody) .defaultReplyHeaders({'Location': 'foo'}) .post('/api/v1/organizations/some-org-id/apps/some-app-id/errors/', '*') .reply(200); var client = opbeat(options); client.handleUncaughtExceptions(function (err, url) { scope.done(); t.equal(url, 'foo'); t.end(); }); process.emit('uncaughtException', new Error('derp')); }); }); test('#trackDeployment()', function (t) { t.test('should send deployment request to the Opbeat server with given rev', function (t) { setup(); var client = opbeat(options); var expected = JSON.stringify({ status: 'completed', rev: 'foo' }); zlib.deflate(expected, function (err, buffer) { t.error(err); var scope = nock('https://opbeat.com') .filteringRequestBody(function (body) { t.equal(body, buffer.toString('hex')); return 'ok'; }) .post('/api/v1/organizations/some-org-id/apps/some-app-id/releases/', 'ok') .reply(200); client.trackDeployment({ rev: 'foo' }, function () { scope.done(); t.end(); }); }); }); t.test('should send deployment request to the Opbeat server with given rev and branch', function (t) { setup(); var client = opbeat(options); var expected = JSON.stringify({ status: 'completed', rev: 'foo', branch: 'bar' }); zlib.deflate(expected, function (err, buffer) { t.error(err); var scope = nock('https://opbeat.com') .filteringRequestBody(function (body) { t.equal(body, buffer.toString('hex')); return 'ok'; }) .post('/api/v1/organizations/some-org-id/apps/some-app-id/releases/', 'ok') .reply(200); client.trackDeployment({ rev: 'foo', branch: 'bar' }, function () { scope.done(); t.end(); }); }); }); t.test('should send deployment request to the Opbeat server with given rev and branch automatically generated', function (t) { setup(); var client = opbeat(options); var expected = JSON.stringify({ status: 'completed', rev: 'foo', branch: 'bar' }); zlib.deflate(expected, function (err, buffer) { t.error(err); var next = afterAll(function (err) { scope.done(); t.error(err); t.end(); }); var cb = next(); var scope = nock('https://opbeat.com') .filteringRequestBody(function (body) { zlib.inflate(new Buffer(body, 'hex'), function (err, buffer) { t.error(err); var json = JSON.parse(buffer.toString()); t.equal(Object.keys(json).length, 3); t.equal(json.status, 'completed'); t.ok(/^[\da-f]{40}$/.test(json.rev)); t.ok(/^[^ ]+$/.test(json.branch)); cb(); }); return '*'; }) .post('/api/v1/organizations/some-org-id/apps/some-app-id/releases/', '*') .reply(200); client.trackDeployment(next()); }); }); });