@flighthq/host 0.5.1-next.1370.903f328

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.
@@ -0,0 +1,689 @@
1
+ import type { EntityWithoutRuntime, Host } from '@flighthq/types/contract';
2
+
3
+ import { createHost } from './host';
4
+ import {
5
+ getHostAudioDevice,
6
+ getHostAudioMixer,
7
+ getHostBitmapEncode,
8
+ getHostBitmapReadback,
9
+ getHostClipboardFormats,
10
+ getHostDevice,
11
+ getHostFileSystem,
12
+ getHostFontLoading,
13
+ getHostGeolocation,
14
+ getHostGlyphRasterizer,
15
+ getHostHaptics,
16
+ getHostImage,
17
+ getHostInputIngress,
18
+ getHostLifecycle,
19
+ getHostNet,
20
+ getHostNotificationPermission,
21
+ getHostPlatform,
22
+ getHostPowerKeepAwake,
23
+ getHostScreenQuery,
24
+ getHostSensors,
25
+ getHostSocket,
26
+ getHostSoftKeyboardInfo,
27
+ getHostStorage,
28
+ getHostStoragePersistenceQuery,
29
+ getHostTextSegmenter,
30
+ getHostTextShaper,
31
+ getHostVideo,
32
+ getHostWgpu,
33
+ hasHostAudioDevice,
34
+ hasHostAudioMixer,
35
+ hasHostBitmapEncode,
36
+ hasHostBitmapReadback,
37
+ hasHostClipboardFormats,
38
+ hasHostDevice,
39
+ hasHostFileSystem,
40
+ hasHostFontLoading,
41
+ hasHostGeolocation,
42
+ hasHostGlyphRasterizer,
43
+ hasHostHaptics,
44
+ hasHostImage,
45
+ hasHostInputIngress,
46
+ hasHostLifecycle,
47
+ hasHostNet,
48
+ hasHostNotificationPermission,
49
+ hasHostPlatform,
50
+ hasHostPowerKeepAwake,
51
+ hasHostScreenQuery,
52
+ hasHostSensors,
53
+ hasHostSocket,
54
+ hasHostSoftKeyboardInfo,
55
+ hasHostStorage,
56
+ hasHostStoragePersistenceQuery,
57
+ hasHostTextSegmenter,
58
+ hasHostTextShaper,
59
+ hasHostVideo,
60
+ hasHostWgpu,
61
+ } from './hostQuery';
62
+
63
+ // Each accessor is exercised through a host built by SLOT NAME, so the spelling the test asserts is
64
+ // independent of the static property access the accessor compiles to. The decoy case fills a different
65
+ // slot in the same capability group: an accessor that reads its neighbour passes the first two cases.
66
+
67
+ describe('getHostAudioDevice', () => {
68
+ it('returns the provider held in host.media.audioDevice', () => {
69
+ expect(getHostAudioDevice(hostWithSlot('media', 'audioDevice'))).toBe(PROVIDER);
70
+ });
71
+
72
+ it('returns null when the slot is empty', () => {
73
+ expect(getHostAudioDevice(createHost())).toBeNull();
74
+ });
75
+
76
+ it('returns null when a different slot in the same group is filled', () => {
77
+ expect(getHostAudioDevice(hostWithSlot('media', 'session'))).toBeNull();
78
+ });
79
+ });
80
+
81
+ describe('getHostAudioMixer', () => {
82
+ it('returns the provider held in host.media.audioMixer', () => {
83
+ expect(getHostAudioMixer(hostWithSlot('media', 'audioMixer'))).toBe(PROVIDER);
84
+ });
85
+
86
+ it('returns null when the slot is empty', () => {
87
+ expect(getHostAudioMixer(createHost())).toBeNull();
88
+ });
89
+
90
+ it('returns null when a different slot in the same group is filled', () => {
91
+ expect(getHostAudioMixer(hostWithSlot('media', 'session'))).toBeNull();
92
+ });
93
+ });
94
+
95
+ describe('getHostBitmapEncode', () => {
96
+ it('returns the provider held in host.graphics.bitmapEncode', () => {
97
+ expect(getHostBitmapEncode(hostWithSlot('graphics', 'bitmapEncode'))).toBe(PROVIDER);
98
+ });
99
+
100
+ it('returns null when the slot is empty', () => {
101
+ expect(getHostBitmapEncode(createHost())).toBeNull();
102
+ });
103
+
104
+ it('returns null when a different slot in the same group is filled', () => {
105
+ expect(getHostBitmapEncode(hostWithSlot('graphics', 'renderContext'))).toBeNull();
106
+ });
107
+ });
108
+
109
+ describe('getHostBitmapReadback', () => {
110
+ it('returns the provider held in host.graphics.bitmapReadback', () => {
111
+ expect(getHostBitmapReadback(hostWithSlot('graphics', 'bitmapReadback'))).toBe(PROVIDER);
112
+ });
113
+
114
+ it('returns null when the slot is empty', () => {
115
+ expect(getHostBitmapReadback(createHost())).toBeNull();
116
+ });
117
+
118
+ it('returns null when a different slot in the same group is filled', () => {
119
+ expect(getHostBitmapReadback(hostWithSlot('graphics', 'renderContext'))).toBeNull();
120
+ });
121
+ });
122
+
123
+ describe('getHostClipboardFormats', () => {
124
+ it('returns the provider held in host.clipboard.formats', () => {
125
+ expect(getHostClipboardFormats(hostWithSlot('clipboard', 'formats'))).toBe(PROVIDER);
126
+ });
127
+
128
+ it('returns null when the slot is empty', () => {
129
+ expect(getHostClipboardFormats(createHost())).toBeNull();
130
+ });
131
+
132
+ it('returns null when a different slot in the same group is filled', () => {
133
+ expect(getHostClipboardFormats(hostWithSlot('clipboard', 'text'))).toBeNull();
134
+ });
135
+ });
136
+
137
+ describe('getHostDevice', () => {
138
+ it('returns the provider held in host.system.device', () => {
139
+ expect(getHostDevice(hostWithSlot('system', 'device'))).toBe(PROVIDER);
140
+ });
141
+
142
+ it('returns null when the slot is empty', () => {
143
+ expect(getHostDevice(createHost())).toBeNull();
144
+ });
145
+
146
+ it('returns null when a different slot in the same group is filled', () => {
147
+ expect(getHostDevice(hostWithSlot('system', 'permissions'))).toBeNull();
148
+ });
149
+ });
150
+
151
+ describe('getHostFileSystem', () => {
152
+ it('returns the provider held in host.storage.fileSystem', () => {
153
+ expect(getHostFileSystem(hostWithSlot('storage', 'fileSystem'))).toBe(PROVIDER);
154
+ });
155
+
156
+ it('returns null when the slot is empty', () => {
157
+ expect(getHostFileSystem(createHost())).toBeNull();
158
+ });
159
+
160
+ it('returns null when a different slot in the same group is filled', () => {
161
+ expect(getHostFileSystem(hostWithSlot('storage', 'change'))).toBeNull();
162
+ });
163
+ });
164
+
165
+ describe('getHostFontLoading', () => {
166
+ it('returns the provider held in host.text.fontLoading', () => {
167
+ expect(getHostFontLoading(hostWithSlot('text', 'fontLoading'))).toBe(PROVIDER);
168
+ });
169
+
170
+ it('returns null when the slot is empty', () => {
171
+ expect(getHostFontLoading(createHost())).toBeNull();
172
+ });
173
+
174
+ it('returns null when a different slot in the same group is filled', () => {
175
+ expect(getHostFontLoading(hostWithSlot('text', 'shaper'))).toBeNull();
176
+ });
177
+ });
178
+
179
+ describe('getHostGeolocation', () => {
180
+ it('returns the provider held in host.system.geolocation', () => {
181
+ expect(getHostGeolocation(hostWithSlot('system', 'geolocation'))).toBe(PROVIDER);
182
+ });
183
+
184
+ it('returns null when the slot is empty', () => {
185
+ expect(getHostGeolocation(createHost())).toBeNull();
186
+ });
187
+
188
+ it('returns null when a different slot in the same group is filled', () => {
189
+ expect(getHostGeolocation(hostWithSlot('system', 'permissions'))).toBeNull();
190
+ });
191
+ });
192
+
193
+ describe('getHostGlyphRasterizer', () => {
194
+ it('returns the provider held in host.text.glyphRasterizer', () => {
195
+ expect(getHostGlyphRasterizer(hostWithSlot('text', 'glyphRasterizer'))).toBe(PROVIDER);
196
+ });
197
+
198
+ it('returns null when the slot is empty', () => {
199
+ expect(getHostGlyphRasterizer(createHost())).toBeNull();
200
+ });
201
+
202
+ it('returns null when a different slot in the same group is filled', () => {
203
+ expect(getHostGlyphRasterizer(hostWithSlot('text', 'shaper'))).toBeNull();
204
+ });
205
+ });
206
+
207
+ describe('getHostHaptics', () => {
208
+ it('returns the provider held in host.input.haptics', () => {
209
+ expect(getHostHaptics(hostWithSlot('input', 'haptics'))).toBe(PROVIDER);
210
+ });
211
+
212
+ it('returns null when the slot is empty', () => {
213
+ expect(getHostHaptics(createHost())).toBeNull();
214
+ });
215
+
216
+ it('returns null when a different slot in the same group is filled', () => {
217
+ expect(getHostHaptics(hostWithSlot('input', 'focus'))).toBeNull();
218
+ });
219
+ });
220
+
221
+ describe('getHostImage', () => {
222
+ it('returns the provider held in host.graphics.image', () => {
223
+ expect(getHostImage(hostWithSlot('graphics', 'image'))).toBe(PROVIDER);
224
+ });
225
+
226
+ it('returns null when the slot is empty', () => {
227
+ expect(getHostImage(createHost())).toBeNull();
228
+ });
229
+
230
+ it('returns null when a different slot in the same group is filled', () => {
231
+ expect(getHostImage(hostWithSlot('graphics', 'renderContext'))).toBeNull();
232
+ });
233
+ });
234
+
235
+ describe('getHostInputIngress', () => {
236
+ it('returns the provider held in host.input.ingress', () => {
237
+ expect(getHostInputIngress(hostWithSlot('input', 'ingress'))).toBe(PROVIDER);
238
+ });
239
+
240
+ it('returns null when the slot is empty', () => {
241
+ expect(getHostInputIngress(createHost())).toBeNull();
242
+ });
243
+
244
+ it('returns null when a different slot in the same group is filled', () => {
245
+ expect(getHostInputIngress(hostWithSlot('input', 'focus'))).toBeNull();
246
+ });
247
+ });
248
+
249
+ describe('getHostLifecycle', () => {
250
+ it('returns the provider held in host.system.lifecycle', () => {
251
+ expect(getHostLifecycle(hostWithSlot('system', 'lifecycle'))).toBe(PROVIDER);
252
+ });
253
+
254
+ it('returns null when the slot is empty', () => {
255
+ expect(getHostLifecycle(createHost())).toBeNull();
256
+ });
257
+
258
+ it('returns null when a different slot in the same group is filled', () => {
259
+ expect(getHostLifecycle(hostWithSlot('system', 'permissions'))).toBeNull();
260
+ });
261
+ });
262
+
263
+ describe('getHostNet', () => {
264
+ it('returns the provider held in host.net.http', () => {
265
+ expect(getHostNet(hostWithSlot('net', 'http'))).toBe(PROVIDER);
266
+ });
267
+
268
+ it('returns null when the slot is empty', () => {
269
+ expect(getHostNet(createHost())).toBeNull();
270
+ });
271
+
272
+ it('returns null when a different slot in the same group is filled', () => {
273
+ expect(getHostNet(hostWithSlot('net', 'socket'))).toBeNull();
274
+ });
275
+ });
276
+
277
+ describe('getHostNotificationPermission', () => {
278
+ it('returns the provider held in host.notification.permission', () => {
279
+ expect(getHostNotificationPermission(hostWithSlot('notification', 'permission'))).toBe(PROVIDER);
280
+ });
281
+
282
+ it('returns null when the slot is empty', () => {
283
+ expect(getHostNotificationPermission(createHost())).toBeNull();
284
+ });
285
+
286
+ it('returns null when a different slot in the same group is filled', () => {
287
+ expect(getHostNotificationPermission(hostWithSlot('notification', 'delivery'))).toBeNull();
288
+ });
289
+ });
290
+
291
+ describe('getHostPlatform', () => {
292
+ it('returns the provider held in host.system.platform', () => {
293
+ expect(getHostPlatform(hostWithSlot('system', 'platform'))).toBe(PROVIDER);
294
+ });
295
+
296
+ it('returns null when the slot is empty', () => {
297
+ expect(getHostPlatform(createHost())).toBeNull();
298
+ });
299
+
300
+ it('returns null when a different slot in the same group is filled', () => {
301
+ expect(getHostPlatform(hostWithSlot('system', 'permissions'))).toBeNull();
302
+ });
303
+ });
304
+
305
+ describe('getHostPowerKeepAwake', () => {
306
+ it('returns the provider held in host.power.keepAwake', () => {
307
+ expect(getHostPowerKeepAwake(hostWithSlot('power', 'keepAwake'))).toBe(PROVIDER);
308
+ });
309
+
310
+ it('returns null when the slot is empty', () => {
311
+ expect(getHostPowerKeepAwake(createHost())).toBeNull();
312
+ });
313
+
314
+ it('returns null when a different slot in the same group is filled', () => {
315
+ expect(getHostPowerKeepAwake(hostWithSlot('power', 'status'))).toBeNull();
316
+ });
317
+ });
318
+
319
+ describe('getHostScreenQuery', () => {
320
+ it('returns the provider held in host.screen.query', () => {
321
+ expect(getHostScreenQuery(hostWithSlot('screen', 'query'))).toBe(PROVIDER);
322
+ });
323
+
324
+ it('returns null when the slot is empty', () => {
325
+ expect(getHostScreenQuery(createHost())).toBeNull();
326
+ });
327
+
328
+ it('returns null when a different slot in the same group is filled', () => {
329
+ expect(getHostScreenQuery(hostWithSlot('screen', 'details'))).toBeNull();
330
+ });
331
+ });
332
+
333
+ describe('getHostSensors', () => {
334
+ it('returns the provider held in host.system.sensors', () => {
335
+ expect(getHostSensors(hostWithSlot('system', 'sensors'))).toBe(PROVIDER);
336
+ });
337
+
338
+ it('returns null when the slot is empty', () => {
339
+ expect(getHostSensors(createHost())).toBeNull();
340
+ });
341
+
342
+ it('returns null when a different slot in the same group is filled', () => {
343
+ expect(getHostSensors(hostWithSlot('system', 'permissions'))).toBeNull();
344
+ });
345
+ });
346
+
347
+ describe('getHostSocket', () => {
348
+ it('returns the provider held in host.net.socket', () => {
349
+ expect(getHostSocket(hostWithSlot('net', 'socket'))).toBe(PROVIDER);
350
+ });
351
+
352
+ it('returns null when the slot is empty', () => {
353
+ expect(getHostSocket(createHost())).toBeNull();
354
+ });
355
+
356
+ it('returns null when a different slot in the same group is filled', () => {
357
+ expect(getHostSocket(hostWithSlot('net', 'http'))).toBeNull();
358
+ });
359
+ });
360
+
361
+ describe('getHostSoftKeyboardInfo', () => {
362
+ it('returns the provider held in host.input.softKeyboardInfo', () => {
363
+ expect(getHostSoftKeyboardInfo(hostWithSlot('input', 'softKeyboardInfo'))).toBe(PROVIDER);
364
+ });
365
+
366
+ it('returns null when the slot is empty', () => {
367
+ expect(getHostSoftKeyboardInfo(createHost())).toBeNull();
368
+ });
369
+
370
+ it('returns null when a different slot in the same group is filled', () => {
371
+ expect(getHostSoftKeyboardInfo(hostWithSlot('input', 'focus'))).toBeNull();
372
+ });
373
+ });
374
+
375
+ describe('getHostStorage', () => {
376
+ it('returns the provider held in host.storage.local', () => {
377
+ expect(getHostStorage(hostWithSlot('storage', 'local'))).toBe(PROVIDER);
378
+ });
379
+
380
+ it('returns null when the slot is empty', () => {
381
+ expect(getHostStorage(createHost())).toBeNull();
382
+ });
383
+
384
+ it('returns null when a different slot in the same group is filled', () => {
385
+ expect(getHostStorage(hostWithSlot('storage', 'change'))).toBeNull();
386
+ });
387
+ });
388
+
389
+ describe('getHostStoragePersistenceQuery', () => {
390
+ it('returns the provider held in host.storage.persistenceQuery', () => {
391
+ expect(getHostStoragePersistenceQuery(hostWithSlot('storage', 'persistenceQuery'))).toBe(PROVIDER);
392
+ });
393
+
394
+ it('returns null when the slot is empty', () => {
395
+ expect(getHostStoragePersistenceQuery(createHost())).toBeNull();
396
+ });
397
+
398
+ it('returns null when a different slot in the same group is filled', () => {
399
+ expect(getHostStoragePersistenceQuery(hostWithSlot('storage', 'change'))).toBeNull();
400
+ });
401
+ });
402
+
403
+ describe('getHostTextSegmenter', () => {
404
+ it('returns the provider held in host.text.segmenter', () => {
405
+ expect(getHostTextSegmenter(hostWithSlot('text', 'segmenter'))).toBe(PROVIDER);
406
+ });
407
+
408
+ it('returns null when the slot is empty', () => {
409
+ expect(getHostTextSegmenter(createHost())).toBeNull();
410
+ });
411
+
412
+ it('returns null when a different slot in the same group is filled', () => {
413
+ expect(getHostTextSegmenter(hostWithSlot('text', 'shaper'))).toBeNull();
414
+ });
415
+ });
416
+
417
+ describe('getHostTextShaper', () => {
418
+ it('returns the provider held in host.text.shaper', () => {
419
+ expect(getHostTextShaper(hostWithSlot('text', 'shaper'))).toBe(PROVIDER);
420
+ });
421
+
422
+ it('returns null when the slot is empty', () => {
423
+ expect(getHostTextShaper(createHost())).toBeNull();
424
+ });
425
+
426
+ it('returns null when a different slot in the same group is filled', () => {
427
+ expect(getHostTextShaper(hostWithSlot('text', 'segmenter'))).toBeNull();
428
+ });
429
+ });
430
+
431
+ describe('getHostVideo', () => {
432
+ it('returns the provider held in host.media.video', () => {
433
+ expect(getHostVideo(hostWithSlot('media', 'video'))).toBe(PROVIDER);
434
+ });
435
+
436
+ it('returns null when the slot is empty', () => {
437
+ expect(getHostVideo(createHost())).toBeNull();
438
+ });
439
+
440
+ it('returns null when a different slot in the same group is filled', () => {
441
+ expect(getHostVideo(hostWithSlot('media', 'session'))).toBeNull();
442
+ });
443
+ });
444
+
445
+ describe('getHostWgpu', () => {
446
+ it('returns the provider held in host.graphics.wgpuHost', () => {
447
+ expect(getHostWgpu(hostWithSlot('graphics', 'wgpuHost'))).toBe(PROVIDER);
448
+ });
449
+
450
+ it('returns null when the slot is empty', () => {
451
+ expect(getHostWgpu(createHost())).toBeNull();
452
+ });
453
+
454
+ it('returns null when a different slot in the same group is filled', () => {
455
+ expect(getHostWgpu(hostWithSlot('graphics', 'renderContext'))).toBeNull();
456
+ });
457
+ });
458
+
459
+ describe('hasHostAudioDevice', () => {
460
+ it('is true only when host.media.audioDevice holds a provider', () => {
461
+ expect(hasHostAudioDevice(hostWithSlot('media', 'audioDevice'))).toBe(true);
462
+ expect(hasHostAudioDevice(hostWithSlot('media', 'session'))).toBe(false);
463
+ expect(hasHostAudioDevice(createHost())).toBe(false);
464
+ });
465
+ });
466
+
467
+ describe('hasHostAudioMixer', () => {
468
+ it('is true only when host.media.audioMixer holds a provider', () => {
469
+ expect(hasHostAudioMixer(hostWithSlot('media', 'audioMixer'))).toBe(true);
470
+ expect(hasHostAudioMixer(hostWithSlot('media', 'session'))).toBe(false);
471
+ expect(hasHostAudioMixer(createHost())).toBe(false);
472
+ });
473
+ });
474
+
475
+ describe('hasHostBitmapEncode', () => {
476
+ it('is true only when host.graphics.bitmapEncode holds a provider', () => {
477
+ expect(hasHostBitmapEncode(hostWithSlot('graphics', 'bitmapEncode'))).toBe(true);
478
+ expect(hasHostBitmapEncode(hostWithSlot('graphics', 'renderContext'))).toBe(false);
479
+ expect(hasHostBitmapEncode(createHost())).toBe(false);
480
+ });
481
+ });
482
+
483
+ describe('hasHostBitmapReadback', () => {
484
+ it('is true only when host.graphics.bitmapReadback holds a provider', () => {
485
+ expect(hasHostBitmapReadback(hostWithSlot('graphics', 'bitmapReadback'))).toBe(true);
486
+ expect(hasHostBitmapReadback(hostWithSlot('graphics', 'renderContext'))).toBe(false);
487
+ expect(hasHostBitmapReadback(createHost())).toBe(false);
488
+ });
489
+ });
490
+
491
+ describe('hasHostClipboardFormats', () => {
492
+ it('is true only when host.clipboard.formats holds a provider', () => {
493
+ expect(hasHostClipboardFormats(hostWithSlot('clipboard', 'formats'))).toBe(true);
494
+ expect(hasHostClipboardFormats(hostWithSlot('clipboard', 'text'))).toBe(false);
495
+ expect(hasHostClipboardFormats(createHost())).toBe(false);
496
+ });
497
+ });
498
+
499
+ describe('hasHostDevice', () => {
500
+ it('is true only when host.system.device holds a provider', () => {
501
+ expect(hasHostDevice(hostWithSlot('system', 'device'))).toBe(true);
502
+ expect(hasHostDevice(hostWithSlot('system', 'permissions'))).toBe(false);
503
+ expect(hasHostDevice(createHost())).toBe(false);
504
+ });
505
+ });
506
+
507
+ describe('hasHostFileSystem', () => {
508
+ it('is true only when host.storage.fileSystem holds a provider', () => {
509
+ expect(hasHostFileSystem(hostWithSlot('storage', 'fileSystem'))).toBe(true);
510
+ expect(hasHostFileSystem(hostWithSlot('storage', 'change'))).toBe(false);
511
+ expect(hasHostFileSystem(createHost())).toBe(false);
512
+ });
513
+ });
514
+
515
+ describe('hasHostFontLoading', () => {
516
+ it('is true only when host.text.fontLoading holds a provider', () => {
517
+ expect(hasHostFontLoading(hostWithSlot('text', 'fontLoading'))).toBe(true);
518
+ expect(hasHostFontLoading(hostWithSlot('text', 'shaper'))).toBe(false);
519
+ expect(hasHostFontLoading(createHost())).toBe(false);
520
+ });
521
+ });
522
+
523
+ describe('hasHostGeolocation', () => {
524
+ it('is true only when host.system.geolocation holds a provider', () => {
525
+ expect(hasHostGeolocation(hostWithSlot('system', 'geolocation'))).toBe(true);
526
+ expect(hasHostGeolocation(hostWithSlot('system', 'permissions'))).toBe(false);
527
+ expect(hasHostGeolocation(createHost())).toBe(false);
528
+ });
529
+ });
530
+
531
+ describe('hasHostGlyphRasterizer', () => {
532
+ it('is true only when host.text.glyphRasterizer holds a provider', () => {
533
+ expect(hasHostGlyphRasterizer(hostWithSlot('text', 'glyphRasterizer'))).toBe(true);
534
+ expect(hasHostGlyphRasterizer(hostWithSlot('text', 'shaper'))).toBe(false);
535
+ expect(hasHostGlyphRasterizer(createHost())).toBe(false);
536
+ });
537
+ });
538
+
539
+ describe('hasHostHaptics', () => {
540
+ it('is true only when host.input.haptics holds a provider', () => {
541
+ expect(hasHostHaptics(hostWithSlot('input', 'haptics'))).toBe(true);
542
+ expect(hasHostHaptics(hostWithSlot('input', 'focus'))).toBe(false);
543
+ expect(hasHostHaptics(createHost())).toBe(false);
544
+ });
545
+ });
546
+
547
+ describe('hasHostImage', () => {
548
+ it('is true only when host.graphics.image holds a provider', () => {
549
+ expect(hasHostImage(hostWithSlot('graphics', 'image'))).toBe(true);
550
+ expect(hasHostImage(hostWithSlot('graphics', 'renderContext'))).toBe(false);
551
+ expect(hasHostImage(createHost())).toBe(false);
552
+ });
553
+ });
554
+
555
+ describe('hasHostInputIngress', () => {
556
+ it('is true only when host.input.ingress holds a provider', () => {
557
+ expect(hasHostInputIngress(hostWithSlot('input', 'ingress'))).toBe(true);
558
+ expect(hasHostInputIngress(hostWithSlot('input', 'focus'))).toBe(false);
559
+ expect(hasHostInputIngress(createHost())).toBe(false);
560
+ });
561
+ });
562
+
563
+ describe('hasHostLifecycle', () => {
564
+ it('is true only when host.system.lifecycle holds a provider', () => {
565
+ expect(hasHostLifecycle(hostWithSlot('system', 'lifecycle'))).toBe(true);
566
+ expect(hasHostLifecycle(hostWithSlot('system', 'permissions'))).toBe(false);
567
+ expect(hasHostLifecycle(createHost())).toBe(false);
568
+ });
569
+ });
570
+
571
+ describe('hasHostNet', () => {
572
+ it('is true only when host.net.http holds a provider', () => {
573
+ expect(hasHostNet(hostWithSlot('net', 'http'))).toBe(true);
574
+ expect(hasHostNet(hostWithSlot('net', 'socket'))).toBe(false);
575
+ expect(hasHostNet(createHost())).toBe(false);
576
+ });
577
+ });
578
+
579
+ describe('hasHostNotificationPermission', () => {
580
+ it('is true only when host.notification.permission holds a provider', () => {
581
+ expect(hasHostNotificationPermission(hostWithSlot('notification', 'permission'))).toBe(true);
582
+ expect(hasHostNotificationPermission(hostWithSlot('notification', 'delivery'))).toBe(false);
583
+ expect(hasHostNotificationPermission(createHost())).toBe(false);
584
+ });
585
+ });
586
+
587
+ describe('hasHostPlatform', () => {
588
+ it('is true only when host.system.platform holds a provider', () => {
589
+ expect(hasHostPlatform(hostWithSlot('system', 'platform'))).toBe(true);
590
+ expect(hasHostPlatform(hostWithSlot('system', 'permissions'))).toBe(false);
591
+ expect(hasHostPlatform(createHost())).toBe(false);
592
+ });
593
+ });
594
+
595
+ describe('hasHostPowerKeepAwake', () => {
596
+ it('is true only when host.power.keepAwake holds a provider', () => {
597
+ expect(hasHostPowerKeepAwake(hostWithSlot('power', 'keepAwake'))).toBe(true);
598
+ expect(hasHostPowerKeepAwake(hostWithSlot('power', 'status'))).toBe(false);
599
+ expect(hasHostPowerKeepAwake(createHost())).toBe(false);
600
+ });
601
+ });
602
+
603
+ describe('hasHostScreenQuery', () => {
604
+ it('is true only when host.screen.query holds a provider', () => {
605
+ expect(hasHostScreenQuery(hostWithSlot('screen', 'query'))).toBe(true);
606
+ expect(hasHostScreenQuery(hostWithSlot('screen', 'details'))).toBe(false);
607
+ expect(hasHostScreenQuery(createHost())).toBe(false);
608
+ });
609
+ });
610
+
611
+ describe('hasHostSensors', () => {
612
+ it('is true only when host.system.sensors holds a provider', () => {
613
+ expect(hasHostSensors(hostWithSlot('system', 'sensors'))).toBe(true);
614
+ expect(hasHostSensors(hostWithSlot('system', 'permissions'))).toBe(false);
615
+ expect(hasHostSensors(createHost())).toBe(false);
616
+ });
617
+ });
618
+
619
+ describe('hasHostSocket', () => {
620
+ it('is true only when host.net.socket holds a provider', () => {
621
+ expect(hasHostSocket(hostWithSlot('net', 'socket'))).toBe(true);
622
+ expect(hasHostSocket(hostWithSlot('net', 'http'))).toBe(false);
623
+ expect(hasHostSocket(createHost())).toBe(false);
624
+ });
625
+ });
626
+
627
+ describe('hasHostSoftKeyboardInfo', () => {
628
+ it('is true only when host.input.softKeyboardInfo holds a provider', () => {
629
+ expect(hasHostSoftKeyboardInfo(hostWithSlot('input', 'softKeyboardInfo'))).toBe(true);
630
+ expect(hasHostSoftKeyboardInfo(hostWithSlot('input', 'focus'))).toBe(false);
631
+ expect(hasHostSoftKeyboardInfo(createHost())).toBe(false);
632
+ });
633
+ });
634
+
635
+ describe('hasHostStorage', () => {
636
+ it('is true only when host.storage.local holds a provider', () => {
637
+ expect(hasHostStorage(hostWithSlot('storage', 'local'))).toBe(true);
638
+ expect(hasHostStorage(hostWithSlot('storage', 'change'))).toBe(false);
639
+ expect(hasHostStorage(createHost())).toBe(false);
640
+ });
641
+ });
642
+
643
+ describe('hasHostStoragePersistenceQuery', () => {
644
+ it('is true only when host.storage.persistenceQuery holds a provider', () => {
645
+ expect(hasHostStoragePersistenceQuery(hostWithSlot('storage', 'persistenceQuery'))).toBe(true);
646
+ expect(hasHostStoragePersistenceQuery(hostWithSlot('storage', 'change'))).toBe(false);
647
+ expect(hasHostStoragePersistenceQuery(createHost())).toBe(false);
648
+ });
649
+ });
650
+
651
+ describe('hasHostTextSegmenter', () => {
652
+ it('is true only when host.text.segmenter holds a provider', () => {
653
+ expect(hasHostTextSegmenter(hostWithSlot('text', 'segmenter'))).toBe(true);
654
+ expect(hasHostTextSegmenter(hostWithSlot('text', 'shaper'))).toBe(false);
655
+ expect(hasHostTextSegmenter(createHost())).toBe(false);
656
+ });
657
+ });
658
+
659
+ describe('hasHostTextShaper', () => {
660
+ it('is true only when host.text.shaper holds a provider', () => {
661
+ expect(hasHostTextShaper(hostWithSlot('text', 'shaper'))).toBe(true);
662
+ expect(hasHostTextShaper(hostWithSlot('text', 'segmenter'))).toBe(false);
663
+ expect(hasHostTextShaper(createHost())).toBe(false);
664
+ });
665
+ });
666
+
667
+ describe('hasHostVideo', () => {
668
+ it('is true only when host.media.video holds a provider', () => {
669
+ expect(hasHostVideo(hostWithSlot('media', 'video'))).toBe(true);
670
+ expect(hasHostVideo(hostWithSlot('media', 'session'))).toBe(false);
671
+ expect(hasHostVideo(createHost())).toBe(false);
672
+ });
673
+ });
674
+
675
+ describe('hasHostWgpu', () => {
676
+ it('is true only when host.graphics.wgpuHost holds a provider', () => {
677
+ expect(hasHostWgpu(hostWithSlot('graphics', 'wgpuHost'))).toBe(true);
678
+ expect(hasHostWgpu(hostWithSlot('graphics', 'renderContext'))).toBe(false);
679
+ expect(hasHostWgpu(createHost())).toBe(false);
680
+ });
681
+ });
682
+
683
+ const PROVIDER = {};
684
+
685
+ function hostWithSlot(group: string, slot: string): Host {
686
+ // A computed key cannot satisfy createHost's capability generic, so the shape is asserted rather than
687
+ // inferred. The assertion claims only what the literal already is: one group holding one provider.
688
+ return createHost({ [group]: { [slot]: PROVIDER } } as Partial<EntityWithoutRuntime<Host>>);
689
+ }