Skip to content

Commit 836f3cd

Browse files
refactoring; investigating #175, adding more tests
1 parent 570a765 commit 836f3cd

File tree

2 files changed

+150
-62
lines changed

2 files changed

+150
-62
lines changed

src/client/RequestClient.ts

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,64 @@ const _runRequest = async (request: Core.InternalRequest, config: InternalConfig
3838
let _batchRequestCollection: Core.BatchRequestCollection = {};
3939
let _responseParseParams: { [key: string]: any[] } = {};
4040

41+
const _nameExceptions = [
42+
"$metadata",
43+
"EntityDefinitions",
44+
"RelationshipDefinitions",
45+
"GlobalOptionSetDefinitions",
46+
"ManagedPropertyDefinitions",
47+
"query",
48+
"suggest",
49+
"autocomplete",
50+
];
51+
52+
const _isEntityNameException = (entityName: string): boolean => {
53+
return _nameExceptions.indexOf(entityName) > -1;
54+
};
55+
56+
const _getCollectionNames = async (entityName: string, config: InternalConfig): Promise<string | null | undefined> => {
57+
if (!Utility.isNull(RequestUtility.entityNames)) {
58+
return RequestUtility.findCollectionName(entityName) || entityName;
59+
}
60+
61+
const request = RequestUtility.compose(
62+
{
63+
method: "GET",
64+
collection: "EntityDefinitions",
65+
select: ["EntitySetName", "LogicalName"],
66+
noCache: true,
67+
functionName: "retrieveMultiple",
68+
},
69+
config
70+
);
71+
72+
const result = await _runRequest(request, config);
73+
RequestUtility.setEntityNames({});
74+
for (let i = 0; i < result.data.value.length; i++) {
75+
RequestUtility.entityNames![result.data.value[i].LogicalName] = result.data.value[i].EntitySetName;
76+
}
77+
78+
return RequestUtility.findCollectionName(entityName) || entityName;
79+
};
80+
81+
const _checkCollectionName = async (entityName: string | null | undefined, config: InternalConfig): Promise<string | null | undefined> => {
82+
if (!entityName || _isEntityNameException(entityName)) {
83+
return entityName;
84+
}
85+
86+
entityName = entityName.toLowerCase();
87+
88+
if (!config.useEntityNames) {
89+
return entityName;
90+
}
91+
92+
try {
93+
return await _getCollectionNames(entityName, config);
94+
} catch (error: any) {
95+
throw new Error("Unable to fetch Collection Names. Error: " + (error as DynamicsWebApiError).message);
96+
}
97+
};
98+
4199
export class RequestClient {
42100
/**
43101
* Sends a request to given URL with given parameters
@@ -116,72 +174,14 @@ export class RequestClient {
116174
});
117175
}
118176

119-
private static async _getCollectionNames(entityName: string, config: InternalConfig): Promise<string | null | undefined> {
120-
if (!Utility.isNull(RequestUtility.entityNames)) {
121-
return RequestUtility.findCollectionName(entityName) || entityName;
122-
}
123-
124-
const request = RequestUtility.compose(
125-
{
126-
method: "GET",
127-
collection: "EntityDefinitions",
128-
select: ["EntitySetName", "LogicalName"],
129-
noCache: true,
130-
functionName: "retrieveMultiple",
131-
},
132-
config
133-
);
134-
135-
const result = await _runRequest(request, config);
136-
RequestUtility.setEntityNames({});
137-
for (let i = 0; i < result.data.value.length; i++) {
138-
RequestUtility.entityNames![result.data.value[i].LogicalName] = result.data.value[i].EntitySetName;
139-
}
140-
141-
return RequestUtility.findCollectionName(entityName) || entityName;
142-
}
143-
144-
private static _isEntityNameException(entityName: string): boolean {
145-
const exceptions = [
146-
"$metadata",
147-
"EntityDefinitions",
148-
"RelationshipDefinitions",
149-
"GlobalOptionSetDefinitions",
150-
"ManagedPropertyDefinitions",
151-
"query",
152-
"suggest",
153-
"autocomplete",
154-
];
155-
156-
return exceptions.indexOf(entityName) > -1;
157-
}
158-
159-
private static async _checkCollectionName(entityName: string | null | undefined, config: InternalConfig): Promise<string | null | undefined> {
160-
if (!entityName || RequestClient._isEntityNameException(entityName)) {
161-
return entityName;
162-
}
163-
164-
entityName = entityName.toLowerCase();
165-
166-
if (!config.useEntityNames) {
167-
return entityName;
168-
}
169-
170-
try {
171-
return await RequestClient._getCollectionNames(entityName, config);
172-
} catch (error: any) {
173-
throw new Error("Unable to fetch Collection Names. Error: " + (error as DynamicsWebApiError).message);
174-
}
175-
}
176-
177177
static async makeRequest(request: Core.InternalRequest, config: InternalConfig): Promise<Core.WebApiResponse | undefined> {
178178
request.responseParameters = request.responseParameters || {};
179179
//we don't want to mix headers set by the library and by the user
180180
request.userHeaders = request.headers;
181181
delete request.headers;
182182

183183
if (!request.isBatch) {
184-
const collectionName = await RequestClient._checkCollectionName(request.collection, config);
184+
const collectionName = await _checkCollectionName(request.collection, config);
185185

186186
request.collection = collectionName;
187187
RequestUtility.compose(request, config);

tests/main.spec.ts

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import nock from "nock";
33
import * as mocks from "./stubs";
44

55
import { DynamicsWebApi, type RetrieveMultipleRequest } from "../src/dynamics-web-api";
6+
import { DWA } from "../lib/dwa";
67

78
const dynamicsWebApiTest = new DynamicsWebApi({
89
dataApi: {
@@ -167,6 +168,93 @@ describe("dynamicsWebApi.retrieveMultiple -", () => {
167168
});
168169
});
169170

171+
describe("dynamicsWebApi.fetch -", () => {
172+
describe("with token", function () {
173+
let scope: nock.Scope;
174+
const testToken = "test token";
175+
before(function () {
176+
const response = mocks.responses.fetchXmlResponsePage2Cookie;
177+
scope = nock(mocks.webApiUrl, {
178+
reqheaders: {
179+
Authorization: `Bearer ${testToken}`,
180+
Prefer: DWA.Prefer.get(DWA.Prefer.Annotations.FormattedValue),
181+
},
182+
})
183+
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml2cookie))
184+
.reply(response.status, response.responseText, response.responseHeaders);
185+
});
186+
187+
after(function () {
188+
nock.cleanAll();
189+
});
190+
191+
it("returns a correct response", async () => {
192+
const pagingInfo = mocks.data.fetchXmls.fetchXmlResultPage1Cookie.PagingInfo;
193+
194+
try {
195+
const object = await dynamicsWebApiTest.fetch({
196+
collection: "tests",
197+
fetchXml: mocks.data.fetchXmls.fetchXml,
198+
includeAnnotations: DWA.Prefer.Annotations.FormattedValue,
199+
pageNumber: pagingInfo.nextPage,
200+
pagingCookie: pagingInfo.cookie,
201+
token: testToken,
202+
});
203+
204+
expect(object).to.deep.equal(mocks.data.fetchXmls.fetchXmlResultPage2Cookie);
205+
} catch (error) {
206+
console.error(error);
207+
throw error;
208+
}
209+
});
210+
211+
it("all requests have been made", function () {
212+
expect(scope.isDone()).to.be.true;
213+
});
214+
});
215+
});
216+
217+
describe("dynamicsWebApi.fetchAll -", () => {
218+
describe("with token", function () {
219+
let scope: nock.Scope;
220+
const testToken = "test token";
221+
before(function () {
222+
var response = mocks.responses.fetchXmlResponsePage1Cookie;
223+
var response2 = mocks.responses.fetchXmlResponsePage2NoCookie;
224+
scope = nock(mocks.webApiUrl, {
225+
reqheaders: {
226+
Authorization: `Bearer ${testToken}`,
227+
},
228+
})
229+
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml1))
230+
.reply(response.status, response.responseText, response.responseHeaders)
231+
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml2cookie))
232+
.reply(response2.status, response2.responseText, response2.responseHeaders);
233+
});
234+
235+
after(function () {
236+
nock.cleanAll();
237+
});
238+
239+
it("returns a correct response", async () => {
240+
try {
241+
const object = await dynamicsWebApiTest.fetchAll({ collection: "tests", fetchXml: mocks.data.fetchXmls.fetchXml, token: testToken });
242+
243+
let checkResponse = mocks.data.fetchXmls.fetchXmlResultPage1Cookie.value;
244+
checkResponse = checkResponse.concat(mocks.data.fetchXmls.fetchXmlResultPage2Cookie.value);
245+
expect(object).to.deep.equal({ value: checkResponse });
246+
} catch (error) {
247+
console.error(error);
248+
throw error;
249+
}
250+
});
251+
252+
it("all requests have been made", function () {
253+
expect(scope.isDone()).to.be.true;
254+
});
255+
});
256+
});
257+
170258
describe("dynamicsWebApi.executeBatch -", () => {
171259
describe("non-atomic global - create / create (Content-ID in a header gets cleared)", function () {
172260
let scope;
@@ -621,7 +709,7 @@ describe("dynamicsWebApi.callFunction -", () => {
621709
name: "FUN",
622710
parameters: { param1: "value1", param2: 2 },
623711
select: ["field1", "field2"],
624-
filter: "field1 eq 1"
712+
filter: "field1 eq 1",
625713
});
626714

627715
expect(object).to.deep.equal(mocks.data.testEntity);
@@ -655,7 +743,7 @@ describe("dynamicsWebApi.callFunction -", () => {
655743
functionName: "FUN",
656744
parameters: { param1: "value1", param2: 2 },
657745
select: ["field1", "field2"],
658-
filter: "field1 eq 1"
746+
filter: "field1 eq 1",
659747
});
660748

661749
expect(object).to.deep.equal(mocks.data.testEntity);
@@ -690,7 +778,7 @@ describe("dynamicsWebApi.callFunction -", () => {
690778
collection: "tests",
691779
parameters: { param1: "value1", param2: 2 },
692780
select: ["field1", "field2"],
693-
filter: "field1 eq 1"
781+
filter: "field1 eq 1",
694782
});
695783

696784
expect(object).to.deep.equal(mocks.data.testEntity);

0 commit comments

Comments
 (0)