box-chrome-sdk
Version:
A Chrome App SDK for the Box V2 API
817 lines (761 loc) • 32.8 kB
JavaScript
/*jshint expr: true*/
describe('box.sdk', function() {
var mocks, boxHttp, boxSdk, observer, chromeStorage, boxApiAuth, apiUrl, authUrl, http, $timeout = angular.noop;
var BoxFile, BoxFolder, BoxGroup, BoxTask, BoxUser, BoxCollaboration, BoxEvent;
var fileResponse, folderResponse, file, folder;
var clientId = 'i3p-----------------------------',
clientSecret = 'uII-----------------------------';
var provide;
beforeEach(function() {
mocks = sinon.sandbox.create();
observer = mocks.spy();
angular.module('box.conf')
.constant('clientSecret', clientSecret)
.constant('clientId', clientId);
module('box.sdk', 'box.http', 'box.objects', 'rx.http', 'box.auth', 'chrome.storage', function($provide) {
provide = $provide;
});
inject(function(_boxHttp_, _chromeStorage_, _boxApiAuth_, _http_) {
boxHttp = mocks.stub(_boxHttp_);
provide.value('boxHttp', boxHttp);
chromeStorage = mocks.stub(_chromeStorage_);
provide.value('chromeStorage', chromeStorage);
boxApiAuth = mocks.stub(_boxApiAuth_);
provide.value('boxApiAuth', boxApiAuth);
http = mocks.stub(_http_);
provide.value('http', http);
provide.value('$timeout', function() { $timeout.apply(this, Array.prototype.slice.call(arguments)); });
});
fileResponse = {
"type": "file",
"id": "5000948880",
"sequence_id": "3",
"etag": "3",
"sha1": "134b65991ed521fcfe4724b7d814ab8ded5185dc",
"name": "tigers.jpeg",
"description": "a picture of tigers",
"size": 629644,
"path_collection": {
"total_count": 2,
"entries": [
{
"type": "folder",
"id": "0",
"sequence_id": null,
"etag": null,
"name": "All Files"
},
{
"type": "folder",
"id": "11446498",
"sequence_id": "1",
"etag": "1",
"name": "Pictures"
}
]
},
"created_at": "2012-12-12T10:55:30-08:00",
"modified_at": "2012-12-12T11:04:26-08:00",
"created_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"modified_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"owned_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"shared_link": {
"url": "https://www.box.com/s/rh935iit6ewrmw0unyul",
"download_url": "https://www.box.com/shared/static/rh935iit6ewrmw0unyul.jpeg",
"vanity_url": null,
"is_password_enabled": false,
"unshared_at": null,
"download_count": 0,
"preview_count": 0,
"access": "open",
"permissions": {
"can_download": true,
"can_preview": true
}
},
"parent": {
"type": "folder",
"id": "11446498",
"sequence_id": "1",
"etag": "1",
"name": "Pictures"
},
"item_status": "active"
};
folderResponse = {
"type": "folder",
"id": "11446498",
"sequence_id": "1",
"etag": "1",
"name": "Pictures",
"created_at": "2012-12-12T10:53:43-08:00",
"modified_at": "2012-12-12T11:15:04-08:00",
"description": "Some pictures I took",
"size": 629644,
"path_collection": {
"total_count": 1,
"entries": [
{
"type": "folder",
"id": "0",
"sequence_id": null,
"etag": null,
"name": "All Files"
}
]
},
"created_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"modified_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"owned_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"shared_link": {
"url": "https://www.box.com/s/vspke7y05sb214wjokpk",
"download_url": "https://www.box.com/shared/static/vspke7y05sb214wjokpk",
"vanity_url": null,
"is_password_enabled": false,
"unshared_at": null,
"download_count": 0,
"preview_count": 0,
"access": "open",
"permissions": {
"can_download": true,
"can_preview": true
}
},
"folder_upload_email": {
"access": "open",
"email": "upload.Picture.k13sdz1@u.box.com"
},
"parent": {
"type": "folder",
"id": "0",
"sequence_id": null,
"etag": null,
"name": "All Files"
},
"item_status": "active",
"item_collection": {
"total_count": 1,
"entries": [
{
"type": "file",
"id": "5000948880",
"sequence_id": "3",
"etag": "3",
"sha1": "134b65991ed521fcfe4724b7d814ab8ded5185dc",
"name": "tigers.jpeg"
}
],
"offset": 0,
"limit": 100
}
};
});
beforeEach(inject(function(_boxSdk_, _apiUrl_, _authUrl_, _BoxFile_, _BoxFolder_, _BoxGroup_, _BoxTask_, _BoxUser_, _BoxCollaboration_, _BoxEvent_) {
boxSdk = _boxSdk_;
apiUrl = _apiUrl_;
authUrl = _authUrl_;
BoxFile = _BoxFile_;
BoxFolder = _BoxFolder_;
BoxGroup = _BoxGroup_;
BoxTask = _BoxTask_;
BoxUser = _BoxUser_;
BoxCollaboration = _BoxCollaboration_;
BoxEvent = _BoxEvent_;
file = new BoxFile(fileResponse);
folder = new BoxFolder(folderResponse);
}));
afterEach(function() {
mocks.restore();
});
describe('logout()', function() {
it('should remove stored tokens and revoke the token', function() {
var postReturn = 'deleted';
chromeStorage.getLocal.returns(Rx.Observable.return({
token: 'refresh_token'
}));
chromeStorage.removeLocal.returns(Rx.Observable.return({}));
http.request.returns(Rx.Observable.return(postReturn));
boxSdk.logout().subscribe(observer);
expect(chromeStorage.getLocal).to.have.been.calledOnce.and.to.have.been.calledWithExactly('refresh_token');
expect(chromeStorage.removeLocal).to.have.been.calledTwice
.and.to.have.been.calledWithExactly('access_token')
.and.to.have.been.calledWithExactly('refresh_token');
expect(http.request).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
'POST',
authUrl + '/revoke',
null,
{
client_id: clientId,
client_secret: clientSecret,
token: 'refresh_token'
}
);
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(postReturn);
});
});
describe('getFolder()', function() {
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return(folderResponse));
boxSdk.getFolder(folderResponse.id).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/folders/' + folderResponse.id
);
});
it('should return a BoxFolder', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(folder);
});
});
describe('getFile()', function() {
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return(fileResponse));
boxSdk.getFile(fileResponse.id).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/files/' + fileResponse.id
);
});
it('should return a BoxFolder', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(file);
});
});
describe('getTrashedFolder()', function() {
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return(folderResponse));
boxSdk.getTrashedFolder(folderResponse.id).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/folders/' + folderResponse.id + '/trash'
);
});
it('should return a BoxFolder', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(folder);
});
});
describe('getTrashedFile()', function() {
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return(fileResponse));
boxSdk.getTrashedFile(fileResponse.id).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/files/' + fileResponse.id + '/trash'
);
});
it('should return a BoxFolder', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(file);
});
});
describe('getTrashedItems()', function() {
var fields = '';
beforeEach(function() {
boxHttp.get
.onFirstCall().returns(Rx.Observable.defer(function() {return Rx.Observable.return({
total_count: 24,
entries: (new Array(20)).fill(0).map(function(entry, i) { return i % 2 ? fileResponse : folderResponse; })
}); }))
.onSecondCall().returns(Rx.Observable.defer(function() {return Rx.Observable.return({
total_count: 24,
entries: (new Array(4)).fill(0).map(function(entry, i) { return i % 2 ? fileResponse : folderResponse; })
}); }));
boxSdk.getTrashedItems(fields).subscribe(observer);
});
it('should call http get twice', function() {
expect(boxHttp.get).to.have.been.calledTwice
.and.to.have.been.calledWithExactly(apiUrl + '/folders/trash/items', {fields: fields, limit: 20, offset: 0})
.and.to.have.been.calledWithExactly(apiUrl + '/folders/trash/items', {fields: fields, limit: 20, offset: 20});
});
it('should return BoxFolders and BoxFiles', function() {
expect(observer).to.have.been.calledWithExactly(file)
.and.to.have.been.calledWithExactly(folder)
.and.to.have.property('callCount', 24);
});
});
describe('getPendingCollaborations()', function() {
var pendingCollabResponse = {
"total_count": 1,
"entries": [
{
"type": "collaboration",
"id": "27513888",
"created_by": {
"type": "user",
"id": "11993747",
"name": "sean",
"login": "sean@box.com"
},
"created_at": "2012-10-17T23:14:42-07:00",
"modified_at": "2012-10-17T23:14:42-07:00",
"expires_at": null,
"status": "Pending",
"accessible_by": {
"type": "user",
"id": "181216415",
"name": "sean rose",
"login": "sean+awesome@box.com"
},
"role": "Editor",
"acknowledged_at": null,
"item": null
}
]
};
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return(pendingCollabResponse));
boxSdk.getPendingCollaborations().subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(apiUrl + '/collaborations?pending');
});
it('should return call the subscriber with a BoxCollaboration', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWith(new BoxCollaboration(pendingCollabResponse.entries[0]));
});
});
describe('search()', function() {
beforeEach(function() {
boxHttp.get.returns(Rx.Observable.return({
total_count: 2,
entries: [
file,
folder
]
}));
boxSdk.search('foo', {scope: 'user_content'}).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/search',
{
params: {
query: 'foo',
limit: 20,
offset: 0,
scope: 'user_content'
}
}
);
});
it('should return various box items', function() {
expect(observer).to.have.been.calledTwice
.and.to.have.been.calledWithExactly(file)
.and.to.have.been.calledWithExactly(folder);
});
});
describe('createTask()', function() {
var taskResponse, params;
beforeEach(function() {
taskResponse = {
"type": "task",
"id": "1839355",
"item": {
"type": "file",
"id": "7287087200",
"sequence_id": "0",
"etag": "0",
"sha1": "0bbd79a105c504f99573e3799756debba4c760cd",
"name": "box-logo.png"
},
"due_at": "2014-04-03T11:09:43-07:00",
"action": "review",
"message": "REVIEW PLZ K THX",
"task_assignment_collection": {
"total_count": 0,
"entries": []
},
"is_completed": false,
"created_by": {
"type": "user",
"id": "11993747",
"name": "☁ sean ☁",
"login": "sean@box.com"
},
"created_at": "2013-04-03T11:12:54-07:00"
};
taskResponse.item.id = fileResponse.id;
params = {
action: 'review'
};
boxHttp.post.returns(Rx.Observable.return(taskResponse));
boxSdk.createTask(file, params).subscribe(observer);
});
it('should call http post', function() {
expect(boxHttp.post).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/tasks',
null,
{
item: {
id: file.id,
type: file.type
},
action: 'review'
}
);
});
it('should return a BoxTask', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(new BoxTask(taskResponse));
});
});
describe('getUserInfo()', function() {
var userResponse;
beforeEach(function() {
userResponse = {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com",
"created_at": "2012-03-26T15:43:07-07:00",
"modified_at": "2012-12-12T11:34:29-08:00",
"language": "en",
"space_amount": 5368709120,
"space_used": 2377016,
"max_upload_size": 262144000,
"status": "active",
"job_title": "Employee",
"phone": "5555555555",
"address": "555 Office Drive",
"avatar_url": "https://www.box.com/api/avatar/large/17738362"
};
boxHttp.get.returns(Rx.Observable.return(userResponse));
boxSdk.getUserInfo(fileResponse.id).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
apiUrl + '/users/me'
);
});
it('should return a BoxUser', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(new BoxUser(userResponse));
});
});
describe('getUsers()', function() {
var usersResponse, filter;
beforeEach(function() {
usersResponse = {
"total_count": 1,
"entries": [
{
"type": "user",
"id": "181216415",
"name": "sean rose",
"login": "sean+awesome@box.com",
"created_at": "2012-05-03T21:39:11-07:00",
"modified_at": "2012-08-23T14:57:48-07:00",
"language": "en",
"space_amount": 5368709120,
"space_used": 52947,
"max_upload_size": 104857600,
"status": "active",
"job_title": "",
"phone": "5555551374",
"address": "10 Cloud Way Los Altos CA",
"avatar_url": "https://api.box.com/api/avatar/large/181216415"
}
]
};
filter = 'sean';
boxHttp.get.returns(Rx.Observable.return(usersResponse));
boxSdk.getUsers(filter).subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(apiUrl + '/users', {params: {filter_term: filter, limit: 20, offset: 0}});
});
it('should return a BoxGroup', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWith(new BoxUser(usersResponse.entries[0]));
});
});
describe('createUser()', function() {
var params, userResponse;
beforeEach(function() {
userResponse = {
"type": "user",
"id": "187273718",
"name": "Ned Stark",
"login": "eddard@box.com",
"created_at": "2012-11-15T16:34:28-08:00",
"modified_at": "2012-11-15T16:34:29-08:00",
"role": "user",
"language": "en",
"space_amount": 5368709120,
"space_used": 0,
"max_upload_size": 2147483648,
"tracking_codes": [],
"can_see_managed_users": true,
"is_sync_enabled": true,
"status": "active",
"job_title": "",
"phone": "555-555-5555",
"address": "555 Box Lane",
"avatar_url": "https://www.box.com/api/avatar/large/187273718",
"is_exempt_from_device_limits": false,
"is_exempt_from_login_verification": false
};
params = {
"name": "Ned Stark",
"login": "eddard@box.com"
};
boxHttp.post.returns(Rx.Observable.return(userResponse));
boxSdk.createUser(params).subscribe(observer);
});
it('should call http post', function() {
expect(boxHttp.post).to.have.been.calledOnce.and.to.have.been.calledWithExactly(apiUrl + '/users', null, params);
});
it('should return a BoxUser', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWith(new BoxUser(userResponse));
});
});
describe('getGroups()', function() {
var groupsResponse;
beforeEach(function() {
groupsResponse = {
"total_count": 1,
"entries": [
{
"type": "group",
"id": "1786931",
"name": "friends"
}
],
"limit": 100,
"offset": 0
};
boxHttp.get.returns(Rx.Observable.return(groupsResponse));
boxSdk.getGroups().subscribe(observer);
});
it('should call http get', function() {
expect(boxHttp.get).to.have.been.calledOnce.and.to.have.been.calledWithExactly(apiUrl + '/groups');
});
it('should return a BoxGroup', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWith(new BoxGroup(groupsResponse.entries[0]));
});
});
describe('createGroup()', function() {
var name, groupResponse;
beforeEach(function() {
groupResponse = {
"type": "group",
"id": "119720",
"name": "family",
"created_at": "2013-05-16T15:27:57-07:00",
"modified_at": "2013-05-16T15:27:57-07:00"
};
name = 'family';
boxHttp.post.returns(Rx.Observable.return(groupResponse));
boxSdk.createGroup(name).subscribe(observer);
});
it('should call http post', function() {
expect(boxHttp.post).to.have.been.calledOnce.and.to.have.been.calledWithExactly(apiUrl + '/groups', null, {name: name});
});
it('should return a BoxGroup', function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWith(new BoxGroup(groupResponse));
});
});
describe('subscribeToEvents()', function() {
var nextStreamPosition, eventsUrl, eventResponse;
beforeEach(function() {
nextStreamPosition = 1;
eventsUrl = 'https://realtime.box.net/event/url';
eventResponse = {
"type": "event",
"event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83",
"created_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"created_at": "2012-12-12T10:53:43-08:00",
"recorded_at": "2012-12-12T10:53:48-08:00",
"event_type": "ITEM_CREATE",
"session_id": "70090280850c8d2a1933c1",
"source": {
"type": "folder",
"id": "11446498",
"sequence_id": "0",
"etag": "0",
"name": "Pictures",
"created_at": "2012-12-12T10:53:43-08:00",
"modified_at": "2012-12-12T10:53:43-08:00",
"description": null,
"size": 0,
"created_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"modified_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"owned_by": {
"type": "user",
"id": "17738362",
"name": "sean rose",
"login": "sean@box.com"
},
"shared_link": null,
"parent": {
"type": "folder",
"id": "0",
"sequence_id": null,
"etag": null,
"name": "All Files"
},
"item_status": "active",
"synced": false
}
};
});
afterEach(function() {
$timeout = angular.noop;
});
it('should get streamPosition now if streamPosition is not passed to subscribe', function() {
boxHttp.get.withArgs(apiUrl + '/events?stream_position=now').returns(Rx.Observable.return({
'next_stream_position': nextStreamPosition
}));
boxHttp.options.withArgs(apiUrl + '/events').returns(Rx.Observable.return({'entries': [
{url: eventsUrl}
]}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + nextStreamPosition).returns(Rx.Observable.empty());
boxSdk.subscribeToEvents().subscribe(observer);
expect(boxHttp.get).to.have.been.called
.and.to.have.been.calledWithExactly(apiUrl + '/events?stream_position=now')
.and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + nextStreamPosition);
expect(boxHttp.options).to.have.been.called.and.to.have.been.calledWithExactly(apiUrl + '/events');
});
it('should use the passed streamPosition if passed', function() {
boxHttp.options.withArgs(apiUrl + '/events').returns(Rx.Observable.return({'entries': [
{url: eventsUrl}
]}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + nextStreamPosition).returns(Rx.Observable.empty());
boxSdk.subscribeToEvents(nextStreamPosition).subscribe(observer);
expect(boxHttp.get).to.have.been.called
.and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + nextStreamPosition);
expect(boxHttp.options).to.have.been.called.and.to.have.been.calledWithExactly(apiUrl + '/events');
});
it('should reconnect when receiving the reconnect message', function(done) {
boxHttp.options.withArgs(apiUrl + '/events').returns(Rx.Observable.return({'entries': [
{url: eventsUrl, retry_timeout: 1}
]}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + nextStreamPosition)
.onFirstCall().returns(Rx.Observable.return({message: 'reconnect'}))
.onSecondCall().returns(Rx.Observable.empty());
var timeoutCalls = 0;
$timeout = function(func) {
timeoutCalls++;
if (timeoutCalls < 2) {
func();
} else {
expect(boxHttp.get).to.have.been.calledTwice.
and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + nextStreamPosition);
expect(boxHttp.options).to.have.been.called.and.to.have.been.calledWithExactly(apiUrl + '/events');
done();
}
};
boxSdk.subscribeToEvents(nextStreamPosition).subscribe(observer);
});
it('should reconnect after waiting for the timeout', function(done) {
boxHttp.options.withArgs(apiUrl + '/events').returns(Rx.Observable.return({'entries': [
{url: eventsUrl, retry_timeout: 0.001}
]}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + nextStreamPosition)
.returns(Rx.Observable.never());
var timeoutCalls = 0;
$timeout = function(func) {
timeoutCalls++;
if (timeoutCalls < 2) {
func();
} else {
expect(boxHttp.get).to.have.been.calledTwice.
and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + nextStreamPosition);
expect(boxHttp.options).to.have.been.called.and.to.have.been.calledWithExactly(apiUrl + '/events');
done();
}
};
boxSdk.subscribeToEvents(nextStreamPosition).subscribe(observer);
});
it('should reconnect after exhausting event stream', function(done) {
var secondStreamPosition = 2;
boxHttp.options.withArgs(apiUrl + '/events').returns(Rx.Observable.return({'entries': [
{url: eventsUrl, retry_timeout: 1}
]}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + nextStreamPosition)
.returns(Rx.Observable.return({message: 'new_change'}));
boxHttp.get.withArgs(eventsUrl + '&stream_position=' + secondStreamPosition)
.returns(Rx.Observable.empty());
boxHttp.get.withArgs(apiUrl + '/events?stream_position=' + nextStreamPosition)
.returns(Rx.Observable.return({
next_stream_position: secondStreamPosition,
chunk_size: 1,
entries: [eventResponse]
}));
boxHttp.get.withArgs(apiUrl + '/events?stream_position=' + secondStreamPosition)
.returns(Rx.Observable.return({
next_stream_position: secondStreamPosition,
chunk_size: 0,
entries: []
}));
var timeoutCalls = 0;
var doneCalls = 0;
function perhapsDone() {
doneCalls++;
if(doneCalls >= 2) {
done();
}
}
$timeout = function(func) {
timeoutCalls++;
if (timeoutCalls < 2) {
func();
} else {
expect(boxHttp.get).to.have.been.called
.and.to.have.been.calledWithExactly(apiUrl + '/events?stream_position=' + nextStreamPosition)
.and.to.have.been.calledWithExactly(apiUrl + '/events?stream_position=' + secondStreamPosition)
.and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + nextStreamPosition)
.and.to.have.been.calledWithExactly(eventsUrl + '&stream_position=' + secondStreamPosition);
expect(boxHttp.options).to.have.been.called.and.to.have.been.calledWithExactly(apiUrl + '/events');
perhapsDone();
}
};
boxSdk.subscribeToEvents(nextStreamPosition).do(observer).subscribe(function() {
expect(observer).to.have.been.calledOnce.and.to.have.been.calledWithExactly(new BoxEvent(eventResponse, secondStreamPosition));
perhapsDone();
});
});
});
});