Skip to content

Commit

Permalink
chore(tests): add jest test framework (#179)
Browse files Browse the repository at this point in the history
* add jest

* configure eslint to respect jest

* add workflow

* add test case

* use npm install

* Update validation.yml

* fix package-lock.json

* move
  • Loading branch information
CFenner committed Aug 14, 2023
1 parent d9b07fc commit 85f230b
Show file tree
Hide file tree
Showing 7 changed files with 4,244 additions and 1,535 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ env:
browser: true
es2021: true
node: true
jest: true
extends:
- standard
parserOptions:
Expand All @@ -12,4 +13,4 @@ globals:
Log: true
rules:
"comma-dangle": ["error", "always-multiline"]

18 changes: 18 additions & 0 deletions .github/workflows/validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,22 @@ jobs:
run: npm clean-install
- name: Validate CSS Sources
run: npm run validate:css
unit:
runs-on: ubuntu-latest
name: 'Unit Tests'
strategy:
matrix:
node-version: [16.x]
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- name: Install Dependencies
run: npm clean-install
- name: Validate JS Sources
run: npm run test

160 changes: 2 additions & 158 deletions node_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,162 +5,6 @@
* MIT Licensed.
*/
const NodeHelper = require('node_helper')
const fs = require('fs')
const path = require('path')
const https = require('https')
const URLSearchParams = require('@ungap/url-search-params')
const api = require('./api')

module.exports = NodeHelper.create({
start: function () {
console.log('Netatmo helper started ...')
this.token = null
this.token_time = null
},
notifications: {
AUTH: 'NETATMO_AUTH',
AUTH_RESPONSE: 'NETATMO_AUTH_RESPONSE',
DATA: 'NETATMO_DATA',
DATA_RESPONSE: 'NETATMO_DATA_RESPONSE',
},
authenticate: function (config) {
const self = this
self.config = config

// TODO: only update if token is invalid

const req = https.request({
hostname: self.config.apiBase,
path: self.config.authEndpoint,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}, self.callbackAuthenticate.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: e.message,
})
})

req.write(new URLSearchParams({
scope: 'read_station',
grant_type: 'password',
username: self.config.username,
password: self.config.password,
client_id: self.config.clientId,
client_secret: self.config.clientSecret,
}).toString())

req.end()
},
loadData: function (config) {
const self = this
self.config = config
if (self.config.mockData === true) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: this.mockData(),
status: 'OK',
})
return
}
if (self.token === null) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: 400,
status: 'INVALID_TOKEN',
message: 'token not set',
})
return
}

const req = https.request({
hostname: self.config.apiBase,
path: self.config.dataEndpoint,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${self.token}`,
},
}, self.callbackData.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: e.message,
status: 'NOTOK',
message: e.message,
})
})
req.end()
},
mockData: function () {
const sample = fs.readFileSync(path.join(__dirname, 'sample', 'sample.json'), 'utf8')
return JSON.parse(sample)
},
callbackAuthenticate: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
console.log('UPDATING TOKEN ' + result.access_token)
self.token = result.access_token
self.token_time = new Date()
// we got a new token, save it to main file to allow it to request the datas
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
status: 'OK',
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
callbackData: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: result.body.devices,
status: 'OK',
})
} else if (response.statusCode === 403) {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'INVALID_TOKEN',
message: result,
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
socketNotificationReceived: function (notification, payload) {
switch (notification) {
case this.notifications.AUTH:
this.authenticate(payload)
break
case this.notifications.DATA:
this.loadData(payload)
break
}
},
})
module.exports = NodeHelper.create(api)
165 changes: 165 additions & 0 deletions node_helper_impl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/* Magic Mirror
* Module: MagicMirror-Netatmo-Module
*
* By Christopher Fenner https://github.com/CFenner
* MIT Licensed.
*/
const fs = require('fs')
const path = require('path')
const https = require('https')
const URLSearchParams = require('@ungap/url-search-params')

module.exports = {
notifications: {
AUTH: 'NETATMO_AUTH',
AUTH_RESPONSE: 'NETATMO_AUTH_RESPONSE',
DATA: 'NETATMO_DATA',
DATA_RESPONSE: 'NETATMO_DATA_RESPONSE',
},
start: function () {
console.log('Netatmo helper started ...')
this.token = null
this.token_time = null
},
authenticate: function (config) {
const self = this
self.config = config

// TODO: only update if token is invalid

const req = https.request({
hostname: self.config.apiBase,
path: self.config.authEndpoint,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}, self.callbackAuthenticate.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: e.message,
})
})

req.write(new URLSearchParams({
scope: 'read_station',
grant_type: 'password',
username: self.config.username,
password: self.config.password,
client_id: self.config.clientId,
client_secret: self.config.clientSecret,
}).toString())

req.end()
},
loadData: function (config) {
const self = this
self.config = config
if (self.config.mockData === true) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: this.mockData(),
status: 'OK',
})
return
}
if (self.token === null) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: 400,
status: 'INVALID_TOKEN',
message: 'token not set',
})
return
}

const req = https.request({
hostname: self.config.apiBase,
path: self.config.dataEndpoint,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${self.token}`,
},
}, self.callbackData.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: e.message,
status: 'NOTOK',
message: e.message,
})
})
req.end()
},
mockData: function () {
const sample = fs.readFileSync(path.join(__dirname, 'sample', 'sample.json'), 'utf8')
return JSON.parse(sample)
},
callbackAuthenticate: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
console.log('UPDATING TOKEN ' + result.access_token)
self.token = result.access_token
self.token_time = new Date()
// we got a new token, save it to main file to allow it to request the datas
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
status: 'OK',
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
callbackData: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: result.body.devices,
status: 'OK',
})
} else if (response.statusCode === 403) {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'INVALID_TOKEN',
message: result,
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
socketNotificationReceived: function (notification, payload) {
switch (notification) {
case this.notifications.AUTH:
this.authenticate(payload)
break
case this.notifications.DATA:
this.loadData(payload)
break
}
},
}
11 changes: 11 additions & 0 deletions node_helper_impl.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const moduleName = 'node_helper_impl'
const moduleUnderTest = require('./' + moduleName + '.js')

describe(moduleName, () => {
test('test notifications map', () => {
expect(moduleUnderTest.notifications).toHaveProperty('AUTH', 'NETATMO_AUTH')
expect(moduleUnderTest.notifications).toHaveProperty('AUTH_RESPONSE', 'NETATMO_AUTH_RESPONSE')
expect(moduleUnderTest.notifications).toHaveProperty('DATA', 'NETATMO_DATA')
expect(moduleUnderTest.notifications).toHaveProperty('DATA_RESPONSE', 'NETATMO_DATA_RESPONSE')
})
})
Loading

0 comments on commit 85f230b

Please sign in to comment.