bluelinky2
Version:
An unofficial nodejs API wrapper for Hyundai bluelink
425 lines (361 loc) • 12 kB
text/typescript
/* eslint-disable */
import got from 'got';
import AmericanVehicle from '../src/vehicles/american.vehicle';
import { AmericanController } from '../src/controllers/american.controller';
import EuropeanVehicle from '../src/vehicles/european.vehicle';
import { EuropeanController } from '../src/controllers/european.controller';
import CanadianVehicle from '../src/vehicles/canadian.vehicle';
import { CanadianController } from '../src/controllers/canadian.controller';
import AMERICAN_STATUS_MOCK from './mock/americanStatus.json';
import EUROPE_STATUS_MOCK from './mock/europeStatus.json';
jest.mock('got');
const gotMock = got as any;
const referenceMap = {
US: {
controller: AmericanController,
vehicle: AmericanVehicle,
},
EU: {
controller: EuropeanController,
vehicle: EuropeanVehicle,
},
CA: {
controller: CanadianController,
vehicle: CanadianVehicle,
},
};
const getVehicle = (region: string) => {
const Vehicle = referenceMap[region].vehicle;
const Controller = referenceMap[region].controller;
const controller = new Controller({
username: 'testuser@gmail.com',
password: 'test',
region: region,
autoLogin: true,
brand: 'hyundai',
pin: '1234',
vin: '4444444444444',
vehicleId: undefined,
});
const vehicle = new Vehicle(
{
nickname: 'Jest is best',
name: 'Jest is best',
vin: '444',
regDate: 'test',
brandIndicator: 'H',
regId: '123123',
generation: '2',
},
controller
);
return vehicle;
};
describe('AmericanVehicle', () => {
const vehicle = getVehicle('US');
it('define new vehicle', () => {
expect(vehicle.nickname()).toEqual('Jest is best');
});
it('refresh expired access token', async () => {
// create session with expired access token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Math.floor(Date.now() / 1000) - 100,
};
// mock token request
gotMock.mockReturnValueOnce({
body: {
access_token: 'JEST_TOKEN',
refresh_token: 'JEST_TOKEN',
expires_in: 10,
},
json: true,
statusCode: 200,
});
const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token refreshed');
// should update access token
expect(vehicle.controller.session.accessToken).toEqual('JEST_TOKEN');
expect(vehicle.controller.session.tokenExpiresAt).toBeGreaterThan(
Math.floor(Date.now() / 1000)
);
expect(vehicle.controller.session.tokenExpiresAt).toBeLessThan(
Math.floor(Date.now() / 1000 + 20)
);
});
it('call lock commmand', async () => {
// default session with a valid token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Date.now() / 1000 + 300,
};
gotMock.mockReturnValueOnce({
body: JSON.stringify({}),
statusCode: 200,
});
const response = await vehicle.lock();
expect(response).toEqual('Lock successful');
});
it('call status commmand', async () => {
gotMock.mockReturnValueOnce({
body: JSON.stringify({ vehicleStatus: AMERICAN_STATUS_MOCK }),
statusCode: 200,
});
const response = await vehicle.status({ parsed: true });
expect(response.engine.range).toEqual(AMERICAN_STATUS_MOCK.dte.value);
});
});
describe('CanadianVehicle', () => {
const vehicle: CanadianVehicle = getVehicle('CA');
it('define new vehicle', () => {
expect(vehicle.nickname()).toEqual('Jest is best');
});
it('refresh expired access token', async () => {
// create session with expired access token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Date.now() / 1000,
controlTokenExpiresAt: 0,
};
// mock token request
gotMock.mockReturnValueOnce({
body: JSON.stringify({
access_token: 'JEST_TOKEN',
refresh_token: 'JEST_TOKEN',
expires_in: 10,
}),
statusCode: 200,
});
const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token refreshed');
// should update access token
expect(vehicle.controller.session.accessToken).toEqual('JEST_TOKEN');
expect(vehicle.controller.session.tokenExpiresAt).toBeGreaterThan(Math.floor(Date.now() / 1000));
expect(vehicle.controller.session.tokenExpiresAt).toBeLessThan(Math.floor(Date.now() / 1000 + 20));
});
it('call lock commmand', async () => {
// default session with a valid token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Date.now() / 1000 + 300,
};
gotMock.mockReturnValueOnce({
body: {
result: {
pAuth: 'test',
},
responseHeader: {
responseCode: 0,
},
},
statusCode: 200,
json: true,
});
gotMock.mockReturnValueOnce({
body: {
responseHeader: {
responseCode: 0,
},
},
statusCode: 200,
json: true,
});
const response = await vehicle.lock();
expect(response).toEqual('Lock successful');
});
it('call start command succesfully', async () => {
// default session with a valid token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Date.now() / 1000 + 300,
};
gotMock.mockReturnValueOnce({
body: {
result: {
pAuth: 'test',
},
responseHeader: {
responseCode: 0,
},
},
statusCode: 200,
json: true,
});
gotMock.mockReturnValueOnce({
body: {
responseHeader: {
responseCode: 0,
},
},
statusCode: 200,
json: true,
});
const response = await vehicle.start({
airCtrl: false,
igniOnDuration: 10,
airTempvalue: 70,
defrost: false,
heating1: false,
});
expect(response).toEqual('Vehicle started!');
});
it('call start command with error', async () => {
// default session with a valid token
vehicle.controller.session = {
accessToken: 'JEST_TOKEN',
refreshToken: 'JEST_TOKEN',
tokenExpiresAt: Date.now() / 1000 + 300,
};
gotMock.mockReturnValueOnce({
body: {
result: {
pAuth: 'test',
},
responseHeader: {
responseCode: 0,
},
},
statusCode: 200,
json: true,
});
gotMock.mockReturnValueOnce({
body: {
responseHeader: {
responseCode: 1,
responseDesc: 'failed'
},
},
statusCode: 200,
json: true,
});
const response = await vehicle.start({
airCtrl: false,
igniOnDuration: 10,
airTempvalue: 70,
defrost: false,
heating1: false,
});
expect(response).toEqual('Failed to start vehicle');
});
});
describe('EuropeanVehicle', () => {
const vehicle = getVehicle('EU');
it('define new vehicle', () => {
expect(vehicle.nickname()).toEqual('Jest is best');
});
it('refresh expired access token', async () => {
// create session with expired access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000,
controlTokenExpiresAt: 0,
};
// mock token request
gotMock.mockReturnValueOnce({
body: JSON.stringify({ access_token: 'AAAAAAAA', expires_in: 10 }),
statusCode: 200,
});
gotMock.mockClear();
const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token refreshed');
// should update access token
expect(vehicle.controller.session.accessToken).toEqual('Bearer AAAAAAAA');
expect(vehicle.controller.session.tokenExpiresAt).toBeGreaterThan(
Math.floor(Date.now() / 1000)
);
expect(vehicle.controller.session.tokenExpiresAt).toBeLessThan(
Math.floor(Date.now() / 1000 + 20)
);
const gotArgs = gotMock.mock.calls[0];
expect(gotArgs[0]).toMatch(/token$/);
expect(gotArgs[1].body).toContain('grant_type=refresh_token');
expect(gotArgs[1].body).toContain('refresh_token=' + vehicle.controller.session.refreshToken);
});
it('not refresh active access token', async () => {
// create session with active access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: 0,
};
gotMock.mockClear();
const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token not expired, no need to refresh');
// should not call got
expect(gotMock.mock.calls).toHaveLength(0);
});
// FIXME: this test it borked with refactor
// it('refresh expired control token', async () => {
// // create session with active access token and expired control token
// vehicle.controller.session = {
// accessToken: 'Bearer eyASKLFABADFJ',
// refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
// controlToken: 'Bearer eyASWAWJPLZL',
// deviceId: 'aaaa-bbbb-cccc-eeee',
// tokenExpiresAt: Date.now() / 1000 + 20,
// controlTokenExpiresAt: Date.now() / 1000 - 10,
// };
// // mock pin request
// gotMock.mockReturnValueOnce({
// body: { controlToken: 'eyASWAWJPLZL', expiresTime: 20 },
// statusCode: 200,
// });
// gotMock.mockClear();
// await vehicle.checkControlToken();
// // should update control token
// expect(vehicle.controller.session.controlToken).toEqual('Bearer eyASWAWJPLZL');
// expect(vehicle.controller.session.controlTokenExpiresAt).toBeGreaterThan(Date.now() / 1000);
// expect(vehicle.controller.session.controlTokenExpiresAt).toBeLessThan(Date.now() / 1000 + 20);
// const gotArgs = gotMock.mock.calls[0];
// expect(gotArgs[0]).toMatch(/pin$/);
// expect(gotArgs[1].headers.Authorization).toEqual(vehicle.controller.session.accessToken);
// expect(gotArgs[1].body.deviceId).toEqual('aaaa-bbbb-cccc-eeee');
// expect(gotArgs[1].body.pin).toEqual('1234');
// });
it('not refresh active control token', async () => {
// create session with active control and access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: Date.now() / 1000 + 10,
};
gotMock.mockClear();
// should not call got
expect(gotMock.mock.calls).toHaveLength(0);
});
// it('call status commmand', async () => {
// // create session with active control and access token
// vehicle.controller.session = {
// accessToken: 'Bearer eyASKLFABADFJ',
// refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
// controlToken: 'Bearer eyASWAWJPLZL',
// deviceId: 'aaaa-bbbb-cccc-eeee',
// tokenExpiresAt: Date.now() / 1000 + 20,
// controlTokenExpiresAt: Date.now() / 1000 + 10,
// };
// // mock the status request
// gotMock.mockReturnValueOnce({
// body: EUROPE_STATUS_MOCK,
// statusCode: 200,
// });
// const response = await vehicle.status({ parsed: true });
// const expected =
// EUROPE_STATUS_MOCK.resMsg.vehicleStatusInfo.vehicleStatus.evStatus.drvDistance[0].rangeByFuel
// .totalAvailableRange.value;
// expect(response.engine.range).toEqual(expected);
// });
});