rollbar
Version:
Effortlessly track and debug errors in your JavaScript applications with Rollbar. This package includes advanced error tracking features and an intuitive interface to help you identify and fix issues more quickly.
965 lines (875 loc) • 26.9 kB
JavaScript
/* globals expect */
/* globals describe */
/* globals it */
/* globals sinon */
import _ from '../src/utility.js';
import utility from '../src/utility.js';
import polyfillJSON from '../vendor/JSON-js/json3.js';
utility.setupJSON();
describe('setupJSON', function () {
beforeEach(function () {
utility.RollbarJSON.stringify = null;
utility.RollbarJSON.parse = null;
});
afterEach(function () {
// Resets utility.RollbarJSON
utility.RollbarJSON.stringify = null;
utility.RollbarJSON.parse = null;
utility.setupJSON();
});
it('should use native interface when polyfill is provided', function () {
var native = { stringify: JSON.stringify, parse: JSON.parse };
utility.setupJSON(polyfillJSON);
expect(utility.RollbarJSON.stringify.toString()).to.equal(
native.stringify.toString(),
);
expect(utility.RollbarJSON.parse.toString()).to.equal(
native.parse.toString(),
);
});
it('should use native interface when polyfill is not provided', function () {
var native = { stringify: JSON.stringify, parse: JSON.parse };
utility.setupJSON();
expect(utility.RollbarJSON.stringify.toString()).to.equal(
native.stringify.toString(),
);
expect(utility.RollbarJSON.parse.toString()).to.equal(
native.parse.toString(),
);
});
it('should replace custom interface when polyfill is provided', function () {
var native = { stringify: JSON.stringify, parse: JSON.parse };
var custom = {
stringify: function (json) {
return json;
},
parse: function (json) {
return json;
},
};
var polyfill = {};
polyfillJSON(polyfill);
// Set to custom interface
JSON.stringify = custom.stringify;
JSON.parse = custom.parse;
utility.setupJSON(polyfillJSON);
expect(utility.RollbarJSON.stringify.toString()).to.equal(
polyfill.stringify.toString(),
);
expect(utility.RollbarJSON.parse.toString()).to.equal(
polyfill.parse.toString(),
);
// restore original interface
JSON.stringify = native.stringify;
JSON.parse = native.parse;
});
it('should keep custom interface when polyfill is not provided', function () {
var native = { stringify: JSON.stringify, parse: JSON.parse };
var custom = {
stringify: function (json) {
return json;
},
parse: function (json) {
return json;
},
};
// Set to custom interface
JSON.stringify = custom.stringify;
JSON.parse = custom.parse;
utility.setupJSON();
expect(utility.RollbarJSON.stringify.toString()).to.equal(
custom.stringify.toString(),
);
expect(utility.RollbarJSON.parse.toString()).to.equal(
custom.parse.toString(),
);
// restore original interface
JSON.stringify = native.stringify;
JSON.parse = native.parse;
});
});
describe('typeName', function () {
it('should handle undefined', function (done) {
expect(_.typeName(undefined)).to.eql('undefined');
done();
});
it('should handle null', function (done) {
expect(_.typeName(null)).to.eql('null');
done();
});
it('should handle numbers', function (done) {
expect(_.typeName(1)).to.eql('number');
expect(_.typeName(-32)).to.eql('number');
expect(_.typeName(1.452)).to.eql('number');
expect(_.typeName(0)).to.eql('number');
done();
});
it('should handle bools', function (done) {
expect(_.typeName(true)).to.eql('boolean');
expect(_.typeName(false)).to.eql('boolean');
done();
});
it('should handle strings', function (done) {
expect(_.typeName('')).to.eql('string');
expect(_.typeName('a longer string')).to.eql('string');
done();
});
it('should handle functions', function (done) {
expect(_.typeName(function () {})).to.eql('function');
var f = function (x) {
return x;
};
expect(_.typeName(f)).to.eql('function');
done();
});
it('should handle objects', function (done) {
expect(_.typeName({})).to.eql('object');
expect(_.typeName({ a: 123 })).to.eql('object');
done();
});
it('should handle arrays', function (done) {
expect(_.typeName([])).to.eql('array');
expect(_.typeName([1, { a: 42 }, null])).to.eql('array');
done();
});
});
describe('isType', function () {
it('should handle all types', function (done) {
expect(_.isType(undefined, 'undefined')).to.be.ok();
expect(_.isType(undefined, 'null')).to.not.be.ok();
expect(_.isType(null, 'null')).to.be.ok();
expect(_.isType(null, 'object')).to.not.be.ok();
expect(_.isType({}, 'object')).to.be.ok();
expect(_.isType(function () {}, 'function')).to.be.ok();
expect(_.isType(42, 'number')).to.be.ok();
expect(_.isType('42', 'string')).to.be.ok();
expect(_.isType([], 'array')).to.be.ok();
expect(_.isType([102, []], 'array')).to.be.ok();
done();
});
});
describe('isFunction', function () {
it('should work for all functions', function (done) {
var f = function () {
return;
};
var g = function (x) {
return f(x);
};
expect(_.isFunction({})).to.not.be.ok();
expect(_.isFunction(null)).to.not.be.ok();
expect(_.isFunction(f)).to.be.ok();
expect(_.isFunction(g)).to.be.ok();
done();
});
});
describe('isNativeFunction', function () {
it('should work for all native functions', function (done) {
var f = function () {
return;
};
var g = function (x) {
return f(x);
};
var h = String.prototype.substr;
var i = Array.prototype.indexOf;
expect(_.isNativeFunction({})).to.not.be.ok();
expect(_.isNativeFunction(null)).to.not.be.ok();
expect(_.isNativeFunction(f)).to.not.be.ok();
expect(_.isNativeFunction(g)).to.not.be.ok();
expect(_.isNativeFunction(h)).to.be.ok();
expect(_.isNativeFunction(i)).to.be.ok();
done();
});
});
describe('isIterable', function () {
it('should work for all types', function (done) {
expect(_.isIterable({})).to.be.ok();
expect(_.isIterable([])).to.be.ok();
expect(_.isIterable([{ a: 1 }])).to.be.ok();
expect(_.isIterable(null)).to.not.be.ok();
expect(_.isIterable(undefined)).to.not.be.ok();
expect(_.isIterable('object')).to.not.be.ok();
expect(_.isIterable(42)).to.not.be.ok();
done();
});
});
describe('isError', function () {
it('should handle null', function (done) {
expect(_.isError(null)).to.not.be.ok();
done();
});
it('should handle errors', function (done) {
var e = new Error('hello');
expect(_.isError(e)).to.be.ok();
done();
});
it('should handle subclasses of error', function (done) {
// This is a mostly browser compliant way of doing this
// just for the sake of doing it, even though we mostly
// need this to work in node environments
function TestCustomError(message) {
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: 'TestCustomError',
});
Object.defineProperty(this, 'message', {
enumerable: false,
writable: true,
value: message,
});
if (Error.hasOwnProperty('captureStackTrace')) {
Error.captureStackTrace(this, TestCustomError);
} else {
Object.defineProperty(this, 'stack', {
enumerable: false,
writable: false,
value: new Error(message).stack,
});
}
}
if (typeof Object.setPrototypeOf === 'function') {
Object.setPrototypeOf(TestCustomError.prototype, Error.prototype);
} else {
TestCustomError.prototype = Object.create(Error.prototype, {
constructor: { value: TestCustomError },
});
}
var e = new TestCustomError('bork');
expect(_.isError(e)).to.be.ok();
done();
});
});
describe('isFiniteNumber', function () {
[NaN, null, undefined, 'x'].forEach(function (value) {
it(`should return false for ${value}`, function (done) {
expect(_.isFiniteNumber(value)).to.equal(false);
done();
});
});
[-100, 0, 100].forEach(function (value) {
it(`should return true for ${value}`, function (done) {
expect(_.isFiniteNumber(value)).to.equal(true);
done();
});
});
});
describe('merge', function () {
it('should work for simple objects', function (done) {
var o1 = { a: 1, b: 2 };
var o2 = { a: 42, c: 101 };
var e = _.merge(o1, o2);
expect(e.a).to.eql(42);
expect(e.b).to.eql(2);
expect(e.c).to.eql(101);
e.a = 100;
expect(o1.a).to.eql(1);
expect(o2.a).to.eql(42);
done();
});
it('should not concat arrays', function (done) {
var o1 = { a: 1, b: ['hello', 'world'] };
var o2 = { a: 42, b: ['goodbye'] };
var e = _.merge(o1, o2);
expect(e.a).to.eql(42);
expect(e.b).to.contain('goodbye');
expect(e.b).to.not.contain('world');
expect(e.b.length).to.eql(1);
expect(o1.b).to.contain('world');
expect(o1.b).not.to.contain('goodbye');
done();
});
it('should handle nested objects', function (done) {
var o1 = {
a: 1,
c: 100,
payload: {
person: {
id: 'xxx',
name: 'hello',
},
environment: 'foo',
},
};
var o2 = {
a: 42,
b: 2,
payload: {
person: {
id: 'yesyes',
email: 'cool',
},
other: 'bar',
},
};
var e = _.merge(o1, o2);
expect(e.a).to.eql(42);
expect(e.c).to.eql(100);
expect(e.b).to.eql(2);
expect(e.payload.person.id).to.eql('yesyes');
expect(e.payload.person.email).to.eql('cool');
expect(e.payload.person.name).to.eql('hello');
expect(e.payload.environment).to.eql('foo');
expect(e.payload.other).to.eql('bar');
done();
});
it('should handle nested arrays and objects, with non-matching structure', function (done) {
var o1 = {
a: 1,
c: {
arr: [3, 4, 5],
other: [99, 100, 101],
payload: {
foo: {
bar: 'baz',
},
hello: 'world',
keeper: 'yup',
},
},
};
var o2 = {
a: 32,
c: {
arr: [1],
other: { fuzz: 'buzz' },
payload: {
foo: 'hello',
hello: {
baz: 'bar',
},
},
},
};
var e = _.merge(o1, o2);
expect(e.a).to.eql(32);
expect(e.c.arr.length).to.eql(1);
expect(e.c.arr[0]).to.eql(1);
expect(e.c.other.fuzz).to.eql('buzz');
expect(e.c.payload.foo).to.eql('hello');
expect(e.c.payload.hello.baz).to.eql('bar');
expect(e.c.payload.keeper).to.eql('yup');
done();
});
it('should handle many nested objects', function (done) {
var o1 = {
a: 1,
c: 100,
payload: {
person: {
id: 'xxx',
name: 'hello',
},
environment: 'foo',
},
};
var o2 = {
a: 42,
b: 2,
payload: {
person: {
id: 'yesyes',
email: 'cool',
},
other: 'bar',
},
};
var o3 = {
payload: {
fuzz: 'buzz',
person: {
name: 'nope',
},
},
amihere: 'yes',
};
var e = _.merge(o1, o2, o3);
expect(e.a).to.eql(42);
expect(e.c).to.eql(100);
expect(e.b).to.eql(2);
expect(e.payload.person.id).to.eql('yesyes');
expect(e.payload.person.email).to.eql('cool');
expect(e.payload.person.name).to.eql('nope');
expect(e.payload.environment).to.eql('foo');
expect(e.payload.fuzz).to.eql('buzz');
expect(e.payload.other).to.eql('bar');
expect(e.amihere).to.eql('yes');
done();
});
});
import traverse from '../src/utility/traverse.js';
describe('traverse', function () {
describe('should call the func for every key,value', function () {
it('simple object', function (done) {
var obj = { a: 1, b: 2 };
var expectedOutput = { a: 2, b: 3 };
var callCount = 0;
var result = traverse(obj, function (k, v) {
callCount++;
return v + 1;
});
expect(result).to.eql(expectedOutput);
expect(callCount).to.eql(2);
done();
});
it('nested object', function (done) {
var obj = { a: 1, b: 2, c: { ca: 11 } };
var expectedOutput = { a: 2, b: 3, c: { ca: 12 } };
var callCount = 0;
var result = traverse(obj, function (k, v) {
callCount++;
if (k === 'c') {
return { ca: v.ca + 1 };
}
return v + 1;
});
expect(result).to.eql(expectedOutput);
expect(callCount).to.eql(3);
done();
});
it('array', function (done) {
var obj = [1, 2, 3];
var expected = [0, 1, 2];
var callCount = 0;
var result = traverse(
obj,
function (k, v) {
callCount++;
return v - 1;
},
[],
);
expect(result).to.eql(expected);
expect(callCount).to.eql(3);
done();
});
});
});
describe('uuid4', function () {
it('should return a version 4 uuid', function (done) {
var id = _.uuid4();
var otherId = _.uuid4();
expect(id).to.not.eql(otherId);
var parts = id.split('-');
expect(parts.length).to.eql(5);
expect(parts[2][0]).to.eql('4');
expect(parts[0].length).to.eql(8);
expect(parts[1].length).to.eql(4);
expect(parts[2].length).to.eql(4);
expect(parts[3].length).to.eql(4);
expect(parts[4].length).to.eql(12);
done();
});
});
describe('redact', function () {
it('should return a string of stars', function (done) {
var s1 = 'thisIsApasswrD';
var s2 = 'short';
var o = { a: 123 };
var a = [12, 34, 56];
expect(_.redact(s1)).to.not.match(/[^*]/);
expect(_.redact(s2)).to.not.match(/[^*]/);
expect(_.redact(s1)).to.eql(_.redact(s2));
expect(_.redact(o)).to.not.match(/[^*]/);
expect(_.redact(a)).to.not.match(/[^*]/);
done();
});
});
describe('LEVELS', function () {
it('should include debug', function () {
expect(_.LEVELS['debug']).to.not.eql(undefined);
});
it('should have critical higher than debug', function () {
expect(_.LEVELS['critical']).to.be.greaterThan(_.LEVELS['debug']);
});
});
describe('formatUrl', function () {
it('should handle a missing protocol', function () {
var u = {
hostname: 'a.b.com',
path: '/wooza/',
port: 42,
};
expect(_.formatUrl(u)).to.eql('https://a.b.com:42/wooza/');
});
it('should use a forced protocol', function () {
var u = {
hostname: 'a.b.com',
path: '/wooza/',
port: 42,
};
expect(_.formatUrl(u, 'file:')).to.eql('file://a.b.com:42/wooza/');
});
it('should pick a protocol based on port if others are missing', function () {
var u = {
hostname: 'a.b.com',
port: 80,
path: '/woo',
};
expect(_.formatUrl(u)).to.eql('http://a.b.com:80/woo');
u.protocol = 'https:';
expect(_.formatUrl(u)).to.eql('https://a.b.com:80/woo');
});
it('should handle missing parts', function () {
var u = {
hostname: 'a.b.com',
};
expect(_.formatUrl(u)).to.eql('https://a.b.com');
expect(_.formatUrl(u, 'http:')).to.eql('http://a.b.com');
});
it('should return null without a hostname', function () {
var u = {};
expect(_.formatUrl(u)).to.not.be.ok();
expect(_.formatUrl(u, 'https:')).to.not.be.ok();
});
});
describe('addParamsAndAccessTokenToPath', function () {
var accessToken = 'abc123';
it('should handle no params and no path', function () {
var options = {};
_.addParamsAndAccessTokenToPath(accessToken, options);
expect(options.path).to.eql('?access_token=abc123');
});
it('should handle existing params', function () {
var options = { path: '/api?a=b' };
_.addParamsAndAccessTokenToPath(accessToken, options);
expect(options.path).to.eql('/api?access_token=abc123&a=b');
});
it('should handle a hash with params', function () {
var options = { path: '/api?a=b#moreStuff??here' };
_.addParamsAndAccessTokenToPath(accessToken, options);
expect(options.path).to.eql('/api?access_token=abc123&a=b#moreStuff??here');
});
it('should handle a hash without params', function () {
var options = { path: '/api#moreStuff??here' };
_.addParamsAndAccessTokenToPath(accessToken, options);
expect(options.path).to.eql('/api?access_token=abc123#moreStuff??here');
});
it('should handle a hash without params and no ?', function () {
var options = { path: '/api#moreStuff' };
_.addParamsAndAccessTokenToPath(accessToken, options);
expect(options.path).to.eql('/api?access_token=abc123#moreStuff');
});
it('should handle extra params', function () {
var options = { path: '/api#moreStuff' };
_.addParamsAndAccessTokenToPath(accessToken, options, { foo: 'boo' });
expect(options.path).to.eql('/api?access_token=abc123&foo=boo#moreStuff');
});
});
describe('json3', function () {
let setupCustomJSON;
before(async function () {
const module = await import('../vendor/JSON-js/json3.js');
setupCustomJSON = module.default;
});
it('should replace stringify if not there', function () {
var j = {};
setupCustomJSON(j);
expect(j.stringify({ a: 1 })).to.eql('{"a":1}');
});
it('should replace parse if not there', function () {
var j = {};
setupCustomJSON(j);
expect(j.parse('{"a":1}').a).to.eql(1);
});
it('should not replace parse if there', function () {
var j = {
parse: function (s) {
return 42;
},
};
setupCustomJSON(j);
expect(j.parse('{"a":1}')).to.eql(42);
expect(j.stringify({ a: 1 })).to.eql('{"a":1}');
});
it('should not replace stringify if there', function () {
var j = {
stringify: function (s) {
return '42';
},
};
setupCustomJSON(j);
expect(j.stringify({ a: 1 })).to.eql('42');
expect(j.parse('{"a":1}').a).to.eql(1);
});
});
describe('get', function () {
it('should get a deeply nested value', function () {
var o = { a: { b: { c: { d: 42 } } } };
expect(_.get(o, 'a.b.c.d')).to.eql(42);
});
it('should be undefined for a missing value', function () {
var o = { a: { b: { c: { d: 42 } } } };
expect(_.get(o, 'a.b.x.d')).to.not.be.ok();
});
it('should handle bad input', function () {
var o = 'hello';
expect(_.get(o, 'oops.1.2.3')).to.not.be.ok();
});
it('should actually work with arrays too', function () {
var o = { a: [{ b: { c: [1, { d: 42 }, null] } }, 99] };
expect(_.get(o, 'a.0.b.c.1.d')).to.eql(42);
});
it('should handle undefined input', function () {
var u = undefined;
expect(_.get(u, 'a.b.c')).to.not.be.ok();
});
});
describe('filterIp', function () {
it('no user_ip', function () {
var requestData = { something: 'but no ip' };
_.filterIp(requestData, false);
expect(requestData['user_ip']).to.not.be.ok();
});
it('capture true', function () {
var ip = '123.32.394.99';
var requestData = { user_ip: ip };
_.filterIp(requestData, true);
expect(requestData['user_ip']).to.eql(ip);
});
it('anonymize ip4', function () {
var ip = '123.32.394.99';
var requestData = { user_ip: ip };
_.filterIp(requestData, 'anonymize');
expect(requestData['user_ip']).to.not.eql(ip);
expect(requestData['user_ip']).to.be.ok();
});
it('capture false', function () {
var ip = '123.32.394.99';
var requestData = { user_ip: ip };
_.filterIp(requestData, false);
expect(requestData['user_ip']).to.not.eql(ip);
expect(requestData['user_ip']).to.not.be.ok();
});
it('ipv6 capture false', function () {
var ip = '2607:f0d0:1002:51::4';
var requestData = { user_ip: ip };
_.filterIp(requestData, false);
expect(requestData['user_ip']).to.not.eql(ip);
expect(requestData['user_ip']).to.not.be.ok();
});
it('ipv6 anonymize', function () {
var ips = [
'FE80:0000:0000:0000:0202:B3FF:FE1E:8329',
'FE80::0202:B3FF:FE1E:8329',
'2607:f0d0:1002:51::4',
];
for (var i = 0; i < ips.length; i++) {
var ip = ips[i];
var requestData = { user_ip: ip };
_.filterIp(requestData, 'anonymize');
expect(requestData['user_ip']).to.not.eql(ip);
expect(requestData['user_ip']).to.be.ok();
}
});
});
describe('set', function () {
it('should handle a top level key', function () {
var o = { a: 42 };
_.set(o, 'b', 1);
expect(o.b).to.eql(1);
expect(o.a).to.eql(42);
});
it('should handle a top level key', function () {
var o = { a: 42, b: { c: 44, d: { e: 99 } } };
_.set(o, 'f', 1);
expect(o.f).to.eql(1);
expect(o.a).to.eql(42);
expect(o.b.c).to.eql(44);
expect(o.b.d.e).to.eql(99);
});
it('should replace a value that is already there', function () {
var o = { a: 42 };
_.set(o, 'a', 1);
expect(o.a).to.eql(1);
});
it('should set a nested value with missing keys', function () {
var o = { baz: 21 };
_.set(o, 'foo.bar', [42]);
expect(o.baz).to.eql(21);
expect(o.foo.bar).to.eql([42]);
});
it('should replace a nested value', function () {
var o = { woo: 99, foo: { bar: { baz: 42, buzz: 97 }, a: 98 } };
_.set(o, 'foo.bar.baz', 1);
expect(o.woo).to.eql(99);
expect(o.foo.a).to.eql(98);
expect(o.foo.bar.buzz).to.eql(97);
expect(o.foo.bar.baz).to.eql(1);
});
it('should set a nested value with some missing keys', function () {
var o = { woo: 99, foo: { bar: { buzz: 97 }, a: 98 } };
_.set(o, 'foo.bar.baz.fizz', 1);
expect(o.woo).to.eql(99);
expect(o.foo.a).to.eql(98);
expect(o.foo.bar.buzz).to.eql(97);
expect(o.foo.bar.baz.fizz).to.eql(1);
});
});
import scrub from '../src/scrub.js';
describe('scrub', function () {
it('should not redact fields that are okay', function () {
var data = {
a: 'somestring',
password: 'abc123',
tempWorker: 'cool',
};
var scrubFields = ['password', 'b', 'pw'];
var result = scrub(data, scrubFields);
expect(result.a).to.eql('somestring');
expect(result.tempWorker).to.eql('cool');
});
it('should redact fields that are in the field list', function () {
var data = {
a: 'somestring',
password: 'abc123',
};
var scrubFields = ['password', 'b'];
var result = scrub(data, scrubFields);
expect(result.password).to.eql(_.redact());
});
it('should handle nested objects', function () {
var data = {
a: {
b: {
badthing: 'secret',
other: 'stuff',
},
c: 'bork',
password: 'abc123',
},
secret: 'blahblah',
};
var scrubFields = ['badthing', 'password', 'secret'];
var result = scrub(data, scrubFields);
expect(result.a.b.other).to.eql('stuff');
expect(result.a.b.badthing).to.eql(_.redact());
expect(result.a.c).to.eql('bork');
expect(result.a.password).to.eql(_.redact());
expect(result.secret).to.eql(_.redact());
expect(data.secret).to.eql('blahblah');
});
it('should do something sane for recursive objects', function () {
var inner = {
a: 'what',
b: 'yes',
};
var data = {
thing: 'stuff',
password: 'abc123',
};
data.inner = inner;
inner.outer = data;
var scrubFields = ['password', 'a'];
var result = scrub(data, scrubFields);
expect(result.thing).to.eql('stuff');
expect(result.password).to.eql(_.redact());
expect(result.inner.a).to.eql(_.redact());
expect(result.inner.a).to.be.ok();
expect(result.inner.b).to.eql('yes');
});
it('should scrub objects seen twice', function () {
var request = {
password: 'foo',
};
var data = {
request,
response: { request },
};
var scrubFields = ['password'];
var result = scrub(data, scrubFields);
expect(result.request.password).to.eql(_.redact());
expect(result.response.request.password).to.eql(_.redact());
});
it('should handle scrubPaths', function () {
var data = {
a: {
b: {
foo: 'secret',
bar: 'stuff',
},
c: 'bork',
password: 'abc123',
},
secret: 'blahblah',
};
var scrubPaths = [
'nowhere', // path not found
'a.b.foo', // nested path
'a.password', // nested path
'secret', // root path
];
var result = scrub(data, [], scrubPaths);
expect(result.a.b.bar).to.eql('stuff');
expect(result.a.b.foo).to.eql(_.redact());
expect(result.a.c).to.eql('bork');
expect(result.a.password).to.eql(_.redact());
expect(result.secret).to.eql(_.redact());
});
});
describe('formatArgsAsString', function () {
it('should handle null', function () {
var args = [null, 1];
var result = _.formatArgsAsString(args);
expect(result).to.eql('null 1');
});
it('should handle undefined', function () {
var args = [null, 1, undefined];
var result = _.formatArgsAsString(args);
expect(result).to.eql('null 1 undefined');
});
it('should handle objects', function () {
var args = [1, { a: 42 }];
var result = _.formatArgsAsString(args);
expect(result).to.eql('1 {"a":42}');
});
it('should handle strings', function () {
var args = [1, 'foo'];
var result = _.formatArgsAsString(args);
expect(result).to.eql('1 foo');
});
it('should handle empty args', function () {
var args = [];
var result = _.formatArgsAsString(args);
expect(result).to.eql('');
});
/*
* PhantomJS does not support Symbol yet
it('should handle symbols', function() {
var args = [1, Symbol('hello')];
var result = _.formatArgsAsString(args);
expect(result).to.eql('1 symbol(\'hello\')');
});
*/
});
describe('addItemAttributes', function () {
it('should skip undefined values', function () {
const item = { data: {} };
const attributes = [
{ key: 'replay_id', value: '12345' },
{ key: 'session_id', value: undefined },
];
_.addItemAttributes(item.data, attributes);
expect(item.data.attributes).to.be.an('array');
expect(item.data.attributes.length).to.equal(1);
expect(item.data.attributes[0].key).to.equal('replay_id');
expect(item.data.attributes[0].value).to.equal('12345');
});
});
describe('getItemAttribute', function () {
it('should skip undefined values', function () {
const item = {
data: {
attributes: [
{ key: 'replay_id', value: '12345' },
{ key: 'session_id', value: '67890' },
],
},
};
let value = _.getItemAttribute(item.data, 'replay_id');
expect(value).to.equal('12345');
value = _.getItemAttribute(item.data, 'session_id');
expect(value).to.equal('67890');
});
});