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.
333 lines (296 loc) • 8.06 kB
JavaScript
/**
* Integration tests for Queue and ReplayMap
*/
/* globals describe */
/* globals it */
/* globals beforeEach */
/* globals afterEach */
import { expect } from 'chai';
import sinon from 'sinon';
import Queue from '../../../src/queue.js';
import Api from '../../../src/api.js';
describe('Queue ReplayMap Integration', function () {
let queue;
let replayMap;
let api;
let transport;
beforeEach(function () {
transport = {
post: sinon
.stub()
.callsFake((accessToken, transportOptions, payload, callback) => {
setTimeout(() => {
callback(
null,
{ err: 0, result: { id: '12345' } },
{ 'Rollbar-Replay-Enabled': 'true' }
);
}, 10);
}),
postJsonPayload: sinon.stub(),
};
const urlMock = { parse: sinon.stub().returns({}) };
const truncationMock = {
truncate: sinon.stub().returns({ error: null, value: '{}' }),
};
api = new Api(
{ accessToken: 'test-token' },
transport,
urlMock,
truncationMock,
);
replayMap = {
add: sinon.stub().returnsArg(0),
send: sinon.stub().resolves(true),
discard: sinon.stub().returns(true),
getSpans: sinon.stub().returns([{ id: 'test-span' }]),
setSpans: sinon.stub(),
};
queue = new Queue(
{ shouldSend: () => ({ shouldSend: true }) },
api,
console,
{ transmit: true },
replayMap,
);
});
afterEach(function () {
sinon.restore();
});
it('should add replayId when processing an item', function (done) {
const item = {
body: {
trace: {
exception: {
message: 'Test error',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
expect(item).to.have.property('replayId', '1234567812345678');
expect(replayMap.add.calledOnce).to.be.true;
done();
});
});
it('should call replayMap.send when API response is successful', function (done) {
const item = {
body: {
trace: {
exception: {
message: 'Test error',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
setTimeout(function () {
expect(replayMap.send.calledWith('1234567812345678')).to.be.true;
done();
}, 50);
});
});
it('should call replayMap.discard when API response has error', function (done) {
transport.post.callsFake(
(accessToken, transportOptions, payload, callback) => {
setTimeout(() => {
callback(null, { err: 1, message: 'API Error' });
}, 10);
},
);
const item = {
body: {
trace: {
exception: {
message: 'Test error with API failure',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
setTimeout(function () {
expect(replayMap.discard.calledWith('1234567812345678')).to.be.true;
expect(replayMap.send.called).to.be.false;
done();
}, 50);
});
});
it('should call replayMap.discard when replay is disabled', function (done) {
transport.post.callsFake(
(accessToken, transportOptions, payload, callback) => {
setTimeout(() => {
callback(
null,
{ err: 0, result: { id: '12345' } },
{ 'Rollbar-Replay-Enabled': 'false' }
);
}, 10);
},
);
const item = {
body: {
trace: {
exception: {
message: 'Test error with replay disabled',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
setTimeout(function () {
expect(replayMap.discard.calledWith('1234567812345678')).to.be.true;
expect(replayMap.send.called).to.be.false;
done();
}, 50);
});
});
it('should call replayMap.discard when over quota', function (done) {
transport.post.callsFake(
(accessToken, transportOptions, payload, callback) => {
setTimeout(() => {
callback(
null,
{ err: 0, result: { id: '12345' } },
{ 'Rollbar-Replay-Enabled': 'true',
'Rollbar-Replay-RateLimit-Remaining': '0'}
);
}, 10);
},
);
const item = {
body: {
trace: {
exception: {
message: 'Test error with replay over quota',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
setTimeout(function () {
expect(replayMap.discard.calledWith('1234567812345678')).to.be.true;
expect(replayMap.send.called).to.be.false;
done();
}, 50);
});
});
it('should handle retrying items with replayId', function (done) {
let apiCallCount = 0;
transport.post.callsFake(
(accessToken, transportOptions, payload, callback) => {
apiCallCount++;
if (apiCallCount === 1) {
setTimeout(() => {
callback({ code: 'ECONNRESET' });
}, 10);
} else {
setTimeout(() => {
callback(
null,
{ err: 0, result: { id: '12345' } },
{ 'Rollbar-Replay-Enabled': 'true' }
);
}, 10);
}
},
);
queue.configure({ retryInterval: 50, maxRetries: 3 });
const item = {
body: {
trace: {
exception: {
message: 'Test error with retry',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function (err, resp) {
if (resp) {
expect(item).to.have.property('replayId', '1234567812345678');
setTimeout(function () {
expect(replayMap.send.calledWith('1234567812345678')).to.be.true;
done();
}, 50);
}
});
});
it('should not add replayId to items without a body', function (done) {
const item = {
level: 'error',
message: 'Test error without body',
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
expect(item).to.not.have.property('replayId');
expect(replayMap.add.called).to.be.false;
done();
});
});
it('should not add replayId to items without a replay_id attribute', function (done) {
const item = {
level: 'error',
message: 'Test error without body',
body: {
trace: {
exception: {
message: 'Test error with retry',
},
},
},
};
queue.addItem(item, function () {
expect(item).to.not.have.property('replayId');
expect(replayMap.add.called).to.be.false;
done();
});
});
it('should handle null response in _handleReplayResponse', function (done) {
transport.post.callsFake(
(accessToken, transportOptions, payload, callback) => {
setTimeout(() => {
callback(null, null);
}, 10);
},
);
const consoleWarnSpy = sinon.spy(console, 'warn');
const item = {
body: {
trace: {
exception: {
message: 'Test error with null response',
},
},
},
attributes: [
{ key: 'replay_id', value: '1234567812345678' },
],
};
queue.addItem(item, function () {
setTimeout(function () {
expect(replayMap.send.called).to.be.false;
expect(replayMap.discard.calledWith('1234567812345678')).to.be.false;
done();
}, 50);
});
});
});