Skip to content

Commit 5e7e658

Browse files
committed
Increase RESTController coverage, fix error handling for incomplete server response
1 parent abe5a53 commit 5e7e658

File tree

2 files changed

+170
-2
lines changed

2 files changed

+170
-2
lines changed

src/RESTController.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ var RESTController = {
9797
try {
9898
response = JSON.parse(xhr.responseText);
9999
} catch (e) {
100-
promise.reject(e);
100+
promise.reject(e.toString());
101+
}
102+
if (response) {
103+
promise.resolve(response, xhr.status, xhr);
101104
}
102-
promise.resolve(response, xhr.status, xhr);
103105
} else if (xhr.status >= 500 || xhr.status === 0) { // retry on 5XX or node-xmlhttprequest error
104106
if (++attempts < CoreManager.get('REQUEST_ATTEMPT_LIMIT')) {
105107
// Exponentially-growing random delay

src/__tests__/RESTController-test.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,170 @@ describe('RESTController', () => {
162162
done();
163163
});
164164
}));
165+
166+
it('handles invalid responses', asyncHelper((done) => {
167+
var XHR = function() { };
168+
XHR.prototype = {
169+
open: function() { },
170+
setRequestHeader: function() { },
171+
send: function() {
172+
this.status = 200;
173+
this.responseText = '{';
174+
this.readyState = 4;
175+
this.onreadystatechange();
176+
}
177+
};
178+
RESTController._setXHR(XHR);
179+
RESTController.request('GET', 'classes/MyObject', {}, {})
180+
.then(null, (error) => {
181+
expect(error.code).toBe(100);
182+
expect(error.message).toBe('XMLHttpRequest failed: "SyntaxError: Unexpected end of input"');
183+
done();
184+
});
185+
}));
186+
187+
it('handles invalid errors', asyncHelper((done) => {
188+
var XHR = function() { };
189+
XHR.prototype = {
190+
open: function() { },
191+
setRequestHeader: function() { },
192+
send: function() {
193+
this.status = 400;
194+
this.responseText = '{';
195+
this.readyState = 4;
196+
this.onreadystatechange();
197+
}
198+
};
199+
RESTController._setXHR(XHR);
200+
RESTController.request('GET', 'classes/MyObject', {}, {})
201+
.then(null, (error) => {
202+
expect(error.code).toBe(107);
203+
expect(error.message).toBe('Received an error with invalid JSON from Parse: {');
204+
done();
205+
});
206+
}));
207+
208+
it('attaches the session token of the current user', () => {
209+
CoreManager.setUserController({
210+
currentUserAsync() {
211+
return ParsePromise.as({ getSessionToken: () => '5678' });
212+
},
213+
setCurrentUser() {},
214+
currentUser() {},
215+
signUp() {},
216+
logIn() {},
217+
become() {},
218+
logOut() {},
219+
requestPasswordReset() {},
220+
upgradeToRevocableSession() {},
221+
linkWith() {},
222+
});
223+
224+
var xhr = {
225+
setRequestHeader: jest.genMockFn(),
226+
open: jest.genMockFn(),
227+
send: jest.genMockFn()
228+
};
229+
RESTController._setXHR(function() { return xhr; });
230+
RESTController.request('GET', 'classes/MyObject', {}, {});
231+
jest.runAllTicks();
232+
expect(JSON.parse(xhr.send.mock.calls[0][0])).toEqual({
233+
_method: 'GET',
234+
_ApplicationId: 'A',
235+
_JavaScriptKey: 'B',
236+
_ClientVersion: 'V',
237+
_InstallationId: 'iid',
238+
_SessionToken: '5678',
239+
});
240+
CoreManager.set('UserController', undefined); // Clean up
241+
});
242+
243+
it('attaches no session token when there is no current user', () => {
244+
CoreManager.setUserController({
245+
currentUserAsync() {
246+
return ParsePromise.as(null);
247+
},
248+
setCurrentUser() {},
249+
currentUser() {},
250+
signUp() {},
251+
logIn() {},
252+
become() {},
253+
logOut() {},
254+
requestPasswordReset() {},
255+
upgradeToRevocableSession() {},
256+
linkWith() {},
257+
});
258+
259+
var xhr = {
260+
setRequestHeader: jest.genMockFn(),
261+
open: jest.genMockFn(),
262+
send: jest.genMockFn()
263+
};
264+
RESTController._setXHR(function() { return xhr; });
265+
RESTController.request('GET', 'classes/MyObject', {}, {});
266+
jest.runAllTicks();
267+
expect(JSON.parse(xhr.send.mock.calls[0][0])).toEqual({
268+
_method: 'GET',
269+
_ApplicationId: 'A',
270+
_JavaScriptKey: 'B',
271+
_ClientVersion: 'V',
272+
_InstallationId: 'iid',
273+
});
274+
CoreManager.set('UserController', undefined); // Clean up
275+
});
276+
277+
it('sends the revocable session upgrade header when the config flag is set', () => {
278+
CoreManager.set('FORCE_REVOCABLE_SESSION', true);
279+
var xhr = {
280+
setRequestHeader: jest.genMockFn(),
281+
open: jest.genMockFn(),
282+
send: jest.genMockFn()
283+
};
284+
RESTController._setXHR(function() { return xhr; });
285+
RESTController.request('GET', 'classes/MyObject', {}, {});
286+
jest.runAllTicks();
287+
expect(JSON.parse(xhr.send.mock.calls[0][0])).toEqual({
288+
_method: 'GET',
289+
_ApplicationId: 'A',
290+
_JavaScriptKey: 'B',
291+
_ClientVersion: 'V',
292+
_InstallationId: 'iid',
293+
_RevocableSession: '1'
294+
});
295+
CoreManager.set('FORCE_REVOCABLE_SESSION', false); // Clean up
296+
});
297+
298+
it('sends the master key when requested', () => {
299+
CoreManager.set('MASTER_KEY', 'M');
300+
var xhr = {
301+
setRequestHeader: jest.genMockFn(),
302+
open: jest.genMockFn(),
303+
send: jest.genMockFn()
304+
};
305+
RESTController._setXHR(function() { return xhr; });
306+
RESTController.request('GET', 'classes/MyObject', {}, { useMasterKey: true });
307+
jest.runAllTicks();
308+
expect(JSON.parse(xhr.send.mock.calls[0][0])).toEqual({
309+
_method: 'GET',
310+
_ApplicationId: 'A',
311+
_MasterKey: 'M',
312+
_ClientVersion: 'V',
313+
_InstallationId: 'iid',
314+
});
315+
});
316+
317+
it('throws when attempted to use an unprovided master key', () => {
318+
CoreManager.set('MASTER_KEY', undefined);
319+
var xhr = {
320+
setRequestHeader: jest.genMockFn(),
321+
open: jest.genMockFn(),
322+
send: jest.genMockFn()
323+
};
324+
RESTController._setXHR(function() { return xhr; });
325+
expect(function() {
326+
RESTController.request('GET', 'classes/MyObject', {}, { useMasterKey: true });
327+
}).toThrow(
328+
'Cannot use the Master Key, it has not been provided.'
329+
);
330+
});
165331
});

0 commit comments

Comments
 (0)