You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

oc-backbone-webdavSpec.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /**
  2. * ownCloud
  3. *
  4. * @author Vincent Petry
  5. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. /* global dav */
  22. describe('Backbone Webdav extension', function() {
  23. var davClientRequestStub;
  24. var davClientPropPatchStub;
  25. var davClientPropFindStub;
  26. var deferredRequest;
  27. beforeEach(function() {
  28. deferredRequest = $.Deferred();
  29. davClientRequestStub = sinon.stub(dav.Client.prototype, 'request');
  30. davClientPropPatchStub = sinon.stub(dav.Client.prototype, 'propPatch');
  31. davClientPropFindStub = sinon.stub(dav.Client.prototype, 'propFind');
  32. davClientRequestStub.returns(deferredRequest.promise());
  33. davClientPropPatchStub.returns(deferredRequest.promise());
  34. davClientPropFindStub.returns(deferredRequest.promise());
  35. });
  36. afterEach(function() {
  37. davClientRequestStub.restore();
  38. davClientPropPatchStub.restore();
  39. davClientPropFindStub.restore();
  40. });
  41. describe('collections', function() {
  42. var TestModel;
  43. var TestCollection;
  44. beforeEach(function() {
  45. TestModel = OC.Backbone.Model.extend({
  46. sync: OC.Backbone.davSync,
  47. davProperties: {
  48. 'firstName': '{http://owncloud.org/ns}first-name',
  49. 'lastName': '{http://owncloud.org/ns}last-name',
  50. 'age': '{http://owncloud.org/ns}age',
  51. 'married': '{http://owncloud.org/ns}married'
  52. },
  53. parse: function(data) {
  54. return {
  55. id: data.id,
  56. firstName: data.firstName,
  57. lastName: data.lastName,
  58. age: parseInt(data.age, 10),
  59. married: data.married === 'true' || data.married === true
  60. };
  61. }
  62. });
  63. TestCollection = OC.Backbone.Collection.extend({
  64. sync: OC.Backbone.davSync,
  65. model: TestModel,
  66. url: 'http://example.com/owncloud/remote.php/test/'
  67. });
  68. });
  69. it('makes a POST request to create model into collection', function(done) {
  70. var collection = new TestCollection();
  71. var model = collection.create({
  72. firstName: 'Hello',
  73. lastName: 'World'
  74. });
  75. expect(davClientRequestStub.calledOnce).toEqual(true);
  76. expect(davClientRequestStub.getCall(0).args[0])
  77. .toEqual('POST');
  78. expect(davClientRequestStub.getCall(0).args[1])
  79. .toEqual('http://example.com/owncloud/remote.php/test/');
  80. expect(davClientRequestStub.getCall(0).args[2]['Content-Type'])
  81. .toEqual('application/json');
  82. expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
  83. .toEqual('XMLHttpRequest');
  84. expect(davClientRequestStub.getCall(0).args[3])
  85. .toEqual(JSON.stringify({
  86. 'firstName': 'Hello',
  87. 'lastName': 'World'
  88. }));
  89. var responseHeaderStub = sinon.stub()
  90. .withArgs('Content-Location')
  91. .returns('http://example.com/owncloud/remote.php/test/123');
  92. deferredRequest.resolve({
  93. status: 201,
  94. body: '',
  95. xhr: {
  96. getResponseHeader: responseHeaderStub
  97. }
  98. });
  99. setTimeout(function() {
  100. expect(model.id).toEqual('123');
  101. done();
  102. }, 0)
  103. });
  104. it('uses PROPFIND to retrieve collection', function(done) {
  105. var successStub = sinon.stub();
  106. var errorStub = sinon.stub();
  107. var collection = new TestCollection();
  108. collection.fetch({
  109. success: successStub,
  110. error: errorStub
  111. });
  112. expect(davClientPropFindStub.calledOnce).toEqual(true);
  113. expect(davClientPropFindStub.getCall(0).args[0])
  114. .toEqual('http://example.com/owncloud/remote.php/test/');
  115. expect(davClientPropFindStub.getCall(0).args[1])
  116. .toEqual([
  117. '{http://owncloud.org/ns}first-name',
  118. '{http://owncloud.org/ns}last-name',
  119. '{http://owncloud.org/ns}age',
  120. '{http://owncloud.org/ns}married'
  121. ]);
  122. expect(davClientPropFindStub.getCall(0).args[2])
  123. .toEqual(1);
  124. expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
  125. .toEqual('XMLHttpRequest');
  126. deferredRequest.resolve({
  127. status: 207,
  128. body: [
  129. // root element
  130. {
  131. href: 'http://example.org/owncloud/remote.php/test/',
  132. propStat: []
  133. },
  134. // first model
  135. {
  136. href: 'http://example.org/owncloud/remote.php/test/123',
  137. propStat: [{
  138. status: 'HTTP/1.1 200 OK',
  139. properties: {
  140. '{http://owncloud.org/ns}first-name': 'Hello',
  141. '{http://owncloud.org/ns}last-name': 'World'
  142. }
  143. }]
  144. },
  145. // second model
  146. {
  147. href: 'http://example.org/owncloud/remote.php/test/456',
  148. propStat: [{
  149. status: 'HTTP/1.1 200 OK',
  150. properties: {
  151. '{http://owncloud.org/ns}first-name': 'Test',
  152. '{http://owncloud.org/ns}last-name': 'Person'
  153. }
  154. }]
  155. }
  156. ]
  157. });
  158. setTimeout(function() {
  159. expect(collection.length).toEqual(2);
  160. var model = collection.get('123');
  161. expect(model.id).toEqual('123');
  162. expect(model.get('firstName')).toEqual('Hello');
  163. expect(model.get('lastName')).toEqual('World');
  164. model = collection.get('456');
  165. expect(model.id).toEqual('456');
  166. expect(model.get('firstName')).toEqual('Test');
  167. expect(model.get('lastName')).toEqual('Person');
  168. expect(successStub.calledOnce).toEqual(true);
  169. expect(errorStub.notCalled).toEqual(true);
  170. done();
  171. }, 0)
  172. });
  173. function testMethodError(doCall, done) {
  174. var successStub = sinon.stub();
  175. var errorStub = sinon.stub();
  176. doCall(successStub, errorStub);
  177. deferredRequest.resolve({
  178. status: 404,
  179. body: ''
  180. });
  181. setTimeout(function() {
  182. expect(successStub.notCalled).toEqual(true);
  183. expect(errorStub.calledOnce).toEqual(true);
  184. done();
  185. }, 0)
  186. }
  187. it('calls error handler if error status in PROPFIND response', function(done) {
  188. testMethodError(function(success, error) {
  189. var collection = new TestCollection();
  190. collection.fetch({
  191. success: success,
  192. error: error
  193. });
  194. }, done);
  195. });
  196. it('calls error handler if error status in POST response', function(done) {
  197. testMethodError(function(success, error) {
  198. var collection = new TestCollection();
  199. collection.create({
  200. firstName: 'Hello',
  201. lastName: 'World'
  202. }, {
  203. success: success,
  204. error: error
  205. });
  206. }, done);
  207. });
  208. });
  209. describe('models', function() {
  210. var TestModel;
  211. beforeEach(function() {
  212. TestModel = OC.Backbone.Model.extend({
  213. sync: OC.Backbone.davSync,
  214. davProperties: {
  215. 'firstName': '{http://owncloud.org/ns}first-name',
  216. 'lastName': '{http://owncloud.org/ns}last-name',
  217. 'age': '{http://owncloud.org/ns}age', // int
  218. 'married': '{http://owncloud.org/ns}married', // bool
  219. },
  220. url: function() {
  221. return 'http://example.com/owncloud/remote.php/test/' + this.id;
  222. },
  223. parse: function(data) {
  224. return {
  225. id: data.id,
  226. firstName: data.firstName,
  227. lastName: data.lastName,
  228. age: parseInt(data.age, 10),
  229. married: data.married === 'true' || data.married === true
  230. };
  231. }
  232. });
  233. });
  234. it('makes a PROPPATCH request to update model', function() {
  235. var model = new TestModel({
  236. id: '123',
  237. firstName: 'Hello',
  238. lastName: 'World',
  239. age: 32,
  240. married: false
  241. });
  242. model.save({
  243. firstName: 'Hey',
  244. age: 33,
  245. married: true
  246. });
  247. expect(davClientPropPatchStub.calledOnce).toEqual(true);
  248. expect(davClientPropPatchStub.getCall(0).args[0])
  249. .toEqual('http://example.com/owncloud/remote.php/test/123');
  250. expect(davClientPropPatchStub.getCall(0).args[1])
  251. .toEqual({
  252. '{http://owncloud.org/ns}first-name': 'Hey',
  253. '{http://owncloud.org/ns}age': '33',
  254. '{http://owncloud.org/ns}married': 'true'
  255. });
  256. expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With'])
  257. .toEqual('XMLHttpRequest');
  258. deferredRequest.resolve({
  259. status: 201,
  260. body: ''
  261. });
  262. expect(model.id).toEqual('123');
  263. expect(model.get('firstName')).toEqual('Hey');
  264. expect(model.get('age')).toEqual(33);
  265. expect(model.get('married')).toEqual(true);
  266. });
  267. it('uses PROPFIND to fetch single model', function(done) {
  268. var model = new TestModel({
  269. id: '123'
  270. });
  271. model.fetch();
  272. expect(davClientPropFindStub.calledOnce).toEqual(true);
  273. expect(davClientPropFindStub.getCall(0).args[0])
  274. .toEqual('http://example.com/owncloud/remote.php/test/123');
  275. expect(davClientPropFindStub.getCall(0).args[1])
  276. .toEqual([
  277. '{http://owncloud.org/ns}first-name',
  278. '{http://owncloud.org/ns}last-name',
  279. '{http://owncloud.org/ns}age',
  280. '{http://owncloud.org/ns}married'
  281. ]);
  282. expect(davClientPropFindStub.getCall(0).args[2])
  283. .toEqual(0);
  284. expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
  285. .toEqual('XMLHttpRequest');
  286. deferredRequest.resolve({
  287. status: 207,
  288. body: {
  289. href: 'http://example.org/owncloud/remote.php/test/123',
  290. propStat: [{
  291. status: 'HTTP/1.1 200 OK',
  292. properties: {
  293. '{http://owncloud.org/ns}first-name': 'Hello',
  294. '{http://owncloud.org/ns}last-name': 'World',
  295. '{http://owncloud.org/ns}age': '35',
  296. '{http://owncloud.org/ns}married': 'true'
  297. }
  298. }]
  299. }
  300. });
  301. setTimeout(function() {
  302. expect(model.id).toEqual('123');
  303. expect(model.get('firstName')).toEqual('Hello');
  304. expect(model.get('lastName')).toEqual('World');
  305. expect(model.get('age')).toEqual(35);
  306. expect(model.get('married')).toEqual(true);
  307. done();
  308. });
  309. });
  310. it('makes a DELETE request to destroy model', function() {
  311. var model = new TestModel({
  312. id: '123',
  313. firstName: 'Hello',
  314. lastName: 'World'
  315. });
  316. model.destroy();
  317. expect(davClientRequestStub.calledOnce).toEqual(true);
  318. expect(davClientRequestStub.getCall(0).args[0])
  319. .toEqual('DELETE');
  320. expect(davClientRequestStub.getCall(0).args[1])
  321. .toEqual('http://example.com/owncloud/remote.php/test/123');
  322. expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
  323. .toEqual('XMLHttpRequest');
  324. expect(davClientRequestStub.getCall(0).args[3])
  325. .toBeFalsy();
  326. deferredRequest.resolve({
  327. status: 200,
  328. body: ''
  329. });
  330. });
  331. function testMethodError(doCall, done) {
  332. var successStub = sinon.stub();
  333. var errorStub = sinon.stub();
  334. doCall(successStub, errorStub);
  335. deferredRequest.resolve({
  336. status: 404,
  337. body: ''
  338. });
  339. setTimeout(function() {
  340. expect(successStub.notCalled).toEqual(true);
  341. expect(errorStub.calledOnce).toEqual(true);
  342. done();
  343. });
  344. }
  345. it('calls error handler if error status in PROPFIND response', function(done) {
  346. testMethodError(function(success, error) {
  347. var model = new TestModel();
  348. model.fetch({
  349. success: success,
  350. error: error
  351. });
  352. }, done);
  353. });
  354. it('calls error handler if error status in PROPPATCH response', function(done) {
  355. testMethodError(function(success, error) {
  356. var model = new TestModel();
  357. model.save({
  358. firstName: 'Hey'
  359. }, {
  360. success: success,
  361. error: error
  362. });
  363. }, done);
  364. });
  365. });
  366. });