2020-05-24 09:16:39 -07:00
const data = require ( './stub/data' ) ;
const logger = require ( './stub/logger' ) ;
const zigbeeHerdsman = require ( './stub/zigbeeHerdsman' ) ;
const MQTT = require ( './stub/mqtt' ) ;
const settings = require ( '../lib/util/settings' ) ;
const Controller = require ( '../lib/controller' ) ;
const flushPromises = ( ) => new Promise ( setImmediate ) ;
2020-09-24 09:06:43 -07:00
const stringify = require ( 'json-stable-stringify-without-jsonify' ) ;
2020-05-24 09:16:39 -07:00
2020-10-09 12:40:33 -07:00
const { coordinator , bulb , unsupported , WXKG11LM , remote , ZNCZ02LM } = zigbeeHerdsman . devices ;
2020-05-24 09:16:39 -07:00
zigbeeHerdsman . returnDevices . push ( coordinator . ieeeAddr ) ;
zigbeeHerdsman . returnDevices . push ( bulb . ieeeAddr ) ;
zigbeeHerdsman . returnDevices . push ( unsupported . ieeeAddr ) ;
2020-07-29 14:10:03 -07:00
zigbeeHerdsman . returnDevices . push ( WXKG11LM . ieeeAddr ) ;
2020-08-31 09:48:04 -07:00
zigbeeHerdsman . returnDevices . push ( remote . ieeeAddr ) ;
2020-10-09 12:40:33 -07:00
zigbeeHerdsman . returnDevices . push ( ZNCZ02LM . ieeeAddr ) ;
2020-05-24 09:16:39 -07:00
describe ( 'Bridge' , ( ) => {
let controller ;
2021-02-06 08:32:20 -07:00
let mockRestart ;
2020-05-24 09:16:39 -07:00
beforeEach ( async ( ) => {
2020-07-28 13:12:22 -07:00
MQTT . mock . reconnecting = false ;
2020-05-24 09:16:39 -07:00
data . writeDefaultConfiguration ( ) ;
2021-03-09 11:50:05 -07:00
settings . reRead ( ) ;
2020-05-24 09:16:39 -07:00
settings . set ( [ 'advanced' , 'legacy_api' ] , false ) ;
data . writeDefaultState ( ) ;
logger . info . mockClear ( ) ;
logger . warn . mockClear ( ) ;
2020-07-28 13:12:22 -07:00
logger . setTransportsEnabled ( false ) ;
2020-05-24 09:16:39 -07:00
MQTT . publish . mockClear ( ) ;
2020-06-13 08:22:00 -07:00
const device = zigbeeHerdsman . devices . bulb ;
device . removeFromDatabase . mockClear ( ) ;
device . removeFromNetwork . mockClear ( ) ;
2021-02-06 08:32:20 -07:00
mockRestart = jest . fn ( ) ;
controller = new Controller ( mockRestart , jest . fn ( ) ) ;
2020-05-24 09:16:39 -07:00
await controller . start ( ) ;
await flushPromises ( ) ;
} ) ;
it ( 'Should publish bridge info on startup' , async ( ) => {
const version = await require ( '../lib/util/utils' ) . getZigbee2mqttVersion ( ) ;
2020-09-04 09:42:24 -07:00
const directory = settings . get ( ) . advanced . log _directory ;
2020-05-24 09:16:39 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/info' ,
2021-04-04 12:00:24 -07:00
stringify ( { "restart_required" : false , "commit" : version . commitHash , "config" : { "advanced" : { "adapter_concurrent" : null , "adapter_delay" : null , "availability_blacklist" : [ ] , "availability_blocklist" : [ ] , "availability_passlist" : [ ] , "availability_timeout" : 0 , "availability_whitelist" : [ ] , "cache_state" : true , "cache_state_persistent" : true , "cache_state_send_on_startup" : true , "channel" : 11 , "elapsed" : false , "ext_pan_id" : [ 221 , 221 , 221 , 221 , 221 , 221 , 221 , 221 ] , "homeassistant_discovery_topic" : "homeassistant" , "homeassistant_legacy_triggers" : true , "homeassistant_status_topic" : "hass/status" , "last_seen" : "disable" , "legacy_api" : false , "log_directory" : directory , "log_file" : "log.txt" , "log_level" : "info" , "log_output" : [ "console" , "file" ] , "log_rotation" : true , "log_syslog" : { } , "pan_id" : 6754 , "report" : false , "soft_reset_timeout" : 0 , "timestamp_format" : "YYYY-MM-DD HH:mm:ss" } , "ban" : [ ] , "blocklist" : [ ] , "device_options" : { } , "devices" : { "0x000b57fffec6a5b2" : { "friendly_name" : "bulb" , "retain" : true } , "0x000b57fffec6a5b3" : { "friendly_name" : "bulb_color" , "retain" : false } , "0x000b57fffec6a5b4" : { "friendly_name" : "bulb_color_2" , "retain" : false } , "0x000b57fffec6a5b7" : { "friendly_name" : "bulb_2" , "retain" : false } , "0x0017880104a44559" : { "friendly_name" : "J1_cover" } , "0x0017880104e43559" : { "friendly_name" : "U202DST600ZB" } , "0x0017880104e44559" : { "friendly_name" : "3157100_thermostat" } , "0x0017880104e45517" : { "friendly_name" : "remote" , "retain" : true } , "0x0017880104e45518" : { "friendly_name" : "0x0017880104e45518" } , "0x0017880104e45520" : { "friendly_name" : "button" , "retain" : false } , "0x0017880104e45521" : { "friendly_name" : "button_double_key" , "retain" : false } , "0x0017880104e45522" : { "friendly_name" : "weather_sensor" , "qos" : 1 , "retain" : false } , "0x0017880104e45523" : { "friendly_name" : "occupancy_sensor" , "retain" : false } , "0x0017880104e45524" : { "friendly_name" : "power_plug" , "retain" : false } , "0x0017880104e45526" : { "friendly_name" : "GL-S-007ZS" } , "0x0017880104e45529" : { "friendly_name" : "unsupported2" , "retain" : false } , "0x0017880104e45530" : { "friendly_name" : "button_double_key_interviewing" , "retain" : false } , "0x0017880104e45540" : { "friendly_name" : "ikea_onoff" } , "0x0017880104e45541" : { "friendly_name" : "wall_switch" , "retain" : false } , "0x0017880104e45542" : { "friendly_name" : "wall_switch_double" , "retain" : false } , "0x0017880104e45543" : { "friendly_name" : "led_controller_1" , "retain" : false } , "0x0017880104e45544" : { "friendly_name" : "led_controller_2" , "retain" : false } , "0x0017880104e45545" : { "friendly_name" : "dimmer_wall_switch" , "retain" : false } , "0x0017880104e45547" : { "friendly_name" : "curtain" , "retain" : false } , "0x0017880104e45548" : { "friendly_name" : "fan" , "retain" : false } , "0x0017880104e45549" : { "friendly_name" : "siren" , "retain" : false } , "0x0017880104e45550" : { "friendly_name" : "thermostat" , "retain" : false } , "0x0017880104e45551" : { "friendly_name" : "smart vent" , "retain" : false } , "0x0017880104e45552" : { "friendly_name" : "j1" , "retain" : false } , "0x0017880104e45553" : { "friendly_name" : "bulb_enddevice" , "retain" : false } , "0x0017880104e45559" : { "friendly_name" : "cc2530_router" , "retain" : false } , "0x0017880104e45560" : { "friendly_name" : "livolo" , "retain" : false } , "0x0017880104e45724" : { "friendly_name" : "GLEDOPTO_2ID" } , "0x0017882104a44559" : { "friendly_name" : "TS0601_thermostat" } , "0x0017882194e45543" : { "friendly_name" : "QS-Zigbee-D02-TRIAC-2C-LN" } , "0x90fd9ffffe4b64aa" : { "friendly_name" : "SP600_OLD" } , "0x90fd9ffffe4b64ab" : { "friendly_name" : "SP600_NEW" } , "0x90fd9ffffe4b64ac" : { "friendly_name" : "MKS-CM-W5" } , "0x90fd9ffffe4b64ae" : { "friendly_name" : "tradfri_remote" , "retain" : false } , "0x90fd9ffffe4b64af" : { "friendly_name" : "roller_shutter" } , "0x90fd9ffffe4b64ax" : { "friendly_name" : "ZNLDP12LM" } } , "experimental" : { "output" : "json" } , "external_converters" : [ ] , "groups" : { "1" : { "friendly_name" : "group_1" , "retain" : false } , "11" : { "devices" : [ "bulb_2" ] , "friendly_name" : "group_with_tradfri" , "retain" : false } , "14" : { "devices" : [ " p
2020-05-24 09:16:39 -07:00
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish devices on startup' , async ( ) => {
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
2021-04-06 13:24:30 -07:00
stringify ( [ { "date_code" : null , "definition" : null , "endpoints" : { "1" : { "bindings" : [ ] , "clusters" : { "input" : [ ] , "output" : [ ] } , "configured_reportings" : [ ] } } , "friendly_name" : "Coordinator" , "ieee_address" : "0x00124b00120144ae" , "interview_completed" : false , "interviewing" : false , "model_id" : null , "network_address" : 0 , "power_source" : null , "software_build_id" : null , "supported" : false , "type" : "Coordinator" } , { "date_code" : null , "definition" : { "description" : "TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white" , "exposes" : [ { "features" : [ { "access" : 7 , "description" : "On/off state of this light" , "name" : "state" , "property" : "state" , "type" : "binary" , "value_off" : "OFF" , "value_on" : "ON" , "value_toggle" : "TOGGLE" } , { "access" : 7 , "description" : "Brightness of this light" , "name" : "brightness" , "property" : "brightness" , "type" : "numeric" , "value_max" : 254 , "value_min" : 0 } , { "access" : 7 , "description" : "Color temperature of this light" , "name" : "color_temp" , "presets" : [ { "description" : "Coolest temperature supported" , "name" : "coolest" , "value" : 250 } , { "description" : "Cool temperature (250 mireds / 4000 Kelvin)" , "name" : "cool" , "value" : 250 } , { "description" : "Neutral temperature (370 mireds / 2700 Kelvin)" , "name" : "neutral" , "value" : 370 } , { "description" : "Warm temperature (454 mireds / 2200 Kelvin)" , "name" : "warm" , "value" : 454 } , { "description" : "Warmest temperature supported" , "name" : "warmest" , "value" : 454 } ] , "property" : "color_temp" , "type" : "numeric" , "unit" : "mired" , "value_max" : 454 , "value_min" : 250 } , { "access" : 7 , "description" : "Color temperature after cold power on of this light" , "name" : "color_temp_startup" , "presets" : [ { "description" : "Coolest temperature supported" , "name" : "coolest" , "value" : 250 } , { "description" : "Cool temperature (250 mireds / 4000 Kelvin)" , "name" : "cool" , "value" : 250 } , { "description" : "Neutral temperature (370 mireds / 2700 Kelvin)" , "name" : "neutral" , "value" : 370 } , { "description" : "Warm temperature (454 mireds / 2200 Kelvin)" , "name" : "warm" , "value" : 454 } , { "description" : "Warmest temperature supported" , "name" : "warmest" , "value" : 454 } , { "description" : "Restore previous color_temp on cold power on" , "name" : "previous" , "value" : 65535 } ] , "property" : "color_temp_startup" , "type" : "numeric" , "unit" : "mired" , "value_max" : 454 , "value_min" : 250 } ] , "type" : "light" } , { "access" : 2 , "description" : "Triggers an effect on the light (e.g. make light blink for a few seconds)" , "name" : "effect" , "property" : "effect" , "type" : "enum" , "values" : [ "blink" , "breathe" , "okay" , "channel_change" , "finish_effect" , "stop_effect" ] } , { "access" : 1 , "description" : "Link quality (signal strength)" , "name" : "linkquality" , "property" : "linkquality" , "type" : "numeric" , "unit" : "lqi" , "value_max" : 255 , "value_min" : 0 } ] , "model" : "LED1545G12" , "supports_ota" : true , "vendor" : "IKEA" } , "endpoints" : { "1" : { "bindings" : [ ] , "clusters" : { "input" : [ "genBasic" , "genScenes" , "genOnOff" , "genLevelCtrl" , "lightingColorCtrl" ] , "output" : [ "genScenes" , "genOta" ] } , "configured_reportings" : [ { "attribute" : "onOff" , "cluster" : "genOnOff" , "maximum_report_interval" : 10 , "minimum_report_interval" : 1 , "reportable_change" : 20 } ] } } , "friendly_name" : "bulb" , "ieee_address" : "0x000b57fffec6a5b2" , "interview_completed" : true , "interviewing" : false , "model_id" : "TRADFRI bulb E27 WS opal 980lm" , "network_address" : 40369 , "power_source" : "Mains (single phase)" , "software_build_id" : null , "supported" : true , "type" : "Router" } , { "date_code" : null , "definition" : { "description" : "Hue dimmer switch" , "exposes" : [ { "access" : 1 , "description" : "Remaining battery in %" , "name" : "battery" , "property" : "battery" , "type" : "numeric" , "unit" : "%" , "value_max" : 100 , "value_min" : 0 } , { "access" : 1 , "description" : "Triggered action (e.g. a button click)" , "name" : "action" , "property" : "action" , "type" : "enum" , "values" : [ "on-press" , "on-hold" , "on-hold-release" , "up-press" , "up-hold" , "up-hold-release" , "down-press" , "down-hold" , "down-hold-release" , "off-press" , "off-hold" , "off-hold-release" ] } , { "access" : 1 , "description" : "Link quality (signal strength)" , "name" : "linkquality" , "property" : "linkquality" , "type" : "numeric" , "unit" : "lqi" , "value_max" : 255 , "value_min" : 0 } ] , "model" : "324131092621" , "supports_ota" : true , "vendor" : "Philips" } , "endpoints" : { "1" : { "bindings" : [ { "cluster" : "genLevelCtrl" , "target" : { "endpoint" : 1 , "ieee_address" : " 0x000b5
2020-10-09 12:57:54 -07:00
{ retain : true , qos : 0 } ,
expect . any ( Function )
2020-05-24 09:16:39 -07:00
) ;
} ) ;
2020-07-28 13:12:22 -07:00
it ( 'Should log to MQTT' , async ( ) => {
logger . setTransportsEnabled ( true ) ;
MQTT . publish . mockClear ( ) ;
logger . info . mockClear ( ) ;
logger . info ( "this is a test" ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/logging' ,
2020-08-13 11:00:35 -07:00
stringify ( { message : 'this is a test' , level : 'info' } ) ,
2020-07-28 13:12:22 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
expect ( logger . info ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'Shouldnt log to MQTT when not connected' , async ( ) => {
logger . setTransportsEnabled ( true ) ;
MQTT . mock . reconnecting = true ;
MQTT . publish . mockClear ( ) ;
logger . info . mockClear ( ) ;
logger . error . mockClear ( ) ;
logger . info ( "this is a test" ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( logger . info ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( logger . error ) . toHaveBeenCalledTimes ( 0 ) ;
} ) ;
2020-08-30 02:30:38 -07:00
it ( 'Should publish groups on startup' , async ( ) => {
2020-07-28 13:12:22 -07:00
logger . setTransportsEnabled ( true ) ;
2020-05-24 09:16:39 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/groups' ,
2021-04-04 12:00:24 -07:00
stringify ( [ { "friendly_name" : "group_1" , "id" : 1 , "members" : [ ] } , { "friendly_name" : "group_tradfri_remote" , "id" : 15071 , "members" : [ ] } , { "friendly_name" : 99 , "id" : 99 , "members" : [ ] } , { "friendly_name" : "group_with_tradfri" , "id" : 11 , "members" : [ ] } , { "friendly_name" : "thermostat_group" , "id" : 12 , "members" : [ ] } , { "friendly_name" : "switch_group" , "id" : 14 , "members" : [ { "endpoint" : 1 , "ieee_address" : "0x0017880104e45524" } ] } , { "friendly_name" : "gledopto_group" , "id" : 21 , "members" : [ ] } , { "friendly_name" : "default_bind_group" , "id" : 901 , "members" : [ ] } , { "friendly_name" : "group_2" , "id" : 2 , "members" : [ ] } ] ) ,
2020-05-24 09:16:39 -07:00
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event when device joined' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceJoined ( { device : zigbeeHerdsman . devices . bulb } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2020-08-13 11:00:35 -07:00
stringify ( { "type" : "device_joined" , "data" : { "friendly_name" : "bulb" , "ieee_address" : "0x000b57fffec6a5b2" } } ) ,
2020-08-20 11:55:40 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event when device announces' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceAnnounce ( { device : zigbeeHerdsman . devices . bulb } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
stringify ( { "type" : "device_announce" , "data" : { "friendly_name" : "bulb" , "ieee_address" : "0x000b57fffec6a5b2" } } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event when device interview started' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceInterview ( { device : zigbeeHerdsman . devices . bulb , status : 'started' } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2020-08-13 11:00:35 -07:00
stringify ( { "type" : "device_interview" , "data" : { "friendly_name" : "bulb" , "status" : "started" , "ieee_address" : "0x000b57fffec6a5b2" } } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event and devices when device interview failed' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceInterview ( { device : zigbeeHerdsman . devices . bulb , status : 'failed' } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2020-08-13 11:00:35 -07:00
stringify ( { "type" : "device_interview" , "data" : { "friendly_name" : "bulb" , "status" : "failed" , "ieee_address" : "0x000b57fffec6a5b2" } } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
expect . any ( String ) ,
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event and devices when device interview successful' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceInterview ( { device : zigbeeHerdsman . devices . bulb , status : 'successful' } ) ;
await zigbeeHerdsman . events . deviceInterview ( { device : zigbeeHerdsman . devices . unsupported , status : 'successful' } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 4 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2021-02-27 13:37:58 -07:00
stringify ( { "data" : { "definition" : { "description" : "TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white" , "exposes" : [ { "features" : [ { "access" : 7 , "description" : "On/off state of this light" , "name" : "state" , "property" : "state" , "type" : "binary" , "value_off" : "OFF" , "value_on" : "ON" , "value_toggle" : "TOGGLE" } , { "access" : 7 , "description" : "Brightness of this light" , "name" : "brightness" , "property" : "brightness" , "type" : "numeric" , "value_max" : 254 , "value_min" : 0 } , { "access" : 7 , "description" : "Color temperature of this light" , "name" : "color_temp" , "presets" : [ { "description" : "Coolest temperature supported" , "name" : "coolest" , "value" : 250 } , { "description" : "Cool temperature (250 mireds / 4000 Kelvin)" , "name" : "cool" , "value" : 250 } , { "description" : "Neutral temperature (370 mireds / 2700 Kelvin)" , "name" : "neutral" , "value" : 370 } , { "description" : "Warm temperature (454 mireds / 2200 Kelvin)" , "name" : "warm" , "value" : 454 } , { "description" : "Warmest temperature supported" , "name" : "warmest" , "value" : 454 } ] , "property" : "color_temp" , "type" : "numeric" , "unit" : "mired" , "value_max" : 454 , "value_min" : 250 } , { "access" : 7 , "description" : "Color temperature after cold power on of this light" , "name" : "color_temp_startup" , "presets" : [ { "description" : "Coolest temperature supported" , "name" : "coolest" , "value" : 250 } , { "description" : "Cool temperature (250 mireds / 4000 Kelvin)" , "name" : "cool" , "value" : 250 } , { "description" : "Neutral temperature (370 mireds / 2700 Kelvin)" , "name" : "neutral" , "value" : 370 } , { "description" : "Warm temperature (454 mireds / 2200 Kelvin)" , "name" : "warm" , "value" : 454 } , { "description" : "Warmest temperature supported" , "name" : "warmest" , "value" : 454 } , { "description" : "Restore previous color_temp on cold power on" , "name" : "previous" , "value" : 65535 } ] , "property" : "color_temp_startup" , "type" : "numeric" , "unit" : "mired" , "value_max" : 454 , "value_min" : 250 } ] , "type" : "light" } , { "access" : 2 , "description" : "Triggers an effect on the light (e.g. make light blink for a few seconds)" , "name" : "effect" , "property" : "effect" , "type" : "enum" , "values" : [ "blink" , "breathe" , "okay" , "channel_change" , "finish_effect" , "stop_effect" ] } , { "access" : 1 , "description" : "Link quality (signal strength)" , "name" : "linkquality" , "property" : "linkquality" , "type" : "numeric" , "unit" : "lqi" , "value_max" : 255 , "value_min" : 0 } ] , "model" : "LED1545G12" , "supports_ota" : true , "vendor" : "IKEA" } , "friendly_name" : "bulb" , "ieee_address" : "0x000b57fffec6a5b2" , "status" : "successful" , "supported" : true } , "type" : "device_interview" } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2020-08-13 11:00:35 -07:00
stringify ( { "type" : "device_interview" , "data" : { "friendly_name" : "0x0017880104e45518" , "status" : "successful" , "ieee_address" : "0x0017880104e45518" , "supported" : false , "definition" : null } } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
expect . any ( String ) ,
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should publish event and devices when device leaves' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceLeave ( { ieeeAddr : zigbeeHerdsman . devices . bulb . ieeeAddr } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledTimes ( 2 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/event' ,
2020-08-13 11:00:35 -07:00
stringify ( { "type" : "device_leave" , "data" : { "ieee_address" : "0x000b57fffec6a5b2" } } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } ,
expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
expect . any ( String ) ,
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should allow permit join' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , 'true' ) ;
2020-05-24 09:16:39 -07:00
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
2021-01-03 03:08:33 -07:00
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( true , undefined , undefined ) ;
2020-05-24 09:16:39 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/permit_join' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : true } , "status" : "ok" } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value" : false } ) ) ;
2020-05-24 09:16:39 -07:00
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
2021-01-03 03:08:33 -07:00
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( false , undefined , undefined ) ;
2020-05-24 09:16:39 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/permit_join' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : false } , "status" : "ok" } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
2021-01-10 08:54:01 -07:00
) ;
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value" : "False" } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( false , undefined , undefined ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/permit_join' ,
stringify ( { "data" : { "value" : false } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
2020-05-24 09:16:39 -07:00
) ;
2020-10-11 06:12:07 -07:00
// Invalid payload
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value_bla" : false } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/permit_join' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-05-24 09:16:39 -07:00
} ) ;
2021-01-03 03:08:33 -07:00
it ( 'Should allow permit join for certain time' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value" : false , "time" : 10 } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( false , undefined , 10 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/permit_join' ,
stringify ( { "data" : { "value" : false , "time" : 10 } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should republish bridge info when permit join changes' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . permitJoinChanged ( { permitted : false , time : 10 } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
} ) ;
2021-02-06 08:32:20 -07:00
it ( 'Shouldnt republish bridge info when permit join changes and hersman is stopping' , async ( ) => {
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . isStopping . mockImplementationOnce ( ( ) => true ) ;
await zigbeeHerdsman . events . permitJoinChanged ( { permitted : false , time : 10 } ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . not . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
} ) ;
2020-10-11 06:05:21 -07:00
it ( 'Should allow permit join via device' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { value : true , device : 'bulb' } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
2021-01-03 03:08:33 -07:00
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( true , device , undefined ) ;
2020-10-11 06:05:21 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/permit_join' ,
stringify ( { "data" : { "value" : true , "device" : "bulb" } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
// Device does not exist
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { value : true , device : 'bulb_not_existing_woeeee' } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/permit_join' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "Device 'bulb_not_existing_woeeee' does not exist" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-05-24 09:16:39 -07:00
it ( 'Should put transaction in response when request is done with transaction' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value" : false , "transaction" : 22 } ) ) ;
2020-05-24 09:16:39 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/permit_join' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : false } , "status" : "ok" , "transaction" : 22 } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-05-26 08:36:04 -07:00
it ( 'Should put error in response when request fails' , async ( ) => {
2020-05-24 09:16:39 -07:00
zigbeeHerdsman . permitJoin . mockImplementationOnce ( ( ) => { throw new Error ( 'Failed to connect to adapter' ) } ) ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/permit_join' , stringify ( { "value" : false } ) ) ;
2020-05-24 09:16:39 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/permit_join' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Failed to connect to adapter" } ) ,
2020-05-24 09:16:39 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-15 09:58:32 -07:00
it ( 'Should put error in response when format is incorrect' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-10-11 06:05:21 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/last_seen' , stringify ( { "value_not_good" : false } ) ) ;
2020-06-15 09:58:32 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-10-11 06:05:21 -07:00
'zigbee2mqtt/bridge/response/config/last_seen' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "No value given" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-05-24 09:16:39 -07:00
it ( 'Coverage satisfaction' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/random' , stringify ( { "value" : false } ) ) ;
2020-05-24 09:16:39 -07:00
const device = zigbeeHerdsman . devices . bulb ;
await zigbeeHerdsman . events . message ( { data : { onOff : 1 } , cluster : 'genOnOff' , device , endpoint : device . getEndpoint ( 1 ) , type : 'attributeReport' , linkquality : 10 } ) ;
await flushPromises ( ) ;
} ) ;
2020-06-13 08:22:00 -07:00
2020-07-21 12:14:39 -07:00
it ( 'Should allow a healthcheck' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/health_check' , '' ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/health_check' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "healthy" : true } , "status" : "ok" } ) ,
2020-07-21 12:14:39 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 08:22:00 -07:00
it ( 'Should allow to remove device by string' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
controller . state . state = { '0x000b57fffec6a5b3' : { brightness : 100 } } ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , 'bulb' ) ;
await flushPromises ( ) ;
expect ( controller . state [ device . ieeeAddr ] ) . toBeUndefined ( ) ;
expect ( device . removeFromNetwork ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . removeFromDatabase ) . not . toHaveBeenCalled ( ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
2020-09-07 08:29:53 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bulb' , '' , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
2020-06-13 08:22:00 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "block" : false , "force" : false } , "status" : "ok" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-07-15 14:22:32 -07:00
expect ( settings . get ( ) . blocklist ) . toStrictEqual ( [ ] ) ;
2020-10-06 10:28:32 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
2020-06-13 08:22:00 -07:00
} ) ;
it ( 'Should allow to remove device by object ID' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , stringify ( { id : "bulb" } ) ) ;
2020-06-13 08:22:00 -07:00
await flushPromises ( ) ;
expect ( device . removeFromNetwork ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . removeFromDatabase ) . not . toHaveBeenCalled ( ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "block" : false , "force" : false } , "status" : "ok" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to force remove device' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , stringify ( { id : "bulb" , force : true } ) ) ;
2020-06-13 08:22:00 -07:00
await flushPromises ( ) ;
expect ( device . removeFromDatabase ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( device . removeFromNetwork ) . not . toHaveBeenCalled ( ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "block" : false , "force" : true } , "status" : "ok" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-07-15 14:22:32 -07:00
it ( 'Should allow to block device' , async ( ) => {
2020-06-13 08:22:00 -07:00
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , stringify ( { id : "bulb" , block : true , force : true } ) ) ;
2020-06-13 08:22:00 -07:00
await flushPromises ( ) ;
expect ( device . removeFromDatabase ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "bulb" , "block" : true , "force" : true } , "status" : "ok" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
2020-07-15 14:22:32 -07:00
expect ( settings . get ( ) . blocklist ) . toStrictEqual ( [ "0x000b57fffec6a5b2" ] ) ;
2020-06-13 08:22:00 -07:00
} ) ;
it ( 'Should allow to remove group' , async ( ) => {
const group = zigbeeHerdsman . groups . group _1 ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/remove' , 'group_1' ) ;
await flushPromises ( ) ;
2020-07-07 12:16:35 -07:00
expect ( group . removeFromNetwork ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( settings . getGroup ( 'group_1' ) ) . toBeNull ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "group_1" , "force" : false } , "status" : "ok" } ) ,
2020-07-07 12:16:35 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to force remove group' , async ( ) => {
const group = zigbeeHerdsman . groups . group _1 ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/remove' , stringify ( { id : "group_1" , force : true } ) ) ;
2020-07-07 12:16:35 -07:00
await flushPromises ( ) ;
2020-06-13 08:22:00 -07:00
expect ( group . removeFromDatabase ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( settings . getGroup ( 'group_1' ) ) . toBeNull ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "id" : "group_1" , "force" : true } , "status" : "ok" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error on removing non-existing device' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , stringify ( { id : "non-existing-device" } ) ) ;
2020-06-13 08:22:00 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Device 'non-existing-device' does not exist" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error when remove device fails' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
MQTT . publish . mockClear ( ) ;
device . removeFromNetwork . mockImplementationOnce ( ( ) => { throw new Error ( 'device timeout' ) } )
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/remove' , stringify ( { id : "bulb" } ) ) ;
2020-06-13 08:22:00 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/remove' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Failed to remove device 'bulb' (block: false, force: false) (Error: device timeout)" } ) ,
2020-06-13 08:22:00 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 10:35:09 -07:00
it ( 'Should allow rename device' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { from : 'bulb' , to : 'bulb_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getDevice ( 'bulb_new_name' ) ) . toStrictEqual ( { "ID" : "0x000b57fffec6a5b2" , "friendly_name" : "bulb_new_name" , "friendlyName" : "bulb_new_name" , "retain" : true } ) ;
2020-09-07 08:29:53 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bulb' , '' , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
2020-06-13 10:35:09 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
2020-10-09 13:59:10 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bulb_new_name' , stringify ( { "brightness" : 50 , "color_temp" : 370 , "linkquality" : 99 , "state" : "ON" } ) , expect . any ( Object ) , expect . any ( Function ) ) ;
2020-06-13 10:35:09 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
2020-09-04 12:08:20 -07:00
stringify ( { "data" : { "from" : "bulb" , "to" : "bulb_new_name" , "homeassistant_rename" : false } , "status" : "ok" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-01-08 12:46:04 -07:00
it ( 'Shouldnt allow rename device with to now allowed name' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { from : 'bulb' , to : 'living_room/blinds/center' } ) ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "friendly_name is not allowed to end with: '/center'" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 10:35:09 -07:00
it ( 'Should allow rename group' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/rename' , stringify ( { from : 'group_1' , to : 'group_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( settings . getGroup ( 'group_1' ) ) . toBeNull ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getGroup ( 'group_new_name' ) ) . toStrictEqual ( { "ID" : 1 , "devices" : [ ] , "friendly_name" : "group_new_name" , "friendlyName" : "group_new_name" , "optimistic" : true , "retain" : false } ) ;
2020-06-13 10:35:09 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/rename' ,
2020-09-04 12:08:20 -07:00
stringify ( { "data" : { "from" : "group_1" , "to" : "group_new_name" , "homeassistant_rename" : false } , "status" : "ok" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error on invalid device rename payload' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { from _bla : 'bulb' , to : 'bulb_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error on non-existing device rename' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { from : 'bulb_not_existing' , to : 'bulb_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Device 'bulb_not_existing' does not exist" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to rename last joined device' , async ( ) => {
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . deviceJoined ( { device : zigbeeHerdsman . devices . bulb } ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { last : true , to : 'bulb_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( settings . getDevice ( 'bulb' ) ) . toBeNull ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getDevice ( 'bulb_new_name' ) ) . toStrictEqual ( { "ID" : "0x000b57fffec6a5b2" , "friendly_name" : "bulb_new_name" , "friendlyName" : "bulb_new_name" , "retain" : true } ) ;
2020-06-13 10:35:09 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/devices' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
2020-09-04 12:08:20 -07:00
stringify ( { "data" : { "from" : "bulb" , "to" : "bulb_new_name" , "homeassistant_rename" : false } , "status" : "ok" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-09-19 01:57:39 -07:00
it ( 'Should throw error when renaming device through not allowed friendlyName' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { from : 'bulb' , to : 'bulb_new_name/1' } ) ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
stringify ( { "data" : { } , "status" : "error" , "error" : ` Friendly name cannot end with a "/DIGIT" ('bulb_new_name/1') ` } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 10:35:09 -07:00
it ( 'Should throw error when renaming last joined device but none has joined' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/rename' , stringify ( { last : true , to : 'bulb_new_name' } ) ) ;
2020-06-13 10:35:09 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/rename' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "No device has joined since start" } ) ,
2020-06-13 10:35:09 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 14:28:06 -07:00
it ( 'Should allow change device options' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getDevice ( 'bulb' ) ) . toStrictEqual ( { "ID" : "0x000b57fffec6a5b2" , "friendly_name" : "bulb" , "friendlyName" : "bulb" , "retain" : true } ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/options' , stringify ( { options : { retain : false , transition : 1 } , id : 'bulb' } ) ) ;
2020-06-13 14:28:06 -07:00
await flushPromises ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getDevice ( 'bulb' ) ) . toStrictEqual ( { "ID" : "0x000b57fffec6a5b2" , "friendly_name" : "bulb" , "friendlyName" : "bulb" , "retain" : false , "transition" : 1 } ) ;
2020-06-13 14:28:06 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-06-13 15:28:24 -07:00
'zigbee2mqtt/bridge/response/device/options' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "from" : { "retain" : true } , "to" : { "retain" : false , "transition" : 1 } , "id" : "bulb" } , "status" : "ok" } ) ,
2020-06-13 14:28:06 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow change group options' , async ( ) => {
MQTT . publish . mockClear ( ) ;
expect ( settings . getGroup ( 'group_1' ) ) . toStrictEqual ( { "ID" : 1 , "devices" : [ ] , "friendly_name" : "group_1" , "retain" : false , "friendlyName" : "group_1" , "optimistic" : true } ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/options' , stringify ( { options : { retain : true , transition : 1 } , id : 'group_1' } ) ) ;
2020-06-13 14:28:06 -07:00
await flushPromises ( ) ;
expect ( settings . getGroup ( 'group_1' ) ) . toStrictEqual ( { "ID" : 1 , "devices" : [ ] , "friendly_name" : "group_1" , "retain" : true , "friendlyName" : "group_1" , "optimistic" : true , "transition" : 1 } ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-06-13 15:28:24 -07:00
'zigbee2mqtt/bridge/response/group/options' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "from" : { "optimistic" : true , "retain" : false } , "to" : { "optimistic" : true , "retain" : true , "transition" : 1 } , "id" : "group_1" } , "status" : "ok" } ) ,
2020-06-13 14:28:06 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error on invalid device change options payload' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/options' , stringify ( { options _ : { retain : true , transition : 1 } , id : 'bulb' } ) ) ;
2020-06-13 14:28:06 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-06-13 15:28:24 -07:00
'zigbee2mqtt/bridge/response/device/options' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
2020-06-13 14:28:06 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 14:42:58 -07:00
it ( 'Should allow to add group by string' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/add' , 'group_193' ) ;
await flushPromises ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getGroup ( 'group_193' ) ) . toStrictEqual ( { "ID" : 3 , "devices" : [ ] , "friendly_name" : "group_193" , "friendlyName" : "group_193" , "optimistic" : true } ) ;
2020-06-13 14:42:58 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/add' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "friendly_name" : "group_193" , "id" : 3 } , "status" : "ok" } ) ,
2020-06-13 14:42:58 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to add group with ID' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/add' , stringify ( { friendly _name : "group_193" , id : 9 } ) ) ;
2020-06-13 14:42:58 -07:00
await flushPromises ( ) ;
2020-07-13 14:00:33 -07:00
expect ( settings . getGroup ( 'group_193' ) ) . toStrictEqual ( { "ID" : 9 , "devices" : [ ] , "friendly_name" : "group_193" , "friendlyName" : "group_193" , "optimistic" : true } ) ;
2020-06-13 14:42:58 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/groups' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/add' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "friendly_name" : "group_193" , "id" : 9 } , "status" : "ok" } ) ,
2020-06-13 14:42:58 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-02-04 10:01:44 -07:00
it ( 'Shouldnt allow to add group with empty name' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/add' , stringify ( { friendly _name : "" , id : 9 } ) ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/add' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "friendly_name must be at least 1 char long" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-13 14:42:58 -07:00
it ( 'Should throw error when add with invalid payload' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/group/add' , stringify ( { friendly _name9 : "group_193" } ) ) ;
2020-06-13 14:42:58 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/group/add' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
2020-06-13 14:42:58 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-15 09:58:32 -07:00
2020-07-29 14:10:03 -07:00
it ( 'Should allow to enable/disable Home Assistant extension' , async ( ) => {
// Test if disabled intially
const device = zigbeeHerdsman . devices . WXKG11LM ;
settings . set ( [ 'devices' , device . ieeeAddr , 'legacy' ] , false ) ;
const payload = { data : { onOff : 1 } , cluster : 'genOnOff' , device , endpoint : device . getEndpoint ( 1 ) , type : 'attributeReport' , linkquality : 10 } ;
await zigbeeHerdsman . events . message ( payload ) ;
expect ( settings . get ( ) . homeassistant ) . toBeFalsy ( ) ;
expect ( MQTT . publish ) . not . toHaveBeenCalledWith ( 'zigbee2mqtt/button/action' , 'single' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
// Disable when already disabled should go OK
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/homeassistant' , stringify ( { value : false } ) ) ;
2020-07-29 14:10:03 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/homeassistant' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : false } , "status" : "ok" } ) ,
2020-07-29 14:10:03 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
expect ( settings . get ( ) . homeassistant ) . toBeFalsy ( ) ;
// Enable
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/homeassistant' , stringify ( { value : true } ) ) ;
2020-07-29 14:10:03 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/homeassistant' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : true } , "status" : "ok" } ) ,
2020-07-29 14:10:03 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
expect ( settings . get ( ) . homeassistant ) . toBeTruthy ( ) ;
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/button/action' , 'single' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
// Disable
2020-08-13 11:00:35 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/homeassistant' , stringify ( { value : false } ) ) ;
2020-07-29 14:10:03 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/homeassistant' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : false } , "status" : "ok" } ) ,
2020-07-29 14:10:03 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
expect ( settings . get ( ) . homeassistant ) . toBeFalsy ( ) ;
MQTT . publish . mockClear ( ) ;
await zigbeeHerdsman . events . message ( payload ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . not . toHaveBeenCalledWith ( 'zigbee2mqtt/button/action' , 'single' , { retain : false , qos : 0 } , expect . any ( Function ) ) ;
} ) ;
it ( 'Should fail to set Home Assistant when invalid type' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/homeassistant' , 'invalid_one' ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . homeassistant ) . toBeFalsy ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/homeassistant' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "'invalid_one' is not an allowed value, allowed: true,false" } ) ,
2020-07-29 14:10:03 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-15 09:58:32 -07:00
it ( 'Should allow to set last_seen' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/last_seen' , 'ISO_8601' ) ;
2020-06-15 09:58:32 -07:00
await flushPromises ( ) ;
expect ( settings . get ( ) . advanced . last _seen ) . toBe ( 'ISO_8601' ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/config/last_seen' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : "ISO_8601" } , "status" : "ok" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should fail to set last_seen when invalid type' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/last_seen' , 'invalid_one' ) ;
2020-06-15 09:58:32 -07:00
await flushPromises ( ) ;
expect ( settings . get ( ) . advanced . last _seen ) . toBe ( 'disable' ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/config/last_seen' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "'invalid_one' is not an allowed value, allowed: disable,ISO_8601,epoch,ISO_8601_local" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to set elapsed' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/elapsed' , 'true' ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . advanced . elapsed ) . toBe ( true ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/elapsed' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : true } , "status" : "ok" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should fail to set last_seen when invalid type' , async ( ) => {
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/elapsed' , 'not_valid' ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . advanced . elapsed ) . toBe ( false ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/config/elapsed' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "'not_valid' is not an allowed value, allowed: true,false" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to set log level' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/log_level' , 'debug' ) ;
2020-06-15 09:58:32 -07:00
await flushPromises ( ) ;
expect ( logger . getLevel ( ) ) . toBe ( 'debug' ) ;
2020-06-15 10:06:08 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , expect . any ( Object ) , expect . any ( Function ) ) ;
2020-06-15 09:58:32 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/config/log_level' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { "value" : 'debug' } , "status" : "ok" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should fail to set log level when invalid type' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/config/log_level' , 'not_valid' ) ;
2020-06-15 09:58:32 -07:00
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/config/log_level' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "'not_valid' is not an allowed value, allowed: error,warn,info,debug" } ) ,
2020-06-15 09:58:32 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-15 10:19:57 -07:00
it ( 'Should allow to touchlink factory reset (succeeds)' , async ( ) => {
2020-09-08 11:24:49 -07:00
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . touchlinkFactoryResetFirst . mockClear ( ) ;
zigbeeHerdsman . touchlinkFactoryResetFirst . mockReturnValueOnce ( true ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/factory_reset' , '' ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . touchlinkFactoryResetFirst ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/touchlink/factory_reset' ,
stringify ( { "data" : { } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Should allow to touchlink factory reset specific device' , async ( ) => {
2020-06-15 10:19:57 -07:00
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . touchlinkFactoryReset . mockClear ( ) ;
zigbeeHerdsman . touchlinkFactoryReset . mockReturnValueOnce ( true ) ;
2020-09-08 11:24:49 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/factory_reset' , stringify ( { ieee _address : '0x1239' , channel : 12 } ) ) ;
2020-06-15 10:19:57 -07:00
await flushPromises ( ) ;
expect ( zigbeeHerdsman . touchlinkFactoryReset ) . toHaveBeenCalledTimes ( 1 ) ;
2020-09-08 11:24:49 -07:00
expect ( zigbeeHerdsman . touchlinkFactoryReset ) . toHaveBeenCalledWith ( '0x1239' , 12 ) ;
2020-06-15 10:19:57 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/touchlink/factory_reset' ,
2020-09-08 11:24:49 -07:00
stringify ( { "data" : { "ieee_address" : '0x1239' , "channel" : 12 } , "status" : "ok" } ) ,
2020-06-15 10:19:57 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-09-09 09:24:32 -07:00
it ( 'Should allow to touchlink identify specific device' , async ( ) => {
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . touchlinkIdentify . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/identify' , stringify ( { ieee _address : '0x1239' , channel : 12 } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . touchlinkIdentify ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . touchlinkIdentify ) . toHaveBeenCalledWith ( '0x1239' , 12 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/touchlink/identify' ,
stringify ( { "data" : { "ieee_address" : '0x1239' , "channel" : 12 } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Touchlink identify fails when payload is invalid' , async ( ) => {
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . touchlinkIdentify . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/identify' , stringify ( { ieee _address : '0x1239' } ) ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . touchlinkIdentify ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/touchlink/identify' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-06-15 10:19:57 -07:00
it ( 'Should allow to touchlink factory reset (fails)' , async ( ) => {
MQTT . publish . mockClear ( ) ;
2020-09-08 11:24:49 -07:00
zigbeeHerdsman . touchlinkFactoryResetFirst . mockClear ( ) ;
zigbeeHerdsman . touchlinkFactoryResetFirst . mockReturnValueOnce ( false ) ;
2020-07-13 14:00:33 -07:00
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/factory_reset' , '' ) ;
2020-06-15 10:19:57 -07:00
await flushPromises ( ) ;
2020-09-08 11:24:49 -07:00
expect ( zigbeeHerdsman . touchlinkFactoryResetFirst ) . toHaveBeenCalledTimes ( 1 ) ;
2020-06-15 10:19:57 -07:00
expect ( MQTT . publish ) . toHaveBeenCalledWith (
2020-07-13 14:00:33 -07:00
'zigbee2mqtt/bridge/response/touchlink/factory_reset' ,
2020-08-13 11:00:35 -07:00
stringify ( { "data" : { } , "status" : "error" , "error" : "Failed to factory reset device through Touchlink" } ) ,
2020-06-15 10:19:57 -07:00
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-09-08 11:24:49 -07:00
it ( 'Should allow to touchlink scan' , async ( ) => {
MQTT . publish . mockClear ( ) ;
zigbeeHerdsman . touchlinkScan . mockClear ( ) ;
zigbeeHerdsman . touchlinkScan . mockReturnValueOnce ( [ { ieeeAddr : '0x123' , channel : 12 } , { ieeeAddr : '0x124' , channel : 24 } ] ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/touchlink/scan' , '' ) ;
await flushPromises ( ) ;
expect ( zigbeeHerdsman . touchlinkScan ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/touchlink/scan' ,
stringify ( { "data" : { "found" : [ { ieee _address : '0x123' , channel : 12 } , { ieee _address : '0x124' , channel : 24 } ] } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2020-12-28 14:57:35 -07:00
it ( 'Should allow to configure reporting' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . getEndpoint ( 1 ) ;
endpoint . configureReporting . mockClear ( ) ;
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/configure_reporting' , stringify ( { id : 'bulb' , cluster : 'genLevelCtrl' , attribute : 'currentLevel' , maximum _report _interval : 10 , minimum _report _interval : 1 , reportable _change : 1 } ) ) ;
await flushPromises ( ) ;
2021-02-10 10:24:37 -07:00
expect ( endpoint . bind ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( endpoint . bind ) . toHaveBeenCalledWith ( 'genLevelCtrl' , coordinator . endpoints [ 0 ] ) ;
2020-12-28 14:57:35 -07:00
expect ( endpoint . configureReporting ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( endpoint . configureReporting ) . toHaveBeenCalledWith ( 'genLevelCtrl' , [ { "attribute" : "currentLevel" , "maximumReportInterval" : 10 , "minimumReportInterval" : 1 , "reportableChange" : 1 } ] ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/configure_reporting' ,
stringify ( { "data" : { id : 'bulb' , cluster : 'genLevelCtrl' , attribute : 'currentLevel' , maximum _report _interval : 10 , minimum _report _interval : 1 , reportable _change : 1 } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/devices' ,
expect . any ( String ) ,
{ retain : true , qos : 0 } ,
expect . any ( Function )
) ;
} ) ;
it ( 'Should throw error when configure reporting is called with misformed payload' , async ( ) => {
const device = zigbeeHerdsman . devices . bulb ;
const endpoint = device . getEndpoint ( 1 ) ;
endpoint . configureReporting . mockClear ( ) ;
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/device/configure_reporting' , stringify ( { id : 'bulb' , cluster : 'genLevelCtrl' , attribute _lala : 'currentLevel' , maximum _report _interval : 10 , minimum _report _interval : 1 , reportable _change : 1 } ) ) ;
await flushPromises ( ) ;
expect ( endpoint . configureReporting ) . toHaveBeenCalledTimes ( 0 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/device/configure_reporting' ,
stringify ( { "data" : { } , "status" : "error" , "error" : "Invalid payload" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-02-06 08:32:20 -07:00
it ( 'Should allow to restart' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
jest . useFakeTimers ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/restart' , '' ) ;
await flushPromises ( ) ;
jest . runAllTimers ( ) ;
expect ( mockRestart ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/restart' ,
stringify ( { "data" : { } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
jest . useRealTimers ( ) ;
} ) ;
it ( 'Change options' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
settings . apply ( { permit _join : false } ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { permit _join : true } } ) ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . permit _join ) . toBe ( true ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( zigbeeHerdsman . permitJoin ) . toHaveBeenCalledWith ( true , undefined , undefined ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : false } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Change options and apply - homeassistant' , async ( ) => {
expect ( controller . extensions . find ( ( e ) => e . constructor . name === 'HomeAssistant' ) ) . toBeUndefined ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { homeassistant : true } } ) ) ;
await flushPromises ( ) ;
expect ( controller . extensions . find ( ( e ) => e . constructor . name === 'HomeAssistant' ) ) . not . toBeUndefined ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : false } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Change options and apply - log_level' , async ( ) => {
logger . setLevel ( 'info' ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { advanced : { log _level : 'debug' } } } ) ) ;
await flushPromises ( ) ;
expect ( logger . getLevel ( ) ) . toBe ( 'debug' ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith ( 'zigbee2mqtt/bridge/info' , expect . any ( String ) , { retain : true , qos : 0 } , expect . any ( Function ) ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : false } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Change options restart required' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
settings . apply ( { serial : { port : '123' } } ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { serial : { port : '/dev/newport' } } } ) ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . serial . port ) . toBe ( '/dev/newport' ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : true } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Change options array' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
expect ( settings . get ( ) . advanced . ext _pan _id ) . toStrictEqual ( [ 221 , 221 , 221 , 221 , 221 , 221 , 221 , 221 ] )
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { advanced : { ext _pan _id : [ 220 , 221 , 221 , 221 , 221 , 221 , 221 , 221 ] } } } ) ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . advanced . ext _pan _id ) . toStrictEqual ( [ 220 , 221 , 221 , 221 , 221 , 221 , 221 , 221 ] ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : true } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-02-07 06:07:27 -07:00
it ( 'Change options with null' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
expect ( settings . get ( ) . serial ) . toStrictEqual ( { "disable_led" : false , "port" : "/dev/dummy" } )
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { "options" : { "serial" : { "disable_led" : false , "port" : null } } } ) ) ;
await flushPromises ( ) ;
expect ( settings . get ( ) . serial ) . toStrictEqual ( { "disable_led" : false , "port" : null } ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { "restart_required" : true } , "status" : "ok" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-02-06 08:32:20 -07:00
it ( 'Change options invalid payload' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , 'I am invalid' ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { } , "error" : "Invalid payload" , "status" : "error" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
it ( 'Change options not valid against schema' , async ( ) => {
zigbeeHerdsman . permitJoin . mockClear ( ) ;
MQTT . publish . mockClear ( ) ;
MQTT . events . message ( 'zigbee2mqtt/bridge/request/options' , stringify ( { options : { permit _join : 'true' } } ) ) ;
await flushPromises ( ) ;
expect ( MQTT . publish ) . toHaveBeenCalledWith (
'zigbee2mqtt/bridge/response/options' ,
stringify ( { "data" : { } , "error" : "permit_join should be boolean" , "status" : "error" } ) ,
{ retain : false , qos : 0 } , expect . any ( Function )
) ;
} ) ;
2021-04-08 07:57:55 -07:00
it ( 'Icon link handling' , async ( ) => {
const bridge = controller . extensions . find ( ( e ) => e . constructor . name === 'Bridge' ) ;
expect ( bridge ) . not . toBeUndefined ( ) ;
const definition = { 'model' : 'lumi.plug' } ;
const device = zigbeeHerdsman . devices . ZNCZ02LM ;
const icon _link = 'https://www.zigbee2mqtt.io/images/devices/ZNCZ02LM.jpg' ;
definition . icon = icon _link ;
let payload = bridge . getDefinitionPayload ( definition , { device : device } ) ;
expect ( payload ) . not . toBeUndefined ( )
expect ( payload [ 'icon' ] ) . not . toBeUndefined ( )
expect ( payload . icon ) . toBe ( icon _link ) ;
definition . icon = '_${model}_' ;
payload = bridge . getDefinitionPayload ( definition , { device : device } ) ;
expect ( payload ) . not . toBeUndefined ( )
expect ( payload [ 'icon' ] ) . not . toBeUndefined ( )
expect ( payload . icon ) . toBe ( '_lumi.plug_' ) ;
definition . icon = '_${model}_${zigbeeModel}_' ;
payload = bridge . getDefinitionPayload ( definition , { device : device } ) ;
expect ( payload ) . not . toBeUndefined ( )
expect ( payload [ 'icon' ] ) . not . toBeUndefined ( )
expect ( payload . icon ) . toBe ( '_lumi.plug_lumi.plug_' ) ;
const svg _icon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo' ;
definition . icon = svg _icon ;
payload = bridge . getDefinitionPayload ( definition , { device : device } ) ;
expect ( payload ) . not . toBeUndefined ( )
expect ( payload [ 'icon' ] ) . not . toBeUndefined ( )
expect ( payload . icon ) . toBe ( svg _icon ) ;
device . modelID = '?._Z\\NC+Z02*LM' ;
definition . model = '&&&&*+' ;
definition . icon = '_${model}_${zigbeeModel}_' ;
payload = bridge . getDefinitionPayload ( definition , { device : device } ) ;
expect ( payload ) . not . toBeUndefined ( )
expect ( payload [ 'icon' ] ) . not . toBeUndefined ( )
expect ( payload . icon ) . toBe ( '_------_-._Z-NC-Z02-LM_' ) ;
} ) ;
} ) ;