From 22ba4520efc24b2b8852ac9e0a20768a52f011be Mon Sep 17 00:00:00 2001 From: StevanFreeborn Date: Fri, 3 Feb 2023 11:17:53 -0600 Subject: [PATCH] feat: implement getFieldsByIds method --- .nycrc | 2 +- src/models/ApiResponse.ts | 25 ++++- src/models/OnspringClient.ts | 3 +- tests/ApiResponse.spec.ts | 66 ++++++++++++- tests/OnspringClient.spec.ts | 179 +++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 4 deletions(-) diff --git a/.nycrc b/.nycrc index f4cb085..80f4ea0 100644 --- a/.nycrc +++ b/.nycrc @@ -3,7 +3,7 @@ "check-coverage": true, "all": true, "include": ["src/**/*.ts"], - "exclude": ["src/onspringApiSdk.ts", "**/*.spec.ts"], + "exclude": ["src/index.ts", "**/*.spec.ts"], "reporter": ["html", "lcov", "text", "text-summary"], "report-dir": "coverage" } diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index c9328d5..8c4119a 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -135,6 +135,29 @@ export class ApiResponse { } public AsFieldCollectionType(): ApiResponse> { - throw new Error('Method not implemented.'); + const apiResponse = this as ApiResponse; + + const fields = apiResponse.data.items.map((item: any) => { + return new Field( + item.id, + item.appId, + item.name, + item.type, + item.status, + item.isRequired, + item.isUnique + ); + }); + + const collectionResponse = new CollectionResponse( + apiResponse.data.count, + fields + ); + + return new ApiResponse>( + apiResponse.statusCode, + apiResponse.message, + collectionResponse + ); } } diff --git a/src/models/OnspringClient.ts b/src/models/OnspringClient.ts index 1cd10bb..d7c0343 100644 --- a/src/models/OnspringClient.ts +++ b/src/models/OnspringClient.ts @@ -129,7 +129,8 @@ export class OnspringClient { fieldIds: number[] ): Promise>> { const endpoint = EndpointFactory.getFieldsByIdsEndpoint(); - const apiResponse = await this.post(endpoint, fieldIds); + const uniqueIds = [...new Set(fieldIds)]; + const apiResponse = await this.post(endpoint, uniqueIds); if (apiResponse.isSuccessful === false) { return apiResponse; diff --git a/tests/ApiResponse.spec.ts b/tests/ApiResponse.spec.ts index 7e18ec5..b3e90d1 100644 --- a/tests/ApiResponse.spec.ts +++ b/tests/ApiResponse.spec.ts @@ -9,7 +9,6 @@ import { FieldType } from '../src/enums/FieldType'; describe('ApiResponse', function () { it('should be defined', function () { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions expect(ApiResponse).to.not.be.undefined; }); @@ -196,6 +195,7 @@ describe('ApiResponse', function () { it('should return an ApiResponse> when data contains app items', function () { const mockResponseData = { + count: 2, items: [ { href: 'https://api.onspring.dev/apps/id/1', @@ -221,6 +221,9 @@ describe('ApiResponse', function () { ); expect(appCollectionResponse.data).to.not.be.null; if (appCollectionResponse.data != null) { + expect(appCollectionResponse.data).to.have.property('count'); + expect(appCollectionResponse.data).to.have.property('items'); + expect(appCollectionResponse.data.count).to.equal(2); expect(appCollectionResponse.data.items).to.be.instanceOf(Array); expect(appCollectionResponse.data.items).to.have.lengthOf(2); appCollectionResponse.data.items.forEach((item) => { @@ -270,4 +273,65 @@ describe('ApiResponse', function () { } }); }); + + describe('AsFieldCollectionType', function () { + it('should be defined', function () { + expect(ApiResponse.prototype.AsFieldCollectionType).to.not.be.undefined; + }); + + it('should have no parameters', function () { + expect(ApiResponse.prototype.AsFieldCollectionType).to.have.lengthOf(0); + }); + + it('should return an ApiResponse> when data contains field items', function () { + const mockResponseData = { + count: 2, + items: [ + { + id: 1, + appId: 1, + name: 'Text Field', + type: 'Text', + status: 'Enabled', + isRequired: false, + isUnique: false, + }, + { + id: 2, + appId: 1, + name: 'Number Field', + type: 'Number', + status: 'Enabled', + isRequired: false, + isUnique: false, + }, + ], + }; + + const apiResponse = new ApiResponse(200, 'OK', mockResponseData); + const fieldCollectionResponse = apiResponse.AsFieldCollectionType(); + + expect(fieldCollectionResponse).to.be.instanceOf( + ApiResponse> + ); + expect(fieldCollectionResponse.data).to.be.instanceOf( + CollectionResponse + ); + expect(fieldCollectionResponse.data).to.not.be.null; + if (fieldCollectionResponse.data != null) { + expect(fieldCollectionResponse.data.items).to.be.instanceOf(Array); + expect(fieldCollectionResponse.data.items).to.have.lengthOf(2); + fieldCollectionResponse.data.items.forEach((item) => { + expect(item).to.be.instanceOf(Field); + expect(item).to.have.property('id'); + expect(item).to.have.property('appId'); + expect(item).to.have.property('name'); + expect(item).to.have.property('type'); + expect(item).to.have.property('status'); + expect(item).to.have.property('isRequired'); + expect(item).to.have.property('isUnique'); + }); + } + }); + }); }); diff --git a/tests/OnspringClient.spec.ts b/tests/OnspringClient.spec.ts index dd1fbe8..ec5ed48 100644 --- a/tests/OnspringClient.spec.ts +++ b/tests/OnspringClient.spec.ts @@ -828,4 +828,183 @@ describe('OnspringClient', function () { expect(result.data).to.be.null; }); }); + + describe('getFieldsByIds', function () { + it('should be a function', function () { + expect(new OnspringClient(baseUrl, apiKey).getFieldsByIds).to.be.a( + 'function' + ); + }); + + it('should return a promise', function () { + expect(new OnspringClient(baseUrl, apiKey).getFieldsByIds([1])).to.be.a( + 'promise' + ); + }); + + it('should return a promise that resolves to an api response of a collection of fields when request is successful', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'post').returns( + Promise.resolve({ + status: 200, + statusText: 'OK', + data: { + count: 2, + items: [ + { + id: 1, + appId: 1, + name: 'Text Field', + type: 'Text', + status: 'Enabled', + isRequired: false, + isUnique: false, + }, + { + id: 2, + appId: 1, + name: 'Number Field', + type: 'Number', + status: 'Enabled', + isRequired: false, + isUnique: false, + }, + ], + }, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getFieldsByIds([1, 2]); + expect(result).to.be.instanceOf(ApiResponse>); + expect(result).to.have.property('statusCode', 200); + expect(result).to.have.property('isSuccessful', true); + expect(result).to.have.property('message', ''); + expect(result).to.have.property('data'); + if (result.data != null) { + expect(result.data).to.be.instanceOf(CollectionResponse); + expect(result.data).to.have.property('count', 2); + expect(result.data).to.have.property('items'); + expect(result.data.items).to.have.lengthOf(2); + result.data.items.forEach((item) => { + expect(item).to.be.instanceOf(Field); + expect(item).to.have.property('id'); + expect(item).to.have.property('appId'); + expect(item).to.have.property('name'); + expect(item).to.have.property('type'); + expect(item).to.have.property('status'); + expect(item).to.have.property('isRequired'); + expect(item).to.have.property('isUnique'); + }); + } + }); + + it('should return a promise that resolves to an api response when request receives a 401 response', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'post').returns( + Promise.resolve({ + status: 401, + statusText: 'Unauthorized', + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getFieldsByIds([1, 2]); + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 401); + expect(result).to.have.property('isSuccessful', false); + expect(result.message).to.be.undefined; + expect(result.data).to.be.null; + }); + + it('should return a promise that resolves to an api response when request receives a 403 response', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'post').returns( + Promise.resolve({ + status: 403, + statusText: 'Forbidden', + data: { + message: 'Client does not have access to read field: 1,2', + }, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getFieldsByIds([1, 2]); + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 403); + expect(result).to.have.property('isSuccessful', false); + expect(result).to.have.property( + 'message', + 'Client does not have access to read field: 1,2' + ); + expect(result.data).to.be.null; + }); + + it('should return a promise that resolves to an api response when request receives a 404 response', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'post').returns( + Promise.resolve({ + status: 404, + statusText: 'Not Found', + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getFieldsByIds([1, 2]); + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 404); + expect(result).to.have.property('isSuccessful', false); + expect(result.message).to.be.undefined; + expect(result.data).to.be.null; + }); + }); });