oc-backbone-webdavSpec.js 11 KB

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