@digital-alchemy/hass 24.9.4 → 24.10.1

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 (89) hide show
  1. package/README.md +1 -1
  2. package/dist/extensions/call-proxy.extension.d.ts +1 -1
  3. package/dist/extensions/call-proxy.extension.js +4 -1
  4. package/dist/extensions/call-proxy.extension.js.map +1 -1
  5. package/dist/extensions/entity.extension.js +3 -0
  6. package/dist/extensions/entity.extension.js.map +1 -1
  7. package/dist/extensions/websocket-api.extension.js +5 -11
  8. package/dist/extensions/websocket-api.extension.js.map +1 -1
  9. package/dist/helpers/notify.helper.d.ts +2 -2
  10. package/package.json +16 -14
  11. package/scripts/mock-assistant.sh +5 -0
  12. package/scripts/run-e2e.sh +7 -0
  13. package/scripts/test.sh +2 -0
  14. package/src/dynamic.ts +4254 -0
  15. package/src/extensions/area.extension.ts +118 -0
  16. package/src/extensions/backup.extension.ts +63 -0
  17. package/src/extensions/call-proxy.extension.ts +122 -0
  18. package/src/extensions/config.extension.ts +119 -0
  19. package/src/extensions/conversation.extension.ts +46 -0
  20. package/src/extensions/device.extension.ts +56 -0
  21. package/src/extensions/entity.extension.ts +347 -0
  22. package/src/extensions/events.extension.ts +25 -0
  23. package/src/extensions/fetch-api.extension.ts +269 -0
  24. package/src/extensions/floor.extension.ts +76 -0
  25. package/src/extensions/id-by.extension.ts +157 -0
  26. package/src/extensions/index.ts +16 -0
  27. package/src/extensions/internal.extension.ts +145 -0
  28. package/src/extensions/label.extension.ts +83 -0
  29. package/src/extensions/reference.extension.ts +330 -0
  30. package/src/extensions/registry.extension.ts +44 -0
  31. package/src/extensions/websocket-api.extension.ts +551 -0
  32. package/src/extensions/zone.extension.ts +69 -0
  33. package/src/hass.module.ts +217 -0
  34. package/src/helpers/backup.helper.ts +11 -0
  35. package/src/helpers/constants.helper.ts +30 -0
  36. package/src/helpers/device.helper.ts +25 -0
  37. package/src/helpers/entity-state.helper.ts +171 -0
  38. package/src/helpers/features.helper.ts +580 -0
  39. package/src/helpers/fetch/calendar.ts +54 -0
  40. package/src/helpers/fetch/configuration.ts +75 -0
  41. package/src/helpers/fetch/index.ts +5 -0
  42. package/src/helpers/fetch/server-log.ts +28 -0
  43. package/src/helpers/fetch/service-list.ts +64 -0
  44. package/src/helpers/fetch/weather-forecasts.ts +86 -0
  45. package/src/helpers/fetch.helper.ts +328 -0
  46. package/src/helpers/id-by.helper.ts +53 -0
  47. package/src/helpers/index.ts +13 -0
  48. package/src/helpers/interfaces.helper.ts +340 -0
  49. package/src/helpers/manifest.helper.ts +0 -0
  50. package/src/helpers/notify.helper.ts +302 -0
  51. package/src/helpers/registry.ts +281 -0
  52. package/src/helpers/utility.helper.ts +147 -0
  53. package/src/helpers/websocket.helper.ts +117 -0
  54. package/src/index.ts +5 -0
  55. package/src/mock_assistant/extensions/area.extension.ts +62 -0
  56. package/src/mock_assistant/extensions/config.extension.ts +33 -0
  57. package/src/mock_assistant/extensions/device.extension.ts +44 -0
  58. package/src/mock_assistant/extensions/entity-registry.extension.ts +41 -0
  59. package/src/mock_assistant/extensions/entity.extension.ts +114 -0
  60. package/src/mock_assistant/extensions/events.extension.ts +37 -0
  61. package/src/mock_assistant/extensions/fetch.extension.ts +3 -0
  62. package/src/mock_assistant/extensions/fixtures.extension.ts +79 -0
  63. package/src/mock_assistant/extensions/floor.extension.ts +64 -0
  64. package/src/mock_assistant/extensions/index.ts +12 -0
  65. package/src/mock_assistant/extensions/label.extension.ts +64 -0
  66. package/src/mock_assistant/extensions/services.extension.ts +25 -0
  67. package/src/mock_assistant/extensions/websocket-api.extension.ts +84 -0
  68. package/src/mock_assistant/extensions/zone.extension.ts +65 -0
  69. package/src/mock_assistant/helpers/fixtures.ts +22 -0
  70. package/src/mock_assistant/helpers/index.ts +1 -0
  71. package/src/mock_assistant/index.ts +3 -0
  72. package/src/mock_assistant/main.ts +46 -0
  73. package/src/mock_assistant/mock-assistant.module.ts +90 -0
  74. package/src/quickboot.module.ts +23 -0
  75. package/src/testing/area.spec.ts +189 -0
  76. package/src/testing/backup.spec.ts +157 -0
  77. package/src/testing/config.spec.ts +188 -0
  78. package/src/testing/device.spec.ts +89 -0
  79. package/src/testing/entity.spec.ts +171 -0
  80. package/src/testing/events.spec.ts +78 -0
  81. package/src/testing/fetch-api.spec.ts +410 -0
  82. package/src/testing/fixtures.spec.ts +158 -0
  83. package/src/testing/floor.spec.ts +186 -0
  84. package/src/testing/id-by.spec.ts +140 -0
  85. package/src/testing/label.spec.ts +186 -0
  86. package/src/testing/ref-by.spec.ts +300 -0
  87. package/src/testing/websocket.spec.ts +63 -0
  88. package/src/testing/workflow.spec.ts +195 -0
  89. package/src/testing/zone.spec.ts +109 -0
