Skip to content

Commit

Permalink
refactoring; investigating #175, adding more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrRogov committed Jul 11, 2024
1 parent 570a765 commit 836f3cd
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 62 deletions.
118 changes: 59 additions & 59 deletions src/client/RequestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,64 @@ const _runRequest = async (request: Core.InternalRequest, config: InternalConfig
let _batchRequestCollection: Core.BatchRequestCollection = {};
let _responseParseParams: { [key: string]: any[] } = {};

const _nameExceptions = [
"$metadata",
"EntityDefinitions",
"RelationshipDefinitions",
"GlobalOptionSetDefinitions",
"ManagedPropertyDefinitions",
"query",
"suggest",
"autocomplete",
];

const _isEntityNameException = (entityName: string): boolean => {
return _nameExceptions.indexOf(entityName) > -1;
};

const _getCollectionNames = async (entityName: string, config: InternalConfig): Promise<string | null | undefined> => {
if (!Utility.isNull(RequestUtility.entityNames)) {
return RequestUtility.findCollectionName(entityName) || entityName;
}

const request = RequestUtility.compose(
{
method: "GET",
collection: "EntityDefinitions",
select: ["EntitySetName", "LogicalName"],
noCache: true,
functionName: "retrieveMultiple",
},
config
);

const result = await _runRequest(request, config);
RequestUtility.setEntityNames({});
for (let i = 0; i < result.data.value.length; i++) {
RequestUtility.entityNames![result.data.value[i].LogicalName] = result.data.value[i].EntitySetName;
}

return RequestUtility.findCollectionName(entityName) || entityName;
};

const _checkCollectionName = async (entityName: string | null | undefined, config: InternalConfig): Promise<string | null | undefined> => {
if (!entityName || _isEntityNameException(entityName)) {
return entityName;
}

entityName = entityName.toLowerCase();

if (!config.useEntityNames) {
return entityName;
}

try {
return await _getCollectionNames(entityName, config);
} catch (error: any) {
throw new Error("Unable to fetch Collection Names. Error: " + (error as DynamicsWebApiError).message);
}
};

export class RequestClient {
/**
* Sends a request to given URL with given parameters
Expand Down Expand Up @@ -116,72 +174,14 @@ export class RequestClient {
});
}

private static async _getCollectionNames(entityName: string, config: InternalConfig): Promise<string | null | undefined> {
if (!Utility.isNull(RequestUtility.entityNames)) {
return RequestUtility.findCollectionName(entityName) || entityName;
}

const request = RequestUtility.compose(
{
method: "GET",
collection: "EntityDefinitions",
select: ["EntitySetName", "LogicalName"],
noCache: true,
functionName: "retrieveMultiple",
},
config
);

const result = await _runRequest(request, config);
RequestUtility.setEntityNames({});
for (let i = 0; i < result.data.value.length; i++) {
RequestUtility.entityNames![result.data.value[i].LogicalName] = result.data.value[i].EntitySetName;
}

return RequestUtility.findCollectionName(entityName) || entityName;
}

private static _isEntityNameException(entityName: string): boolean {
const exceptions = [
"$metadata",
"EntityDefinitions",
"RelationshipDefinitions",
"GlobalOptionSetDefinitions",
"ManagedPropertyDefinitions",
"query",
"suggest",
"autocomplete",
];

return exceptions.indexOf(entityName) > -1;
}

private static async _checkCollectionName(entityName: string | null | undefined, config: InternalConfig): Promise<string | null | undefined> {
if (!entityName || RequestClient._isEntityNameException(entityName)) {
return entityName;
}

entityName = entityName.toLowerCase();

if (!config.useEntityNames) {
return entityName;
}

try {
return await RequestClient._getCollectionNames(entityName, config);
} catch (error: any) {
throw new Error("Unable to fetch Collection Names. Error: " + (error as DynamicsWebApiError).message);
}
}

static async makeRequest(request: Core.InternalRequest, config: InternalConfig): Promise<Core.WebApiResponse | undefined> {
request.responseParameters = request.responseParameters || {};
//we don't want to mix headers set by the library and by the user
request.userHeaders = request.headers;
delete request.headers;

if (!request.isBatch) {
const collectionName = await RequestClient._checkCollectionName(request.collection, config);
const collectionName = await _checkCollectionName(request.collection, config);

request.collection = collectionName;
RequestUtility.compose(request, config);
Expand Down
94 changes: 91 additions & 3 deletions tests/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import nock from "nock";
import * as mocks from "./stubs";

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

const dynamicsWebApiTest = new DynamicsWebApi({
dataApi: {
Expand Down Expand Up @@ -167,6 +168,93 @@ describe("dynamicsWebApi.retrieveMultiple -", () => {
});
});

describe("dynamicsWebApi.fetch -", () => {
describe("with token", function () {
let scope: nock.Scope;
const testToken = "test token";
before(function () {
const response = mocks.responses.fetchXmlResponsePage2Cookie;
scope = nock(mocks.webApiUrl, {
reqheaders: {
Authorization: `Bearer ${testToken}`,
Prefer: DWA.Prefer.get(DWA.Prefer.Annotations.FormattedValue),
},
})
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml2cookie))
.reply(response.status, response.responseText, response.responseHeaders);
});

after(function () {
nock.cleanAll();
});

it("returns a correct response", async () => {
const pagingInfo = mocks.data.fetchXmls.fetchXmlResultPage1Cookie.PagingInfo;

try {
const object = await dynamicsWebApiTest.fetch({
collection: "tests",
fetchXml: mocks.data.fetchXmls.fetchXml,
includeAnnotations: DWA.Prefer.Annotations.FormattedValue,
pageNumber: pagingInfo.nextPage,
pagingCookie: pagingInfo.cookie,
token: testToken,
});

expect(object).to.deep.equal(mocks.data.fetchXmls.fetchXmlResultPage2Cookie);
} catch (error) {
console.error(error);
throw error;
}
});

it("all requests have been made", function () {
expect(scope.isDone()).to.be.true;
});
});
});

describe("dynamicsWebApi.fetchAll -", () => {
describe("with token", function () {
let scope: nock.Scope;
const testToken = "test token";
before(function () {
var response = mocks.responses.fetchXmlResponsePage1Cookie;
var response2 = mocks.responses.fetchXmlResponsePage2NoCookie;
scope = nock(mocks.webApiUrl, {
reqheaders: {
Authorization: `Bearer ${testToken}`,
},
})
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml1))
.reply(response.status, response.responseText, response.responseHeaders)
.get(mocks.responses.collectionUrl + "?fetchXml=" + encodeURIComponent(mocks.data.fetchXmls.fetchXml2cookie))
.reply(response2.status, response2.responseText, response2.responseHeaders);
});

after(function () {
nock.cleanAll();
});

it("returns a correct response", async () => {
try {
const object = await dynamicsWebApiTest.fetchAll({ collection: "tests", fetchXml: mocks.data.fetchXmls.fetchXml, token: testToken });

let checkResponse = mocks.data.fetchXmls.fetchXmlResultPage1Cookie.value;
checkResponse = checkResponse.concat(mocks.data.fetchXmls.fetchXmlResultPage2Cookie.value);
expect(object).to.deep.equal({ value: checkResponse });
} catch (error) {
console.error(error);
throw error;
}
});

it("all requests have been made", function () {
expect(scope.isDone()).to.be.true;
});
});
});

describe("dynamicsWebApi.executeBatch -", () => {
describe("non-atomic global - create / create (Content-ID in a header gets cleared)", function () {
let scope;
Expand Down Expand Up @@ -621,7 +709,7 @@ describe("dynamicsWebApi.callFunction -", () => {
name: "FUN",
parameters: { param1: "value1", param2: 2 },
select: ["field1", "field2"],
filter: "field1 eq 1"
filter: "field1 eq 1",
});

expect(object).to.deep.equal(mocks.data.testEntity);
Expand Down Expand Up @@ -655,7 +743,7 @@ describe("dynamicsWebApi.callFunction -", () => {
functionName: "FUN",
parameters: { param1: "value1", param2: 2 },
select: ["field1", "field2"],
filter: "field1 eq 1"
filter: "field1 eq 1",
});

expect(object).to.deep.equal(mocks.data.testEntity);
Expand Down Expand Up @@ -690,7 +778,7 @@ describe("dynamicsWebApi.callFunction -", () => {
collection: "tests",
parameters: { param1: "value1", param2: 2 },
select: ["field1", "field2"],
filter: "field1 eq 1"
filter: "field1 eq 1",
});

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

0 comments on commit 836f3cd

Please sign in to comment.