eightsleep
Version:
eightsleep api client
593 lines (570 loc) • 18 kB
text/typescript
import EightSleep, { OptsType } from '..'
import MockEightAppAPIServer, {
PORT as appAPIServerPort,
} from './__fixtures__/MockEightAppAPIServer'
import MockEightClientAPIServer, {
PORT as clientAPIServerPort,
} from './__fixtures__/MockEightClientAPIServer'
import { Sides } from './../EightSleepAppApi'
const email = process.env.EMAIL || 'owner@email.com'
const password = process.env.PASSWORD || 'ownerpassword'
const oauthClient = {
id: process.env.OAUTH_CLIENT_ID || '1234567890abcdef1234567890123456',
secret:
process.env.OAUTH_CLIENT_SECRET ||
'1234567890123456789012345678901234567890234567890123456789012345',
}
function createEightSleep(customAuth?: {
email: OptsType['email']
password: OptsType['password']
}) {
const eightSleep = new EightSleep({
email: customAuth?.email || email,
password: customAuth?.password || password,
oauthClient,
})
if (!process.env.REAL_API) {
// hack so request hit mock api servers
// @ts-ignore
eightSleep.host = `http://localhost:${clientAPIServerPort}`
const appApi = eightSleep.getAppApiClient()
// @ts-ignore
appApi.host = `http://localhost:${appAPIServerPort}`
}
return eightSleep
}
describe('eightsleep', () => {
const clientServer = new MockEightClientAPIServer()
const appServer = new MockEightAppAPIServer()
beforeEach(async () => {
await clientServer.start()
await appServer.start()
})
afterEach(async () => {
await clientServer.stop()
await appServer.stop()
})
it('should not login with invalid credentials', async () => {
const e = createEightSleep({
email,
password: password + password,
})
await expect(async () => {
await e.login()
}).rejects.toMatchInlineSnapshot(`[StatusCodeError: unexpected status]`)
})
it('should login', async () => {
const e = createEightSleep()
const session = await e.login()
expect(session).toMatchInlineSnapshot(`
Object {
"expirationDate": 3020-06-30T05:40:30.880Z,
"token": "1234567890abcdef1234567890abcdef-1234567890abcdef1234567890abcdef",
"userId": "1234567890abcdef123456789011111",
}
`)
})
it('should get me', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getMe()
expect(me).toMatchInlineSnapshot(`
Object {
"currentDevice": Object {
"id": "123456789012345678901234",
"side": "left",
},
"devices": Array [
"123456789012345678901234",
],
"dob": 1900-04-01T08:34:30.000Z,
"email": "owner@email.com",
"emailVerified": true,
"features": Array [
"warming",
"cooling",
],
"firstName": "Owner",
"gender": "male",
"lastName": "Person",
"notifications": Object {
"sessionProcessed": true,
"weeklyReportEmail": true,
},
"sharingMetricsFrom": Array [
"1234567890abcdef123456789022222",
],
"sharingMetricsTo": Array [
"1234567890abcdef123456789022222",
],
"timezone": "America/Los_Angeles",
"userId": "1234567890abcdef123456789011111",
"zip": 11111,
}
`)
})
it('should get a device', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getDevice('123456789012345678901234')
expect(me).toMatchInlineSnapshot(`
Object {
"deviceId": "123456789012345678901234",
"features": Array [
"warming",
"cooling",
],
"firmwareUpdated": true,
"firmwareUpdating": false,
"firmwareVersion": "2.3.18.0",
"hasWater": true,
"hubInfo": "12345-0001-A01-AABBCCDD",
"lastHeard": 2020-06-21T03:36:57.441Z,
"lastLowWater": 2020-03-04T21:10:38.334Z,
"lastPrime": 2020-03-04T21:11:23.746Z,
"ledBrightnessLevel": 30,
"leftHeatingDuration": 0,
"leftHeatingLevel": -15,
"leftKelvin": Object {
"active": false,
"alarms": Array [],
"currentActivity": "off",
"currentTargetLevel": 0,
"level": 0,
"scheduleProfiles": Array [
Object {
"enabled": true,
"startLocalTime": "22:00:00",
"weekDays": Object {
"friday": true,
"monday": true,
"saturday": true,
"sunday": true,
"thursday": true,
"tuesday": true,
"wednesday": true,
},
},
],
"targetLevels": Array [
-10,
-10,
-20,
],
},
"leftNowHeating": false,
"leftSchedule": Object {
"daysUTC": Object {
"friday": false,
"monday": false,
"saturday": false,
"sunday": false,
"thursday": false,
"tuesday": false,
"wednesday": false,
},
"durationSeconds": 0,
"enabled": false,
"startUTCHour": 0,
"startUTCMinute": 0,
},
"leftTargetHeatingLevel": 0,
"leftUserId": "1234567890abcdef123456789011111",
"location": Array [
-122.32171311,
37.55987324,
],
"mattressInfo": Object {
"brand": null,
"eightMattress": null,
"firstUsedDate": null,
},
"needsPriming": false,
"online": true,
"ownerId": "1234567890abcdef123456789011111",
"priming": false,
"rightHeatingDuration": 3575,
"rightHeatingLevel": 21,
"rightKelvin": Object {
"active": true,
"alarms": Array [],
"currentActivity": "schedule",
"currentTargetLevel": 50,
"level": 50,
"phases": Array [
Object {
"active": false,
"operation": "on",
"position": 0,
},
Object {
"active": true,
"level": 50,
"operation": "temperature",
"position": 0,
},
Object {
"active": false,
"level": 10,
"operation": "temperature",
"position": 0.33,
},
Object {
"active": false,
"level": 30,
"operation": "temperature",
"position": 0.67,
},
Object {
"active": false,
"operation": "off",
"position": 1,
},
],
"scheduleProfiles": Array [
Object {
"enabled": true,
"startLocalTime": "21:30:00",
"weekDays": Object {
"friday": true,
"monday": true,
"saturday": true,
"sunday": true,
"thursday": true,
"tuesday": true,
"wednesday": true,
},
},
],
"targetLevels": Array [
50,
10,
30,
],
},
"rightNowHeating": true,
"rightSchedule": Object {
"daysUTC": Object {
"friday": false,
"monday": false,
"saturday": false,
"sunday": false,
"thursday": false,
"tuesday": false,
"wednesday": false,
},
"durationSeconds": 0,
"enabled": false,
"startUTCHour": 0,
"startUTCMinute": 0,
},
"rightTargetHeatingLevel": 50,
"rightUserId": "1234567890abcdef123456789022222",
"sensorInfo": Object {
"connected": true,
"hwRevision": "A01",
"label": "12345-0001-A01-00000000",
"lastConnected": 2020-06-21T03:36:57.441Z,
"partNumber": "12345",
"serialNumber": "00000000",
"sku": "0001",
"skuName": "queen",
},
"timezone": "America/Los_Angeles",
}
`)
})
it('should get a device', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getDevice('123456789012345678901234', {
filter: 'sensorInfo',
})
expect(me).toMatchInlineSnapshot(`
Object {
"sensorInfo": Object {
"connected": true,
"hwRevision": "A01",
"label": "12345-0001-A01-00000000",
"lastConnected": "2020-06-21T03:36:57.441Z",
"partNumber": "12345",
"serialNumber": "00000000",
"sku": "0001",
"skuName": "queen",
},
}
`)
})
it('should get a device w/ filter', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getMe()
const device = await e.getDevice(me.currentDevice.id, {
filter: 'deviceId',
})
expect(device).toMatchInlineSnapshot(`
Object {
"deviceId": "123456789012345678901234",
}
`)
})
it('should get owner user by id', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getUser('1234567890abcdef123456789011111')
expect(me).toMatchInlineSnapshot(`
Object {
"currentDevice": Object {
"id": "123456789012345678901234",
"side": "left",
},
"devices": Array [
"123456789012345678901234",
],
"dob": 1900-04-01T08:34:30.000Z,
"email": "owner@email.com",
"emailVerified": true,
"features": Array [
"warming",
"cooling",
],
"firstName": "Owner",
"gender": "male",
"lastName": "Person",
"notifications": Object {
"sessionProcessed": true,
"weeklyReportEmail": true,
},
"sharingMetricsFrom": Array [
"1234567890abcdef123456789022222",
],
"sharingMetricsTo": Array [
"1234567890abcdef123456789022222",
],
"timezone": "America/Los_Angeles",
"userId": "1234567890abcdef123456789011111",
"zip": 11111,
}
`)
})
it('should get partner user by id', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getUser('1234567890abcdef123456789022222')
expect(me).toMatchInlineSnapshot(`
Object {
"currentDevice": Object {
"id": "123456789012345678901234",
"side": "right",
},
"devices": Array [
"123456789012345678901234",
],
"dob": 1900-10-26T08:34:30.000Z,
"email": "partner@email.com",
"emailVerified": true,
"features": Array [
"warming",
"cooling",
],
"firstName": "Partner",
"gender": "female",
"lastName": "Person",
"notifications": Object {
"sessionProcessed": true,
"weeklyReportEmail": true,
},
"sharingMetricsFrom": Array [
"1234567890abcdef123456789011111",
],
"sharingMetricsTo": Array [
"1234567890abcdef123456789011111",
],
"timezone": "America/Los_Angeles",
"userId": "1234567890abcdef123456789022222",
"zip": 11111,
}
`)
})
it('should get oauth tokens', async () => {
const e = createEightSleep()
await e.login()
const oauth = await e.oauth()
expect(oauth).toMatchInlineSnapshot(`
Object {
"accessToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZiIsImlzcyI6ImVpZ2h0OnYxIiwiYXVkIjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJzdWIiOiJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYiIsImV4cCI6MTU5NDU4ODE2OSwic2NvIjpbInJlYWRfc2xlZXAiLCJ3cml0ZV9zbGVlcCIsInJlYWRfZGV2aWNlIiwid3JpdGVfZGV2aWNlIl0sInR5cCI6ImF1dGgiLCJpYXQiOjE1OTQ1MDE3Njl9.2odxApSPTrELwtTlIRtJeek8ke96sWcbxvDGJLcgEehXeNRGIrUPnqwHLjI6gsyregEJ6wetF8qtHB7MCu_b-A",
"expiresIn": 2020-07-11T21:10:38.035Z,
"refreshToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZiIsImlzcyI6ImVpZ2h0OnYxIiwiYXVkIjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJzdWIiOiJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYiIsImV4cCI6MTU5NDU4ODE2OSwic2NvIjpbInJlYWRfc2xlZXAiLCJ3cml0ZV9zbGVlcCIsInJlYWRfZGV2aWNlIiwid3JpdGVfZGV2aWNlIl0sInR5cCI6ImF1dGgiLCJpYXQiOjE1OTQ1MDE3Njl9.l3XCxV4Sy_Bbg8398p8I5a4sAgiVt8pU2gxTLRpIrlfMrf0IGeRsvIVWC4UzcWUlwfn-RwANnAJ6Y-38K7yoAA",
"tokenType": "bearer",
}
`)
})
describe('appApi', () => {
it('should get device status', async () => {
const e = createEightSleep()
await e.login()
const appApi = e.getAppApiClient()
const status = await appApi.getDeviceStatus('123456789012345678901234')
expect(status).toMatchInlineSnapshot(`
Object {
"left": Object {
"currentActivity": "off",
"currentLevel": -29,
"currentTargetLevel": 0,
"version": 2,
},
"right": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
}
`)
})
it('should turn device side off', async () => {
const e = createEightSleep()
await e.login()
const appApi = e.getAppApiClient()
const status = await appApi.setDeviceSideOff(
'123456789012345678901234',
Sides.LEFT,
)
expect(status).toMatchInlineSnapshot(`
Object {
"left": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
"right": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
}
`)
})
it('should turn device side on', async () => {
const e = createEightSleep()
await e.login()
const appApi = e.getAppApiClient()
const status = await appApi.setDeviceSideOn(
'123456789012345678901234',
Sides.LEFT,
)
expect(status).toMatchInlineSnapshot(`
Object {
"left": Object {
"currentActivity": "schedule",
"currentLevel": -31,
"currentTargetLevel": 10,
"smartTemperature": Object {
"bedLocalTime": "00:00:00",
"bedTimeLevel": 10,
"currentPhase": "bedtime",
"finalSleepLevel": -10,
"initialSleepLevel": -10,
},
"version": 2,
},
"right": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
}
`)
})
it('should set device side temperature (while off)', async () => {
const e = createEightSleep()
await e.login()
const appApi = e.getAppApiClient()
await appApi.setDeviceSideOff('123456789012345678901234', Sides.LEFT)
const status = await appApi.setDeviceSideLevel(
'123456789012345678901234',
Sides.LEFT,
10,
)
expect(status).toMatchInlineSnapshot(`
Object {
"left": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
"right": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
}
`)
})
it('should set device side temperature (while on)', async () => {
const e = createEightSleep()
await e.login()
const appApi = e.getAppApiClient()
await appApi.setDeviceSideOn('123456789012345678901234', Sides.LEFT)
const status = await appApi.setDeviceSideLevel(
'123456789012345678901234',
Sides.LEFT,
10,
)
expect(status).toMatchInlineSnapshot(`
Object {
"left": Object {
"currentActivity": "schedule",
"currentLevel": -31,
"currentTargetLevel": 10,
"smartTemperature": Object {
"bedLocalTime": "00:00:00",
"bedTimeLevel": 10,
"currentPhase": "bedtime",
"finalSleepLevel": -10,
"initialSleepLevel": -10,
},
"version": 2,
},
"right": Object {
"currentActivity": "off",
"currentLevel": -33,
"currentTargetLevel": 0,
"version": 2,
},
}
`)
})
if (process.env.REAL_API) {
it.only('test', async () => {
const e = createEightSleep()
await e.login()
const me = await e.getMe()
const appApi = e.getAppApiClient()
const json = await e.getDevice(me.currentDevice.id)
// const json = await appApi.get(
// 'v1/devices/' +
// me.currentDevice.id +
// '/metrics/ambient?granularity=minute&from=2020-07-19T10:20:59.495Z&scope=humidity&scope=roomTemperature',
// {
// headers: {
// 'user-agent': 'Eight/786 CFNetwork/1125.2 Darwin/19.4.0',
// 'accept-language': 'en-us',
// 'accept-encoding': 'gzip, deflate, br',
// accept: 'application/json',
// 'user-id': '1234567890abcdef123456789011111',
// 'session-token':
// '1234567890abcdef1234567890abcdef-1234567890abcdef1234567890abcdef',
// },
// },
// )
console.log(JSON.stringify(json, null, 2))
})
}
})
})