@digital-alchemy/hass 24.9.3 → 24.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/README.md +3 -0
  2. package/dist/dynamic.d.ts +1 -1
  3. package/dist/dynamic.js +7 -2
  4. package/dist/dynamic.js.map +1 -1
  5. package/dist/extensions/area.extension.d.ts +2 -12
  6. package/dist/extensions/area.extension.js +20 -26
  7. package/dist/extensions/area.extension.js.map +1 -1
  8. package/dist/extensions/backup.extension.d.ts +2 -7
  9. package/dist/extensions/backup.extension.js +5 -8
  10. package/dist/extensions/backup.extension.js.map +1 -1
  11. package/dist/extensions/call-proxy.extension.d.ts +1 -1
  12. package/dist/extensions/call-proxy.extension.js +3 -22
  13. package/dist/extensions/call-proxy.extension.js.map +1 -1
  14. package/dist/extensions/config.extension.d.ts +2 -6
  15. package/dist/extensions/config.extension.js +21 -25
  16. package/dist/extensions/config.extension.js.map +1 -1
  17. package/dist/extensions/conversation.extension.d.ts +2 -6
  18. package/dist/extensions/conversation.extension.js +5 -8
  19. package/dist/extensions/conversation.extension.js.map +1 -1
  20. package/dist/extensions/device.extension.d.ts +2 -5
  21. package/dist/extensions/device.extension.js +16 -22
  22. package/dist/extensions/device.extension.js.map +1 -1
  23. package/dist/extensions/entity.extension.d.ts +2 -61
  24. package/dist/extensions/entity.extension.js +42 -83
  25. package/dist/extensions/entity.extension.js.map +1 -1
  26. package/dist/extensions/events.extension.d.ts +3 -11
  27. package/dist/extensions/events.extension.js +8 -11
  28. package/dist/extensions/events.extension.js.map +1 -1
  29. package/dist/extensions/fetch-api.extension.d.ts +12 -4
  30. package/dist/extensions/fetch-api.extension.js +23 -35
  31. package/dist/extensions/fetch-api.extension.js.map +1 -1
  32. package/dist/extensions/floor.extension.d.ts +2 -9
  33. package/dist/extensions/floor.extension.js +17 -23
  34. package/dist/extensions/floor.extension.js.map +1 -1
  35. package/dist/extensions/id-by.extension.js +15 -20
  36. package/dist/extensions/id-by.extension.js.map +1 -1
  37. package/dist/extensions/index.d.ts +1 -0
  38. package/dist/extensions/index.js +16 -18
  39. package/dist/extensions/index.js.map +1 -1
  40. package/dist/extensions/internal.extension.d.ts +18 -0
  41. package/dist/extensions/internal.extension.js +102 -0
  42. package/dist/extensions/internal.extension.js.map +1 -0
  43. package/dist/extensions/label.extension.d.ts +2 -9
  44. package/dist/extensions/label.extension.js +17 -23
  45. package/dist/extensions/label.extension.js.map +1 -1
  46. package/dist/extensions/reference.extension.d.ts +2 -12
  47. package/dist/extensions/reference.extension.js +19 -25
  48. package/dist/extensions/reference.extension.js.map +1 -1
  49. package/dist/extensions/registry.extension.d.ts +2 -7
  50. package/dist/extensions/registry.extension.js +1 -4
  51. package/dist/extensions/registry.extension.js.map +1 -1
  52. package/dist/extensions/websocket-api.extension.d.ts +3 -78
  53. package/dist/extensions/websocket-api.extension.js +82 -165
  54. package/dist/extensions/websocket-api.extension.js.map +1 -1
  55. package/dist/extensions/zone.extension.d.ts +2 -7
  56. package/dist/extensions/zone.extension.js +15 -21
  57. package/dist/extensions/zone.extension.js.map +1 -1
  58. package/dist/hass.module.d.ts +47 -36
  59. package/dist/hass.module.js +70 -70
  60. package/dist/hass.module.js.map +1 -1
  61. package/dist/helpers/backup.helper.js +1 -2
  62. package/dist/helpers/constants.helper.js +15 -18
  63. package/dist/helpers/constants.helper.js.map +1 -1
  64. package/dist/helpers/device.helper.js +2 -5
  65. package/dist/helpers/device.helper.js.map +1 -1
  66. package/dist/helpers/entity-state.helper.d.ts +3 -8
  67. package/dist/helpers/entity-state.helper.js +1 -8
  68. package/dist/helpers/entity-state.helper.js.map +1 -1
  69. package/dist/helpers/features.helper.js +79 -85
  70. package/dist/helpers/features.helper.js.map +1 -1
  71. package/dist/helpers/fetch/calendar.js +1 -2
  72. package/dist/helpers/fetch/configuration.js +2 -5
  73. package/dist/helpers/fetch/configuration.js.map +1 -1
  74. package/dist/helpers/fetch/index.js +5 -8
  75. package/dist/helpers/fetch/index.js.map +1 -1
  76. package/dist/helpers/fetch/server-log.js +1 -2
  77. package/dist/helpers/fetch/server-log.js.map +1 -1
  78. package/dist/helpers/fetch/service-list.js +1 -2
  79. package/dist/helpers/fetch/weather-forecasts.js +1 -2
  80. package/dist/helpers/fetch/weather-forecasts.js.map +1 -1
  81. package/dist/helpers/fetch.helper.d.ts +162 -0
  82. package/dist/helpers/fetch.helper.js +161 -0
  83. package/dist/helpers/fetch.helper.js.map +1 -0
  84. package/dist/helpers/id-by.helper.js +1 -2
  85. package/dist/helpers/index.d.ts +2 -1
  86. package/dist/helpers/index.js +13 -15
  87. package/dist/helpers/index.js.map +1 -1
  88. package/dist/helpers/interfaces.helper.d.ts +228 -0
  89. package/dist/helpers/interfaces.helper.js +10 -0
  90. package/dist/helpers/interfaces.helper.js.map +1 -0
  91. package/dist/helpers/manifest.helper.d.ts +0 -1
  92. package/dist/helpers/manifest.helper.js +0 -1
  93. package/dist/helpers/notify.helper.d.ts +13 -5
  94. package/dist/helpers/notify.helper.js +1 -2
  95. package/dist/helpers/registry.js +7 -10
  96. package/dist/helpers/registry.js.map +1 -1
  97. package/dist/helpers/utility.helper.d.ts +6 -1
  98. package/dist/helpers/utility.helper.js +9 -13
  99. package/dist/helpers/utility.helper.js.map +1 -1
  100. package/dist/helpers/websocket.helper.d.ts +1 -2
  101. package/dist/helpers/websocket.helper.js +1 -2
  102. package/dist/index.js +5 -8
  103. package/dist/index.js.map +1 -1
  104. package/dist/mock_assistant/extensions/area.extension.d.ts +8 -0
  105. package/dist/mock_assistant/extensions/area.extension.js +51 -0
  106. package/dist/mock_assistant/extensions/area.extension.js.map +1 -0
  107. package/dist/mock_assistant/extensions/config.extension.d.ts +14 -0
  108. package/dist/mock_assistant/extensions/config.extension.js +29 -0
  109. package/dist/mock_assistant/extensions/config.extension.js.map +1 -0
  110. package/dist/mock_assistant/extensions/device.extension.d.ts +8 -0
  111. package/dist/mock_assistant/extensions/device.extension.js +33 -0
  112. package/dist/mock_assistant/extensions/device.extension.js.map +1 -0
  113. package/dist/mock_assistant/extensions/entity-registry.extension.d.ts +13 -0
  114. package/dist/mock_assistant/extensions/entity-registry.extension.js +28 -0
  115. package/dist/mock_assistant/extensions/entity-registry.extension.js.map +1 -0
  116. package/dist/mock_assistant/extensions/entity.extension.d.ts +30 -0
  117. package/dist/mock_assistant/extensions/entity.extension.js +77 -0
  118. package/dist/mock_assistant/extensions/entity.extension.js.map +1 -0
  119. package/dist/mock_assistant/extensions/events.extension.d.ts +1 -1
  120. package/dist/mock_assistant/extensions/events.extension.js +3 -6
  121. package/dist/mock_assistant/extensions/events.extension.js.map +1 -1
  122. package/dist/mock_assistant/extensions/fetch.extension.d.ts +1 -0
  123. package/dist/mock_assistant/extensions/fetch.extension.js +4 -0
  124. package/dist/mock_assistant/extensions/fetch.extension.js.map +1 -0
  125. package/dist/mock_assistant/extensions/fixtures.extension.d.ts +1 -1
  126. package/dist/mock_assistant/extensions/fixtures.extension.js +29 -33
  127. package/dist/mock_assistant/extensions/fixtures.extension.js.map +1 -1
  128. package/dist/mock_assistant/extensions/floor.extension.d.ts +8 -0
  129. package/dist/mock_assistant/extensions/floor.extension.js +51 -0
  130. package/dist/mock_assistant/extensions/floor.extension.js.map +1 -0
  131. package/dist/mock_assistant/extensions/index.d.ts +10 -0
  132. package/dist/mock_assistant/extensions/index.js +12 -5
  133. package/dist/mock_assistant/extensions/index.js.map +1 -1
  134. package/dist/mock_assistant/extensions/label.extension.d.ts +8 -0
  135. package/dist/mock_assistant/extensions/label.extension.js +51 -0
  136. package/dist/mock_assistant/extensions/label.extension.js.map +1 -0
  137. package/dist/mock_assistant/extensions/services.extension.d.ts +12 -0
  138. package/dist/mock_assistant/extensions/services.extension.js +20 -0
  139. package/dist/mock_assistant/extensions/services.extension.js.map +1 -0
  140. package/dist/mock_assistant/extensions/websocket-api.extension.d.ts +15 -0
  141. package/dist/mock_assistant/extensions/websocket-api.extension.js +68 -0
  142. package/dist/mock_assistant/extensions/websocket-api.extension.js.map +1 -0
  143. package/dist/mock_assistant/extensions/zone.extension.d.ts +8 -0
  144. package/dist/mock_assistant/extensions/zone.extension.js +51 -0
  145. package/dist/mock_assistant/extensions/zone.extension.js.map +1 -0
  146. package/dist/mock_assistant/helpers/fixtures.js +1 -2
  147. package/dist/mock_assistant/helpers/index.d.ts +0 -1
  148. package/dist/mock_assistant/helpers/index.js +1 -5
  149. package/dist/mock_assistant/helpers/index.js.map +1 -1
  150. package/dist/mock_assistant/index.js +3 -6
  151. package/dist/mock_assistant/index.js.map +1 -1
  152. package/dist/mock_assistant/main.js +11 -15
  153. package/dist/mock_assistant/main.js.map +1 -1
  154. package/dist/mock_assistant/mock-assistant.module.d.ts +156 -3
  155. package/dist/mock_assistant/mock-assistant.module.js +56 -11
  156. package/dist/mock_assistant/mock-assistant.module.js.map +1 -1
  157. package/dist/quickboot.module.js +5 -8
  158. package/dist/quickboot.module.js.map +1 -1
  159. package/dist/testing/area.spec.js +106 -194
  160. package/dist/testing/area.spec.js.map +1 -1
  161. package/dist/testing/backup.spec.js +97 -139
  162. package/dist/testing/backup.spec.js.map +1 -1
  163. package/dist/testing/config.spec.js +79 -153
  164. package/dist/testing/config.spec.js.map +1 -1
  165. package/dist/testing/device.spec.js +35 -69
  166. package/dist/testing/device.spec.js.map +1 -1
  167. package/dist/testing/entity.spec.js +94 -149
  168. package/dist/testing/entity.spec.js.map +1 -1
  169. package/dist/testing/events.spec.js +33 -57
  170. package/dist/testing/events.spec.js.map +1 -1
  171. package/dist/testing/fetch-api.spec.js +242 -427
  172. package/dist/testing/fetch-api.spec.js.map +1 -1
  173. package/dist/testing/fixtures.spec.d.ts +1 -0
  174. package/dist/testing/fixtures.spec.js +150 -0
  175. package/dist/testing/fixtures.spec.js.map +1 -0
  176. package/dist/testing/floor.spec.js +106 -194
  177. package/dist/testing/floor.spec.js.map +1 -1
  178. package/dist/testing/id-by.spec.js +68 -107
  179. package/dist/testing/id-by.spec.js.map +1 -1
  180. package/dist/testing/label.spec.js +106 -194
  181. package/dist/testing/label.spec.js.map +1 -1
  182. package/dist/testing/ref-by.spec.js +155 -219
  183. package/dist/testing/ref-by.spec.js.map +1 -1
  184. package/dist/testing/websocket.spec.d.ts +1 -8
  185. package/dist/testing/websocket.spec.js +35 -50
  186. package/dist/testing/websocket.spec.js.map +1 -1
  187. package/dist/testing/workflow.spec.js +82 -81
  188. package/dist/testing/workflow.spec.js.map +1 -1
  189. package/dist/testing/zone.spec.js +61 -113
  190. package/dist/testing/zone.spec.js.map +1 -1
  191. package/package.json +62 -44
  192. package/scripts/mock-assistant.sh +5 -0
  193. package/scripts/run-e2e.sh +7 -0
  194. package/scripts/test.sh +2 -0
  195. package/src/dynamic.ts +4254 -0
  196. package/src/extensions/area.extension.ts +118 -0
  197. package/src/extensions/backup.extension.ts +63 -0
  198. package/src/extensions/call-proxy.extension.ts +113 -0
  199. package/src/extensions/config.extension.ts +119 -0
  200. package/src/extensions/conversation.extension.ts +46 -0
  201. package/src/extensions/device.extension.ts +56 -0
  202. package/src/extensions/entity.extension.ts +344 -0
  203. package/src/extensions/events.extension.ts +25 -0
  204. package/src/extensions/fetch-api.extension.ts +269 -0
  205. package/src/extensions/floor.extension.ts +76 -0
  206. package/src/extensions/id-by.extension.ts +157 -0
  207. package/src/extensions/index.ts +16 -0
  208. package/src/extensions/internal.extension.ts +145 -0
  209. package/src/extensions/label.extension.ts +83 -0
  210. package/src/extensions/reference.extension.ts +330 -0
  211. package/src/extensions/registry.extension.ts +44 -0
  212. package/src/extensions/websocket-api.extension.ts +554 -0
  213. package/src/extensions/zone.extension.ts +69 -0
  214. package/src/hass.module.ts +217 -0
  215. package/src/helpers/backup.helper.ts +11 -0
  216. package/src/helpers/constants.helper.ts +30 -0
  217. package/src/helpers/device.helper.ts +25 -0
  218. package/src/helpers/entity-state.helper.ts +171 -0
  219. package/src/helpers/features.helper.ts +580 -0
  220. package/src/helpers/fetch/calendar.ts +54 -0
  221. package/src/helpers/fetch/configuration.ts +75 -0
  222. package/src/helpers/fetch/index.ts +5 -0
  223. package/src/helpers/fetch/server-log.ts +28 -0
  224. package/src/helpers/fetch/service-list.ts +64 -0
  225. package/src/helpers/fetch/weather-forecasts.ts +86 -0
  226. package/src/helpers/fetch.helper.ts +328 -0
  227. package/src/helpers/id-by.helper.ts +53 -0
  228. package/src/helpers/index.ts +13 -0
  229. package/src/helpers/interfaces.helper.ts +340 -0
  230. package/src/helpers/manifest.helper.ts +0 -0
  231. package/src/helpers/notify.helper.ts +302 -0
  232. package/src/helpers/registry.ts +281 -0
  233. package/src/helpers/utility.helper.ts +147 -0
  234. package/src/helpers/websocket.helper.ts +117 -0
  235. package/src/index.ts +5 -0
  236. package/src/mock_assistant/extensions/area.extension.ts +62 -0
  237. package/src/mock_assistant/extensions/config.extension.ts +33 -0
  238. package/src/mock_assistant/extensions/device.extension.ts +44 -0
  239. package/src/mock_assistant/extensions/entity-registry.extension.ts +41 -0
  240. package/src/mock_assistant/extensions/entity.extension.ts +114 -0
  241. package/src/mock_assistant/extensions/events.extension.ts +37 -0
  242. package/src/mock_assistant/extensions/fetch.extension.ts +3 -0
  243. package/src/mock_assistant/extensions/fixtures.extension.ts +79 -0
  244. package/src/mock_assistant/extensions/floor.extension.ts +64 -0
  245. package/src/mock_assistant/extensions/index.ts +12 -0
  246. package/src/mock_assistant/extensions/label.extension.ts +64 -0
  247. package/src/mock_assistant/extensions/services.extension.ts +25 -0
  248. package/src/mock_assistant/extensions/websocket-api.extension.ts +84 -0
  249. package/src/mock_assistant/extensions/zone.extension.ts +65 -0
  250. package/src/mock_assistant/helpers/fixtures.ts +22 -0
  251. package/src/mock_assistant/helpers/index.ts +1 -0
  252. package/src/mock_assistant/index.ts +3 -0
  253. package/src/mock_assistant/main.ts +46 -0
  254. package/src/mock_assistant/mock-assistant.module.ts +90 -0
  255. package/src/quickboot.module.ts +23 -0
  256. package/src/testing/area.spec.ts +189 -0
  257. package/src/testing/backup.spec.ts +157 -0
  258. package/src/testing/config.spec.ts +188 -0
  259. package/src/testing/device.spec.ts +89 -0
  260. package/src/testing/entity.spec.ts +171 -0
  261. package/src/testing/events.spec.ts +78 -0
  262. package/src/testing/fetch-api.spec.ts +410 -0
  263. package/src/testing/fixtures.spec.ts +158 -0
  264. package/src/testing/floor.spec.ts +186 -0
  265. package/src/testing/id-by.spec.ts +140 -0
  266. package/src/testing/label.spec.ts +186 -0
  267. package/src/testing/ref-by.spec.ts +300 -0
  268. package/src/testing/websocket.spec.ts +63 -0
  269. package/src/testing/workflow.spec.ts +195 -0
  270. package/src/testing/zone.spec.ts +109 -0
  271. package/dist/helpers/metrics.helper.d.ts +0 -29
  272. package/dist/helpers/metrics.helper.js +0 -62
  273. package/dist/helpers/metrics.helper.js.map +0 -1
  274. package/dist/mock_assistant/helpers/utils.d.ts +0 -4
  275. package/dist/mock_assistant/helpers/utils.js +0 -57
  276. package/dist/mock_assistant/helpers/utils.js.map +0 -1
