From 0b18b9c0a2ea341b8fd784de93498a724bfe5005 Mon Sep 17 00:00:00 2001 From: Evan Peterson Date: Tue, 11 Apr 2023 06:32:25 -0700 Subject: [PATCH] feat(vehicle): get & set charge limit (#161) --- .gitignore | 3 + doc/readme.md | 61 ++++++++ lib/vehicle.js | 67 ++++++++- package-lock.json | 275 +++++++++++++++++++++++++++++++++++++ package.json | 1 + test/end-to-end/vehicle.js | 20 ++- test/unit/lib/vehicle.js | 43 +++++- 7 files changed, 466 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index cd25b7ff..f3c37e63 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ Package Control.cache/ Package Control.ca-certs/ bh_unicode_properties.cache GitHub.sublime-settings + +## env +.env diff --git a/doc/readme.md b/doc/readme.md index 7ef46a06..722a8fc9 100644 --- a/doc/readme.md +++ b/doc/readme.md @@ -48,6 +48,8 @@ the following fields :

Permissions : Object
+
ChargeLimit
+
WebhookSubscription : Object
Batch : Object
@@ -549,6 +551,8 @@ Initializes a new Service object to make requests to the Smartcar API. * [Vehicle](#Vehicle) * [new Vehicle(id, token, [options])](#new_Vehicle_new) * [.permissions([paging])](#Vehicle+permissions) ⇒ [Permissions](#Permissions) + * [.getChargeLimit()](#Vehicle+getChargeLimit) ⇒ [ChargeLimit](#ChargeLimit) + * [.setChargeLimit(limit)](#Vehicle+setChargeLimit) ⇒ [ChargeLimit](#ChargeLimit) * [.subscribe(webhookId)](#Vehicle+subscribe) ⇒ Object * [.unsubscribe(amt, webhookId)](#Vehicle+unsubscribe) ⇒ [Meta](#Meta) * [.batch(paths)](#Vehicle+batch) ⇒ [Batch](#Batch) @@ -603,6 +607,53 @@ Fetch the list of permissions that this application has been granted | [paging.limit] | String | number of permissions to return | | [options.offset] | Object | The current start index of the returned list of elements. | + + +### vehicle.getChargeLimit() ⇒ [ChargeLimit](#ChargeLimit) +Fetch the charge limit for an electric vehicle + +**Kind**: instance method of [Vehicle](#Vehicle) +**Throws**: + +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. + See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + for all possible errors. + +**Example** +```js +{ + limit: .7, + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` + + +### vehicle.setChargeLimit(limit) ⇒ [ChargeLimit](#ChargeLimit) +Set the charge limit for an electric vehicle. + +**Kind**: instance method of [Vehicle](#Vehicle) +**Throws**: + +- [SmartcarError](#SmartcarError) - an instance of SmartcarError. + See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + for all possible errors. + + +| Param | Type | Description | +| --- | --- | --- | +| limit | number | a number between 0 and 1 | + +**Example** +```js +{ + status: string, + meta: { + requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + } +} +``` ### vehicle.subscribe(webhookId) ⇒ Object @@ -935,6 +986,16 @@ the following fields : } } ``` + + +## ChargeLimit +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| limit | number | the charge limit expressed as a decimal value between 0 and 1. | + ## WebhookSubscription : Object diff --git a/lib/vehicle.js b/lib/vehicle.js index 067c2112..ddeb2e44 100644 --- a/lib/vehicle.js +++ b/lib/vehicle.js @@ -124,7 +124,7 @@ _.forEach(METHODS_MAP, (attributes, methodName) => { * @param {Object} [paging] * @param {String} [paging.limit] - number of permissions to return * @param {Object} [options.offset] - The current start index of the returned list of elements. - * @return {Permissions} + * @returns {Permissions} * @throws {SmartcarError} - an instance of SmartcarError. * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) * for all possible errors. @@ -139,6 +139,71 @@ Vehicle.prototype.permissions = async function(paging = {}) { return response; }; +/** + * @typedef ChargeLimit + * @property {number} limit - the charge limit expressed as a decimal value between 0 and 1. + */ + +/** + * Fetch the charge limit for an electric vehicle + * + * @method + * @returns {ChargeLimit} + * @throws {SmartcarError} - an instance of SmartcarError. + * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + * for all possible errors. + * + * @example + * { + * limit: .7, + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } + */ + +Vehicle.prototype.getChargeLimit = async function() { + const response = await this.service.request( + 'get', + 'charge/limit', + ); + + return response; +}; + +/** + * Set the charge limit for an electric vehicle. + * + * @method + * @param {number} limit - a number between 0 and 1 + * @returns {ChargeLimit} + * @throws {SmartcarError} - an instance of SmartcarError. + * See the [errors section](https://github.com/smartcar/node-sdk/tree/master/doc#errors) + * for all possible errors. + * + * @example + * { + * status: string, + * meta: { + * requestId: '26c14915-0c26-43c5-8e42-9edfc2a66a0f', + * } + * } + */ +Vehicle.prototype.setChargeLimit = async function(limit) { + + const body = { + limit: String(limit), + }; + + const response = await this.service.request( + 'post', + 'charge/limit', + {body}, + ); + + return response; +}; + /** * @type {Object} * @typedef WebhookSubscription diff --git a/package-lock.json b/package-lock.json index 5df8eec2..d8fde0b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "nyc": "^15.1.0", "selenium-webdriver": "^4.1.1", "semantic-release": "^19.0.2", + "sinon": "^15.0.3", "uuid": "^8.3.2" }, "engines": { @@ -967,6 +968,59 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "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/fake-timers/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/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/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/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/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -2620,6 +2674,15 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4622,6 +4685,12 @@ "set-immediate-shim": "~1.0.1" } }, + "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/keyv": { "version": "4.2.9", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.9.tgz", @@ -4740,6 +4809,12 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "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/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -5225,6 +5300,28 @@ "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", "dev": true }, + "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/nise/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/nock": { "version": "13.2.4", "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.4.tgz", @@ -8357,6 +8454,21 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "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/path-to-regexp/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/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9663,6 +9775,24 @@ "node": ">=4" } }, + "node_modules/sinon": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.3.tgz", + "integrity": "sha512-si3geiRkeovP7Iel2O+qGL4NrO9vbMf3KsrJEi0ghP1l5aBkB5UxARea5j0FUsSqH3HLBh0dQPAyQ8fObRUqHw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -10360,6 +10490,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -11615,6 +11754,63 @@ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "dev": true }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "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" + }, + "dependencies": { + "@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/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + }, + "dependencies": { + "@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/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 + }, "@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -12887,6 +13083,12 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -14395,6 +14597,12 @@ "set-immediate-shim": "~1.0.1" } }, + "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 + }, "keyv": { "version": "4.2.9", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.9.tgz", @@ -14495,6 +14703,12 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "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 + }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -14859,6 +15073,30 @@ "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", "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" + }, + "dependencies": { + "@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" + } + } + } + }, "nock": { "version": "13.2.4", "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.4.tgz", @@ -17077,6 +17315,23 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "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" + }, + "dependencies": { + "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 + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -18034,6 +18289,20 @@ } } }, + "sinon": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.3.tgz", + "integrity": "sha512-si3geiRkeovP7Iel2O+qGL4NrO9vbMf3KsrJEi0ghP1l5aBkB5UxARea5j0FUsSqH3HLBh0dQPAyQ8fObRUqHw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -18585,6 +18854,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", diff --git a/package.json b/package.json index 39eb5b88..d615114d 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "nyc": "^15.1.0", "selenium-webdriver": "^4.1.1", "semantic-release": "^19.0.2", + "sinon": "^15.0.3", "uuid": "^8.3.2" } } diff --git a/test/end-to-end/vehicle.js b/test/end-to-end/vehicle.js index 5153770f..523f18b9 100644 --- a/test/end-to-end/vehicle.js +++ b/test/end-to-end/vehicle.js @@ -20,16 +20,20 @@ const getVehicle = async function(brand, scope) { }; test.before(async(t) => { - const [volt, ford] = await Promise.all([ + const [volt, ford, kia] = await Promise.all([ getVehicle('CHEVROLET', DEFAULT_SCOPES), getVehicle('FORD', [ 'required:control_charge', 'required:control_security', ]), + getVehicle('KIA', [ + 'required:read_charge', + 'required:control_charge', + ]), ]); smartcar.setApiVersion('1.0'); - t.context = {volt, ford}; + t.context = {volt, ford, kia}; }); test('vehicle vin', async(t) => { @@ -457,6 +461,18 @@ test('vehicle request - override auth header', async(t) => { }); }); +test('vehicle request - get charge limit', async(t) => { + const response = await t.context.kia.getChargeLimit(); + + t.is(typeof response.limit, 'number'); +}); + +test('vehicle request - set charge limit', async(t) => { + const response = await t.context.kia.setChargeLimit(0.9); + + t.is(response.status, 'success'); +}); + test.after.always('vehicle disconnect', async(t) => { const response = await t.context.volt.disconnect(); t.deepEqual( diff --git a/test/unit/lib/vehicle.js b/test/unit/lib/vehicle.js index baf286b6..ddf38c44 100644 --- a/test/unit/lib/vehicle.js +++ b/test/unit/lib/vehicle.js @@ -2,6 +2,7 @@ const nock = require('nock'); const test = require('ava'); +const sinon = require('sinon'); const Vehicle = require('../../../lib/vehicle'); const {USER_AGENT} = require('../../../lib/util'); @@ -297,7 +298,7 @@ test('request - override non-sc headers', async function(t) { t.is(response.meta.requestId, 'requestId'); }); -test('request - rate limit ', async function(t) { +test('request - rate limit', async function(t) { const retryAfter = new Date().valueOf(); t.context.n = nock( `https://api.smartcar.com/v${vehicle.version}/vehicles/${VID}`, @@ -309,3 +310,43 @@ test('request - rate limit ', async function(t) { const error = await t.throwsAsync(vehicle.odometer()); t.is(error.retryAfter, String(retryAfter)); }); + +test('request - get charge limit', async function(t) { + sinon.restore(); // clear all spys + + t.context.n = nocks + .base() + .get('/charge/limit') + .reply(200, {limit: 0.7}, {'sc-request-id': 'requestId'}); + + const serviceRequestSpy = sinon.spy(vehicle.service, 'request'); + + const response = await vehicle.getChargeLimit(); + + t.true(serviceRequestSpy.calledOnceWith('get', 'charge/limit')); + t.is(response.meta.requestId, 'requestId'); + t.is(response.limit, 0.7); + t.true(t.context.n.isDone()); +}); + +test('request - set charge limit', async function(t) { + sinon.restore(); // clear all spys + + t.context.n = nocks + .base() + .post('/charge/limit') + .reply(200, {}, {'sc-request-id': 'requestId'}); + + const chargeLimit = 0.6; + const serviceRequestSpy = sinon.spy(vehicle.service, 'request'); + const response = await vehicle.setChargeLimit(chargeLimit); + + t.is(response.meta.requestId, 'requestId'); + t.true(serviceRequestSpy.calledOnce); + t.true( + serviceRequestSpy.calledWith( + 'post', 'charge/limit', sinon.match({body: {limit: String(chargeLimit)}}), + ), + ); + t.true(t.context.n.isDone()); +});