/
creator-spec.ts
547 lines (428 loc) · 22 KB
/
creator-spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
import { SpawnOptions } from 'child_process';
import * as fs from 'fs-extra';
import * as mockFs from 'mock-fs';
import * as os from 'os';
import * as path from 'path';
jest.mock('../src/utils/rc-edit', () => ({
createStubExe: jest.fn()
}));
import { MSICreator, UIOptions } from '../src/creator';
import { createStubExe } from '../src/utils/rc-edit';
import { getMockFileSystem, numberOfFiles, root } from './mocks/mock-fs';
import { MockSpawn } from './mocks/mock-spawn';
const mockPassedFs = fs;
const mockSpawnArgs = {
name: '',
args: [],
options: {}
};
beforeAll(() => {
// console.log call needed as workaround to make jest work with mock-fs
console.log('');
// Load into cache
require('callsites');
(createStubExe as jest.Mock).mockReturnValue('C:\\Stub.exe');
jest.mock('child_process', () => ({
execSync(name: string) {
if (name === 'node -v') {
return new Buffer('8.0.0');
}
if (name === 'light -?' || name === 'candle -?' && mockWixInstalled) {
return new Buffer(' version 3.11.0.1701');
}
throw new Error('Command not found');
},
spawn(name: string, args: Array<string>, options: SpawnOptions) {
mockSpawnArgs.name = name;
mockSpawnArgs.args = args as any;
mockSpawnArgs.options = options;
return new MockSpawn(name, args, options, mockPassedFs);
}
}));
mockFs(getMockFileSystem());
});
afterAll(() => {
mockFs.restore();
jest.unmock('child_process');
});
afterEach(() => {
mockWixInstalled = true;
mockSpawnArgs.name = '';
mockSpawnArgs.args = [];
mockSpawnArgs.options = {};
});
const defaultOptions = {
appDirectory: root,
description: 'ACME is the best company ever',
exe: 'acme',
name: 'Acme',
manufacturer: 'Acme Technologies',
version: '1.0.0',
outputDirectory: path.join(os.tmpdir(), 'electron-wix-msi-test')
};
const testIncludesBase = (title: string, expectation: boolean , ...content: Array<string>) => {
return test(`.wxs file includes ${title}`, () => {
if (Array.isArray(content)) {
// We want to be able to search across line breaks and multiple spaces.
const singleLineWxContent = wxsContent.replace(/\s\s+/g, ' ');
content.forEach((innerContent) => {
if (expectation) expect(singleLineWxContent).toContain(innerContent);
else expect(singleLineWxContent).not.toContain(innerContent);
});
}
});
};
const testIncludes = (title: string, ...content: Array<string>) => {
return testIncludesBase(title, true, ...content );
};
const testIncludesNot = (title: string, ...content: Array<string>) => {
return testIncludesBase(title, false, ...content );
};
const regexTestIncludesBase = (title: string, expectation: boolean , ...content: Array<RegExp>) => {
return test(`.wxs file includes ${title}`, () => {
if (Array.isArray(content)) {
// We want to be able to search across line breaks and multiple spaces.
const singleLineWxContent = wxsContent.replace(/\s\s+/g, ' ');
content.forEach((innerContent) => {
expect(innerContent.test(singleLineWxContent)).toBe(expectation);
});
}
});
};
const regexTestIncludes = (title: string, ...content: Array<RegExp>) => {
return regexTestIncludesBase(title, true, ...content );
};
const regexTestIncludesNot = (title: string, ...content: Array<RegExp>) => {
return regexTestIncludesBase(title, false, ...content );
};
let wxsContent = '';
let mockWixInstalled = true;
test('MSICreator() can be constructed without errors', () => {
expect(new MSICreator(defaultOptions)).toBeTruthy();
});
test('MSICreator create() creates a basic Wix file', async () => {
const msiCreator = new MSICreator(defaultOptions);
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('.wxs file has content', () => {
expect(wxsContent.length).toBeGreaterThan(50);
});
testIncludes('the root element', '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"');
testIncludes('a package element', '<Package');
testIncludes('an APPLICATIONROOTDIRECTORY', '<Directory Id="APPLICATIONROOTDIRECTORY"');
testIncludes('an ApplicationProgramsFolder', '<Directory Id="ApplicationProgramsFolder"');
testIncludes('a default appUserModelId', 'Key="System.AppUserModel.ID" Value="com.squirrel.acme.acme"');
regexTestIncludes('versioned app folder', /<Directory\s*Id=".*"\s*Name="app-1\.0\.0"/);
regexTestIncludes('stubbed exe', /<File\s*Name="acme\.exe"\s*Id=".*"\s*Source="C:\\Stub\.exe"/);
test('.wxs file has as many components as we have files', () => {
// Files + 2 Shortcuts + 2 special files + 7 registry + 1 purge components
const count = wxsContent.split('</Component>').length - 1;
expect(count).toEqual(numberOfFiles + 12);
});
test('MSICreator create() creates Wix file with UI properties', async () => {
const ui: UIOptions = {
images: {
background: 'resources/background.bmp',
banner: 'resources/banner.bmp',
exclamationIcon: 'resources/exclamationIcon.bmp',
infoIcon: 'resources/infoIcon.bmp',
newIcon: 'resources/newIcon.bmp',
upIcon: 'resources/upIcon.bmp'
}
};
const msiCreator = new MSICreator({ ...defaultOptions, ui });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('a background definition', 'Id="WixUIDialogBmp" Value="resources/background.bmp" />');
testIncludes('a banner definition', 'Id="WixUIBannerBmp" Value="resources/banner.bmp" />');
testIncludes('a exclamationIcon definition', 'Id="WixUIExclamationIco" Value="resources/exclamationIcon.bmp" />');
testIncludes('a infoIcon definition', 'Id="WixUIInfoIco" Value="resources/infoIcon.bmp" />');
testIncludes('a newIcon definition', 'Id="WixUINewIco" Value="resources/newIcon.bmp" />');
testIncludes('a banupIconner definition', 'Id="WixUIUpIco" Value="resources/upIcon.bmp" />');
test('.wxs file contains as many component refs as components', () => {
const comoponentCount = wxsContent.split('</Component>').length - 1;
const refCount = wxsContent.split('<ComponentRef').length - 1;
expect(comoponentCount).toEqual(refCount);
});
test('MSICreator create() does not throw if properties are weird', async () => {
const ui: any = {
images: {
nope: 'resources/background.bmp'
}
};
const msiCreator = new MSICreator({ ...defaultOptions, ui });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('MSICreator create() does not throw if UI is just true', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, ui: true });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('MSICreator create() does not throw if UI is just false', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, ui: true });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('MSICreator create() does not throw if UI is just an object', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, ui: { chooseDirectory: true } });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('MSICreator create() sets the appUserModelId', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, appUserModelId: 'Hi' });
const { wxsFile } = await msiCreator.create();
expect(wxsFile).toBeTruthy();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsContent.includes(`Key="System.AppUserModel.ID" Value="Hi"`)).toBeTruthy();
});
test('MSICreator compile() throws if candle/light are not installed', async () => {
mockWixInstalled = false;
const msiCreator = new MSICreator(defaultOptions);
expect(msiCreator.compile()).rejects.toEqual(new Error('Could not find light.exe or candle.exe'));
});
test('MSICreator compile() throws if there is no wxsFile', async () => {
const msiCreator = new MSICreator(defaultOptions);
expect(msiCreator.compile()).rejects.toEqual(new Error('wxsFile not found. Did you run create() yet?'));
});
test('MSICreator compile() creates a wixobj and msi file', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, ui: false });
await msiCreator.create();
const { wixobjFile, msiFile } = await msiCreator.compile();
expect(wixobjFile).toBeTruthy();
expect(fs.existsSync(wixobjFile)).toBeTruthy();
expect(msiFile).toBeTruthy();
expect(fs.existsSync(msiFile)).toBeTruthy();
});
test('MSICreator compile() creates a wixobj and msi file with ui extensions', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, ui: true });
await msiCreator.create();
await msiCreator.compile();
expect(mockSpawnArgs.args).toContain('WixUIExtension');
});
test('MSICreator compile() passes cultures args to the binary', async () => {
const cultures = 'en-US;fr-FR;neutral-cn';
const msiCreator = new MSICreator({ ...defaultOptions, cultures });
await msiCreator.create();
await msiCreator.compile();
expect(mockSpawnArgs.args).toContain(`-cultures:${cultures}`);
});
test('MSICreator compile() passes extension args to the binary', async () => {
const extensions = ['WixUIExtension', 'WixUtilExtension'];
const msiCreator = new MSICreator({ ...defaultOptions, extensions });
await msiCreator.create();
await msiCreator.compile();
extensions.forEach((extension) => {
expect(mockSpawnArgs.args).toContain(extension);
});
});
test('MSICreator compile() combines custom extensions with ui extensions', async () => {
const extensions = ['WixNetFxExtension', 'WixUtilExtension'];
const msiCreator = new MSICreator({ ...defaultOptions, extensions, ui: true });
await msiCreator.create();
await msiCreator.compile();
expect(mockSpawnArgs.args).toContain('WixUIExtension');
extensions.forEach((extension) => {
expect(mockSpawnArgs.args).toContain(extension);
});
});
test('MSICreator compile() throws if candle or light fail', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, exe: 'fail-code-candle' });
const err = 'A bit of error';
const out = 'A bit of data';
const expectedErr = new Error(`Could not create wixobj file. Code: 1 StdErr: ${err} StdOut: ${out}`);
await msiCreator.create();
await expect(msiCreator.compile()).rejects.toEqual(expectedErr);
});
test('MSICreator compile() throws if candle does not create a file', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, exe: 'fail-candle' });
const err = 'A bit of error';
const out = 'A bit of data';
const expectedErr = new Error(`Could not create wixobj file. Code: 0 StdErr: ${err} StdOut: ${out}`);
await msiCreator.create();
await expect(msiCreator.compile()).rejects.toEqual(expectedErr);
});
test('MSICreator compile() throws if light does not create a file', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, exe: 'fail-light' });
const err = 'A bit of error';
const out = 'A bit of data';
const expectedErr = new Error(`Could not create msi file. Code: 0 StdErr: ${err} StdOut: ${out}`);
await msiCreator.create();
await expect(msiCreator.compile()).rejects.toEqual(expectedErr);
});
test('MSICreator compile() tries to sign the MSI with default options', async () => {
const certOptions = { certificateFile: 'path/to/file', certificatePassword: 'hi' };
const msiCreator = new MSICreator({ ...defaultOptions, ...certOptions });
await msiCreator.create();
await msiCreator.compile();
const expectedCert = path.join(process.cwd(), 'path/to/file');
const expectedMsi = path.join(defaultOptions.outputDirectory, 'acme.msi');
const expectedArgs = ['sign', '/a', '/f', `${expectedCert}`, '/p', 'hi', `${expectedMsi}`];
expect(mockSpawnArgs.name.endsWith('signtool.exe')).toBeTruthy();
expect(mockSpawnArgs.args).toEqual(expectedArgs);
});
test('MSICreator compile() tries to sign the MSI with custom options', async () => {
const certOptions = { certificateFile: 'path/to/file', signWithParams: 'hello "how are you"'};
const msiCreator = new MSICreator({ ...defaultOptions, ...certOptions });
await msiCreator.create();
await msiCreator.compile();
const expectedMsi = path.join(defaultOptions.outputDirectory, 'acme.msi');
const expectedArgs = ['sign', 'hello', '"how are you"', expectedMsi];
expect(mockSpawnArgs.name.endsWith('signtool.exe')).toBeTruthy();
expect(mockSpawnArgs.args).toEqual(expectedArgs);
});
test('MSICreator compile() throws if certificateFile is set without certificatePassword', async () => {
const certOptions = { certificateFile: 'hello "how are you"'};
const msiCreator = new MSICreator({ ...defaultOptions, exe: 'fail-code-signtool', ...certOptions });
const expectedErr = new Error('You must provide a certificatePassword with a certificateFile');
await msiCreator.create();
await expect(msiCreator.compile()).rejects.toEqual(expectedErr);
});
test('MSICreator compile() throws if signing throws', async () => {
const certOptions = { certificateFile: 'path/to/file', signWithParams: 'hello "how are you"'};
const msiCreator = new MSICreator({ ...defaultOptions, exe: 'fail-code-signtool', ...certOptions });
const expectedErr = new Error(`Signtool exited with code 1. Stderr: A bit of error. Stdout: A bit of data`);
await msiCreator.create();
await expect(msiCreator.compile()).rejects.toEqual(expectedErr);
});
test('MSICreator create() creates x86 version by default', async () => {
const msiCreator = new MSICreator({ ...defaultOptions});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('32 bit package declaration', 'Platform="x86"');
testIncludes('32 bit component declarations', 'Win64="no"');
testIncludes('32 bit file architecture declaration', 'ProcessorArchitecture="x86"');
test('MSICreator create() creates x86 version explicitly', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, arch: 'x86'});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('32 bit package declaration', 'Platform="x86"');
testIncludes('32 bit component declarations', 'Win64="no"');
testIncludes('32 bit file architecture declaration', 'ProcessorArchitecture="x86"');
test('MSICreator create() creates x64 version', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, arch: 'x64'});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('32 bit package declaration', 'Platform="x64"');
testIncludes('32 bit component declarations', 'Win64="yes"');
testIncludes('32 bit file architecture declaration', 'ProcessorArchitecture="x64"');
test('MSICreator create() creates ia64 version', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, arch: 'ia64'});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('32 bit package declaration', 'Platform="ia64"');
testIncludes('32 bit component declarations', 'Win64="yes"');
testIncludes('32 bit file architecture declaration', 'ProcessorArchitecture="ia64"');
test('MSICreator create() shortcut name override', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, shortcutName: 'BeepBeep'});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('Custom shortcut name', '<Shortcut Id="ApplicationStartMenuShortcut" Name="BeepBeep"');
testIncludes('Single Package Authoring setting', '<Property Id="ALLUSERS" Secure="yes" Value="2" />');
testIncludes('correct default perUser setting', '<Property Id="MSIINSTALLPERUSER" Secure="yes" Value="0" />');
testIncludes('Install path property', '<Property Id="INSTALLPATH">');
testIncludes('Install RegistrySearch', 'RegistrySearch Key="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall');
testIncludes('RegistryInstallPath component', '<Component Id="RegistryInstallPath"');
testIncludes('RegistryInstallPath component-ref', '<ComponentRef Id="RegistryInstallPath" />');
testIncludes('PurgeOnUninstall component', '<Component Id="PurgeOnUninstall" ');
testIncludes('PurgeOnUninstall component-ref', '<ComponentRef Id="PurgeOnUninstall" />');
testIncludes('RegistryInstallPath component-ref', '<ComponentRef Id="RegistryInstallPath" />');
testIncludes('UninstallDisplayName component-ref', '<ComponentRef Id="UninstallDisplayName" />');
testIncludes('UninstallPublisher component-ref', '<ComponentRef Id="UninstallPublisher" />');
testIncludes('UninstallDisplayVersion component-ref', '<ComponentRef Id="UninstallDisplayVersion" />');
testIncludes('UninstallModifyString component-ref', '<ComponentRef Id="UninstallModifyString" />');
testIncludes('UninstallString component-ref', '<ComponentRef Id="UninstallString" />');
testIncludes('UninstallDisplayIcon component-ref', '<ComponentRef Id="UninstallDisplayIcon" />');
testIncludesNot('RegistryRunKey component', '<Component Id="RegistryRunKey"');
testIncludesNot('RegistryRunKey component-ref', '<ComponentRef Id="RegistryRunKey" />');
regexTestIncludesNot('AutoLaunch feature', /<Feature Id="AutoLaunch" Title="Launch On Login" Level="2" .*>/);
regexTestIncludesNot('AutoUpdate feature', /<Feature Id="AutoUpdate" Title="Auto Update" Level="3" .*>/);
regexTestIncludesNot('Squirrel executable component-ref', /<ComponentRef Id="_msq.exe_.*" \/>/ );
testIncludesNot('Permission component-ref', `<ComponentRef Id="SetFolderPermissions" />`);
testIncludesNot('RegistryRunKey component-ref', '<ComponentRef Id="SetUninstallDisplayVersionPermissions" />');
describe('auto-update', () => {
test('MSICreator includes Auto-Updater feature', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, features: {autoUpdate: true, autoLaunch: false }});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('.wxs file has as many components as we have files', () => {
// Files + 2 Shortcuts + 3 special files + 9 registry + 1 permission component + 1 purge components
const count = wxsContent.split('</Component>').length - 1;
expect(count).toEqual(numberOfFiles + 16);
});
test('.wxs file contains as many component refs as components', () => {
const componentCount = wxsContent.split('</Component>').length - 1;
const refCount = wxsContent.split('<ComponentRef').length - 1;
expect(componentCount).toEqual(refCount);
});
regexTestIncludes('Squirrel executable component', /<Component Id="_msq.exe_.*"/);
testIncludes('Permission component', `<Component Id="SetFolderPermissions"`);
testIncludes('PermissionEx call', '<util:PermissionEx User="[UPDATERUSERGROUP]" GenericAll="yes" />');
testIncludes('Updater user group property', '<Property Id="UPDATERUSERGROUP" Value="Users" />');
regexTestIncludes('AutoUpdate feature', /<Feature Id="AutoUpdate" Title="Auto Update" Level="3" .*>/);
regexTestIncludes('Squirrel executable component-ref', /<ComponentRef Id="_msq.exe_.*" \/>/ );
testIncludes('Permission component-ref', `<ComponentRef Id="SetFolderPermissions" />`);
testIncludes('SetUninstallDisplayVersionPermissions component-ref', '<ComponentRef Id="SetUninstallDisplayVersionPermissions" />');
});
describe('auto-launch', () => {
test('MSICreator includes Auto-Updater feature', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, features: {autoUpdate: false, autoLaunch: true }});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
test('.wxs file has as many components as we have files', () => {
// Files + 2 Shortcuts + 2 special files + 8 registry + 1 purge components
const count = wxsContent.split('</Component>').length - 1;
expect(count).toEqual(numberOfFiles + 13);
});
test('.wxs file contains as many component refs as components', () => {
const componentCount = wxsContent.split('</Component>').length - 1;
const refCount = wxsContent.split('<ComponentRef').length - 1;
expect(componentCount).toEqual(refCount);
});
testIncludes('RegistryRunKey', '<RegistryKey Root="HKMU" Key="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" ForceCreateOnInstall="no" ForceDeleteOnUninstall="no"');
testIncludes('RegistryRunKeyValue', '<RegistryValue Name="com.squirrel.acme.acme" Type="string" Value=""[APPLICATIONROOTDIRECTORY]acme.exe"" KeyPath="yes"/>');
testIncludes('RegistryRunKey component', '<Component Id="RegistryRunKey"');
testIncludes('RegistryRunKey component-ref', '<ComponentRef Id="RegistryRunKey" />');
regexTestIncludes('AutoLaunch feature', /<Feature Id="AutoLaunch" Title="Launch On Login" Level="2" .*>/);
test('MSICreator includes Auto-Updater feature with arguments', async () => {
const msiCreator = new MSICreator({
...defaultOptions,
features: {autoUpdate: false, autoLaunch: {enabled: true, arguments: ['arg1', 'arg2'] } }});
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
console.log(wxsContent);
expect(wxsFile).toBeTruthy();
});
testIncludes('RegistryRunKey', '<RegistryValue Name="com.squirrel.acme.acme" Type="string" Value=""[APPLICATIONROOTDIRECTORY]acme.exe" arg1 arg2" KeyPath="yes"/>');
});
describe('perUser install by default', () => {
test('MSICreator includes Auto-Updater feature', async () => {
const msiCreator = new MSICreator({ ...defaultOptions, defaultInstallMode: 'perUser' });
const { wxsFile } = await msiCreator.create();
wxsContent = await fs.readFile(wxsFile, 'utf-8');
expect(wxsFile).toBeTruthy();
});
testIncludes('correct defautlt perUser setting', '<Property Id="MSIINSTALLPERUSER" Secure="yes" Value="1" />');
});