@flighthq/host-electron 0.5.1-next.920.da8f530 → 0.6.0
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.
- package/README.md +2 -2
- package/dist/contract.d.ts +19 -24
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +18 -24
- package/dist/contract.js.map +1 -1
- package/dist/electronApp.d.ts +62 -34
- package/dist/electronApp.d.ts.map +1 -1
- package/dist/electronApp.js +175 -234
- package/dist/electronApp.js.map +1 -1
- package/dist/electronClipboard.d.ts +7 -5
- package/dist/electronClipboard.d.ts.map +1 -1
- package/dist/electronClipboard.js +91 -66
- package/dist/electronClipboard.js.map +1 -1
- package/dist/electronDefaultHostGroups.d.ts +59 -0
- package/dist/electronDefaultHostGroups.d.ts.map +1 -0
- package/dist/electronDefaultHostGroups.js +109 -0
- package/dist/electronDefaultHostGroups.js.map +1 -0
- package/dist/electronDialog.d.ts +12 -9
- package/dist/electronDialog.d.ts.map +1 -1
- package/dist/electronDialog.js +28 -21
- package/dist/electronDialog.js.map +1 -1
- package/dist/electronIpc.d.ts +13 -11
- package/dist/electronIpc.d.ts.map +1 -1
- package/dist/electronIpc.js +32 -26
- package/dist/electronIpc.js.map +1 -1
- package/dist/electronMenu.d.ts +12 -6
- package/dist/electronMenu.d.ts.map +1 -1
- package/dist/electronMenu.js +41 -30
- package/dist/electronMenu.js.map +1 -1
- package/dist/electronMenuTemplate.d.ts +2 -1
- package/dist/electronMenuTemplate.d.ts.map +1 -1
- package/dist/electronMenuTemplate.js.map +1 -1
- package/dist/electronNotification.d.ts +25 -7
- package/dist/electronNotification.d.ts.map +1 -1
- package/dist/electronNotification.js +39 -16
- package/dist/electronNotification.js.map +1 -1
- package/dist/electronPlatform.d.ts +5 -3
- package/dist/electronPlatform.d.ts.map +1 -1
- package/dist/electronPlatform.js +9 -7
- package/dist/electronPlatform.js.map +1 -1
- package/dist/electronPower.d.ts +22 -11
- package/dist/electronPower.d.ts.map +1 -1
- package/dist/electronPower.js +48 -59
- package/dist/electronPower.js.map +1 -1
- package/dist/electronProtocol.d.ts +16 -8
- package/dist/electronProtocol.d.ts.map +1 -1
- package/dist/electronProtocol.js +45 -28
- package/dist/electronProtocol.js.map +1 -1
- package/dist/electronRegister.d.ts +5 -7
- package/dist/electronRegister.d.ts.map +1 -1
- package/dist/electronRegister.js +72 -99
- package/dist/electronRegister.js.map +1 -1
- package/dist/electronScreen.d.ts +7 -6
- package/dist/electronScreen.d.ts.map +1 -1
- package/dist/electronScreen.js +17 -14
- package/dist/electronScreen.js.map +1 -1
- package/dist/electronShell.d.ts +16 -8
- package/dist/electronShell.d.ts.map +1 -1
- package/dist/electronShell.js +50 -43
- package/dist/electronShell.js.map +1 -1
- package/dist/electronShortcut.d.ts +6 -4
- package/dist/electronShortcut.d.ts.map +1 -1
- package/dist/electronShortcut.js +16 -10
- package/dist/electronShortcut.js.map +1 -1
- package/dist/electronStorage.d.ts +5 -3
- package/dist/electronStorage.d.ts.map +1 -1
- package/dist/electronStorage.js +9 -7
- package/dist/electronStorage.js.map +1 -1
- package/dist/electronTray.d.ts +38 -21
- package/dist/electronTray.d.ts.map +1 -1
- package/dist/electronTray.js +110 -76
- package/dist/electronTray.js.map +1 -1
- package/dist/electronUpdater.d.ts +6 -3
- package/dist/electronUpdater.d.ts.map +1 -1
- package/dist/electronUpdater.js +10 -7
- package/dist/electronUpdater.js.map +1 -1
- package/dist/electronWindow.d.ts +23 -7
- package/dist/electronWindow.d.ts.map +1 -1
- package/dist/electronWindow.js +234 -152
- package/dist/electronWindow.js.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/types/ElectronApi.d.ts +393 -0
- package/dist/types/ElectronApi.d.ts.map +1 -0
- package/dist/types/ElectronApi.js +20 -0
- package/dist/types/ElectronApi.js.map +1 -0
- package/dist/types/ElectronAppCapabilitiesFor.d.ts +8 -0
- package/dist/types/ElectronAppCapabilitiesFor.d.ts.map +1 -0
- package/dist/types/ElectronAppCapabilitiesFor.js +2 -0
- package/dist/types/ElectronAppCapabilitiesFor.js.map +1 -0
- package/dist/types/ElectronHost.d.ts +43 -0
- package/dist/types/ElectronHost.d.ts.map +1 -0
- package/dist/types/ElectronHost.js +2 -0
- package/dist/types/ElectronHost.js.map +1 -0
- package/dist/types/ElectronHostGroups.d.ts +85 -0
- package/dist/types/ElectronHostGroups.d.ts.map +1 -0
- package/dist/types/ElectronHostGroups.js +2 -0
- package/dist/types/ElectronHostGroups.js.map +1 -0
- package/dist/types/ElectronHostOptions.d.ts +7 -0
- package/dist/types/ElectronHostOptions.d.ts.map +1 -0
- package/dist/types/ElectronHostOptions.js +2 -0
- package/dist/types/ElectronHostOptions.js.map +1 -0
- package/dist/types/ElectronProtocolCapabilities.d.ts +3 -0
- package/dist/types/ElectronProtocolCapabilities.d.ts.map +1 -0
- package/dist/types/ElectronProtocolCapabilities.js +2 -0
- package/dist/types/ElectronProtocolCapabilities.js.map +1 -0
- package/dist/types/ElectronTrayCapabilitiesFor.d.ts +7 -0
- package/dist/types/ElectronTrayCapabilitiesFor.d.ts.map +1 -0
- package/dist/types/ElectronTrayCapabilitiesFor.js +2 -0
- package/dist/types/ElectronTrayCapabilitiesFor.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +42 -21
- package/src/electronApp.test.ts +158 -131
- package/src/electronClipboard.test.ts +40 -13
- package/src/electronDefaultHostGroups.test.ts +148 -0
- package/src/electronDialog.test.ts +55 -53
- package/src/electronHostTreeShaking.test.ts +51 -0
- package/src/electronIpc.test.ts +47 -66
- package/src/electronMenu.test.ts +61 -47
- package/src/electronMenuTemplate.test.ts +1 -1
- package/src/electronNotification.test.ts +71 -21
- package/src/electronPlatform.test.ts +17 -12
- package/src/electronPower.test.ts +112 -88
- package/src/electronProtocol.test.ts +68 -35
- package/src/electronRegister.test.ts +280 -26
- package/src/electronScreen.test.ts +34 -25
- package/src/electronShell.test.ts +99 -59
- package/src/electronShortcut.test.ts +22 -19
- package/src/electronStorage.test.ts +26 -24
- package/src/electronTray.test.ts +225 -109
- package/src/electronUpdater.test.ts +26 -19
- package/src/electronWindow.test.ts +229 -101
package/src/electronTray.test.ts
CHANGED
|
@@ -7,34 +7,49 @@ import {
|
|
|
7
7
|
setTrayIconContextMenu,
|
|
8
8
|
setTrayIconTemplate,
|
|
9
9
|
} from '@flighthq/tray/contract';
|
|
10
|
+
import type { TrayIcon } from '@flighthq/tray/contract';
|
|
11
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
electronHostTray,
|
|
15
|
+
electronHostTrayBalloon,
|
|
16
|
+
electronHostTrayBalloonEvents,
|
|
17
|
+
electronHostTrayBounds,
|
|
18
|
+
electronHostTrayDoubleClickPolicy,
|
|
19
|
+
electronHostTrayDropEvents,
|
|
20
|
+
electronHostTrayImage,
|
|
21
|
+
electronHostTrayInteractionEvents,
|
|
22
|
+
electronHostTrayLifecycle,
|
|
23
|
+
electronHostTrayMenu,
|
|
24
|
+
electronHostTrayMenuSelectionEvents,
|
|
25
|
+
electronHostTrayPopupMenu,
|
|
26
|
+
electronHostTrayPressedImage,
|
|
27
|
+
electronHostTrayTemplateImage,
|
|
28
|
+
electronHostTrayTitle,
|
|
29
|
+
electronHostTrayTooltip,
|
|
30
|
+
populateElectronHostTrayBalloon,
|
|
31
|
+
populateElectronHostTrayBalloonEvents,
|
|
32
|
+
populateElectronHostTrayBounds,
|
|
33
|
+
populateElectronHostTrayDoubleClickPolicy,
|
|
34
|
+
populateElectronHostTrayDropEvents,
|
|
35
|
+
populateElectronHostTrayImage,
|
|
36
|
+
populateElectronHostTrayInteractionEvents,
|
|
37
|
+
populateElectronHostTrayLifecycle,
|
|
38
|
+
populateElectronHostTrayMenu,
|
|
39
|
+
populateElectronHostTrayMenuSelectionEvents,
|
|
40
|
+
populateElectronHostTrayPopupMenu,
|
|
41
|
+
populateElectronHostTrayPressedImage,
|
|
42
|
+
populateElectronHostTrayTemplateImage,
|
|
43
|
+
populateElectronHostTrayTitle,
|
|
44
|
+
populateElectronHostTrayTooltip,
|
|
45
|
+
} from './electronTray.ts';
|
|
10
46
|
import type {
|
|
11
47
|
ElectronApi,
|
|
12
48
|
ElectronMenu,
|
|
13
49
|
ElectronMenuItemOptions,
|
|
14
50
|
ElectronNativeImage,
|
|
15
51
|
ElectronTray,
|
|
16
|
-
|
|
17
|
-
} from '@flighthq/types/contract';
|
|
18
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
createElectronTrayCapabilities,
|
|
22
|
-
initializeTrayBalloonBackend,
|
|
23
|
-
initializeTrayBalloonEventsBackend,
|
|
24
|
-
initializeTrayBoundsBackend,
|
|
25
|
-
initializeTrayDoubleClickPolicyBackend,
|
|
26
|
-
initializeTrayDropEventsBackend,
|
|
27
|
-
initializeTrayImageBackend,
|
|
28
|
-
initializeTrayInteractionEventsBackend,
|
|
29
|
-
initializeTrayLifecycleBackend,
|
|
30
|
-
initializeTrayMenuBackend,
|
|
31
|
-
initializeTrayMenuSelectionEventsBackend,
|
|
32
|
-
initializeTrayPopupMenuBackend,
|
|
33
|
-
initializeTrayPressedImageBackend,
|
|
34
|
-
initializeTrayTemplateImageBackend,
|
|
35
|
-
initializeTrayTitleBackend,
|
|
36
|
-
initializeTrayTooltipBackend,
|
|
37
|
-
} from './electronTray';
|
|
52
|
+
} from './types/index.ts';
|
|
38
53
|
|
|
39
54
|
interface FakeImage extends ElectronNativeImage {
|
|
40
55
|
source: string;
|
|
@@ -71,7 +86,7 @@ function fakeElectron() {
|
|
|
71
86
|
templates.push(template);
|
|
72
87
|
return { popup() {} };
|
|
73
88
|
},
|
|
74
|
-
|
|
89
|
+
setAppMenu() {},
|
|
75
90
|
},
|
|
76
91
|
Tray: function (this: FakeTray, image: ElectronNativeImage) {
|
|
77
92
|
this.destroyed = false;
|
|
@@ -118,19 +133,19 @@ function fakeElectron() {
|
|
|
118
133
|
return { electron, templates, trays };
|
|
119
134
|
}
|
|
120
135
|
|
|
121
|
-
async function acquire
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const result = await createTrayIcon(
|
|
136
|
+
async function acquire(
|
|
137
|
+
hostTrayLifecycle: NonNullable<ReturnType<typeof electronHostTray>['lifecycle']>,
|
|
138
|
+
): Promise<TrayIcon> {
|
|
139
|
+
const result = await createTrayIcon(hostTrayLifecycle, { icon: 'icon.png' });
|
|
125
140
|
if (result.outcome !== 'created') throw new Error(result.outcome);
|
|
126
141
|
return result.tray;
|
|
127
142
|
}
|
|
128
143
|
|
|
129
|
-
describe('
|
|
130
|
-
it('exposes
|
|
144
|
+
describe('electronHostTray', () => {
|
|
145
|
+
it('exposes the slots supported by the injected OS profile and none exclusive to another', () => {
|
|
131
146
|
const { electron } = fakeElectron();
|
|
132
|
-
|
|
133
|
-
[
|
|
147
|
+
const supported = {
|
|
148
|
+
linux: [
|
|
134
149
|
'bounds',
|
|
135
150
|
'image',
|
|
136
151
|
'interactionEvents',
|
|
@@ -139,10 +154,8 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
139
154
|
'menuSelectionEvents',
|
|
140
155
|
'popupMenu',
|
|
141
156
|
'tooltip',
|
|
142
|
-
]
|
|
143
|
-
|
|
144
|
-
expect(Object.keys(createElectronTrayCapabilities(electron, 'macos')).sort()).toEqual(
|
|
145
|
-
[
|
|
157
|
+
],
|
|
158
|
+
macos: [
|
|
146
159
|
'bounds',
|
|
147
160
|
'doubleClickPolicy',
|
|
148
161
|
'dropEvents',
|
|
@@ -156,10 +169,8 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
156
169
|
'templateImage',
|
|
157
170
|
'title',
|
|
158
171
|
'tooltip',
|
|
159
|
-
]
|
|
160
|
-
|
|
161
|
-
expect(Object.keys(createElectronTrayCapabilities(electron, 'windows')).sort()).toEqual(
|
|
162
|
-
[
|
|
172
|
+
],
|
|
173
|
+
windows: [
|
|
163
174
|
'balloon',
|
|
164
175
|
'balloonEvents',
|
|
165
176
|
'bounds',
|
|
@@ -170,14 +181,26 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
170
181
|
'menuSelectionEvents',
|
|
171
182
|
'popupMenu',
|
|
172
183
|
'tooltip',
|
|
173
|
-
]
|
|
174
|
-
|
|
184
|
+
],
|
|
185
|
+
} as const;
|
|
186
|
+
for (const profile of ['linux', 'macos', 'windows'] as const) {
|
|
187
|
+
const slots = Object.keys(electronHostTray(electron, profile));
|
|
188
|
+
const exclusiveElsewhere: readonly string[] = Object.entries(supported)
|
|
189
|
+
.filter(([other]) => other !== profile)
|
|
190
|
+
.flatMap(([, others]) => others)
|
|
191
|
+
.filter((slot) => !(supported[profile] as readonly string[]).includes(slot));
|
|
192
|
+
expect(slots, profile).toEqual(expect.arrayContaining([...supported[profile]]));
|
|
193
|
+
expect(
|
|
194
|
+
slots.filter((slot) => exclusiveElsewhere.includes(slot)),
|
|
195
|
+
profile,
|
|
196
|
+
).toEqual([]);
|
|
197
|
+
}
|
|
175
198
|
});
|
|
176
199
|
|
|
177
|
-
it('constructs the native resource before publishing
|
|
200
|
+
it('constructs the native resource before publishing', async () => {
|
|
178
201
|
const { electron, trays } = fakeElectron();
|
|
179
|
-
const host = { tray:
|
|
180
|
-
const result = await createTrayIcon(host, {
|
|
202
|
+
const host = { tray: electronHostTray(electron, 'macos') };
|
|
203
|
+
const result = await createTrayIcon(host.tray.lifecycle, {
|
|
181
204
|
icon: 'icon.png',
|
|
182
205
|
iconTemplate: true,
|
|
183
206
|
title: 'Flight',
|
|
@@ -191,12 +214,12 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
191
214
|
|
|
192
215
|
it('keeps one native listener while delivering full pointer payload to multiple subscribers', async () => {
|
|
193
216
|
const { electron, trays } = fakeElectron();
|
|
194
|
-
const host = { tray:
|
|
195
|
-
const tray = await acquire(host);
|
|
217
|
+
const host = { tray: electronHostTray(electron, 'linux') };
|
|
218
|
+
const tray = await acquire(host.tray.lifecycle);
|
|
196
219
|
const first = vi.fn();
|
|
197
220
|
const second = vi.fn();
|
|
198
|
-
onTrayInteraction(tray, first);
|
|
199
|
-
onTrayInteraction(tray, second);
|
|
221
|
+
onTrayInteraction(host.tray.interactionEvents, tray, first);
|
|
222
|
+
onTrayInteraction(host.tray.interactionEvents, tray, second);
|
|
200
223
|
expect(trays[0].handlers.click).toHaveLength(1);
|
|
201
224
|
trays[0].handlers.click[0]!({ altKey: true, ctrlKey: true, metaKey: true, shiftKey: true }, { x: 7, y: 9 });
|
|
202
225
|
expect(first).toHaveBeenCalledWith(
|
|
@@ -207,14 +230,14 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
207
230
|
|
|
208
231
|
it('routes a menu selection only through that Tray signal', async () => {
|
|
209
232
|
const { electron, templates } = fakeElectron();
|
|
210
|
-
const host = { tray:
|
|
211
|
-
const first = await acquire(host);
|
|
212
|
-
const second = await acquire(host);
|
|
233
|
+
const host = { tray: electronHostTray(electron, 'linux') };
|
|
234
|
+
const first = await acquire(host.tray.lifecycle);
|
|
235
|
+
const second = await acquire(host.tray.lifecycle);
|
|
213
236
|
const firstIds: string[] = [];
|
|
214
237
|
const secondIds: string[] = [];
|
|
215
|
-
onTrayMenuSelection(first, ({ id }) => firstIds.push(id));
|
|
216
|
-
onTrayMenuSelection(second, ({ id }) => secondIds.push(id));
|
|
217
|
-
await setTrayIconContextMenu(first, [{ id: 'open', label: 'Open' }]);
|
|
238
|
+
onTrayMenuSelection(host.tray.menuSelectionEvents, first, ({ id }) => firstIds.push(id));
|
|
239
|
+
onTrayMenuSelection(host.tray.menuSelectionEvents, second, ({ id }) => secondIds.push(id));
|
|
240
|
+
await setTrayIconContextMenu(host.tray.menu, first, [{ id: 'open', label: 'Open' }]);
|
|
218
241
|
templates[0][0].click?.();
|
|
219
242
|
expect(firstIds).toEqual(['open']);
|
|
220
243
|
expect(secondIds).toEqual([]);
|
|
@@ -222,16 +245,16 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
222
245
|
|
|
223
246
|
it('realizes later template changes through the current native image', async () => {
|
|
224
247
|
const { electron, trays } = fakeElectron();
|
|
225
|
-
const host = { tray:
|
|
226
|
-
const tray = await acquire(host);
|
|
227
|
-
expect((await setTrayIconTemplate(tray, true)).outcome).toBe('updated');
|
|
248
|
+
const host = { tray: electronHostTray(electron, 'macos') };
|
|
249
|
+
const tray = await acquire(host.tray.lifecycle);
|
|
250
|
+
expect((await setTrayIconTemplate(host.tray.templateImage, tray, true)).outcome).toBe('updated');
|
|
228
251
|
expect((trays[0].image as FakeImage).template).toBe(true);
|
|
229
252
|
});
|
|
230
253
|
|
|
231
254
|
it('returns invalid-icon without publishing a ghost record', async () => {
|
|
232
255
|
const { electron, trays } = fakeElectron();
|
|
233
|
-
const host = { tray:
|
|
234
|
-
const result = await createTrayIcon(host, { icon: 'invalid' });
|
|
256
|
+
const host = { tray: electronHostTray(electron, 'linux') };
|
|
257
|
+
const result = await createTrayIcon(host.tray.lifecycle, { icon: 'invalid' });
|
|
235
258
|
expect(result.outcome).toBe('invalid-icon');
|
|
236
259
|
expect(trays).toHaveLength(0);
|
|
237
260
|
expect(host.tray.lifecycle.list()).toEqual([]);
|
|
@@ -239,8 +262,8 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
239
262
|
|
|
240
263
|
it('attempts listener and native teardown, then retries only failed steps', async () => {
|
|
241
264
|
const { electron, trays } = fakeElectron();
|
|
242
|
-
const host = { tray:
|
|
243
|
-
const tray = await acquire(host);
|
|
265
|
+
const host = { tray: electronHostTray(electron, 'linux') };
|
|
266
|
+
const tray = await acquire(host.tray.lifecycle);
|
|
244
267
|
trays[0].removeFailures = 1;
|
|
245
268
|
trays[0].destroyFailures = 1;
|
|
246
269
|
expect((await destroyTrayIcon(tray)).outcome).toBe('tray-destroy-failed');
|
|
@@ -250,97 +273,190 @@ describe('createElectronTrayCapabilities', () => {
|
|
|
250
273
|
|
|
251
274
|
it('owns balloon commands only on the Windows shape', async () => {
|
|
252
275
|
const { electron } = fakeElectron();
|
|
253
|
-
const host = { tray:
|
|
254
|
-
const tray = await acquire(host);
|
|
255
|
-
expect((await displayTrayBalloon(tray, { text: 'Done', title: 'Flight' })).outcome).toBe(
|
|
276
|
+
const host = { tray: electronHostTray(electron, 'windows') };
|
|
277
|
+
const tray = await acquire(host.tray.lifecycle);
|
|
278
|
+
expect((await displayTrayBalloon(host.tray.balloon, tray, { text: 'Done', title: 'Flight' })).outcome).toBe(
|
|
279
|
+
'displayed',
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('electronHostTrayBalloon', () => {
|
|
285
|
+
it('constructs a tray balloon provider', () => {
|
|
286
|
+
expect(electronHostTrayBalloon(fakeElectron().electron)).toBeDefined();
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe('electronHostTrayBalloonEvents', () => {
|
|
291
|
+
it('constructs a tray balloon events provider', () => {
|
|
292
|
+
expect(electronHostTrayBalloonEvents(fakeElectron().electron)).toBeDefined();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('electronHostTrayBounds', () => {
|
|
297
|
+
it('constructs a tray bounds provider', () => {
|
|
298
|
+
expect(electronHostTrayBounds(fakeElectron().electron, 'linux')).toBeDefined();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('electronHostTrayDoubleClickPolicy', () => {
|
|
303
|
+
it('constructs a tray double click policy provider', () => {
|
|
304
|
+
expect(electronHostTrayDoubleClickPolicy(fakeElectron().electron)).toBeDefined();
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe('electronHostTrayDropEvents', () => {
|
|
309
|
+
it('constructs a tray drop events provider', () => {
|
|
310
|
+
expect(electronHostTrayDropEvents(fakeElectron().electron)).toBeDefined();
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
describe('electronHostTrayImage', () => {
|
|
315
|
+
it('constructs a tray image provider', () => {
|
|
316
|
+
expect(electronHostTrayImage(fakeElectron().electron, 'linux')).toBeDefined();
|
|
256
317
|
});
|
|
257
318
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
319
|
+
|
|
320
|
+
describe('electronHostTrayInteractionEvents', () => {
|
|
321
|
+
it('constructs a tray interaction events provider', () => {
|
|
322
|
+
expect(electronHostTrayInteractionEvents(fakeElectron().electron, 'linux')).toBeDefined();
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('electronHostTrayLifecycle', () => {
|
|
327
|
+
it('constructs a tray lifecycle provider', () => {
|
|
328
|
+
expect(electronHostTrayLifecycle(fakeElectron().electron, 'linux')).toBeDefined();
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
describe('electronHostTrayMenu', () => {
|
|
333
|
+
it('constructs a tray menu provider', () => {
|
|
334
|
+
expect(electronHostTrayMenu(fakeElectron().electron, 'linux')).toBeDefined();
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('electronHostTrayMenuSelectionEvents', () => {
|
|
339
|
+
it('constructs a tray menu selection events provider', () => {
|
|
340
|
+
expect(electronHostTrayMenuSelectionEvents(fakeElectron().electron, 'linux')).toBeDefined();
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('electronHostTrayPopupMenu', () => {
|
|
345
|
+
it('constructs a tray popup menu provider', () => {
|
|
346
|
+
expect(electronHostTrayPopupMenu(fakeElectron().electron, 'linux')).toBeDefined();
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
describe('electronHostTrayPressedImage', () => {
|
|
351
|
+
it('constructs a tray pressed image provider', () => {
|
|
352
|
+
expect(electronHostTrayPressedImage(fakeElectron().electron)).toBeDefined();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe('electronHostTrayTemplateImage', () => {
|
|
357
|
+
it('constructs a tray template image provider', () => {
|
|
358
|
+
expect(electronHostTrayTemplateImage(fakeElectron().electron)).toBeDefined();
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
describe('electronHostTrayTitle', () => {
|
|
363
|
+
it('constructs a tray title provider', () => {
|
|
364
|
+
expect(electronHostTrayTitle(fakeElectron().electron)).toBeDefined();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('electronHostTrayTooltip', () => {
|
|
369
|
+
it('constructs a tray tooltip provider', () => {
|
|
370
|
+
expect(electronHostTrayTooltip(fakeElectron().electron, 'linux')).toBeDefined();
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
describe('populateElectronHostTrayBalloon', () => {
|
|
375
|
+
it('is the construction initializer of electronHostTrayBalloon', () => {
|
|
376
|
+
expect(typeof populateElectronHostTrayBalloon).toBe('function');
|
|
261
377
|
});
|
|
262
378
|
});
|
|
263
379
|
|
|
264
|
-
describe('
|
|
265
|
-
it('is the construction initializer of
|
|
266
|
-
expect(typeof
|
|
380
|
+
describe('populateElectronHostTrayBalloonEvents', () => {
|
|
381
|
+
it('is the construction initializer of electronHostTrayBalloonEvents', () => {
|
|
382
|
+
expect(typeof populateElectronHostTrayBalloonEvents).toBe('function');
|
|
267
383
|
});
|
|
268
384
|
});
|
|
269
385
|
|
|
270
|
-
describe('
|
|
271
|
-
it('is the construction initializer of
|
|
272
|
-
expect(typeof
|
|
386
|
+
describe('populateElectronHostTrayBounds', () => {
|
|
387
|
+
it('is the construction initializer of electronHostTrayBounds', () => {
|
|
388
|
+
expect(typeof populateElectronHostTrayBounds).toBe('function');
|
|
273
389
|
});
|
|
274
390
|
});
|
|
275
391
|
|
|
276
|
-
describe('
|
|
277
|
-
it('is the construction initializer of
|
|
278
|
-
expect(typeof
|
|
392
|
+
describe('populateElectronHostTrayDoubleClickPolicy', () => {
|
|
393
|
+
it('is the construction initializer of electronHostTrayDoubleClickPolicy', () => {
|
|
394
|
+
expect(typeof populateElectronHostTrayDoubleClickPolicy).toBe('function');
|
|
279
395
|
});
|
|
280
396
|
});
|
|
281
397
|
|
|
282
|
-
describe('
|
|
283
|
-
it('is the construction initializer of
|
|
284
|
-
expect(typeof
|
|
398
|
+
describe('populateElectronHostTrayDropEvents', () => {
|
|
399
|
+
it('is the construction initializer of electronHostTrayDropEvents', () => {
|
|
400
|
+
expect(typeof populateElectronHostTrayDropEvents).toBe('function');
|
|
285
401
|
});
|
|
286
402
|
});
|
|
287
403
|
|
|
288
|
-
describe('
|
|
289
|
-
it('is the construction initializer of
|
|
290
|
-
expect(typeof
|
|
404
|
+
describe('populateElectronHostTrayImage', () => {
|
|
405
|
+
it('is the construction initializer of electronHostTrayImage', () => {
|
|
406
|
+
expect(typeof populateElectronHostTrayImage).toBe('function');
|
|
291
407
|
});
|
|
292
408
|
});
|
|
293
409
|
|
|
294
|
-
describe('
|
|
295
|
-
it('is the construction initializer of
|
|
296
|
-
expect(typeof
|
|
410
|
+
describe('populateElectronHostTrayInteractionEvents', () => {
|
|
411
|
+
it('is the construction initializer of electronHostTrayInteractionEvents', () => {
|
|
412
|
+
expect(typeof populateElectronHostTrayInteractionEvents).toBe('function');
|
|
297
413
|
});
|
|
298
414
|
});
|
|
299
415
|
|
|
300
|
-
describe('
|
|
301
|
-
it('is the construction initializer of
|
|
302
|
-
expect(typeof
|
|
416
|
+
describe('populateElectronHostTrayLifecycle', () => {
|
|
417
|
+
it('is the construction initializer of electronHostTrayLifecycle', () => {
|
|
418
|
+
expect(typeof populateElectronHostTrayLifecycle).toBe('function');
|
|
303
419
|
});
|
|
304
420
|
});
|
|
305
421
|
|
|
306
|
-
describe('
|
|
307
|
-
it('is the construction initializer of
|
|
308
|
-
expect(typeof
|
|
422
|
+
describe('populateElectronHostTrayMenu', () => {
|
|
423
|
+
it('is the construction initializer of electronHostTrayMenu', () => {
|
|
424
|
+
expect(typeof populateElectronHostTrayMenu).toBe('function');
|
|
309
425
|
});
|
|
310
426
|
});
|
|
311
427
|
|
|
312
|
-
describe('
|
|
313
|
-
it('is the construction initializer of
|
|
314
|
-
expect(typeof
|
|
428
|
+
describe('populateElectronHostTrayMenuSelectionEvents', () => {
|
|
429
|
+
it('is the construction initializer of electronHostTrayMenuSelectionEvents', () => {
|
|
430
|
+
expect(typeof populateElectronHostTrayMenuSelectionEvents).toBe('function');
|
|
315
431
|
});
|
|
316
432
|
});
|
|
317
433
|
|
|
318
|
-
describe('
|
|
319
|
-
it('is the construction initializer of
|
|
320
|
-
expect(typeof
|
|
434
|
+
describe('populateElectronHostTrayPopupMenu', () => {
|
|
435
|
+
it('is the construction initializer of electronHostTrayPopupMenu', () => {
|
|
436
|
+
expect(typeof populateElectronHostTrayPopupMenu).toBe('function');
|
|
321
437
|
});
|
|
322
438
|
});
|
|
323
439
|
|
|
324
|
-
describe('
|
|
325
|
-
it('is the construction initializer of
|
|
326
|
-
expect(typeof
|
|
440
|
+
describe('populateElectronHostTrayPressedImage', () => {
|
|
441
|
+
it('is the construction initializer of electronHostTrayPressedImage', () => {
|
|
442
|
+
expect(typeof populateElectronHostTrayPressedImage).toBe('function');
|
|
327
443
|
});
|
|
328
444
|
});
|
|
329
445
|
|
|
330
|
-
describe('
|
|
331
|
-
it('is the construction initializer of
|
|
332
|
-
expect(typeof
|
|
446
|
+
describe('populateElectronHostTrayTemplateImage', () => {
|
|
447
|
+
it('is the construction initializer of electronHostTrayTemplateImage', () => {
|
|
448
|
+
expect(typeof populateElectronHostTrayTemplateImage).toBe('function');
|
|
333
449
|
});
|
|
334
450
|
});
|
|
335
451
|
|
|
336
|
-
describe('
|
|
337
|
-
it('is the construction initializer of
|
|
338
|
-
expect(typeof
|
|
452
|
+
describe('populateElectronHostTrayTitle', () => {
|
|
453
|
+
it('is the construction initializer of electronHostTrayTitle', () => {
|
|
454
|
+
expect(typeof populateElectronHostTrayTitle).toBe('function');
|
|
339
455
|
});
|
|
340
456
|
});
|
|
341
457
|
|
|
342
|
-
describe('
|
|
343
|
-
it('is the construction initializer of
|
|
344
|
-
expect(typeof
|
|
458
|
+
describe('populateElectronHostTrayTooltip', () => {
|
|
459
|
+
it('is the construction initializer of electronHostTrayTooltip', () => {
|
|
460
|
+
expect(typeof populateElectronHostTrayTooltip).toBe('function');
|
|
345
461
|
});
|
|
346
462
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
electronHostUpdater,
|
|
3
|
+
electronHostUpdaterCommand,
|
|
4
|
+
populateElectronHostUpdaterCommand,
|
|
5
|
+
} from './electronUpdater.ts';
|
|
6
|
+
import type { ElectronApi } from './types/index.ts';
|
|
5
7
|
|
|
6
8
|
type NativeListener = (...args: unknown[]) => void;
|
|
7
9
|
|
|
@@ -58,12 +60,18 @@ function emit(listeners: Map<string, Set<NativeListener>>, event: string, ...arg
|
|
|
58
60
|
for (const listener of [...(listeners.get(event) ?? [])]) listener(...args);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
describe('
|
|
63
|
+
describe('electronHostUpdater', () => {
|
|
64
|
+
it('constructs the Entity-backed updater command slot', () => {
|
|
65
|
+
const updater = electronHostUpdater(fakeElectron().electron);
|
|
66
|
+
expect(Object.keys(updater)).toEqual(['command']);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('electronHostUpdaterCommand', () => {
|
|
62
71
|
it('returns an Entity and applies its immutable feed policy at construction', () => {
|
|
63
72
|
const { electron, calls } = fakeElectron();
|
|
64
|
-
const backend =
|
|
73
|
+
const backend = electronHostUpdaterCommand(electron, 'https://updates.test/feed');
|
|
65
74
|
|
|
66
|
-
expect(EntityRuntimeKey in backend).toBe(true);
|
|
67
75
|
expect(calls.feedUrls).toEqual(['https://updates.test/feed']);
|
|
68
76
|
|
|
69
77
|
backend.destroy();
|
|
@@ -72,7 +80,7 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
72
80
|
|
|
73
81
|
it('runs one awaited Squirrel check through the private native event transaction', async () => {
|
|
74
82
|
const { electron, listeners, calls } = fakeElectron();
|
|
75
|
-
const backend =
|
|
83
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
76
84
|
|
|
77
85
|
const pending = backend.check();
|
|
78
86
|
expect(calls.checks).toBe(1);
|
|
@@ -83,7 +91,6 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
83
91
|
const outcome = await pending;
|
|
84
92
|
expect(outcome.reason).toBe('downloaded');
|
|
85
93
|
if (outcome.reason !== 'downloaded') throw new Error('expected downloaded update');
|
|
86
|
-
expect(EntityRuntimeKey in outcome.update).toBe(true);
|
|
87
94
|
expect(outcome.update.info).toEqual({
|
|
88
95
|
downloadSizeBytes: null,
|
|
89
96
|
isMandatory: null,
|
|
@@ -100,7 +107,7 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
100
107
|
|
|
101
108
|
it('copies and freezes downloaded metadata and uses null for every unknown field', async () => {
|
|
102
109
|
const { electron, listeners } = fakeElectron();
|
|
103
|
-
const backend =
|
|
110
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
104
111
|
const nativeArgs: unknown[] = [{}, '', undefined, ''];
|
|
105
112
|
|
|
106
113
|
const pending = backend.check();
|
|
@@ -125,19 +132,19 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
125
132
|
|
|
126
133
|
it('settles not-available and native error with method-tight portable outcomes', async () => {
|
|
127
134
|
const first = fakeElectron();
|
|
128
|
-
const notAvailable =
|
|
135
|
+
const notAvailable = electronHostUpdaterCommand(first.electron).check();
|
|
129
136
|
emit(first.listeners, 'update-not-available');
|
|
130
137
|
await expect(notAvailable).resolves.toEqual({ reason: 'not-available' });
|
|
131
138
|
|
|
132
139
|
const second = fakeElectron();
|
|
133
|
-
const failed =
|
|
140
|
+
const failed = electronHostUpdaterCommand(second.electron).check();
|
|
134
141
|
emit(second.listeners, 'error', new Error('native detail'));
|
|
135
142
|
await expect(failed).resolves.toEqual({ reason: 'operation-failed' });
|
|
136
143
|
});
|
|
137
144
|
|
|
138
145
|
it('classifies a concurrent check without dispatching a second native operation', async () => {
|
|
139
146
|
const { electron, listeners, calls } = fakeElectron();
|
|
140
|
-
const backend =
|
|
147
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
141
148
|
|
|
142
149
|
const first = backend.check();
|
|
143
150
|
await expect(backend.check()).resolves.toEqual({ reason: 'check-in-progress' });
|
|
@@ -148,7 +155,7 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
148
155
|
|
|
149
156
|
it('rolls back every listener acquired before a partial attach failure', async () => {
|
|
150
157
|
const { electron, listeners, calls } = fakeElectron({ failAttachFor: 'update-not-available' });
|
|
151
|
-
const backend =
|
|
158
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
152
159
|
|
|
153
160
|
await expect(backend.check()).resolves.toEqual({ reason: 'operation-failed' });
|
|
154
161
|
expect(calls.checks).toBe(0);
|
|
@@ -160,7 +167,7 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
160
167
|
const { electron, listeners, calls } = fakeElectron({
|
|
161
168
|
removeFailures: { 'update-available': 1 },
|
|
162
169
|
});
|
|
163
|
-
const backend =
|
|
170
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
164
171
|
|
|
165
172
|
const pending = backend.check();
|
|
166
173
|
emit(listeners, 'update-not-available');
|
|
@@ -186,7 +193,7 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
186
193
|
|
|
187
194
|
it('settles an in-flight transaction and deduplicates repeated provider destroy aliases', async () => {
|
|
188
195
|
const { electron, calls } = fakeElectron();
|
|
189
|
-
const backend =
|
|
196
|
+
const backend = electronHostUpdaterCommand(electron);
|
|
190
197
|
const pending = backend.check();
|
|
191
198
|
|
|
192
199
|
backend.destroy();
|
|
@@ -203,8 +210,8 @@ describe('createElectronUpdaterBackend', () => {
|
|
|
203
210
|
expect(calls.feedUrls).toEqual([]);
|
|
204
211
|
});
|
|
205
212
|
});
|
|
206
|
-
describe('
|
|
207
|
-
it('is the construction initializer of
|
|
208
|
-
expect(typeof
|
|
213
|
+
describe('populateElectronHostUpdaterCommand', () => {
|
|
214
|
+
it('is the construction initializer of electronHostUpdaterCommand', () => {
|
|
215
|
+
expect(typeof populateElectronHostUpdaterCommand).toBe('function');
|
|
209
216
|
});
|
|
210
217
|
});
|