Skip to content

Commit dfcfffc

Browse files
authored
Merge pull request #191 from bookcreator/fix_#169
Fix for #169 (TypeError: Cannot read property 'error' of undefined)
2 parents 8918db2 + 65fd8b9 commit dfcfffc

File tree

4 files changed

+343
-12
lines changed

4 files changed

+343
-12
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
language: node_js
22
node_js:
3-
- '0.10'
4-
- '0.12'
3+
- 4
4+
- 6
5+
- 8
56
- 'stable'

lib/client.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,17 @@ export default class Client {
6060
return new Bluebird((resolve, reject) => {
6161
const resolver = (err, data) => {
6262
if (err) {
63-
reject(new Error(JSON.stringify(err)));
63+
reject(err);
6464
} else {
6565
resolve(data);
6666
}
6767
};
68-
this.request(args, (_, r) => {
69-
callbackHandler(resolver, r);
68+
this.request(args, (err, r) => {
69+
callbackHandler(resolver, err, r);
7070
});
7171
});
7272
} else {
73-
this.request(args, (_, r) => this.callback(f, r));
73+
this.request(args, (err, r) => this.callback(f, err, r));
7474
}
7575
}
7676
ping(f) {
@@ -138,19 +138,29 @@ export default class Client {
138138
callback
139139
).auth(this.usernamePart, this.passwordPart);
140140
}
141-
callback(f, data) {
141+
callback(f, err, res) {
142142
if (!f) {
143143
return;
144144
}
145145
if (f.length >= 2) {
146-
const hasErrors = data.error || (data.body && data.body.type === 'error.list');
147-
if (hasErrors) {
148-
f(data, null);
146+
if (res && res.body && res.body.type === 'error.list') {
147+
let message = null;
148+
if (Array.isArray(res.body.errors) && res.body.errors[0] && 'message' in res.body.errors) {
149+
// Try to use the first errors message
150+
message = res.body.errors[0].message;
151+
}
152+
err = new Error(message || 'Response error');
153+
err.statusCode = res.statusCode;
154+
err.body = res.body;
155+
err.headers = res.headers;
156+
}
157+
if (err) {
158+
f(err, null);
149159
} else {
150-
f(null, data);
160+
f(null, res);
151161
}
152162
} else {
153-
f(data);
163+
f(res || null);
154164
}
155165
}
156166
}

test/errors.js

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
import assert from 'assert';
2+
import {Client} from '../lib';
3+
import nock from 'nock';
4+
5+
describe.only('errors', () => {
6+
describe('with promises', () => {
7+
it('should fail with ESOCKETTIMEDOUT error', () => {
8+
9+
const socketErr = new Error('Socket timeout');
10+
socketErr.code = 'ESOCKETTIMEDOUT';
11+
12+
nock('https://api.intercom.io').replyContentLength().get('/admins').replyWithError(socketErr);
13+
const client = new Client('foo', 'bar').usePromises();
14+
return client.admins.list().then(r => {
15+
assert.strictEqual(r, null, 'Valid response');
16+
}).catch(err => {
17+
assert.deepStrictEqual(err, socketErr);
18+
});
19+
});
20+
it('should fail with unauthorized (401) error', () => {
21+
nock('https://api.intercom.io').replyContentLength().get('/admins').reply(401,
22+
{
23+
type: 'error.list',
24+
request_id: 'b2i3ri5909msvfqskol0',
25+
errors: [
26+
{
27+
code: 'token_unauthorized',
28+
message: 'Not authorized to access resource'
29+
}
30+
]
31+
},
32+
{
33+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
34+
'X-RateLimit-Limit': '83',
35+
'X-RateLimit-Remaining': '27',
36+
'X-RateLimit-Reset': '1522850540',
37+
'X-Request-Id': 'b2i3ri5909msvfqskol0',
38+
'X-Runtime': '0.037708'
39+
}
40+
);
41+
const client = new Client('foo', 'bar').usePromises();
42+
return client.admins.list().then(r => {
43+
assert.strictEqual(r, null, 'Valid response');
44+
}).catch(err => {
45+
assert.strictEqual(err.statusCode, 401);
46+
assert.strictEqual(err.body.request_id, 'b2i3ri5909msvfqskol0');
47+
assert.deepStrictEqual(err.body.errors, [{ code: 'token_unauthorized', message: 'Not authorized to access resource' }]);
48+
assert.strictEqual(err.headers['x-request-id'], 'b2i3ri5909msvfqskol0');
49+
});
50+
});
51+
it('should fail with too many requests (429) error', () => {
52+
nock('https://api.intercom.io').replyContentLength().get('/me').reply(429,
53+
{
54+
type: 'error.list',
55+
request_id: 'b2i3mhcboc6pcbe33q80',
56+
errors: [
57+
{
58+
code: 'rate_limit_exceeded',
59+
message: 'Exceeded rate limit of 83 in 10_seconds'
60+
}
61+
]
62+
},
63+
{
64+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
65+
'X-RateLimit-Limit': '83',
66+
'X-RateLimit-Remaining': '0',
67+
'X-RateLimit-Reset': '1522849880',
68+
'X-Request-Id': 'b2i3mhcboc6pcbe33q80',
69+
'X-Runtime': '0.037708'
70+
}
71+
);
72+
const client = new Client('foo', 'bar').usePromises();
73+
return client.admins.me().then(r => {
74+
assert.strictEqual(r, null, 'Valid response');
75+
}).catch(err => {
76+
assert.strictEqual(err.statusCode, 429);
77+
assert.strictEqual(err.body.request_id, 'b2i3mhcboc6pcbe33q80');
78+
assert.deepStrictEqual(err.body.errors, [{ code: 'rate_limit_exceeded', message: 'Exceeded rate limit of 83 in 10_seconds' }]);
79+
assert.strictEqual(err.headers['x-request-id'], 'b2i3mhcboc6pcbe33q80');
80+
assert.strictEqual(err.headers['x-ratelimit-reset'], '1522849880');
81+
});
82+
});
83+
});
84+
85+
describe('with callback', () => {
86+
describe('with 1 arg', () => {
87+
it('should fail with ESOCKETTIMEDOUT error', done => {
88+
89+
const socketErr = new Error('Socket timeout');
90+
socketErr.code = 'ESOCKETTIMEDOUT';
91+
92+
nock('https://api.intercom.io').replyContentLength().get('/admins').replyWithError(socketErr);
93+
const client = new Client('foo', 'bar');
94+
client.admins.list(r => {
95+
assert.strictEqual(r, null, 'Valid response');
96+
97+
done();
98+
});
99+
});
100+
it('should fail with unauthorized (401) error', done => {
101+
nock('https://api.intercom.io').replyContentLength().get('/admins').reply(401,
102+
{
103+
type: 'error.list',
104+
request_id: 'b2i3ri5909msvfqskol0',
105+
errors: [
106+
{
107+
code: 'token_unauthorized',
108+
message: 'Not authorized to access resource'
109+
}
110+
]
111+
},
112+
{
113+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
114+
'X-RateLimit-Limit': '83',
115+
'X-RateLimit-Remaining': '27',
116+
'X-RateLimit-Reset': '1522850540',
117+
'X-Request-Id': 'b2i3ri5909msvfqskol0',
118+
'X-Runtime': '0.037708'
119+
}
120+
);
121+
const client = new Client('foo', 'bar');
122+
client.admins.list(r => {
123+
assert.strictEqual(r.statusCode, 401);
124+
assert.strictEqual(r.body.type, 'error.list');
125+
assert.strictEqual(r.body.request_id, 'b2i3ri5909msvfqskol0');
126+
assert.ok(Array.isArray(r.body.errors));
127+
128+
done();
129+
});
130+
});
131+
it('should fail with too many requests (429) error', done => {
132+
nock('https://api.intercom.io').replyContentLength().get('/me').reply(429,
133+
{
134+
type: 'error.list',
135+
request_id: 'b2i3mhcboc6pcbe33q80',
136+
errors: [
137+
{
138+
code: 'rate_limit_exceeded',
139+
message: 'Exceeded rate limit of 83 in 10_seconds'
140+
}
141+
]
142+
},
143+
{
144+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
145+
'X-RateLimit-Limit': '83',
146+
'X-RateLimit-Remaining': '0',
147+
'X-RateLimit-Reset': '1522849880',
148+
'X-Request-Id': 'b2i3mhcboc6pcbe33q80',
149+
'X-Runtime': '0.037708'
150+
}
151+
);
152+
const client = new Client('foo', 'bar');
153+
client.admins.me(r => {
154+
assert.strictEqual(r.statusCode, 429);
155+
assert.strictEqual(r.body.type, 'error.list');
156+
assert.strictEqual(r.body.request_id, 'b2i3mhcboc6pcbe33q80');
157+
assert.ok(Array.isArray(r.body.errors));
158+
159+
done();
160+
});
161+
});
162+
});
163+
describe('with 2 args', () => {
164+
it('should fail with ESOCKETTIMEDOUT error', done => {
165+
166+
const socketErr = new Error('Socket timeout');
167+
socketErr.code = 'ESOCKETTIMEDOUT';
168+
169+
nock('https://api.intercom.io').replyContentLength().get('/admins').replyWithError(socketErr);
170+
const client = new Client('foo', 'bar');
171+
client.admins.list((err, r) => {
172+
assert.strictEqual(r, null, 'Valid response');
173+
174+
assert.deepStrictEqual(err, socketErr);
175+
176+
done();
177+
});
178+
});
179+
it('should fail with unauthorized (401) error', done => {
180+
nock('https://api.intercom.io').replyContentLength().get('/admins').reply(401,
181+
{
182+
type: 'error.list',
183+
request_id: 'b2i3ri5909msvfqskol0',
184+
errors: [
185+
{
186+
code: 'token_unauthorized',
187+
message: 'Not authorized to access resource'
188+
}
189+
]
190+
},
191+
{
192+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
193+
'X-RateLimit-Limit': '83',
194+
'X-RateLimit-Remaining': '27',
195+
'X-RateLimit-Reset': '1522850540',
196+
'X-Request-Id': 'b2i3ri5909msvfqskol0',
197+
'X-Runtime': '0.037708'
198+
}
199+
);
200+
const client = new Client('foo', 'bar');
201+
client.admins.list((err, r) => {
202+
assert.strictEqual(r, null, 'Valid response');
203+
204+
assert.strictEqual(err.statusCode, 401);
205+
assert.strictEqual(err.body.request_id, 'b2i3ri5909msvfqskol0');
206+
assert.deepStrictEqual(err.body.errors, [{ code: 'token_unauthorized', message: 'Not authorized to access resource' }]);
207+
assert.strictEqual(err.headers['x-request-id'], 'b2i3ri5909msvfqskol0');
208+
209+
done();
210+
});
211+
});
212+
it('should fail with too many requests (429) error', done => {
213+
nock('https://api.intercom.io').replyContentLength().get('/me').reply(429,
214+
{
215+
type: 'error.list',
216+
request_id: 'b2i3mhcboc6pcbe33q80',
217+
errors: [
218+
{
219+
code: 'rate_limit_exceeded',
220+
message: 'Exceeded rate limit of 83 in 10_seconds'
221+
}
222+
]
223+
},
224+
{
225+
'X-Intercom-Version': '3736ab533ad11d88d93cdef3fcef9a98a5724229',
226+
'X-RateLimit-Limit': '83',
227+
'X-RateLimit-Remaining': '0',
228+
'X-RateLimit-Reset': '1522849880',
229+
'X-Request-Id': 'b2i3mhcboc6pcbe33q80',
230+
'X-Runtime': '0.037708'
231+
}
232+
);
233+
const client = new Client('foo', 'bar');
234+
client.admins.me((err, r) => {
235+
assert.strictEqual(r, null, 'Valid response');
236+
237+
assert.strictEqual(err.statusCode, 429);
238+
assert.strictEqual(err.body.request_id, 'b2i3mhcboc6pcbe33q80');
239+
assert.deepStrictEqual(err.body.errors, [{ code: 'rate_limit_exceeded', message: 'Exceeded rate limit of 83 in 10_seconds' }]);
240+
assert.strictEqual(err.headers['x-request-id'], 'b2i3mhcboc6pcbe33q80');
241+
assert.strictEqual(err.headers['x-ratelimit-reset'], '1522849880');
242+
243+
done();
244+
});
245+
});
246+
});
247+
});
248+
});

0 commit comments

Comments
 (0)