@@ -0,0 +1,300 @@
1
+ import dayjs from "dayjs";
2
+
3
+ import { ANY_ENTITY, ENTITY_STATE } from "../helpers";
4
+ import { hassTestRunner } from "../mock_assistant";
5
+
6
+ describe("References", () => {
7
+ afterEach(async () => {
8
+ await hassTestRunner.teardown();
9
+ jest.restoreAllMocks();
10
+ });
11
+
12
+ describe("loading", function () {
13
+ describe("refBy.id", () => {
14
+ it("can grab references by id", async () => {
15
+ expect.assertions(2);
16
+ await hassTestRunner.run(({ lifecycle, hass }) => {
17
+ lifecycle.onReady(() => {
18
+ const sensor = hass.refBy.id("sensor.magic");
19
+ expect(sensor).toBeDefined();
20
+ expect(sensor.state).toBe("unavailable");
21
+ });
22
+ });
23
+ });
24
+ });
25
+
26
+ describe("domain", () => {
27
+ it("load references by domain", async () => {
28
+ expect.assertions(1);
29
+ await hassTestRunner.run(({ lifecycle, hass }) => {
30
+ lifecycle.onReady(() => {
31
+ const sensor = hass.refBy.domain("sensor");
32
+ expect(sensor.length).toBe(8);
33
+ });
34
+ });
35
+ });
36
+ });
37
+
38
+ describe("unique_id", () => {
39
+ it("load references by unique_id", async () => {
40
+ expect.assertions(1);
41
+ await hassTestRunner.run(({ lifecycle, hass }) => {
42
+ lifecycle.onReady(() => {
43
+ const sensor = hass.refBy.unique_id(
44
+ "e1806fdc93296bbd5ab42967003cd38729ff9ba6cfeefc3e15a03ad01ac894fe",
45
+ );
46
+ expect(sensor?.entity_id).toBe("sensor.magic");
47
+ });
48
+ });
49
+ });
50
+ });
51
+
52
+ describe("label", () => {
53
+ it("load references by label", async () => {
54
+ expect.assertions(1);
55
+ await hassTestRunner.run(({ lifecycle, hass }) => {
56
+ lifecycle.onReady(() => {
57
+ const list = hass.refBy.label("synapse");
58
+ expect(list.length).toBe(7);
59
+ });
60
+ });
61
+ });
62
+
63
+ it("load references by label limiting by domain", async () => {
64
+ expect.assertions(1);
65
+ await hassTestRunner.run(({ lifecycle, hass }) => {
66
+ lifecycle.onReady(() => {
67
+ const list = hass.refBy.label("synapse", "light");
68
+ expect(list.length).toBe(0);
69
+ });
70
+ });
71
+ });
72
+ });
73
+
74
+ describe("area", () => {
75
+ it("load references by area", async () => {
76
+ expect.assertions(2);
77
+ await hassTestRunner.run(({ lifecycle, hass }) => {
78
+ lifecycle.onReady(() => {
79
+ const bedroom = hass.refBy.area("bedroom");
80
+ const kitchen = hass.refBy.area("kitchen");
81
+ expect(bedroom.length).toBe(2);
82
+ expect(kitchen.length).toBe(1);
83
+ });
84
+ });
85
+ });
86
+
87
+ it("load references by area limiting by domain", async () => {
88
+ expect.assertions(2);
89
+ await hassTestRunner.run(({ lifecycle, hass }) => {
90
+ lifecycle.onReady(() => {
91
+ const bedroom = hass.refBy.area("bedroom", "light");
92
+ const kitchen = hass.refBy.area("kitchen", "light");
93
+ expect(bedroom.length).toBe(1);
94
+ expect(kitchen.length).toBe(0);
95
+ });
96
+ });
97
+ });
98
+ });
99
+
100
+ describe("device", () => {
101
+ it("load references by device", async () => {
102
+ expect.assertions(1);
103
+ await hassTestRunner.run(({ lifecycle, hass }) => {
104
+ lifecycle.onReady(() => {
105
+ const synapse = hass.refBy.device("308e39cf50a9fc6c30b4110724ed1f2e");
106
+ expect(synapse.length).toBe(9);
107
+ });
108
+ });
109
+ });
110
+
111
+ it("load references by device limiting by domain", async () => {
112
+ expect.assertions(1);
113
+ await hassTestRunner.run(({ lifecycle, hass }) => {
114
+ lifecycle.onReady(() => {
115
+ const synapse = hass.refBy.device("308e39cf50a9fc6c30b4110724ed1f2e", "light");
116
+ expect(synapse.length).toBe(0);
117
+ });
118
+ });
119
+ });
120
+ });
121
+
122
+ describe("platform", () => {
123
+ it("load references by platform", async () => {
124
+ expect.assertions(1);
125
+ await hassTestRunner.run(({ lifecycle, hass }) => {
126
+ lifecycle.onReady(() => {
127
+ const synapse = hass.refBy.platform("synapse");
128
+ expect(synapse.length).toBe(7);
129
+ });
130
+ });
131
+ });
132
+
133
+ it("load references by platform limiting by domain", async () => {
134
+ expect.assertions(1);
135
+ await hassTestRunner.run(({ lifecycle, hass }) => {
136
+ lifecycle.onReady(() => {
137
+ const synapse = hass.refBy.platform("synapse", "light");
138
+ expect(synapse.length).toBe(0);
139
+ });
140
+ });
141
+ });
142
+ });
143
+
144
+ describe("floor", () => {
145
+ it("load references by floor", async () => {
146
+ expect.assertions(1);
147
+ await hassTestRunner.run(({ lifecycle, hass }) => {
148
+ lifecycle.onReady(() => {
149
+ const synapse = hass.refBy.floor("downstairs");
150
+ expect(synapse.length).toBe(3);
151
+ });
152
+ });
153
+ });
154
+
155
+ it("load references by floor limiting by domain", async () => {
156
+ expect.assertions(1);
157
+ await hassTestRunner.run(({ lifecycle, hass }) => {
158
+ lifecycle.onReady(() => {
159
+ const synapse = hass.refBy.floor("downstairs", "light");
160
+ expect(synapse.length).toBe(0);
161
+ });
162
+ });
163
+ });
164
+ });
165
+ });
166
+
167
+ describe("functionality", () => {
168
+ describe("operators", () => {
169
+ it("has", async () => {
170
+ expect.assertions(15);
171
+ await hassTestRunner.run(({ lifecycle, hass }) => {
172
+ lifecycle.onReady(() => {
173
+ const entity = hass.refBy.id("switch.bedroom_lamp");
174
+ // always there stuff
175
+ expect("does not exist" in entity).toBe(false);
176
+ [
177
+ "attributes",
178
+ "entity_id",
179
+ "history",
180
+ "last",
181
+ "nextState",
182
+ "once",
183
+ "onUpdate",
184
+ "previous",
185
+ "removeAllListeners",
186
+ "state",
187
+ "waitForState",
188
+ ].forEach(property => expect(property in entity).toBe(true));
189
+ // service calls exist too
190
+ ["toggle", "turn_off", "turn_on"].forEach(method =>
191
+ expect(method in entity).toBe(true),
192
+ );
193
+ });
194
+ });
195
+ });
196
+
197
+ it("ownKeys", async () => {
198
+ expect.assertions(1);
199
+ await hassTestRunner.run(({ lifecycle, hass }) => {
200
+ lifecycle.onReady(() => {
201
+ const entity = hass.refBy.id("switch.bedroom_lamp");
202
+ const keys = Object.keys(entity);
203
+ // note: each section sorted alphabetically
204
+ expect(keys).toEqual([
205
+ // hard coded
206
+ "entity_id",
207
+ "state",
208
+ "attributes",
209
+ "last_changed",
210
+ "last_reported",
211
+ "last_updated",
212
+ "context",
213
+ "history",
214
+ "last",
215
+ "nextState",
216
+ "once",
217
+ "onUpdate",
218
+ "previous",
219
+ "removeAllListeners",
220
+ "waitForState",
221
+ // services
222
+ "toggle",
223
+ "turn_off",
224
+ "turn_on",
225
+ ]);
226
+ });
227
+ });
228
+ });
229
+ describe("set", () => {
230
+ it("state", () => {
231
+ // stub
232
+ });
233
+ it("attributes", () => {
234
+ // stub
235
+ });
236
+ it("everything else", () => {
237
+ // stub
238
+ });
239
+ });
240
+ });
241
+
242
+ describe("get", () => {
243
+ it("references have attributes", async () => {
244
+ expect.assertions(2);
245
+ await hassTestRunner.run(({ lifecycle, hass }) => {
246
+ lifecycle.onReady(() => {
247
+ const sensor = hass.refBy.id("sensor.magic");
248
+ expect("attributes" in sensor).toBe(true);
249
+ expect(sensor.attributes).toEqual(expect.objectContaining({ friendly_name: "magic" }));
250
+ });
251
+ });
252
+ });
253
+
254
+ // mental note: legacy test
255
+ // better covered by the ownKeys & has operator tests now
256
+ it("references do not return random attributes", async () => {
257
+ expect.assertions(1);
258
+ await hassTestRunner.run(({ lifecycle, hass }) => {
259
+ lifecycle.onReady(() => {
260
+ const sensor = hass.refBy.id("sensor.magic");
261
+ // @ts-expect-error it's the test
262
+ expect(sensor.foo).toBeUndefined();
263
+ });
264
+ });
265
+ });
266
+
267
+ it("references provide last_* as dayjs", async () => {
268
+ expect.assertions(3);
269
+ await hassTestRunner.run(({ lifecycle, hass }) => {
270
+ lifecycle.onReady(() => {
271
+ const sensor = hass.refBy.id("sensor.magic");
272
+ expect(sensor.last_changed instanceof dayjs).toBe(true);
273
+ expect(sensor.last_reported instanceof dayjs).toBe(true);
274
+ expect(sensor.last_updated instanceof dayjs).toBe(true);
275
+ });
276
+ });
277
+ });
278
+
279
+ it("passes through history calls", async () => {
280
+ expect.assertions(2);
281
+ await hassTestRunner.run(({ lifecycle, hass }) => {
282
+ lifecycle.onReady(async () => {
283
+ const result = [] as ENTITY_STATE<ANY_ENTITY>[];
284
+ const spy = jest
285
+ .spyOn(hass.fetch, "fetchEntityHistory")
286
+ .mockImplementation(async () => result);
287
+ const from = new Date();
288
+ const to = new Date();
289
+ const entity_id = "sensor.magic";
290
+
291
+ const entity = hass.refBy.id(entity_id);
292
+ const out = await entity.history(from, to);
293
+ expect(spy).toHaveBeenCalledWith(entity_id, from, to);
294
+ expect(out).toBe(result);
295
+ });
296
+ });
297
+ });
298
+ });
299
+ });
300
+ });
@@ -0,0 +1,63 @@
1
+ import { hassTestRunner } from "../mock_assistant";
2
+
3
+ describe("Websocket", () => {
4
+ afterEach(async () => {
5
+ await hassTestRunner.teardown();
6
+ jest.restoreAllMocks();
7
+ });
8
+
9
+ describe("API Interactions", () => {
10
+ it("should emit events onConnect", async () => {
11
+ expect.assertions(1);
12
+ await hassTestRunner.run(({ lifecycle, hass }) => {
13
+ let hit = false;
14
+ hass.socket.onConnect(() => (hit = true));
15
+ lifecycle.onReady(() => {
16
+ expect(hit).toBe(true);
17
+ });
18
+ });
19
+ });
20
+
21
+ it("should emit a socket message with subscribeEvents", async () => {
22
+ expect.assertions(1);
23
+ await hassTestRunner.run(({ lifecycle, hass, context }) => {
24
+ const spy = jest
25
+ .spyOn(hass.socket, "sendMessage")
26
+ .mockImplementation(async () => undefined);
27
+ lifecycle.onReady(async () => {
28
+ await hass.socket.subscribe({
29
+ context,
30
+ event_type: "test",
31
+ exec: () => {},
32
+ });
33
+ expect(spy).toHaveBeenCalledWith(
34
+ expect.objectContaining({
35
+ event_type: "test",
36
+ type: "subscribe_events",
37
+ }),
38
+ );
39
+ });
40
+ });
41
+ });
42
+
43
+ it("should emit a socket message with fireEvent", async () => {
44
+ expect.assertions(1);
45
+ await hassTestRunner.run(({ lifecycle, hass }) => {
46
+ const spy = jest
47
+ .spyOn(hass.socket, "sendMessage")
48
+ .mockImplementation(async () => undefined);
49
+ lifecycle.onReady(async () => {
50
+ const data = { example: "data" };
51
+ await hass.socket.fireEvent("test_event", data);
52
+ expect(spy).toHaveBeenCalledWith(
53
+ expect.objectContaining({
54
+ event_data: data,
55
+ event_type: "test_event",
56
+ type: "fire_event",
57
+ }),
58
+ );
59
+ });
60
+ });
61
+ });
62
+ });
63
+ });
@@ -0,0 +1,195 @@
1
+ import { CronExpression, SECOND, sleep } from "@digital-alchemy/core";
2
+ import dayjs from "dayjs";
3
+
4
+ import { hassTestRunner } from "../mock_assistant";
5
+
6
+ describe("Workflows", () => {
7
+ beforeAll(() => {
8
+ hassTestRunner.appendService(({ hass, scheduler }) => {
9
+ scheduler.cron({
10
+ async exec() {
11
+ await hass.call.switch.turn_on({
12
+ entity_id: "switch.bedroom_lamp",
13
+ });
14
+ },
15
+ schedule: CronExpression.EVERY_DAY_AT_8PM,
16
+ });
17
+
18
+ const entity = hass.refBy.id("sensor.magic");
19
+ entity.onUpdate(async () => {
20
+ const action = entity.state === "test" ? "turn_on" : "turn_off";
21
+ await hass.call.switch[action]({
22
+ entity_id: "switch.porch_light",
23
+ });
24
+ });
25
+
26
+ entity.onUpdate(async (new_state, old_state) => {
27
+ if (old_state.state === "away" && new_state.state === "here") {
28
+ await hass.call.switch.turn_on({
29
+ entity_id: "switch.living_room_mood_lights",
30
+ });
31
+ }
32
+ });
33
+ });
34
+ });
35
+
36
+ afterEach(async () => {
37
+ await hassTestRunner.teardown();
38
+ jest.restoreAllMocks();
39
+ });
40
+
41
+ describe("Event and Response", () => {
42
+ it("should be able to trigger a workflow", async () => {
43
+ expect.assertions(2);
44
+ await hassTestRunner.run(({ mock_assistant, hass, lifecycle }) => {
45
+ lifecycle.onReady(async () => {
46
+ const turnOn = jest.spyOn(hass.call.switch, "turn_on");
47
+ const turnOff = jest.spyOn(hass.call.switch, "turn_off");
48
+ await mock_assistant.events.emitEntityUpdate("sensor.magic", {
49
+ state: "test",
50
+ });
51
+ await mock_assistant.events.emitEntityUpdate("sensor.magic", {
52
+ state: "foo",
53
+ });
54
+ expect(turnOn).toHaveBeenCalledTimes(1);
55
+ expect(turnOff).toHaveBeenCalledTimes(1);
56
+ });
57
+ });
58
+ });
59
+
60
+ it("should be able to trigger a from an initial state", async () => {
61
+ expect.assertions(1);
62
+ await hassTestRunner.run(({ mock_assistant, hass, lifecycle }) => {
63
+ mock_assistant.fixtures.setState({
64
+ "sensor.magic": {
65
+ state: "away",
66
+ },
67
+ });
68
+ lifecycle.onReady(async () => {
69
+ const turnOn = jest.spyOn(hass.call.switch, "turn_on");
70
+ await mock_assistant.events.emitEntityUpdate("sensor.magic", {
71
+ state: "here",
72
+ });
73
+ await sleep(1);
74
+ expect(turnOn).toHaveBeenCalledWith({
75
+ entity_id: "switch.living_room_mood_lights",
76
+ });
77
+ });
78
+ });
79
+ });
80
+
81
+ it("should not trigger a from an invalid initial state", async () => {
82
+ expect.assertions(1);
83
+ await hassTestRunner.run(({ mock_assistant, hass, lifecycle }) => {
84
+ mock_assistant.fixtures.setState({
85
+ "sensor.magic": {
86
+ state: "mars",
87
+ },
88
+ });
89
+ lifecycle.onReady(async () => {
90
+ const turnOn = jest.spyOn(hass.call.switch, "turn_on");
91
+ await mock_assistant.events.emitEntityUpdate("sensor.magic", {
92
+ state: "here",
93
+ });
94
+ expect(turnOn).not.toHaveBeenCalledWith({
95
+ entity_id: "switch.living_room_mood_lights",
96
+ });
97
+ });
98
+ });
99
+ });
100
+ });
101
+
102
+ describe("Timers", () => {
103
+ beforeEach(() => {
104
+ jest.useFakeTimers();
105
+ });
106
+
107
+ afterEach(() => {
108
+ jest.useRealTimers();
109
+ });
110
+
111
+ it("should run at 3PM", async () => {
112
+ expect.assertions(1);
113
+ jest.setSystemTime(dayjs("2024-01-01 19:59:59").toDate());
114
+ jest.runOnlyPendingTimersAsync();
115
+ await hassTestRunner.run(({ hass, lifecycle }) => {
116
+ lifecycle.onReady(() => {
117
+ const turnOn = jest.spyOn(hass.call.switch, "turn_on");
118
+ jest.advanceTimersByTime(2 * SECOND);
119
+ expect(turnOn).toHaveBeenCalledWith({
120
+ entity_id: "switch.bedroom_lamp",
121
+ });
122
+ });
123
+ });
124
+ });
125
+ });
126
+
127
+ describe("Call", () => {
128
+ const EXPECTED_KEYS = [
129
+ "persistent_notification",
130
+ "homeassistant",
131
+ "system_log",
132
+ "logger",
133
+ "recorder",
134
+ "person",
135
+ "frontend",
136
+ "cloud",
137
+ "ffmpeg",
138
+ "tts",
139
+ "scene",
140
+ "timer",
141
+ "input_number",
142
+ "conversation",
143
+ "input_select",
144
+ "zone",
145
+ "input_button",
146
+ "script",
147
+ "automation",
148
+ "logbook",
149
+ "input_boolean",
150
+ "button",
151
+ "switch",
152
+ "input_datetime",
153
+ "backup",
154
+ "shopping_list",
155
+ "counter",
156
+ "schedule",
157
+ "input_text",
158
+ "synapse",
159
+ "todo",
160
+ "notify",
161
+ "calendar",
162
+ ];
163
+ it("does not allow set", async () => {
164
+ expect.assertions(1);
165
+ await hassTestRunner.run(({ hass }) => {
166
+ try {
167
+ // @ts-expect-error testing
168
+ hass.call.button = {};
169
+ } catch (error) {
170
+ expect(error).toBeDefined();
171
+ }
172
+ });
173
+ });
174
+
175
+ it("provides keys via ownKeys", async () => {
176
+ expect.assertions(1);
177
+ await hassTestRunner.run(({ hass, lifecycle }) => {
178
+ lifecycle.onReady(() => {
179
+ const keys = Object.keys(hass.call);
180
+ expect(keys).toEqual(EXPECTED_KEYS);
181
+ });
182
+ });
183
+ });
184
+
185
+ it("does has correctly", async () => {
186
+ expect.assertions(34);
187
+ await hassTestRunner.run(({ hass, lifecycle }) => {
188
+ lifecycle.onReady(() => {
189
+ EXPECTED_KEYS.forEach(i => expect(i in hass.call).toBe(true));
190
+ expect("unknown_property" in hass.call).toBe(false);
191
+ });
192
+ });
193
+ });
194
+ });
195
+ });
@@ -0,0 +1,109 @@
1
+ import { sleep } from "@digital-alchemy/core";
2
+
3
+ import { ZONE_REGISTRY_UPDATED, ZoneDetails } from "../helpers";
4
+ import { hassTestRunner } from "../mock_assistant";
5
+
6
+ describe("Zone", () => {
7
+ afterEach(async () => {
8
+ await hassTestRunner.teardown();
9
+ jest.restoreAllMocks();
10
+ });
11
+
12
+ const EXAMPLE_ZONE = {
13
+ icon: "",
14
+ latitude: 0,
15
+ longitude: 0,
16
+ name: "Test",
17
+ passive: true,
18
+ } as ZoneDetails;
19
+
20
+ describe("Lifecycle", () => {
21
+ it("should force values to be available before ready", async () => {
22
+ expect.assertions(1);
23
+ await hassTestRunner.run(({ lifecycle, hass }) => {
24
+ const spy = jest
25
+ .spyOn(hass.socket, "sendMessage")
26
+ .mockImplementation(async () => [EXAMPLE_ZONE]);
27
+ lifecycle.onReady(async () => {
28
+ await hass.zone.list();
29
+ expect(spy).toHaveBeenCalledWith(expect.objectContaining({ type: "zone/list" }));
30
+ });
31
+ });
32
+ });
33
+ });
34
+
35
+ describe("API", () => {
36
+ describe("Formatting", () => {
37
+ it("should call list properly", async () => {
38
+ expect.assertions(1);
39
+ await hassTestRunner.run(({ lifecycle, hass }) => {
40
+ const spy = jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => []);
41
+ lifecycle.onReady(async () => {
42
+ await hass.zone.list();
43
+ expect(spy).toHaveBeenCalledWith(expect.objectContaining({ type: "zone/list" }));
44
+ });
45
+ });
46
+ });
47
+
48
+ it("should call create properly", async () => {
49
+ expect.assertions(1);
50
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
51
+ const spy = jest
52
+ .spyOn(hass.socket, "sendMessage")
53
+ .mockImplementation(async () => undefined);
54
+ lifecycle.onReady(async () => {
55
+ setImmediate(() => event.emit(ZONE_REGISTRY_UPDATED));
56
+ await hass.zone.create(EXAMPLE_ZONE);
57
+
58
+ expect(spy).toHaveBeenCalledWith({
59
+ type: "zone/create",
60
+ ...EXAMPLE_ZONE,
61
+ });
62
+ });
63
+ });
64
+ });
65
+ });
66
+
67
+ describe("Order of operations", () => {
68
+ it("should debounce updates properly", async () => {
69
+ expect.assertions(1);
70
+ await hassTestRunner.run(({ lifecycle, hass }) => {
71
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
72
+ let counter = 0;
73
+ hass.events.onZoneRegistryUpdate(() => counter++);
74
+ lifecycle.onReady(async () => {
75
+ setImmediate(async () => {
76
+ hass.socket.socketEvents.emit("zone_registry_updated");
77
+ await sleep(5);
78
+ hass.socket.socketEvents.emit("zone_registry_updated");
79
+ await sleep(5);
80
+ hass.socket.socketEvents.emit("zone_registry_updated");
81
+ await sleep(75);
82
+ hass.socket.socketEvents.emit("zone_registry_updated");
83
+ });
84
+ await sleep(200);
85
+ expect(counter).toBe(2);
86
+ });
87
+ });
88
+ });
89
+
90
+ it("should wait for an update before returning when creating", async () => {
91
+ expect.assertions(1);
92
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
93
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
94
+ lifecycle.onReady(async () => {
95
+ const response = hass.zone.create(EXAMPLE_ZONE);
96
+ let order = "";
97
+ setTimeout(() => {
98
+ order += "a";
99
+ event.emit(ZONE_REGISTRY_UPDATED);
100
+ }, 5);
101
+ await response;
102
+ order += "b";
103
+ expect(order).toEqual("ab");
104
+ });
105
+ });
106
+ });
107
+ });
108
+ });
109
+ });
@@ -1,29 +0,0 @@
1
- import { Counter, Gauge, Summary } from "prom-client";
2
- /**
3
- * Tracks the number of times a socket event callback has been executed.
4
- */
5
- export declare const SOCKET_EVENT_EXECUTION_COUNT: Counter<"event" | "context" | "label">;
6
- /**
7
- * Counts the number of errors occurred during socket event callback executions.
8
- */
9
- export declare const SOCKET_EVENT_ERRORS: Counter<"event" | "context" | "label">;
10
- /**
11
- * Counts the number of errors occurred during socket event callback executions.
12
- */
13
- export declare const SOCKET_SENT_MESSAGES: Counter<"type">;
14
- /**
15
- * Counts the number of errors occurred during socket event callback executions.
16
- */
17
- export declare const SOCKET_RECEIVED_MESSAGES: Counter<"type">;
18
- /**
19
- * Summary for Execution Time
20
- */
21
- export declare const SOCKET_EVENT_EXECUTION_TIME: Summary<"event" | "context" | "label">;
22
- /**
23
- * Show the current state
24
- */
25
- export declare const SOCKET_CONNECTION_STATE: Gauge<"state">;
26
- /**
27
- * Counter for service calls made through the call proxy
28
- */
29
- export declare const CALL_PROXY_SERVICE_CALL: Counter<"service" | "domain">;