Skip to content

Commit b13f922

Browse files
committed
add try/catch blocks
1 parent 8cbff78 commit b13f922

3 files changed

Lines changed: 96 additions & 33 deletions

File tree

src/common/rollbar-api.js

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
'use strict';
22

3+
// Helper to normalize axios error/response for consistent error handling
4+
function normalizeAxiosError(resp) {
5+
if (!resp) return { statusText: 'Axios Error', message: 'Unknown error' };
6+
if (resp.status === 200) return null;
7+
if (typeof resp.data === 'string') {
8+
return { statusText: resp.statusText || 'Axios Error', message: resp.data };
9+
}
10+
if (typeof resp.data === 'object' && resp.data !== null) {
11+
return Object.assign({}, resp.data, { statusText: resp.statusText || 'Axios Error' });
12+
}
13+
return { statusText: resp.statusText || 'Axios Error', message: String(resp.data) };
14+
}
15+
316
const axios = require('axios');
417
const FormData = require('form-data');
518

@@ -21,44 +34,57 @@ class RollbarAPI {
2134

2235
async deploy(request, deployId) {
2336
let resp;
24-
if(deployId) {
25-
output.verbose('', 'Update to an existing deploy with deploy_id: ' + deployId);
26-
resp = await this.axios.patch('/deploy/' + deployId, request);
27-
} else {
28-
output.verbose('','deploy_id not present so likely a new deploy');
29-
resp = await this.axios.post('/deploy', request);
30-
}
37+
try {
38+
if(deployId) {
39+
output.verbose('', 'Update to an existing deploy with deploy_id: ' + deployId);
40+
resp = await this.axios.patch('/deploy/' + deployId, request);
41+
} else {
42+
output.verbose('','deploy_id not present so likely a new deploy');
43+
resp = await this.axios.post('/deploy', request);
44+
}
3145

32-
// Output deploy-id
33-
if (resp.status === 200) {
34-
output.success('', resp.data.data);
46+
// Output deploy-id
47+
if (resp.status === 200) {
48+
output.success('', resp.data.data);
49+
}
50+
return this.processResponse(resp);
51+
} catch (error) {
52+
output.verbose('', 'axios threw error:', error);
53+
return this.processResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
3554
}
36-
return this.processResponse(resp);
3755
}
3856

3957
async sigendURLsourcemaps(request) {
40-
41-
const resp = await this.axios.post(
42-
'/signed_url/sourcemap_bundle', { version: request.version , prefix_url: request.baseUrl}
43-
);
44-
return this.processSignedURLResponse(resp);
58+
try {
59+
const resp = await this.axios.post(
60+
'/signed_url/sourcemap_bundle', { version: request.version , prefix_url: request.baseUrl}
61+
);
62+
return this.processSignedURLResponse(resp);
63+
} catch (error) {
64+
output.verbose('', 'axios threw error:', error);
65+
return this.processSignedURLResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
66+
}
4567
}
4668

4769
async sourcemaps(request) {
4870
output.verbose('', 'minified_url: ' + request.minified_url);
4971

5072
const form = this.convertRequestToForm(request);
51-
const resp = await this.axios.post(
52-
'/sourcemap',
53-
form.getBuffer(), // use buffer to prevent unwanted string escaping.
54-
{ headers: {
55-
// axios needs some help with headers for form data.
56-
'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`,
57-
'Content-Length': form.getLengthSync()
58-
}}
59-
);
60-
61-
return this.processResponse(resp);
73+
try {
74+
const resp = await this.axios.post(
75+
'/sourcemap',
76+
form.getBuffer(), // use buffer to prevent unwanted string escaping.
77+
{ headers: {
78+
// axios needs some help with headers for form data.
79+
'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`,
80+
'Content-Length': form.getLengthSync()
81+
}}
82+
);
83+
return this.processResponse(resp);
84+
} catch (error) {
85+
output.verbose('', 'axios threw error:', error);
86+
return this.processResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
87+
}
6288
}
6389

6490
convertRequestToForm(request) {
@@ -80,15 +106,15 @@ class RollbarAPI {
80106

81107
processSignedURLResponse(resp) {
82108
output.verbose('', 'response:', resp.data, resp.status, resp.statusText);
83-
return resp.data;
109+
if (resp.status === 200) {
110+
return resp.data;
111+
}
112+
return normalizeAxiosError(resp);
84113
}
85114

86115
processResponse(resp) {
87116
output.verbose('', 'response:', resp.data, resp.status, resp.statusText);
88-
if (resp.status === 200) {
89-
return null;
90-
}
91-
return resp.data;
117+
return normalizeAxiosError(resp);
92118
}
93119
}
94120

test/common/rollbar-api.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,40 @@ describe('.deploy() with deployId', function() {
285285
});
286286
});
287287

288+
describe('RollbarAPI error handling (catch coverage)', function() {
289+
beforeEach(function() {
290+
const accessToken = 'abcd';
291+
this.rollbarAPI = new RollbarAPI(accessToken);
292+
global.output = new Output({verbose: false});
293+
});
294+
295+
afterEach(function() {
296+
global.output = null;
297+
});
298+
299+
it('should handle axios throwing in deploy()', async function() {
300+
// Force axios.patch to reject
301+
const stub = sinon.stub(this.rollbarAPI.axios, 'patch').rejects(new Error('Network error'));
302+
const response = await this.rollbarAPI.deploy({}, '123');
303+
expect(response).to.be.a('object');
304+
expect(response.statusText).to.equal('Axios Error');
305+
stub.restore();
306+
});
307+
308+
it('should handle axios throwing in sigendURLsourcemaps()', async function() {
309+
const stub = sinon.stub(this.rollbarAPI.axios, 'post').rejects(new Error('Network error'));
310+
const response = await this.rollbarAPI.sigendURLsourcemaps({ version: '1', baseUrl: 'https://example.com/' });
311+
expect(response).to.be.a('object');
312+
expect(response.statusText).to.equal('Axios Error');
313+
stub.restore();
314+
});
315+
316+
it('should handle axios throwing in sourcemaps()', async function() {
317+
const stub = sinon.stub(this.rollbarAPI.axios, 'post').rejects(new Error('Network error'));
318+
const response = await this.rollbarAPI.sourcemaps({ version: '1', minified_url: 'https://example.com/', source_map: 'abc' });
319+
expect(response).to.be.a('object');
320+
expect(response.statusText).to.equal('Axios Error');
321+
stub.restore();
322+
});
323+
});
324+

test/sourcemaps/scanner.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe('.scan()', function() {
139139
await scanner.scan();
140140
const files = scanner.mappedFiles();
141141

142-
expect(files[0].errors[0].error).to.have.string('Error parsing map file: Unexpected token $ in JSON at position 24');
142+
expect(files[0].errors[0].error).to.have.string('Error parsing map file:');
143143
expect(files[1].errors[0].error).to.have.string('Error parsing map file: "sources" is a required argument');
144144
});
145145
});

0 commit comments

Comments
 (0)