@@ -0,0 +1,186 @@
1
+ import { sleep } from "@digital-alchemy/core";
2
+
3
+ import { TFloorId } from "../dynamic";
4
+ import { FLOOR_REGISTRY_UPDATED, FloorDetails } from "../helpers";
5
+ import { hassTestRunner } from "../mock_assistant";
6
+
7
+ describe("Floor", () => {
8
+ const EXAMPLE_FLOOR = {
9
+ aliases: [],
10
+ floor_id: "upstairs",
11
+ icon: null,
12
+ level: 2,
13
+ name: "Upstairs",
14
+ } as unknown as FloorDetails;
15
+
16
+ afterEach(async () => {
17
+ await hassTestRunner.teardown();
18
+ jest.restoreAllMocks();
19
+ });
20
+
21
+ describe("Lifecycle", () => {
22
+ it("should force values to be available before ready", async () => {
23
+ expect.assertions(1);
24
+ await hassTestRunner.run(({ lifecycle, hass }) => {
25
+ const spy = jest
26
+ .spyOn(hass.socket, "sendMessage")
27
+ .mockImplementation(async () => [EXAMPLE_FLOOR]);
28
+ lifecycle.onReady(async () => {
29
+ await hass.floor.list();
30
+ expect(spy).toHaveBeenCalledWith(
31
+ expect.objectContaining({ type: "config/floor_registry/list" }),
32
+ );
33
+ });
34
+ });
35
+ });
36
+ });
37
+
38
+ describe("API", () => {
39
+ describe("Formatting", () => {
40
+ it("should call list properly", async () => {
41
+ expect.assertions(1);
42
+ await hassTestRunner.run(({ lifecycle, hass }) => {
43
+ const spy = jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => []);
44
+ lifecycle.onReady(async () => {
45
+ await hass.floor.list();
46
+ expect(spy).toHaveBeenCalledWith(
47
+ expect.objectContaining({ type: "config/floor_registry/list" }),
48
+ );
49
+ });
50
+ });
51
+ });
52
+
53
+ it("should call update properly", async () => {
54
+ expect.assertions(1);
55
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
56
+ const spy = jest
57
+ .spyOn(hass.socket, "sendMessage")
58
+ .mockImplementation(async () => undefined);
59
+ lifecycle.onReady(async () => {
60
+ setImmediate(() => event.emit(FLOOR_REGISTRY_UPDATED));
61
+ await hass.floor.update(EXAMPLE_FLOOR);
62
+
63
+ expect(spy).toHaveBeenCalledWith({
64
+ type: "config/floor_registry/update",
65
+ ...EXAMPLE_FLOOR,
66
+ });
67
+ });
68
+ });
69
+ });
70
+
71
+ it("should call delete properly", async () => {
72
+ expect.assertions(1);
73
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
74
+ const spy = jest
75
+ .spyOn(hass.socket, "sendMessage")
76
+ .mockImplementation(async () => undefined);
77
+ lifecycle.onReady(async () => {
78
+ setImmediate(() => event.emit(FLOOR_REGISTRY_UPDATED));
79
+ await hass.floor.delete(EXAMPLE_FLOOR.floor_id);
80
+
81
+ expect(spy).toHaveBeenCalledWith({
82
+ floor_id: "upstairs",
83
+ type: "config/floor_registry/delete",
84
+ });
85
+ });
86
+ });
87
+ });
88
+
89
+ it("should call create properly", async () => {
90
+ expect.assertions(1);
91
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
92
+ const spy = jest
93
+ .spyOn(hass.socket, "sendMessage")
94
+ .mockImplementation(async () => undefined);
95
+ lifecycle.onReady(async () => {
96
+ setImmediate(() => event.emit(FLOOR_REGISTRY_UPDATED));
97
+ await hass.floor.create(EXAMPLE_FLOOR);
98
+
99
+ expect(spy).toHaveBeenCalledWith({
100
+ type: "config/floor_registry/create",
101
+ ...EXAMPLE_FLOOR,
102
+ });
103
+ });
104
+ });
105
+ });
106
+ });
107
+
108
+ describe("Order of operations", () => {
109
+ it("should wait for an update before returning when updating", async () => {
110
+ expect.assertions(1);
111
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
112
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
113
+ lifecycle.onReady(async () => {
114
+ const response = hass.floor.update(EXAMPLE_FLOOR);
115
+ let order = "";
116
+ setTimeout(() => {
117
+ order += "a";
118
+ event.emit(FLOOR_REGISTRY_UPDATED);
119
+ }, 5);
120
+ await response;
121
+ order += "b";
122
+ expect(order).toEqual("ab");
123
+ });
124
+ });
125
+ });
126
+
127
+ it("should debounce updates properly", async () => {
128
+ expect.assertions(1);
129
+ await hassTestRunner.run(({ lifecycle, hass }) => {
130
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
131
+ let counter = 0;
132
+ hass.events.onFloorRegistryUpdate(() => counter++);
133
+ lifecycle.onReady(async () => {
134
+ setImmediate(async () => {
135
+ hass.socket.socketEvents.emit("floor_registry_updated");
136
+ await sleep(5);
137
+ hass.socket.socketEvents.emit("floor_registry_updated");
138
+ await sleep(5);
139
+ hass.socket.socketEvents.emit("floor_registry_updated");
140
+ await sleep(75);
141
+ hass.socket.socketEvents.emit("floor_registry_updated");
142
+ });
143
+ await sleep(200);
144
+ expect(counter).toBe(2);
145
+ });
146
+ });
147
+ });
148
+
149
+ it("should wait for an update before returning when deleting", async () => {
150
+ expect.assertions(1);
151
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
152
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
153
+ lifecycle.onReady(async () => {
154
+ const response = hass.floor.delete("example_floor" as TFloorId);
155
+ let order = "";
156
+ setTimeout(() => {
157
+ order += "a";
158
+ event.emit(FLOOR_REGISTRY_UPDATED);
159
+ }, 5);
160
+ await response;
161
+ order += "b";
162
+ expect(order).toEqual("ab");
163
+ });
164
+ });
165
+ });
166
+
167
+ it("should wait for an update before returning when creating", async () => {
168
+ expect.assertions(1);
169
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
170
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
171
+ lifecycle.onReady(async () => {
172
+ const response = hass.floor.create(EXAMPLE_FLOOR);
173
+ let order = "";
174
+ setTimeout(() => {
175
+ order += "a";
176
+ event.emit(FLOOR_REGISTRY_UPDATED);
177
+ }, 5);
178
+ await response;
179
+ order += "b";
180
+ expect(order).toEqual("ab");
181
+ });
182
+ });
183
+ });
184
+ });
185
+ });
186
+ });
@@ -0,0 +1,140 @@
1
+ import { PICK_ENTITY } from "../helpers";
2
+ import { hassTestRunner } from "../mock_assistant";
3
+
4
+ describe("ID By", () => {
5
+ afterEach(async () => {
6
+ await hassTestRunner.teardown();
7
+ jest.restoreAllMocks();
8
+ });
9
+
10
+ describe("area", () => {
11
+ it("find entities by area", async () => {
12
+ expect.assertions(2);
13
+ await hassTestRunner.run(({ lifecycle, hass }) => {
14
+ lifecycle.onReady(() => {
15
+ const bedroom = hass.idBy.area("bedroom");
16
+ const kitchen = hass.idBy.area("kitchen");
17
+ expect(bedroom.length).toBe(2);
18
+ expect(kitchen.length).toBe(1);
19
+ });
20
+ });
21
+ });
22
+
23
+ it("finds entities only related by device", async () => {
24
+ expect.assertions(1);
25
+ await hassTestRunner.run(({ lifecycle, hass }) => {
26
+ lifecycle.onReady(() => {
27
+ // merges 1 from direct area, 2 via device
28
+ // ignores 2 from the device assigned to another area
29
+ const list = hass.idBy.area("test") as PICK_ENTITY[];
30
+ const expected = [
31
+ "sensor.sun_next_dusk",
32
+ "climate.hallway_thermostat",
33
+ "binary_sensor.garage_door",
34
+ ] as PICK_ENTITY[];
35
+ expect(expected.every(expected => list.includes(expected))).toBe(true);
36
+ });
37
+ });
38
+ });
39
+
40
+ it("find entities by area limiting by domain", async () => {
41
+ expect.assertions(2);
42
+ await hassTestRunner.run(({ lifecycle, hass }) => {
43
+ lifecycle.onReady(() => {
44
+ const bedroom = hass.idBy.area("bedroom", "light");
45
+ const kitchen = hass.idBy.area("kitchen", "light");
46
+ expect(bedroom.length).toBe(1);
47
+ expect(kitchen.length).toBe(0);
48
+ });
49
+ });
50
+ });
51
+ });
52
+
53
+ describe("label", () => {
54
+ it("find entities by label", async () => {
55
+ expect.assertions(1);
56
+ await hassTestRunner.run(({ lifecycle, hass }) => {
57
+ lifecycle.onReady(() => {
58
+ const synapse = hass.idBy.label("synapse");
59
+ expect(synapse.length).toBe(7);
60
+ });
61
+ });
62
+ });
63
+
64
+ it("find entities by label limiting by domain", async () => {
65
+ expect.assertions(1);
66
+ await hassTestRunner.run(({ lifecycle, hass }) => {
67
+ lifecycle.onReady(() => {
68
+ const synapse = hass.idBy.label("synapse", "light");
69
+ expect(synapse.length).toBe(0);
70
+ });
71
+ });
72
+ });
73
+ });
74
+
75
+ describe("device", () => {
76
+ it("find entities by device", async () => {
77
+ expect.assertions(1);
78
+ await hassTestRunner.run(({ lifecycle, hass }) => {
79
+ lifecycle.onReady(() => {
80
+ const synapse = hass.idBy.device("308e39cf50a9fc6c30b4110724ed1f2e");
81
+ expect(synapse.length).toBe(9);
82
+ });
83
+ });
84
+ });
85
+
86
+ it("find entities by device limiting by domain", async () => {
87
+ expect.assertions(1);
88
+ await hassTestRunner.run(({ lifecycle, hass }) => {
89
+ lifecycle.onReady(() => {
90
+ const synapse = hass.idBy.device("308e39cf50a9fc6c30b4110724ed1f2e", "light");
91
+ expect(synapse.length).toBe(0);
92
+ });
93
+ });
94
+ });
95
+ });
96
+
97
+ describe("platform", () => {
98
+ it("find entities by platform", async () => {
99
+ expect.assertions(1);
100
+ await hassTestRunner.run(({ lifecycle, hass }) => {
101
+ lifecycle.onReady(() => {
102
+ const synapse = hass.idBy.platform("synapse");
103
+ expect(synapse.length).toBe(7);
104
+ });
105
+ });
106
+ });
107
+
108
+ it("find entities by platform limiting by domain", async () => {
109
+ expect.assertions(1);
110
+ await hassTestRunner.run(({ lifecycle, hass }) => {
111
+ lifecycle.onReady(() => {
112
+ const synapse = hass.idBy.platform("synapse", "light");
113
+ expect(synapse.length).toBe(0);
114
+ });
115
+ });
116
+ });
117
+ });
118
+
119
+ describe("floor", () => {
120
+ it("find entities by floor", async () => {
121
+ expect.assertions(1);
122
+ await hassTestRunner.run(({ lifecycle, hass }) => {
123
+ lifecycle.onReady(() => {
124
+ const synapse = hass.idBy.floor("downstairs");
125
+ expect(synapse.length).toBe(3);
126
+ });
127
+ });
128
+ });
129
+
130
+ it("find entities by floor limiting by domain", async () => {
131
+ expect.assertions(1);
132
+ await hassTestRunner.run(({ lifecycle, hass }) => {
133
+ lifecycle.onReady(() => {
134
+ const synapse = hass.idBy.floor("downstairs", "light");
135
+ expect(synapse.length).toBe(0);
136
+ });
137
+ });
138
+ });
139
+ });
140
+ });
@@ -0,0 +1,186 @@
1
+ import { sleep } from "@digital-alchemy/core";
2
+
3
+ import { TLabelId } from "../dynamic";
4
+ import { LABEL_REGISTRY_UPDATED, LabelDefinition } from "../helpers";
5
+ import { hassTestRunner } from "../mock_assistant";
6
+
7
+ describe("Label", () => {
8
+ const EXAMPLE_LABEL = {
9
+ color: "accent",
10
+ description: "test",
11
+ icon: "mdi:brain",
12
+ label_id: "synapse",
13
+ name: "synapse",
14
+ } as unknown as LabelDefinition;
15
+
16
+ afterEach(async () => {
17
+ await hassTestRunner.teardown();
18
+ jest.restoreAllMocks();
19
+ });
20
+
21
+ describe("Lifecycle", () => {
22
+ it("should force values to be available before ready", async () => {
23
+ expect.assertions(1);
24
+ await hassTestRunner.run(({ lifecycle, hass }) => {
25
+ const spy = jest
26
+ .spyOn(hass.socket, "sendMessage")
27
+ .mockImplementation(async () => [EXAMPLE_LABEL]);
28
+ lifecycle.onReady(async () => {
29
+ await hass.label.list();
30
+ expect(spy).toHaveBeenCalledWith(
31
+ expect.objectContaining({ type: "config/label_registry/list" }),
32
+ );
33
+ });
34
+ });
35
+ });
36
+ });
37
+
38
+ describe("API", () => {
39
+ describe("Formatting", () => {
40
+ it("should call list properly", async () => {
41
+ expect.assertions(1);
42
+ await hassTestRunner.run(({ lifecycle, hass }) => {
43
+ const spy = jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => []);
44
+ lifecycle.onReady(async () => {
45
+ await hass.label.list();
46
+ expect(spy).toHaveBeenCalledWith(
47
+ expect.objectContaining({ type: "config/label_registry/list" }),
48
+ );
49
+ });
50
+ });
51
+ });
52
+
53
+ it("should call update properly", async () => {
54
+ expect.assertions(1);
55
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
56
+ const spy = jest
57
+ .spyOn(hass.socket, "sendMessage")
58
+ .mockImplementation(async () => undefined);
59
+ lifecycle.onReady(async () => {
60
+ setImmediate(() => event.emit(LABEL_REGISTRY_UPDATED));
61
+ await hass.label.update(EXAMPLE_LABEL);
62
+
63
+ expect(spy).toHaveBeenCalledWith({
64
+ type: "config/label_registry/update",
65
+ ...EXAMPLE_LABEL,
66
+ });
67
+ });
68
+ });
69
+ });
70
+
71
+ it("should call delete properly", async () => {
72
+ expect.assertions(1);
73
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
74
+ const spy = jest
75
+ .spyOn(hass.socket, "sendMessage")
76
+ .mockImplementation(async () => undefined);
77
+ lifecycle.onReady(async () => {
78
+ setImmediate(() => event.emit(LABEL_REGISTRY_UPDATED));
79
+ await hass.label.delete(EXAMPLE_LABEL.label_id);
80
+
81
+ expect(spy).toHaveBeenCalledWith({
82
+ label_id: "synapse",
83
+ type: "config/label_registry/delete",
84
+ });
85
+ });
86
+ });
87
+ });
88
+
89
+ it("should call create properly", async () => {
90
+ expect.assertions(1);
91
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
92
+ const spy = jest
93
+ .spyOn(hass.socket, "sendMessage")
94
+ .mockImplementation(async () => undefined);
95
+ lifecycle.onReady(async () => {
96
+ setImmediate(() => event.emit(LABEL_REGISTRY_UPDATED));
97
+ await hass.label.create(EXAMPLE_LABEL);
98
+
99
+ expect(spy).toHaveBeenCalledWith({
100
+ type: "config/label_registry/create",
101
+ ...EXAMPLE_LABEL,
102
+ });
103
+ });
104
+ });
105
+ });
106
+ });
107
+
108
+ describe("Order of operations", () => {
109
+ it("should wait for an update before returning when updating", async () => {
110
+ expect.assertions(1);
111
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
112
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
113
+ lifecycle.onReady(async () => {
114
+ const response = hass.label.update(EXAMPLE_LABEL);
115
+ let order = "";
116
+ setTimeout(() => {
117
+ order += "a";
118
+ event.emit(LABEL_REGISTRY_UPDATED);
119
+ }, 5);
120
+ await response;
121
+ order += "b";
122
+ expect(order).toEqual("ab");
123
+ });
124
+ });
125
+ });
126
+
127
+ it("should debounce updates properly", async () => {
128
+ expect.assertions(1);
129
+ await hassTestRunner.run(({ lifecycle, hass }) => {
130
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
131
+ let counter = 0;
132
+ hass.events.onLabelRegistryUpdate(() => counter++);
133
+ lifecycle.onReady(async () => {
134
+ setImmediate(async () => {
135
+ hass.socket.socketEvents.emit("label_registry_updated");
136
+ await sleep(5);
137
+ hass.socket.socketEvents.emit("label_registry_updated");
138
+ await sleep(5);
139
+ hass.socket.socketEvents.emit("label_registry_updated");
140
+ await sleep(75);
141
+ hass.socket.socketEvents.emit("label_registry_updated");
142
+ });
143
+ await sleep(200);
144
+ expect(counter).toBe(2);
145
+ });
146
+ });
147
+ });
148
+
149
+ it("should wait for an update before returning when deleting", async () => {
150
+ expect.assertions(1);
151
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
152
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
153
+ lifecycle.onReady(async () => {
154
+ const response = hass.label.delete("example_label" as TLabelId);
155
+ let order = "";
156
+ setTimeout(() => {
157
+ order += "a";
158
+ event.emit(LABEL_REGISTRY_UPDATED);
159
+ }, 5);
160
+ await response;
161
+ order += "b";
162
+ expect(order).toEqual("ab");
163
+ });
164
+ });
165
+ });
166
+
167
+ it("should wait for an update before returning when creating", async () => {
168
+ expect.assertions(1);
169
+ await hassTestRunner.run(({ lifecycle, hass, event }) => {
170
+ jest.spyOn(hass.socket, "sendMessage").mockImplementation(async () => undefined);
171
+ lifecycle.onReady(async () => {
172
+ const response = hass.label.create(EXAMPLE_LABEL);
173
+ let order = "";
174
+ setTimeout(() => {
175
+ order += "a";
176
+ event.emit(LABEL_REGISTRY_UPDATED);
177
+ }, 5);
178
+ await response;
179
+ order += "b";
180
+ expect(order).toEqual("ab");
181
+ });
182
+ });
183
+ });
184
+ });
185
+ });
186
+ });