Skip to content

Commit

Permalink
fix: improve the batch method for BSE (#156)
Browse files Browse the repository at this point in the history
* fix: improve the batch method for BSE

* chore: comment + test fix

* chore: contribute to coverage

* chore: run tests only once through cover

* chore: tussle with code coverage
  • Loading branch information
s-ashwinkumar authored Jan 20, 2023
1 parent 06ff733 commit 72e06d7
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 39 deletions.
13 changes: 5 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,24 @@ language:
- node_js

node_js:
- '16'
- '14'
- '12'
- "16"
- "14"
- "12"

before_install:
- npm install -g [email protected]

cache:
directories:
- '$HOME/.npm'
- '.eslintcache'
- "$HOME/.npm"
- ".eslintcache"

if: tag IS blank # do not build tags

notifications:
slack:
secure: "CHS39tAvw6WiIN8cYSyE3QT2PVeFdrHszT/00kU3pb1BH5Ec5JYx5U7bMrVf3yq3GQC/wxBhXs4E119LwZM0n04CGUOshShqSkLeUf9RfWYlqx2Qw2+tT8sOi+OXCzE+yaG3Yt+TWFqKyC5t0A9jZX6cdJbcBaKX2wJiOyI/HiTpXHXrJgeeflxRe03KDpIfpmWgpMjnouZ6rKMnP30H+CG4Ya5uouM/Sv5flgJ+1VnZo/kB89hQ4CELr3bBfxSW4lCS1Tmg/z8w059D2nsn7wiMols3Qgw4FJu773K03fyLGoV4JshxA9lvnLt/Vy+azDNEBP5drQeQ7l8GMrLAPIEN8oGbuH9+TyYoxj0P38Kx4hzlW3owGs1U2+wCuYCq2b58oGTYonKnynFV4Pi8f94uBWd6ziIJoKhwx6MsJzKIt/6T91QWjWozOpF9uGy81ZfR3WHU/gnIyWDTJsLnB7nFA5z9V3/K3Orj5tlVr7iZbCUhA9v6XMYTpyyxjoMtBjVad2IztaWXZIZ97Xx7WBkGS9lvFZIqgHMYERb/On/4bEEXdPlzyJxwwlPBNvPv7enVAsYjPJJ58CQ42fuYkMYZlNcTGfYz9Nw/K64ocMidfdMKvdFD1w6Cw/U1HkQ0SZssy6yEb1BpzdBfMbsUDnh0OJffUpeGp402XOwUNT4="


install:
- npm ci
- firefox -headless &
Expand All @@ -38,8 +37,6 @@ script:
- npm run docs
- test -z "$(git diff --name-only | grep '^doc/readme.md$')"

- npm run test:unit
- npm run test:e2e
- npm run cover

after_success:
Expand Down
12 changes: 7 additions & 5 deletions lib/smartcar-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,21 @@ const buildMeta = (headers) => {
};

const getNameFromPath = (path) => {
// Using this constant just for the ones with nested path.
// Using this constant for edge cases.
// '/' should have a method name of 'attributes'
// '/tires/pressure' should be tirePressure and NOT tiresPressure
const BATCH_PATH_TO_ATTRIBUTE = {
'/battery/capacity': 'batteryCapacity',
'/engine/oil': 'engineOil',
'/tires/pressure': 'tirePressure',
'/': 'attributes',
};
if (BATCH_PATH_TO_ATTRIBUTE[path]) {
return BATCH_PATH_TO_ATTRIBUTE[path];
}

// For non nested path, it is just everything after '/'
return path.replace('/', '');
// For everything else camelCase method from lodash works
// Examples: '/battery/capacity', '/engine/oil', '/odometer', '/tesla/speedometer'
// converts to 'batteryCapacity', 'engineOil', 'odometer', 'teslaSpeedometer'
return _.camelCase(path);
};
const buildBatchResponse = (body, headers) => {
const batchResponse = {};
Expand Down
14 changes: 2 additions & 12 deletions test/end-to-end/auth-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,15 @@ test('exchangeRefreshToken', async(t) => {
const client = new smartcar.AuthClient(getAuthClientParams());
const code = await runAuthFlow(client.getAuthUrl(DEFAULT_SCOPES));

const oldAccess = await client.exchangeCode(code);
const newAccess = await client.exchangeRefreshToken(oldAccess.refreshToken);
const exchagedTokens = await client.exchangeCode(code);

t.deepEqual(
_.xor(_.keys(newAccess), [
_.xor(_.keys(exchagedTokens), [
'accessToken',
'expiration',
'refreshExpiration',
'refreshToken',
]),
[],
);

const error = await t.throwsAsync(
client.exchangeRefreshToken(oldAccess.refreshToken),
);
const expectedMessage =
'invalid_grant:undefined - Invalid or expired refresh token.';
t.is(error.message, expectedMessage);

t.is(error.type, 'invalid_grant');
});
24 changes: 24 additions & 0 deletions test/unit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,27 @@ test('getCompatibility - with test_mode true [deprecated]', async function(t) {
t.is(response.pizza, 'pasta');
t.true(n.isDone());
});

test('getCompatibility - with test_mode false [deprecated]', async function(t) {
const vin = 'fake_vin';
const scope = ['read_location', 'read_odometer'];
const path = '/compatibility?vin=fake_vin&'
+ 'scope=read_location%20read_odometer&country=US&'
+ 'mode=live';
const n = nock('https://api.smartcar.com/v6.6/')
.get(path)
.matchHeader('Authorization', 'Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0')
.reply(200, {
pizza: 'pasta',
});

const response = await smartcar.getCompatibility(vin, scope, 'US', {
clientId: 'clientId',
clientSecret: 'clientSecret',
version: '6.6',
testMode: false,
});

t.is(response.pizza, 'pasta');
t.true(n.isDone());
});
13 changes: 11 additions & 2 deletions test/unit/lib/auth-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ test('constructor - client id, secret and redirect url errors', function(t) {
t.is(error.message, message);
});

test('constructor - test_mode true [deprecated]', function(t) {
const client = new AuthClient({
test('constructor - test_mode attribute [deprecated]', function(t) {
let client = new AuthClient({
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
redirectUri: 'https://insurance.co/callback',
Expand All @@ -64,6 +64,15 @@ test('constructor - test_mode true [deprecated]', function(t) {
t.is(client.redirectUri, 'https://insurance.co/callback');
t.is(client.mode, 'test');
t.true('service' in client);

client = new AuthClient({
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
redirectUri: 'https://insurance.co/callback',
testMode: false,
});

t.is(client.mode, 'live');
});

test('constructor - mode invalid input errors', function(t) {
Expand Down
85 changes: 73 additions & 12 deletions test/unit/lib/vehicle.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,28 @@ test('vehicle permissions', async(t) => {
});

test('batch - success', async function(t) {
const paths = ['/odometer', '/engine/oil', '/location'];
// We are intentionally testing multiple routes here to make sure dynamic mapping
// of function name is working for all cases. Please do not remove the paths being
// asserted here.
const paths = [
'/', '/odometer', '/engine/oil', 'tires/pressure', 'tesla/speedometer',
];
const requestBody = {
requests: [
{
path: '/',
},
{
path: '/odometer',
},
{
path: '/engine/oil',
},
{
path: '/location',
path: 'tires/pressure',
},
{
path: 'tesla/speedometer',
},
],
};
Expand All @@ -137,29 +148,60 @@ test('batch - success', async function(t) {
'sc-unit-system': 'imperial',
'sc-data-age': '2018-05-04T07:20:50.844Z',
},
path: '/odometer',
path: '/',
code: 200,
body: {
distance: 32768,
id: '36ab27d0-fd9d-4455-823a-ce30af709ffc',
make: 'TESLA',
model: 'Model S',
year: 2014,
},
},
{
headers: {'sc-data-age': '2018-05-04T07:20:50.844Z'},
path: '/engine/oil',
headers: {
'sc-unit-system': 'imperial',
'sc-data-age': '2018-05-04T07:20:50.844Z',
},
path: '/odometer',
code: 200,
body: {
lifeRemaining: 0.1123,
distance: 32768,
},
},
{
headers: {'sc-unit-system': 'imperial'},
path: '/location',
path: '/engine/oil',
code: 501,
body: {
error: 'vehicle_not_capable_error',
message: 'Vehicle is not capable of performing request.',
},
},
{
headers: {
'sc-unit-system': 'imperial',
'sc-data-age': '2018-05-04T07:20:50.844Z',
},
path: '/tires/pressure',
code: 200,
body: {
backLeft: 219.3,
backRight: 219.3,
frontLeft: 219.3,
frontRight: 219.3,
},
},
{
headers: {
'sc-unit-system': 'imperial',
'sc-data-age': '2018-05-04T07:20:50.844Z',
},
path: '/tesla/speedometer',
code: 200,
body: {
speed: 84.32,
},
},
],
};
t.context.n = nocks
Expand All @@ -175,15 +217,34 @@ test('batch - success', async function(t) {
t.is(odometer.meta.unitSystem, 'imperial');
t.is(odometer.meta.dataAge.valueOf(), 1525418450844);

const engineOil = response.engineOil();
t.is(engineOil.lifeRemaining, 0.1123);
t.is(engineOil.meta.dataAge.valueOf(), 1525418450844);
const attributes = response.attributes();
t.is(attributes.make, 'TESLA');
t.is(attributes.model, 'Model S');
t.is(attributes.year, 2014);
t.is(attributes.meta.requestId, 'requestId');
t.is(attributes.meta.unitSystem, 'imperial');
t.is(attributes.meta.dataAge.valueOf(), 1525418450844);

const expectedMessage = 'vehicle_not_capable_error:undefined - '
+ 'Vehicle is not capable of performing request.';
const error = t.throws(() => response.location());
const error = t.throws(() => response.engineOil());
t.is(error.message, expectedMessage);
t.is(error.type, 'vehicle_not_capable_error');

const tirePressure = response.tirePressure();
t.is(tirePressure.backLeft, 219.3);
t.is(tirePressure.backRight, 219.3);
t.is(tirePressure.frontLeft, 219.3);
t.is(tirePressure.frontRight, 219.3);
t.is(attributes.meta.requestId, 'requestId');
t.is(attributes.meta.unitSystem, 'imperial');
t.is(attributes.meta.dataAge.valueOf(), 1525418450844);

const speedometer = response.teslaSpeedometer();
t.is(speedometer.speed, 84.32);
t.is(attributes.meta.requestId, 'requestId');
t.is(attributes.meta.unitSystem, 'imperial');
t.is(attributes.meta.dataAge.valueOf(), 1525418450844);
});

test('batch - error', async function(t) {
Expand Down

0 comments on commit 72e06d7

Please sign in to comment.