Skip to content

Commit 099e6f5

Browse files
add: batch tests, fix issues
1 parent ec7f65e commit 099e6f5

File tree

3 files changed

+281
-48
lines changed

3 files changed

+281
-48
lines changed

lib/requests/helpers/parseResponse.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,15 @@ function parseBatchResponse(response, parseParams, requestNumber) {
134134
var batchToProcess = batchResponse
135135
.substring(batchResponse.indexOf('\r\n') + 1).trim();
136136

137-
result = result.concat(parseBatchResponse(batchToProcess, requestNumber));
137+
result = result.concat(parseBatchResponse(batchToProcess, parseParams, requestNumber));
138138
}
139139
else {
140140
var responseData = batchResponse.substring(batchResponse.indexOf("{"), batchResponse.lastIndexOf("}") + 1);
141141

142142
if (!responseData) {
143-
var entityUrl = /OData-EntityId.+/i.exec(responseData);
143+
var entityUrl = /OData-EntityId.+/i.exec(batchResponse);
144144

145-
if (entityUrl.length) {
145+
if (entityUrl && entityUrl.length) {
146146
result.push(/([0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12})\)$/i.exec(entityUrl[0])[1]);
147147
}
148148
else if (parseParams[i].hasOwnProperty('valueIfEmpty')) {

tests/main-tests.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4478,6 +4478,122 @@ describe("promises -", function () {
44784478
});
44794479
});
44804480

4481+
describe("dynamicsWebApi.executeBatch -", function () {
4482+
describe("retrieve multiple / create / retrieve multiple", function () {
4483+
var scope;
4484+
var rBody = mocks.data.batchRetrieveMultipleCreateRetrieveMultiple;
4485+
var rBodys = rBody.split('\n');
4486+
var checkBody = '';
4487+
for (var i = 0; i < rBodys.length; i++) {
4488+
checkBody += rBodys[i];
4489+
}
4490+
before(function () {
4491+
var response = mocks.responses.batchRetrieveMultipleCreateRetrieveMultiple;
4492+
scope = nock(mocks.webApiUrl + '$batch')
4493+
.filteringRequestBody(function (body) {
4494+
body = body.replace(/dwa_batch_[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}/g, 'dwa_batch_XXX');
4495+
body = body.replace(/changeset_[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}/g, 'changeset_XXX');
4496+
var bodys = body.split('\n');
4497+
4498+
var resultBody = '';
4499+
for (var i = 0; i < bodys.length; i++) {
4500+
resultBody += bodys[i];
4501+
}
4502+
return resultBody;
4503+
})
4504+
.post("", checkBody)
4505+
.reply(response.status, response.responseText, response.responseHeaders);
4506+
});
4507+
4508+
after(function () {
4509+
nock.cleanAll();
4510+
});
4511+
4512+
it("returns a correct response", function (done) {
4513+
dynamicsWebApiTest.startBatch();
4514+
4515+
dynamicsWebApiTest.retrieveMultiple('tests');
4516+
dynamicsWebApiTest.create({ firstname: "Test", lastname: "Batch!" }, 'records');
4517+
dynamicsWebApiTest.retrieveMultiple('morerecords');
4518+
4519+
dynamicsWebApiTest.executeBatch()
4520+
.then(function (object) {
4521+
expect(object.length).to.be.eq(3);
4522+
4523+
expect(object[0]).to.deep.equal(mocks.responses.multiple());
4524+
expect(object[1]).to.deep.equal(mocks.data.testEntityId);
4525+
expect(object[2]).to.deep.equal(mocks.responses.multiple2());
4526+
4527+
done();
4528+
}).catch(function (object) {
4529+
expect(object).to.be.undefined;
4530+
done();
4531+
});
4532+
});
4533+
4534+
it("all requests have been made", function () {
4535+
expect(scope.isDone()).to.be.true;
4536+
});
4537+
});
4538+
4539+
describe("retrieve multiple / update / retrieve multiple", function () {
4540+
var scope;
4541+
var rBody = mocks.data.batchRetrieveMultipleCreateRetrieveMultiple;
4542+
var rBodys = rBody.split('\n');
4543+
var checkBody = '';
4544+
for (var i = 0; i < rBodys.length; i++) {
4545+
checkBody += rBodys[i];
4546+
}
4547+
before(function () {
4548+
var response = mocks.responses.batchRetrieveMultipleCreateRetrieveMultiple;
4549+
scope = nock(mocks.webApiUrl + '$batch')
4550+
.filteringRequestBody(function (body) {
4551+
body = body.replace(/dwa_batch_[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}/g, 'dwa_batch_XXX');
4552+
body = body.replace(/changeset_[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}/g, 'changeset_XXX');
4553+
var bodys = body.split('\n');
4554+
4555+
var resultBody = '';
4556+
for (var i = 0; i < bodys.length; i++) {
4557+
resultBody += bodys[i];
4558+
}
4559+
return resultBody;
4560+
})
4561+
.post("", checkBody)
4562+
.reply(response.status, response.responseText, response.responseHeaders);
4563+
});
4564+
4565+
after(function () {
4566+
nock.cleanAll();
4567+
});
4568+
4569+
it("returns a correct response", function (done) {
4570+
dynamicsWebApiTest.startBatch();
4571+
4572+
dynamicsWebApiTest.retrieveMultiple('tests');
4573+
dynamicsWebApiTest.update({ firstname: "Test", lastname: "Batch!" }, 'records');
4574+
dynamicsWebApiTest.retrieveMultiple('morerecords');
4575+
4576+
dynamicsWebApiTest.executeBatch()
4577+
.then(function (object) {
4578+
expect(object.length).to.be.eq(3);
4579+
4580+
expect(object[0]).to.deep.equal(mocks.responses.multiple());
4581+
expect(object[1]).to.deep.equal(true);
4582+
expect(object[2]).to.deep.equal(mocks.responses.multiple2());
4583+
4584+
done();
4585+
}).catch(function (object) {
4586+
expect(object).to.be.undefined;
4587+
done();
4588+
});
4589+
});
4590+
4591+
it("all requests have been made", function () {
4592+
expect(scope.isDone()).to.be.true;
4593+
});
4594+
});
4595+
});
4596+
44814597
describe("dynamicsWebApi.constructor -", function () {
44824598

44834599
describe("webApiVersion", function () {

tests/stubs.js

Lines changed: 162 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ var dataStubs = {
102102
{ name: "name2", subject: "subject2" }
103103
]
104104
},
105+
multiple2: {
106+
"@odata.context": "context",
107+
value: [
108+
{ name: "name3", subject: "subject3" },
109+
{ name: "name4", subject: "subject4" }
110+
]
111+
},
105112
multipleFormatted: {
106113
"@odata.context": "context",
107114
value: [
@@ -126,47 +133,77 @@ var dataStubs = {
126133
]
127134
},
128135
batch:
129-
'--dwa_batch_XXX\n' +
130-
'Content-Type: application/http\n' +
131-
'Content-Transfer-Encoding: binary\n\n' +
132-
'GET {0} HTTP/1.1\n' +
133-
'Accept: application/json\n' +
134-
'OData-MaxVersion: 4.0\n' +
135-
'OData-Version: 4.0\n' +
136-
'Content-Type: application/json; charset=utf-8\n\n' +
137-
'--dwa_batch_XXX--',
138-
136+
'--dwa_batch_XXX\n' +
137+
'Content-Type: application/http\n' +
138+
'Content-Transfer-Encoding: binary\n\n' +
139+
'GET {0} HTTP/1.1\n' +
140+
'Accept: application/json\n' +
141+
'OData-MaxVersion: 4.0\n' +
142+
'OData-Version: 4.0\n' +
143+
'Content-Type: application/json; charset=utf-8\n\n' +
144+
'--dwa_batch_XXX--',
145+
batchRetrieveMultipleCreateRetrieveMultiple:
146+
'--dwa_batch_XXX\n' +
147+
'Content-Type: application/http\n' +
148+
'Content-Transfer-Encoding: binary\n' +
149+
'\n' +
150+
'GET ' + webApiUrl + 'tests HTTP/1.1\n' +
151+
'Accept: application/json\n' +
152+
'\n' +
153+
'--dwa_batch_XXX\n' +
154+
'Content-Type: multipart/mixed;boundary=changeset_XXX\n' +
155+
'\n' +
156+
'--changeset_XXX\n' +
157+
'Content-Type: application/http\n' +
158+
'Content-Transfer-Encoding: binary\n' +
159+
'Content-ID: 1\n' +
160+
'\n' +
161+
'POST ' + webApiUrl + 'records HTTP/1.1\n' +
162+
'Content-Type: application/json\n' +
163+
'\n' +
164+
'{"firstname":"Test","lastname":"Batch!"}\n' +
165+
'\n' +
166+
'--changeset_XXX--\n' +
167+
'\n' +
168+
'--dwa_batch_XXX\n' +
169+
'Content-Type: application/http\n' +
170+
'Content-Transfer-Encoding: binary\n' +
171+
'\n' +
172+
'GET ' + webApiUrl + 'morerecords HTTP/1.1\n' +
173+
'Accept: application/json\n' +
174+
'\n' +
175+
'--dwa_batch_XXX--',
139176
fetchXmls: {
140177
cookiePage1: "%253Ccookie%2520pagenumber%253D%25222%2522%2520pagingcookie%253D%2522%253Ccookie%2520page%253D%25221%2522%253E%253Caccountid%2520last%253D%2522%257BEF72AE29-B3DE-E611-8102-5065F38A7BF1%257D%2522%2520first%253D%2522%257B475B158C-541C-E511-80D3-3863BB347BA8%257D%2522%2520/%253E%253C/cookie%253E%2522%2520istracking%253D%2522False%2522%2520/%253E",
141178
cookiePage2: "%253Ccookie%2520pagenumber%253D%25222%2522%2520pagingcookie%253D%2522%253Ccookie%2520page%253D%25222%2522%253E%253Caccountid%2520last%253D%2522%257BF972AE29-B3DE-E611-8102-5065F38A7BF1%257D%2522%2520first%253D%2522%257BF172AE29-B3DE-E611-8102-5065F38A7BF1%257D%2522%2520/%253E%253C/cookie%253E%2522%2520istracking%253D%2522False%2522%2520/%253E",
142179
fetchXml:
143-
'<fetch mapping="logical" count="5">' +
144-
'<entity name="account">' +
145-
'<attribute name="accountid"/>' +
146-
'<attribute name="name"/>' +
147-
'</entity>' +
148-
'</fetch>',
180+
'<fetch mapping="logical" count="5">' +
181+
'<entity name="account">' +
182+
'<attribute name="accountid"/>' +
183+
'<attribute name="name"/>' +
184+
'</entity>' +
185+
'</fetch>',
149186
fetchXml1:
150-
'<fetch page="1" mapping="logical" count="5">' +
151-
'<entity name="account">' +
152-
'<attribute name="accountid"/>' +
153-
'<attribute name="name"/>' +
154-
'</entity>' +
155-
'</fetch>',
187+
'<fetch page="1" mapping="logical" count="5">' +
188+
'<entity name="account">' +
189+
'<attribute name="accountid"/>' +
190+
'<attribute name="name"/>' +
191+
'</entity>' +
192+
'</fetch>',
156193
fetchXml2cookie:
157-
'<fetch page="2" paging-cookie="&lt;cookie page=&quot;1&quot;&gt;&lt;accountid last=&quot;{EF72AE29-B3DE-E611-8102-5065F38A7BF1}&quot; first=&quot;{475B158C-541C-E511-80D3-3863BB347BA8}&quot; /&gt;&lt;/cookie&gt;" mapping="logical" count="5">' +
158-
'<entity name="account">' +
159-
'<attribute name="accountid"/>' +
160-
'<attribute name="name"/>' +
161-
'</entity>' +
162-
'</fetch>',
194+
'<fetch page="2" paging-cookie="&lt;cookie page=&quot;1&quot;&gt;&lt;accountid last=&quot;{EF72AE29-B3DE-E611-8102-5065F38A7BF1}&quot; first=&quot;{475B158C-541C-E511-80D3-3863BB347BA8}&quot; /&gt;&lt;/cookie&gt;" mapping="logical" count="5">' +
195+
'<entity name="account">' +
196+
'<attribute name="accountid"/>' +
197+
'<attribute name="name"/>' +
198+
'</entity>' +
199+
'</fetch>',
163200
fetchXml2:
164-
'<fetch page="2" mapping="logical" count="5">' +
165-
'<entity name="account">' +
166-
'<attribute name="accountid"/>' +
167-
'<attribute name="name"/>' +
168-
'</entity>' +
169-
'</fetch>',
201+
'<fetch page="2" mapping="logical" count="5">' +
202+
'<entity name="account">' +
203+
'<attribute name="accountid"/>' +
204+
'<attribute name="name"/>' +
205+
'</entity>' +
206+
'</fetch>',
170207
fetchXmlResponsePage1Cookie: {
171208
"@odata.context": "context",
172209
"@Microsoft.Dynamics.CRM.fetchxmlpagingcookie": "%253Ccookie%2520pagenumber%253D%25222%2522%2520pagingcookie%253D%2522%253Ccookie%2520page%253D%25221%2522%253E%253Caccountid%2520last%253D%2522%257BEF72AE29-B3DE-E611-8102-5065F38A7BF1%257D%2522%2520first%253D%2522%257B475B158C-541C-E511-80D3-3863BB347BA8%257D%2522%2520/%253E%253C/cookie%253E%2522%2520istracking%253D%2522False%2522%2520/%253E",
@@ -322,17 +359,93 @@ var responseStubs = {
322359
batch: {
323360
status: 200,
324361
responseText:
325-
'--batchresponse_904020fa-6213-43d4-a26a-5347b70095e8\r\n' +
326-
'Content-Type: application/http\r\n' +
327-
'Content-Transfer-Encoding: binary\r\n\r\n' +
362+
'--batchresponse_904020fa-6213-43d4-a26a-5347b70095e8\r\n' +
363+
'Content-Type: application/http\r\n' +
364+
'Content-Transfer-Encoding: binary\r\n\r\n' +
365+
366+
'HTTP/ 1.1 200 OK\r\n' +
367+
'Access-Control-Expose-Headers: Preference-Applied, OData-EntityId, Location, ETag, OData-Version, Content-Encoding, Transfer-Encoding, Content-Length, Retry-After\r\n' +
368+
'Content-Type: application/json; odata.metadata=minimal\r\n' +
369+
'OData-Version: 4.0\r\n\r\n' +
370+
371+
JSON.stringify(dataStubs.multiple) + '\r\n' +
372+
'--batchresponse_904020fa-6213-43d4-a26a-5347b70095e8--'
373+
},
374+
batchRetrieveMultipleCreateRetrieveMultiple: {
375+
status: 200,
376+
responseText:
377+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
378+
'Content-Type: application/http\r\n' +
379+
'Content-Transfer-Encoding: binary\r\n' +
380+
381+
'HTTP/1.1 200 OK\r\n' +
382+
'Content-Type: application/json; odata.metadata=minimal\r\n' +
383+
'OData-Version: 4.0\r\n' +
384+
385+
JSON.stringify(dataStubs.multiple) + '\r\n' +
386+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
387+
'Content-Type: multipart/mixed; boundary=changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd\r\n' +
388+
'\r\n' +
389+
'--changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd\r\n' +
390+
'Content-Type: application/http\r\n' +
391+
'Content-Transfer-Encoding: binary\r\n' +
392+
'Content-ID: 1' +
393+
394+
'HTTP/1.1 204 No Content\r\n' +
395+
'OData-Version: 4.0\r\n' +
396+
'Location: https://url.com/api/data/v8.2/tests(' + dataStubs.testEntityId + ')\r\n' +
397+
'OData-EntityId: https://url.com/api/data/v8.2/tests(' + dataStubs.testEntityId + ')\r\n' +
398+
'\r\n' +
399+
'\r\n' +
400+
'--changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd--\r\n' +
401+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
402+
'Content-Type: application/http\r\n' +
403+
'Content-Transfer-Encoding: binary\r\n' +
404+
405+
'HTTP/1.1 200 OK\r\n' +
406+
'Content-Type: application/json; odata.metadata=minimal\r\n' +
407+
'OData-Version: 4.0\r\n' +
408+
409+
JSON.stringify(dataStubs.multiple2) + '\r\n' +
410+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae--'
411+
},
412+
batchRetrieveMultipleUpdateRetrieveMultiple: {
413+
status: 200,
414+
responseText:
415+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
416+
'Content-Type: application/http\r\n' +
417+
'Content-Transfer-Encoding: binary\r\n' +
418+
419+
'HTTP/1.1 200 OK\r\n' +
420+
'Content-Type: application/json; odata.metadata=minimal\r\n' +
421+
'OData-Version: 4.0\r\n' +
422+
423+
JSON.stringify(dataStubs.multiple) + '\r\n' +
424+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
425+
'Content-Type: multipart/mixed; boundary=changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd\r\n' +
426+
'\r\n' +
427+
'--changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd\r\n' +
428+
'Content-Type: application/http\r\n' +
429+
'Content-Transfer-Encoding: binary\r\n' +
430+
'Content-ID: 1' +
328431

329-
'HTTP/ 1.1 200 OK\r\n' +
330-
'Access-Control-Expose-Headers: Preference-Applied, OData-EntityId, Location, ETag, OData-Version, Content-Encoding, Transfer-Encoding, Content-Length, Retry-After\r\n' +
331-
'Content-Type: application/json; odata.metadata=minimal\r\n' +
332-
'OData-Version: 4.0\r\n\r\n' +
432+
'HTTP/1.1 204 No Content\r\n' +
433+
'OData-Version: 4.0\r\n' +
434+
'Location: https://url.com/api/data/v8.2/tests(' + dataStubs.testEntityId + ')\r\n' +
435+
'OData-EntityId: https://url.com/api/data/v8.2/tests(' + dataStubs.testEntityId + ')\r\n' +
436+
'\r\n' +
437+
'\r\n' +
438+
'--changesetresponse_08f5ebfd-5cee-4b64-bc51-ee16c02d47bd--\r\n' +
439+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae\r\n' +
440+
'Content-Type: application/http\r\n' +
441+
'Content-Transfer-Encoding: binary\r\n' +
333442

334-
JSON.stringify(dataStubs.multiple) + '\r\n' +
335-
'--batchresponse_904020fa-6213-43d4-a26a-5347b70095e8--'
443+
'HTTP/1.1 200 OK\r\n' +
444+
'Content-Type: application/json; odata.metadata=minimal\r\n' +
445+
'OData-Version: 4.0\r\n' +
446+
447+
JSON.stringify(dataStubs.multiple2) + '\r\n' +
448+
'--batchresponse_8b19b76e-c553-4c4c-af9d-b5521bfda1ae--'
336449
},
337450
fetchXmlResponsePage1Cookie: {
338451
status: 200,
@@ -394,7 +507,7 @@ var responseStubs = {
394507
value1: stub["alias_x002e_value1"],
395508
value1_Formatted: stub["[email protected]"],
396509
397-
}
510+
};
398511
return stub;
399512
},
400513
multipleWithLink: function () {
@@ -407,7 +520,11 @@ var responseStubs = {
407520
var stub = dataStubs.multiple;
408521
stub.oDataContext = stub["@odata.context"];
409522
return stub;
410-
523+
},
524+
multiple2: function () {
525+
var stub = dataStubs.multiple2;
526+
stub.oDataContext = stub["@odata.context"];
527+
return stub;
411528
},
412529
multipleFormatted: function () {
413530
var stub = dataStubs.multipleFormatted;

0 commit comments

Comments
 (0)