From f66edb0e2ad86663940dc4ffa6f661068281f01c Mon Sep 17 00:00:00 2001 From: StevanFreeborn Date: Fri, 27 Jan 2023 15:00:34 -0600 Subject: [PATCH] feat: added sinon for stubbing in tests. fix: added jsdoc comments to enums. feat: begin working on implementing OnspringClient methods --- package-lock.json | 237 ++++++++++++++++++++++++++++ package.json | 2 + src/OnspringClient.ts | 26 ++- src/enums/DataFormat.ts | 14 +- src/enums/FieldStatus.ts | 19 ++- src/enums/FieldType.ts | 72 +++++++++ src/enums/FileStorageSite.ts | 14 ++ src/enums/FormulaOutputType.ts | 19 +++ src/enums/HttpStatusCode.ts | 77 +++++++++ src/enums/Multiplicity.ts | 12 ++ src/enums/ReportDataType.ts | 11 ++ src/enums/ResultValueType.ts | 61 +++++++ src/enums/TimeSpanIncrement.ts | 37 +++++ src/enums/TimeSpanRecurrenceType.ts | 18 +++ src/models/ApiResponseFactory.ts | 58 +++++++ tests/OnspringClient.spec.ts | 42 ++++- 16 files changed, 710 insertions(+), 9 deletions(-) create mode 100644 src/models/ApiResponseFactory.ts diff --git a/package-lock.json b/package-lock.json index 7677e2c..ef6fe33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,11 @@ "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/chai": "^4.3.4", "@types/mocha": "^10.0.1", + "@types/sinon": "^10.0.13", "chai": "^4.3.7", "mocha": "^10.2.0", "nyc": "^15.1.0", + "sinon": "^15.0.1", "ts-node": "^10.9.1", "typescript": "^4.9.4" } @@ -591,6 +593,41 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -634,6 +671,21 @@ "dev": true, "peer": true }, + "node_modules/@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "node_modules/acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", @@ -1598,6 +1650,12 @@ "node": ">=0.10.0" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1752,6 +1810,12 @@ "node": ">=6" } }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1773,6 +1837,12 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -1917,6 +1987,19 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -2223,6 +2306,15 @@ "node": ">=8" } }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -2474,6 +2566,36 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/sinon": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.1.tgz", + "integrity": "sha512-PZXKc08f/wcA/BMRGBze2Wmw50CWPiAH3E21EOi4B49vJ616vW4DQh4fQrqsYox2aNR/N3kCqLuB0PwwOucQrg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "10.0.2", + "@sinonjs/samsam": "^7.0.1", + "diff": "^5.0.0", + "nise": "^5.1.2", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3336,6 +3458,41 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0" + } + }, + "@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -3379,6 +3536,21 @@ "dev": true, "peer": true }, + "@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", @@ -4055,6 +4227,12 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4172,6 +4350,12 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4187,6 +4371,12 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4293,6 +4483,19 @@ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true }, + "nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -4529,6 +4732,15 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -4711,6 +4923,31 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "sinon": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.1.tgz", + "integrity": "sha512-PZXKc08f/wcA/BMRGBze2Wmw50CWPiAH3E21EOi4B49vJ616vW4DQh4fQrqsYox2aNR/N3kCqLuB0PwwOucQrg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "10.0.2", + "@sinonjs/samsam": "^7.0.1", + "diff": "^5.0.0", + "nise": "^5.1.2", + "supports-color": "^7.2.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 3ea7f89..fa62cff 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,11 @@ "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/chai": "^4.3.4", "@types/mocha": "^10.0.1", + "@types/sinon": "^10.0.13", "chai": "^4.3.7", "mocha": "^10.2.0", "nyc": "^15.1.0", + "sinon": "^15.0.1", "ts-node": "^10.9.1", "typescript": "^4.9.4" }, diff --git a/src/OnspringClient.ts b/src/OnspringClient.ts index bc3bd1b..7c9b6dc 100644 --- a/src/OnspringClient.ts +++ b/src/OnspringClient.ts @@ -2,6 +2,8 @@ import { AxiosInstance } from 'axios'; import axios from 'axios'; import { ArgumentValidator } from './models/ArgumentValidator'; import { EndpointFactory } from './models/EndpointFactory'; +import { ApiResponseFactory } from './models/ApiResponseFactory'; +import { ApiResponse } from './models/ApiResponse'; /** * @class OnspringClient - A client that can communicate with the Onspring API. @@ -41,18 +43,30 @@ export class OnspringClient { }); } + /** + * @method canConnect - Determines if the client can connect to the Onspring API. + * @returns {Promise} - A promise that resolves to a boolean indicating if the client can connect to the Onspring API. + */ public async canConnect(): Promise { - const endpoint = EndpointFactory.getPingEndpoint(this._client.defaults.baseURL); + const endpoint = EndpointFactory.getPingEndpoint( + this._client.defaults.baseURL + ); try { - var response = await this._client.get(endpoint); - return response.status === 200; + const response = await this.get>(endpoint); + return response.isSuccessful; } catch (error) { return false; } } - private async get(endpoint: string): Promise { - const response = await this._client.get(endpoint); - return response.data; + /** + * @method get - Makes a GET request to the specified endpoint. + * @param {string} endpoint - The endpoint that will be used to make the request. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type T. + */ + private async get(endpoint: string): Promise> { + const response = await this._client.get(endpoint); + const apiResponse = ApiResponseFactory.getApiResponse(response); + return apiResponse; } } diff --git a/src/enums/DataFormat.ts b/src/enums/DataFormat.ts index e468558..6b4a908 100644 --- a/src/enums/DataFormat.ts +++ b/src/enums/DataFormat.ts @@ -1,4 +1,16 @@ +/** + * @enum DataFormat - The format of the data to be returned. + */ export enum DataFormat { + /** + * @constant Raw - The raw data will be returned. + * @type {string} + */ Raw = 'Raw', + + /** + * @constant Formatted - The formatted data will be returned. + * @type {string} + */ Formatted = 'Formatted', -} \ No newline at end of file +} diff --git a/src/enums/FieldStatus.ts b/src/enums/FieldStatus.ts index f9890d2..b00e367 100644 --- a/src/enums/FieldStatus.ts +++ b/src/enums/FieldStatus.ts @@ -1,5 +1,22 @@ +/** + * @enum FieldStatus - The status of a field. + */ export enum FieldStatus { + /** + * @constant Enabled - The field is enabled. + * @type {string} + */ Enabled = 'Enabled', + + /** + * @constant Disabled - The field is disabled. + * @type {string} + */ Disabled = 'Disabled', + + /** + * @constant Invalid - The field is invalid. + * @type {string} + */ Invalid = 'Invalid', -} \ No newline at end of file +} diff --git a/src/enums/FieldType.ts b/src/enums/FieldType.ts index b79587b..6d267bc 100644 --- a/src/enums/FieldType.ts +++ b/src/enums/FieldType.ts @@ -1,16 +1,88 @@ +/** + * @enum FieldType - The type of field. + */ export enum FieldType { + /** + * @constant Text - The field is a text field. + * @type {string} + */ Text = 'Text', + + /** + * @constant Number - The field is a number field. + * @type {string} + */ Number = 'Number', + + /** + * @constant AutoNumber - The field is a autonumber field. + * @type {string} + */ AutoNumber = 'AutoNumber', + + /** + * @constant Date - The field is a date field. + * @type {string} + */ Date = 'Date', + + /** + * @constant TimeSpan - The field is a timespan field. + * @type {string} + */ TimeSpan = 'TimeSpan', + + /** + * @constant List - The field is a list field. + * @type {string} + */ List = 'List', + + /** + * @constant Reference - The field is a reference field. + * @type {string} + */ Reference = 'Reference', + + /** + * @constant SurveyReference - The field is a survey reference field. + * @type {string} + */ SurveyReference = 'SurveyReference', + + /** + * @constant SurveyGroupScoring - The field is a survey group scoring field. + * @type {string} + */ SurveyGroupScoring = 'SurveyGroupScoring', + + /** + * @constant SurveyCampaign - The field is a survey campaign field. + * @type {string} + */ SurveyCampaign = 'SurveyCampaign', + + /** + * @constant SurveyUnifiedAnswer - The field is a survey unified answer field. + * @type {string} + */ SurveyUnifiedAnswer = 'SurveyUnifiedAnswer', + + /** + * @constant Attachment - The field is a attachment field. + * @type {string} + */ Attachment = 'Attachment', + + /** + * @constant Image - The field is a image field. + * @type {string} + */ Image = 'Image', + + /** + * @constant Formula - The field is a formula field. + * @type {string} + */ Formula = 'Formula', } diff --git a/src/enums/FileStorageSite.ts b/src/enums/FileStorageSite.ts index bf69f71..34883a1 100644 --- a/src/enums/FileStorageSite.ts +++ b/src/enums/FileStorageSite.ts @@ -1,5 +1,19 @@ export enum FileStorageSite { + /** + * @constant Internal - The file is stored in the internal file storage. + * @type {string} + */ Internal = 'Internal', + + /** + * @constant OneDrive - The file is stored in OneDrive. + * @type {string} + */ OneDrive = 'OneDrive', + + /** + * @constant GoogleDrive - The file is stored in Google Drive. + * @type {string} + */ GoogleDrive = 'GoogleDrive', } diff --git a/src/enums/FormulaOutputType.ts b/src/enums/FormulaOutputType.ts index 2981177..ca7c9b8 100644 --- a/src/enums/FormulaOutputType.ts +++ b/src/enums/FormulaOutputType.ts @@ -1,6 +1,25 @@ export enum FormulaOutputType { + /** + * @constant Text - The formula output is a text value. + * @type {string} + */ Text = 'Text', + + /** + * @constant Numeric - The formula output is a numeric value. + * @type {string} + */ Numeric = 'Numeric', + + /** + * @constant DateAndTime - The formula output is a date and time value. + * @type {string} + */ DateAndTime = 'DateAndTime', + + /** + * @constant ListValue - The formula output is a list value. + * @type {string} + */ ListValue = 'ListValue', } diff --git a/src/enums/HttpStatusCode.ts b/src/enums/HttpStatusCode.ts index 973091b..141091f 100644 --- a/src/enums/HttpStatusCode.ts +++ b/src/enums/HttpStatusCode.ts @@ -1,17 +1,94 @@ +/** + * @enum HttpStatusCode - Enum for HTTP status codes + */ export enum HttpStatusCode { + /** + * @constant OK - The request was successful. + * @type {number} + */ OK = 200, + + /** + * @constant Created - The request was successful and a new resource was created. + * @type {number} + */ Created = 201, + + /** + * @constant Accepted - The request was accepted for processing. + * @type {number} + */ Accepted = 202, + + /** + * @constant NoContent - The request was successful but there is no content to return. + * @type {number} + */ NoContent = 204, + + /** + * @constant BadRequest - The request was invalid. + * @type {number} + */ BadRequest = 400, + + /** + * @constant Unauthorized - The request did not include an authentication token. + * @type {number} + */ Unauthorized = 401, + + /** + * @constant Forbidden - The request included an authentication token but the token was not valid. + * @type {number} + */ Forbidden = 403, + + /** + * @constant NotFound - The requested resource does not exist. + * @type {number} + */ NotFound = 404, + + /** + * @constant MethodNotAllowed - The requested method is not supported for the resource. + * @type {number} + */ MethodNotAllowed = 405, + + /** + * @constant Conflict - The request could not be completed due to a conflict with the current state of the resource. + * @type {number} + */ Conflict = 409, + + /** + * @constant InternalServerError - An unexpected error occurred on the server. + * @type {number} + */ InternalServerError = 500, + + /** + * @constant NotImplemented - The requested method is not implemented. + * @type {number} + */ NotImplemented = 501, + + /** + * @constant BadGateway - The server received an invalid response from an upstream server. + * @type {number} + */ BadGateway = 502, + + /** + * @constant ServiceUnavailable - The server is currently unavailable. + * @type {number} + */ ServiceUnavailable = 503, + + /** + * @constant GatewayTimeout - The server did not receive a response from an upstream server in a timely manner. + * @type {number} + */ GatewayTimeout = 504, } diff --git a/src/enums/Multiplicity.ts b/src/enums/Multiplicity.ts index 4e74c84..9589970 100644 --- a/src/enums/Multiplicity.ts +++ b/src/enums/Multiplicity.ts @@ -1,4 +1,16 @@ +/** + * @enum Multiplicity - The multiplicity type of the object. + */ export enum Multiplicity { + /** + * @constant SingleSelect - Single select multiplicity. + * @type {string} + */ SingleSelect = 'SingleSelect', + + /** + * @constant MultiSelect - Multi select multiplicity. + * @type {string} + */ MultiSelect = 'MultiSelect', } diff --git a/src/enums/ReportDataType.ts b/src/enums/ReportDataType.ts index b0cd8e5..277a0cf 100644 --- a/src/enums/ReportDataType.ts +++ b/src/enums/ReportDataType.ts @@ -1,4 +1,15 @@ +/** + * @enum ReportDataType - Enum for report data type + */ export enum ReportDataType { + /** + * @constant ReportData - Report data + * @type {string} + */ ReportData = 'ReportData', + /** + * @constant ChartData - Chart data + * @type {string} + */ ChartData = 'ChartData', } diff --git a/src/enums/ResultValueType.ts b/src/enums/ResultValueType.ts index 52b3b57..d2fe242 100644 --- a/src/enums/ResultValueType.ts +++ b/src/enums/ResultValueType.ts @@ -1,14 +1,75 @@ +/** + * @enum ResultValueType - The type of the result value. + */ export enum ResultValueType { + /** + * @constant String - The result value is a string. + * @type {string} + */ String = 'String', + + /** + * @constant Integer - The result value is an integer. + * @type {string} + */ Integer = 'Integer', + + /** + * @constant Decimal - The result value is a decimal. + * @type {string} + */ Decimal = 'Decimal', + + /** + * @constant Date - The result value is a Date. + * @type {string} + */ Date = 'Date', + + /** + * @constant TimeSpan - The result value is a TimeSpan. + * @type {string} + */ TimeSpan = 'TimeSpan', + + /** + * @constant Guid - The result value is a Guid. + */ Guid = 'Guid', + + /** + * @constant StringList - The result value is a list of strings. + * @type {string} + */ StringList = 'StringList', + + /** + * @constant IntegerList - The result value is a list of integers. + * @type {string} + */ IntegerList = 'IntegerList', + + /** + * @constant GuidList - The result value is a list of Guids. + * @type {string} + */ GuidList = 'GuidList', + + /** + * @constant AttachmentList - The result value is a list of attachments. + * @type {string} + */ AttachmentList = 'AttachmentList', + + /** + * @constant ScoringGroupList - The result value is a list of scoring groups. + * @type {string} + */ ScoringGroupList = 'ScoringGroupList', + + /** + * @constant FileList - The result value is a list of files. + * @type {string} + */ FileList = 'FileList', } diff --git a/src/enums/TimeSpanIncrement.ts b/src/enums/TimeSpanIncrement.ts index 3c07d6a..e178261 100644 --- a/src/enums/TimeSpanIncrement.ts +++ b/src/enums/TimeSpanIncrement.ts @@ -1,9 +1,46 @@ +/** + * @enum TimeSpanIncrement - The increment values for a time span field. + */ export enum TimeSpanIncrement { + /** + * @constant Seconds - The time span increment is seconds. + * @type {string} + */ Seconds = 'Seconds', + + /** + * @constant Minutes - The time span increment is minutes. + * @type {string} + */ Minutes = 'Minutes', + + /** + * @constant Hours - The time span increment is hours. + * @type {string} + */ Hours = 'Hours', + + /** + * @constant Days - The time span increment is days. + * @type {string} + */ Days = 'Days', + + /** + * @constant Weeks - The time span increment is weeks. + * @type {string} + */ Weeks = 'Weeks', + + /** + * @constant Months - The time span increment is months. + * @type {string} + */ Months = 'Months', + + /** + * @constant Years - The time span increment is years. + * @type {string} + */ Years = 'Years', } diff --git a/src/enums/TimeSpanRecurrenceType.ts b/src/enums/TimeSpanRecurrenceType.ts index 2d52829..a2a55bd 100644 --- a/src/enums/TimeSpanRecurrenceType.ts +++ b/src/enums/TimeSpanRecurrenceType.ts @@ -1,5 +1,23 @@ +/** + * @enum TimeSpanRecurrenceType - The type of recurrence for a time span. + * @type {string} + */ export enum TimeSpanRecurrenceType { + /** + * @constant None - The time span does not recur. + * @type {string} + */ None = 'None', + + /** + * @constant EndByDate - The time span recurs until a specific date. + * @type {string} + */ EndByDate = 'EndByDate', + + /** + * @constant EndAfterOccurrences - The time span recurs for a specific number of occurrences. + * @type {string} + */ EndAfterOccurrences = 'EndAfterOccurrences', } diff --git a/src/models/ApiResponseFactory.ts b/src/models/ApiResponseFactory.ts new file mode 100644 index 0000000..270a4d6 --- /dev/null +++ b/src/models/ApiResponseFactory.ts @@ -0,0 +1,58 @@ +import { AxiosResponse } from "axios"; +import { HttpStatusCode } from "../enums/HttpStatusCode"; +import { ApiResponse } from "./ApiResponse"; + +/** + * @class ApiResponseFactory - Factory class for creating ApiResponse objects + */ +export class ApiResponseFactory { + /** + * @method getApiResponse - Creates an ApiResponse object from an AxiosResponse object + * @param {AxiosResponse} response - The AxiosResponse object that will be used to create the ApiResponse object + * @returns {ApiResponse} - An ApiResponse object of type T + */ + public static getApiResponse(response: AxiosResponse): ApiResponse { + const message = this.TryToGetMessage(response); + + if (this.isSuccessStatusCode(response.status) === true) + { + const data = response.data as T; + return new ApiResponse(response.status, message, data); + } + + return new ApiResponse(response.status, message, null); + } + + /** + * @method TryToGetMessage - Attempts to get the message from the response data + * @param {AxiosResponse} response - The AxiosResponse object that will be used to get the message + * @returns {string} - The message from the response data + */ + private static TryToGetMessage(response: AxiosResponse): string { + + if ( + response.status == HttpStatusCode.Unauthorized || + response.status == HttpStatusCode.Forbidden || + response.status == HttpStatusCode.NotFound + ) + { + return response.data?.message; + } + + if (this.isSuccessStatusCode(response.status) === false) + { + return JSON.stringify(response.data); + } + + return ""; + } + + /** + * @method isSuccessStatusCode - Determines if the specified status code is a success status code + * @param {number} statusCode - The status code that will be used to determine if it is a success status code + * @returns {boolean} - A boolean indicating if the specified status code is a success status code + */ + private static isSuccessStatusCode(statusCode: number): boolean { + return statusCode >= HttpStatusCode.OK && statusCode <= 299; + } +} diff --git a/tests/OnspringClient.spec.ts b/tests/OnspringClient.spec.ts index 9299cd8..705e470 100644 --- a/tests/OnspringClient.spec.ts +++ b/tests/OnspringClient.spec.ts @@ -1,8 +1,10 @@ import { OnspringClient } from '../src/OnspringClient'; +import { ApiResponse } from '../src/models/ApiResponse'; import { expect } from 'chai'; +import * as sinon from 'sinon'; describe('OnspringClient', function () { - const baseUrl = 'https://api.onspring.com'; + const baseUrl = 'https://api.onspring.dev'; const apiKey = 'apiKey'; it('should be defined', function () { @@ -86,4 +88,42 @@ describe('OnspringClient', function () { it('should have a client property', function () { expect(new OnspringClient(baseUrl, apiKey)).to.have.property('_client'); }); + + describe('canConnect', function () { + it('should be defined', function () { + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.not.be.undefined; + }); + + it('should be a function', function () { + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.be.a('function'); + }); + + it('should have 0 parameters', function () { + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.have.lengthOf(0); + }); + + it('should return a promise', function () { + expect(new OnspringClient(baseUrl, apiKey).canConnect()).to.be.a('promise'); + }); + + it('should return a promise that resolves to a boolean', async function () { + const client = new OnspringClient(baseUrl, apiKey); + const result = await client.canConnect(); + expect(result).to.be.a('boolean'); + }); + + it('should return a promise that resolves to true when able to connect to the Onspring API', async function () { + const client = new OnspringClient(baseUrl, apiKey); + sinon.stub(client, 'get' as any).returns(Promise.resolve(new ApiResponse(200, 'OK', null))); + const result = await client.canConnect(); + expect(result).to.be.true; + }); + + it('should return a promise that resolves to false when unable to connect to the Onspring API', async function () { + const client = new OnspringClient(baseUrl, apiKey); + sinon.stub(client, 'get' as any).returns(Promise.resolve(new ApiResponse(500, 'Internal Server Error', null))); + const result = await client.canConnect(); + expect(result).to.be.false; + }); + }); });