@theia/getting-started 1.76.0-next.14 → 1.76.0-next.18
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 +44 -0
- package/lib/browser/getting-started-frontend-module.d.ts.map +1 -1
- package/lib/browser/getting-started-frontend-module.js +3 -0
- package/lib/browser/getting-started-frontend-module.js.map +1 -1
- package/lib/browser/getting-started-widget.d.ts +0 -7
- package/lib/browser/getting-started-widget.d.ts.map +1 -1
- package/lib/browser/getting-started-widget.js +1 -29
- package/lib/browser/getting-started-widget.js.map +1 -1
- package/lib/browser/walkthrough-section.d.ts +2 -2
- package/lib/browser/walkthrough-section.d.ts.map +1 -1
- package/lib/browser/walkthrough-section.js +7 -5
- package/lib/browser/walkthrough-section.js.map +1 -1
- package/lib/browser/walkthrough-section.spec.js +17 -1
- package/lib/browser/walkthrough-section.spec.js.map +1 -1
- package/lib/browser/walkthrough-service.d.ts +26 -5
- package/lib/browser/walkthrough-service.d.ts.map +1 -1
- package/lib/browser/walkthrough-service.js +77 -22
- package/lib/browser/walkthrough-service.js.map +1 -1
- package/lib/browser/walkthrough-service.spec.js +173 -57
- package/lib/browser/walkthrough-service.spec.js.map +1 -1
- package/lib/common/walkthrough-provider.d.ts +22 -0
- package/lib/common/walkthrough-provider.d.ts.map +1 -0
- package/lib/common/walkthrough-provider.js +27 -0
- package/lib/common/walkthrough-provider.js.map +1 -0
- package/lib/common/walkthrough-types.d.ts +18 -5
- package/lib/common/walkthrough-types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/browser/getting-started-frontend-module.ts +3 -0
- package/src/browser/getting-started-widget.tsx +31 -101
- package/src/browser/style/index.css +69 -35
- package/src/browser/walkthrough-section.spec.tsx +29 -1
- package/src/browser/walkthrough-section.tsx +7 -5
- package/src/browser/walkthrough-service.spec.ts +207 -57
- package/src/browser/walkthrough-service.ts +82 -25
- package/src/common/walkthrough-provider.ts +38 -0
- package/src/common/walkthrough-types.ts +20 -5
|
@@ -36,6 +36,7 @@ describe('WalkthroughService', () => {
|
|
|
36
36
|
let mockOpenerOpenCalls;
|
|
37
37
|
let reportedErrors;
|
|
38
38
|
let mockDisabledByTrust;
|
|
39
|
+
let mockWalkthroughProviders;
|
|
39
40
|
function createContribution(overrides) {
|
|
40
41
|
return {
|
|
41
42
|
id: 'test-walkthrough',
|
|
@@ -59,6 +60,10 @@ describe('WalkthroughService', () => {
|
|
|
59
60
|
...overrides
|
|
60
61
|
};
|
|
61
62
|
}
|
|
63
|
+
/** Registers a plugin contribution the way {@link WalkthroughService.collectPluginWalkthroughs} does. */
|
|
64
|
+
function registerContribution(contribution) {
|
|
65
|
+
service.registerWalkthrough(`${contribution.pluginId}.${contribution.id}`, contribution, contribution.pluginId, contribution.pluginIcon);
|
|
66
|
+
}
|
|
62
67
|
beforeEach(() => {
|
|
63
68
|
storedData = {};
|
|
64
69
|
onDidChangePluginsEmitter = new event_1.Emitter();
|
|
@@ -72,6 +77,7 @@ describe('WalkthroughService', () => {
|
|
|
72
77
|
mockOpenerOpenCalls = [];
|
|
73
78
|
reportedErrors = [];
|
|
74
79
|
mockDisabledByTrust = new Set();
|
|
80
|
+
mockWalkthroughProviders = [];
|
|
75
81
|
const mockOpener = { open: (...args) => { mockOpenerOpenCalls.push(String(args[0])); } };
|
|
76
82
|
mockOpenerGetOpener = () => Promise.resolve(mockOpener);
|
|
77
83
|
onDidExpandViewEmitter = new event_1.Emitter();
|
|
@@ -130,6 +136,9 @@ describe('WalkthroughService', () => {
|
|
|
130
136
|
get disabledByTrust() { return mockDisabledByTrust; },
|
|
131
137
|
onDidChangePlugins: onDidChangePluginsEmitter.event
|
|
132
138
|
};
|
|
139
|
+
service.walkthroughProviders = {
|
|
140
|
+
getContributions: () => mockWalkthroughProviders
|
|
141
|
+
};
|
|
133
142
|
});
|
|
134
143
|
afterEach(() => {
|
|
135
144
|
service.dispose();
|
|
@@ -142,7 +151,7 @@ describe('WalkthroughService', () => {
|
|
|
142
151
|
describe('registerWalkthrough', () => {
|
|
143
152
|
it('should register a walkthrough and make it retrievable', () => {
|
|
144
153
|
const contribution = createContribution();
|
|
145
|
-
|
|
154
|
+
registerContribution(contribution);
|
|
146
155
|
const walkthroughs = service.getWalkthroughs();
|
|
147
156
|
(0, chai_1.expect)(walkthroughs).to.have.lengthOf(1);
|
|
148
157
|
(0, chai_1.expect)(walkthroughs[0].id).to.equal('test.publisher.test-plugin.test-walkthrough');
|
|
@@ -151,17 +160,17 @@ describe('WalkthroughService', () => {
|
|
|
151
160
|
});
|
|
152
161
|
it('should construct full ID from pluginId and walkthrough id', () => {
|
|
153
162
|
const contribution = createContribution({ pluginId: 'my.plugin', id: 'my-wt' });
|
|
154
|
-
|
|
163
|
+
registerContribution(contribution);
|
|
155
164
|
(0, chai_1.expect)(service.getWalkthrough('my.plugin.my-wt')).to.not.be.undefined;
|
|
156
165
|
});
|
|
157
166
|
it('should fire onDidChangeWalkthroughs event', () => {
|
|
158
167
|
let fired = false;
|
|
159
168
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
160
|
-
|
|
169
|
+
registerContribution(createContribution());
|
|
161
170
|
(0, chai_1.expect)(fired).to.be.true;
|
|
162
171
|
});
|
|
163
172
|
it('should initialize steps as not complete', () => {
|
|
164
|
-
|
|
173
|
+
registerContribution(createContribution());
|
|
165
174
|
const walkthrough = service.getWalkthroughs()[0];
|
|
166
175
|
for (const step of walkthrough.steps) {
|
|
167
176
|
(0, chai_1.expect)(step.isComplete).to.be.false;
|
|
@@ -170,7 +179,7 @@ describe('WalkthroughService', () => {
|
|
|
170
179
|
});
|
|
171
180
|
describe('markStepComplete', () => {
|
|
172
181
|
beforeEach(() => {
|
|
173
|
-
|
|
182
|
+
registerContribution(createContribution());
|
|
174
183
|
});
|
|
175
184
|
it('should mark a step as complete', async () => {
|
|
176
185
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
@@ -214,7 +223,7 @@ describe('WalkthroughService', () => {
|
|
|
214
223
|
describe('markStepIncomplete', () => {
|
|
215
224
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
216
225
|
beforeEach(() => {
|
|
217
|
-
|
|
226
|
+
registerContribution(createContribution());
|
|
218
227
|
});
|
|
219
228
|
it('should take the completion mark off a step again', async () => {
|
|
220
229
|
await service.markStepComplete(wtId, 'step1');
|
|
@@ -250,7 +259,7 @@ describe('WalkthroughService', () => {
|
|
|
250
259
|
describe('markAllStepsComplete', () => {
|
|
251
260
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
252
261
|
beforeEach(() => {
|
|
253
|
-
|
|
262
|
+
registerContribution(createContribution());
|
|
254
263
|
});
|
|
255
264
|
it('should complete every step', async () => {
|
|
256
265
|
await service.markAllStepsComplete(wtId);
|
|
@@ -280,7 +289,7 @@ describe('WalkthroughService', () => {
|
|
|
280
289
|
});
|
|
281
290
|
describe('resetProgress', () => {
|
|
282
291
|
beforeEach(async () => {
|
|
283
|
-
|
|
292
|
+
registerContribution(createContribution());
|
|
284
293
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
285
294
|
await service.markStepComplete(wtId, 'step1');
|
|
286
295
|
await service.markStepComplete(wtId, 'step2');
|
|
@@ -306,7 +315,7 @@ describe('WalkthroughService', () => {
|
|
|
306
315
|
});
|
|
307
316
|
describe('getStepProgress', () => {
|
|
308
317
|
beforeEach(() => {
|
|
309
|
-
|
|
318
|
+
registerContribution(createContribution());
|
|
310
319
|
});
|
|
311
320
|
it('should return correct progress', () => {
|
|
312
321
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
@@ -329,7 +338,7 @@ describe('WalkthroughService', () => {
|
|
|
329
338
|
});
|
|
330
339
|
describe('completion event handling', () => {
|
|
331
340
|
beforeEach(() => {
|
|
332
|
-
|
|
341
|
+
registerContribution(createContribution());
|
|
333
342
|
// Wire up the event handlers that @postConstruct would normally set up
|
|
334
343
|
service.toDispose.push(service.commandRegistry.onDidExecuteCommand((e) => {
|
|
335
344
|
service.handleCompletionEvent(`onCommand:${e.commandId}`);
|
|
@@ -373,7 +382,7 @@ describe('WalkthroughService', () => {
|
|
|
373
382
|
};
|
|
374
383
|
// Simulate what loadProgress does
|
|
375
384
|
await service.loadProgress();
|
|
376
|
-
|
|
385
|
+
registerContribution(createContribution());
|
|
377
386
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
378
387
|
const walkthrough = service.getWalkthrough(wtId);
|
|
379
388
|
(0, chai_1.expect)(walkthrough.steps[0].isComplete).to.be.true;
|
|
@@ -404,7 +413,7 @@ describe('WalkthroughService', () => {
|
|
|
404
413
|
});
|
|
405
414
|
it('should handle missing storage data gracefully', async () => {
|
|
406
415
|
await service.loadProgress();
|
|
407
|
-
|
|
416
|
+
registerContribution(createContribution());
|
|
408
417
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
409
418
|
const walkthrough = service.getWalkthrough(wtId);
|
|
410
419
|
for (const step of walkthrough.steps) {
|
|
@@ -414,12 +423,12 @@ describe('WalkthroughService', () => {
|
|
|
414
423
|
});
|
|
415
424
|
describe('extension icon', () => {
|
|
416
425
|
it('should carry the icon of the contributing extension', () => {
|
|
417
|
-
|
|
426
|
+
registerContribution(createContribution({ pluginIcon: 'hostedPlugin/pub_name/icon.png' }));
|
|
418
427
|
const walkthrough = service.getWalkthrough('test.publisher.test-plugin.test-walkthrough');
|
|
419
428
|
(0, chai_1.expect)(walkthrough.pluginIcon).to.equal('hostedPlugin/pub_name/icon.png');
|
|
420
429
|
});
|
|
421
430
|
it('should leave the icon undefined when the extension declares none', () => {
|
|
422
|
-
|
|
431
|
+
registerContribution(createContribution());
|
|
423
432
|
const walkthrough = service.getWalkthrough('test.publisher.test-plugin.test-walkthrough');
|
|
424
433
|
(0, chai_1.expect)(walkthrough.pluginIcon).to.be.undefined;
|
|
425
434
|
});
|
|
@@ -431,7 +440,7 @@ describe('WalkthroughService', () => {
|
|
|
431
440
|
(0, chai_1.expect)(service.selectedStep).to.be.undefined;
|
|
432
441
|
});
|
|
433
442
|
it('should retain the selected walkthrough and fire onDidChangeSelection', () => {
|
|
434
|
-
|
|
443
|
+
registerContribution(createContribution());
|
|
435
444
|
let fired = 0;
|
|
436
445
|
service.onDidChangeSelection(() => { fired++; });
|
|
437
446
|
service.selectWalkthrough(wtId);
|
|
@@ -439,18 +448,18 @@ describe('WalkthroughService', () => {
|
|
|
439
448
|
(0, chai_1.expect)(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
440
449
|
});
|
|
441
450
|
it('should preselect the first pending step', () => {
|
|
442
|
-
|
|
451
|
+
registerContribution(createContribution());
|
|
443
452
|
service.selectWalkthrough(wtId);
|
|
444
453
|
(0, chai_1.expect)(service.selectedStep?.id).to.equal('step1');
|
|
445
454
|
});
|
|
446
455
|
it('should preselect the first step that is not yet complete', async () => {
|
|
447
|
-
|
|
456
|
+
registerContribution(createContribution());
|
|
448
457
|
await service.markStepComplete(wtId, 'step1');
|
|
449
458
|
service.selectWalkthrough(wtId);
|
|
450
459
|
(0, chai_1.expect)(service.selectedStep?.id).to.equal('step2');
|
|
451
460
|
});
|
|
452
461
|
it('should accept the VS Code `publisher.name#walkthroughId` form', () => {
|
|
453
|
-
|
|
462
|
+
registerContribution(createContribution());
|
|
454
463
|
service.selectWalkthrough('test.publisher.test-plugin#test-walkthrough');
|
|
455
464
|
(0, chai_1.expect)(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
456
465
|
});
|
|
@@ -462,19 +471,19 @@ describe('WalkthroughService', () => {
|
|
|
462
471
|
(0, chai_1.expect)(service.selectedWalkthrough).to.be.undefined;
|
|
463
472
|
});
|
|
464
473
|
it('should select another step of the selected walkthrough', () => {
|
|
465
|
-
|
|
474
|
+
registerContribution(createContribution());
|
|
466
475
|
service.selectWalkthrough(wtId);
|
|
467
476
|
service.selectStep('step2');
|
|
468
477
|
(0, chai_1.expect)(service.selectedStep?.id).to.equal('step2');
|
|
469
478
|
});
|
|
470
479
|
it('should ignore a step that does not belong to the selected walkthrough', () => {
|
|
471
|
-
|
|
480
|
+
registerContribution(createContribution());
|
|
472
481
|
service.selectWalkthrough(wtId);
|
|
473
482
|
service.selectStep('nonexistent');
|
|
474
483
|
(0, chai_1.expect)(service.selectedStep?.id).to.equal('step1');
|
|
475
484
|
});
|
|
476
485
|
it('should clear the selection', () => {
|
|
477
|
-
|
|
486
|
+
registerContribution(createContribution());
|
|
478
487
|
service.selectWalkthrough(wtId);
|
|
479
488
|
let fired = 0;
|
|
480
489
|
service.onDidChangeSelection(() => { fired++; });
|
|
@@ -490,7 +499,7 @@ describe('WalkthroughService', () => {
|
|
|
490
499
|
(0, chai_1.expect)(fired).to.be.false;
|
|
491
500
|
});
|
|
492
501
|
it('should reflect step completion in the selected step', async () => {
|
|
493
|
-
|
|
502
|
+
registerContribution(createContribution());
|
|
494
503
|
service.selectWalkthrough(wtId);
|
|
495
504
|
await service.markStepComplete(wtId, 'step1');
|
|
496
505
|
(0, chai_1.expect)(service.selectedStep?.id).to.equal('step1');
|
|
@@ -501,23 +510,23 @@ describe('WalkthroughService', () => {
|
|
|
501
510
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
502
511
|
it('should hide a walkthrough whose when clause does not hold', () => {
|
|
503
512
|
mockContextKeyMatchResult = false;
|
|
504
|
-
|
|
513
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
505
514
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
506
515
|
(0, chai_1.expect)(service.getWalkthrough(wtId)).to.be.undefined;
|
|
507
516
|
});
|
|
508
517
|
it('should list a walkthrough whose when clause holds', () => {
|
|
509
518
|
mockContextKeyMatchResult = true;
|
|
510
|
-
|
|
519
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
511
520
|
(0, chai_1.expect)(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
512
521
|
});
|
|
513
522
|
it('should always list a walkthrough without a when clause', () => {
|
|
514
523
|
mockContextKeyMatchResult = false;
|
|
515
|
-
|
|
524
|
+
registerContribution(createContribution());
|
|
516
525
|
(0, chai_1.expect)(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
517
526
|
});
|
|
518
527
|
it('should hide the steps whose when clause does not hold', () => {
|
|
519
528
|
mockContextKeyMatchResult = false;
|
|
520
|
-
|
|
529
|
+
registerContribution(createContribution({
|
|
521
530
|
steps: [
|
|
522
531
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
523
532
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -529,7 +538,7 @@ describe('WalkthroughService', () => {
|
|
|
529
538
|
});
|
|
530
539
|
it('should exclude hidden steps from the progress', () => {
|
|
531
540
|
mockContextKeyMatchResult = false;
|
|
532
|
-
|
|
541
|
+
registerContribution(createContribution({
|
|
533
542
|
steps: [
|
|
534
543
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
535
544
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -539,13 +548,13 @@ describe('WalkthroughService', () => {
|
|
|
539
548
|
});
|
|
540
549
|
it('should not select a hidden walkthrough', () => {
|
|
541
550
|
mockContextKeyMatchResult = false;
|
|
542
|
-
|
|
551
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
543
552
|
service.selectWalkthrough(wtId);
|
|
544
553
|
(0, chai_1.expect)(service.selectedWalkthrough).to.be.undefined;
|
|
545
554
|
});
|
|
546
555
|
it('should preselect the first pending visible step', () => {
|
|
547
556
|
mockContextKeyMatchResult = false;
|
|
548
|
-
|
|
557
|
+
registerContribution(createContribution({
|
|
549
558
|
steps: [
|
|
550
559
|
{ id: 'hidden', title: 'Hidden', description: 'd', when: 'someKey' },
|
|
551
560
|
{ id: 'visible', title: 'Visible', description: 'd' }
|
|
@@ -556,13 +565,13 @@ describe('WalkthroughService', () => {
|
|
|
556
565
|
});
|
|
557
566
|
it('should re-evaluate visibility whenever it is queried', () => {
|
|
558
567
|
mockContextKeyMatchResult = false;
|
|
559
|
-
|
|
568
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
560
569
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
561
570
|
mockContextKeyMatchResult = true;
|
|
562
571
|
(0, chai_1.expect)(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
563
572
|
});
|
|
564
573
|
it('should collect the context keys of every when clause and onContext event', () => {
|
|
565
|
-
|
|
574
|
+
registerContribution(createContribution({
|
|
566
575
|
when: 'walkthroughKey',
|
|
567
576
|
steps: [{ id: 's1', title: 'S1', description: 'd', when: 'stepKey', completionEvents: ['onContext:eventKey'] }]
|
|
568
577
|
}));
|
|
@@ -570,7 +579,7 @@ describe('WalkthroughService', () => {
|
|
|
570
579
|
(0, chai_1.expect)(Array.from(keys).sort()).to.deep.equal(['eventKey', 'stepKey', 'walkthroughKey']);
|
|
571
580
|
});
|
|
572
581
|
it('should notify when visibility changed', () => {
|
|
573
|
-
|
|
582
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
574
583
|
let fired = false;
|
|
575
584
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
576
585
|
service.handleVisibilityChanged();
|
|
@@ -578,7 +587,7 @@ describe('WalkthroughService', () => {
|
|
|
578
587
|
});
|
|
579
588
|
it('should close a selected walkthrough that becomes hidden', () => {
|
|
580
589
|
mockContextKeyMatchResult = true;
|
|
581
|
-
|
|
590
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
582
591
|
service.selectWalkthrough(wtId);
|
|
583
592
|
(0, chai_1.expect)(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
584
593
|
mockContextKeyMatchResult = false;
|
|
@@ -587,7 +596,7 @@ describe('WalkthroughService', () => {
|
|
|
587
596
|
});
|
|
588
597
|
it('should mark only the visible steps done', async () => {
|
|
589
598
|
mockContextKeyMatchResult = false;
|
|
590
|
-
|
|
599
|
+
registerContribution(createContribution({
|
|
591
600
|
steps: [
|
|
592
601
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
593
602
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -605,8 +614,8 @@ describe('WalkthroughService', () => {
|
|
|
605
614
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
606
615
|
});
|
|
607
616
|
it('should return all registered walkthroughs', () => {
|
|
608
|
-
|
|
609
|
-
|
|
617
|
+
registerContribution(createContribution({ id: 'wt1' }));
|
|
618
|
+
registerContribution(createContribution({ id: 'wt2' }));
|
|
610
619
|
const walkthroughs = service.getWalkthroughs();
|
|
611
620
|
(0, chai_1.expect)(walkthroughs).to.have.lengthOf(2);
|
|
612
621
|
});
|
|
@@ -617,7 +626,7 @@ describe('WalkthroughService', () => {
|
|
|
617
626
|
beforeEach(() => {
|
|
618
627
|
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
619
628
|
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
620
|
-
service.
|
|
629
|
+
service.syncWalkthroughs();
|
|
621
630
|
});
|
|
622
631
|
it('should offer the walkthrough of an installed plugin', () => {
|
|
623
632
|
(0, chai_1.expect)(service.getWalkthrough(wtId)).to.not.be.undefined;
|
|
@@ -632,7 +641,7 @@ describe('WalkthroughService', () => {
|
|
|
632
641
|
})]
|
|
633
642
|
}
|
|
634
643
|
});
|
|
635
|
-
service.
|
|
644
|
+
service.syncWalkthroughs();
|
|
636
645
|
const steps = service.getWalkthrough(wtId).steps;
|
|
637
646
|
(0, chai_1.expect)(steps).to.have.lengthOf(1);
|
|
638
647
|
(0, chai_1.expect)(steps[0].id).to.equal('only');
|
|
@@ -640,34 +649,34 @@ describe('WalkthroughService', () => {
|
|
|
640
649
|
it('should keep a walkthrough whose definition is unchanged', () => {
|
|
641
650
|
let fired = false;
|
|
642
651
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
643
|
-
service.
|
|
652
|
+
service.syncWalkthroughs();
|
|
644
653
|
(0, chai_1.expect)(fired, 'an unchanged sync must not notify').to.be.false;
|
|
645
654
|
});
|
|
646
655
|
it('should not offer the walkthrough of a plugin restricted by workspace trust', () => {
|
|
647
656
|
(0, chai_1.expect)(service.getWalkthrough(wtId), 'offered while the workspace is trusted').to.not.be.undefined;
|
|
648
657
|
mockDisabledByTrust.add(pluginId);
|
|
649
|
-
service.
|
|
658
|
+
service.syncWalkthroughs();
|
|
650
659
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
651
660
|
});
|
|
652
661
|
it('should offer it again once the workspace is trusted', () => {
|
|
653
662
|
mockDisabledByTrust.add(pluginId);
|
|
654
|
-
service.
|
|
663
|
+
service.syncWalkthroughs();
|
|
655
664
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
656
665
|
mockDisabledByTrust.delete(pluginId);
|
|
657
|
-
service.
|
|
666
|
+
service.syncWalkthroughs();
|
|
658
667
|
(0, chai_1.expect)(service.getWalkthrough(wtId)).to.not.be.undefined;
|
|
659
668
|
});
|
|
660
669
|
it('should close a restricted walkthrough that was open', () => {
|
|
661
670
|
service.selectWalkthrough(wtId);
|
|
662
671
|
(0, chai_1.expect)(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
663
672
|
mockDisabledByTrust.add(pluginId);
|
|
664
|
-
service.
|
|
673
|
+
service.syncWalkthroughs();
|
|
665
674
|
(0, chai_1.expect)(service.selectedWalkthrough).to.be.undefined;
|
|
666
675
|
});
|
|
667
676
|
it('should drop the walkthrough once the plugin is out of sync', () => {
|
|
668
677
|
// Theia keeps an uninstalled or disabled plugin loaded until the next reload, flagged as out of sync.
|
|
669
678
|
mockPlugins[0].outOfSync = true;
|
|
670
|
-
service.
|
|
679
|
+
service.syncWalkthroughs();
|
|
671
680
|
(0, chai_1.expect)(service.getWalkthrough(wtId)).to.be.undefined;
|
|
672
681
|
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
673
682
|
});
|
|
@@ -675,17 +684,124 @@ describe('WalkthroughService', () => {
|
|
|
675
684
|
let fired = false;
|
|
676
685
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
677
686
|
mockPlugins[0].outOfSync = true;
|
|
678
|
-
service.
|
|
687
|
+
service.syncWalkthroughs();
|
|
679
688
|
(0, chai_1.expect)(fired).to.be.true;
|
|
680
689
|
});
|
|
681
690
|
it('should close the walkthrough if it was open', () => {
|
|
682
691
|
service.selectWalkthrough(wtId);
|
|
683
692
|
(0, chai_1.expect)(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
684
693
|
mockPlugins[0].outOfSync = true;
|
|
685
|
-
service.
|
|
694
|
+
service.syncWalkthroughs();
|
|
686
695
|
(0, chai_1.expect)(service.selectedWalkthrough).to.be.undefined;
|
|
687
696
|
});
|
|
688
697
|
});
|
|
698
|
+
describe('contributed walkthroughs', () => {
|
|
699
|
+
const providedId = 'theia.test-walkthrough';
|
|
700
|
+
const pluginId = 'test.publisher.test-plugin';
|
|
701
|
+
const pluginWalkthroughId = 'test.publisher.test-plugin.test-walkthrough';
|
|
702
|
+
function createDefinition(overrides) {
|
|
703
|
+
return {
|
|
704
|
+
id: providedId,
|
|
705
|
+
title: 'Provided Walkthrough',
|
|
706
|
+
description: 'Contributed by a Theia extension',
|
|
707
|
+
icon: 'sparkle',
|
|
708
|
+
steps: [
|
|
709
|
+
{ id: 'first', title: 'First', description: 'First step' },
|
|
710
|
+
{ id: 'second', title: 'Second', description: 'Second step' }
|
|
711
|
+
],
|
|
712
|
+
...overrides
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function provide(...definitions) {
|
|
716
|
+
mockWalkthroughProviders = [{ getWalkthroughs: () => definitions }];
|
|
717
|
+
}
|
|
718
|
+
it('should register the walkthroughs of a provider under their own id', () => {
|
|
719
|
+
provide(createDefinition());
|
|
720
|
+
service.syncWalkthroughs();
|
|
721
|
+
const walkthrough = service.getWalkthrough(providedId);
|
|
722
|
+
(0, chai_1.expect)(walkthrough).to.not.be.undefined;
|
|
723
|
+
(0, chai_1.expect)(walkthrough.title).to.equal('Provided Walkthrough');
|
|
724
|
+
(0, chai_1.expect)(walkthrough.icon).to.equal('sparkle');
|
|
725
|
+
(0, chai_1.expect)(walkthrough.pluginId).to.be.undefined;
|
|
726
|
+
(0, chai_1.expect)(walkthrough.steps.map(step => step.isComplete)).to.deep.equal([false, false]);
|
|
727
|
+
});
|
|
728
|
+
it('should keep plugin and provided walkthroughs alongside each other', () => {
|
|
729
|
+
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
730
|
+
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
731
|
+
provide(createDefinition());
|
|
732
|
+
service.syncWalkthroughs();
|
|
733
|
+
(0, chai_1.expect)(service.getWalkthroughs().map(walkthrough => walkthrough.id)).to.have.members([pluginWalkthroughId, providedId]);
|
|
734
|
+
});
|
|
735
|
+
it('should not drop a provided walkthrough when plugins change', async () => {
|
|
736
|
+
provide(createDefinition());
|
|
737
|
+
service.syncWalkthroughs();
|
|
738
|
+
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
739
|
+
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
740
|
+
await service.handlePluginsChanged();
|
|
741
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
742
|
+
});
|
|
743
|
+
it('should keep the progress of a re-synced, unchanged walkthrough', async () => {
|
|
744
|
+
provide(createDefinition());
|
|
745
|
+
service.syncWalkthroughs();
|
|
746
|
+
await service.markStepComplete(providedId, 'first');
|
|
747
|
+
service.syncWalkthroughs();
|
|
748
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId).steps[0].isComplete).to.be.true;
|
|
749
|
+
});
|
|
750
|
+
it('should re-register a walkthrough whose definition changed', () => {
|
|
751
|
+
provide(createDefinition());
|
|
752
|
+
service.syncWalkthroughs();
|
|
753
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId).steps).to.have.lengthOf(2);
|
|
754
|
+
provide(createDefinition({ steps: [{ id: 'only', title: 'Only', description: 'Only step' }] }));
|
|
755
|
+
service.syncWalkthroughs();
|
|
756
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId).steps).to.have.lengthOf(1);
|
|
757
|
+
});
|
|
758
|
+
it('should drop a walkthrough that is no longer provided', () => {
|
|
759
|
+
provide(createDefinition());
|
|
760
|
+
service.syncWalkthroughs();
|
|
761
|
+
provide();
|
|
762
|
+
service.syncWalkthroughs();
|
|
763
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId)).to.be.undefined;
|
|
764
|
+
});
|
|
765
|
+
it('should keep the other walkthroughs when a provider throws', () => {
|
|
766
|
+
mockWalkthroughProviders = [
|
|
767
|
+
{ getWalkthroughs: () => { throw new Error('provider is broken'); } },
|
|
768
|
+
{ getWalkthroughs: () => [createDefinition()] }
|
|
769
|
+
];
|
|
770
|
+
service.syncWalkthroughs();
|
|
771
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
772
|
+
});
|
|
773
|
+
it('should not reject the sync when a provider throws', async () => {
|
|
774
|
+
mockWalkthroughProviders = [{ getWalkthroughs: () => { throw new Error('provider is broken'); } }];
|
|
775
|
+
service.init();
|
|
776
|
+
// A rejected `progressReady` would stop every later sync, so it has to survive a failing provider.
|
|
777
|
+
await service.progressReady;
|
|
778
|
+
});
|
|
779
|
+
it('should ignore a walkthrough whose id is already taken', () => {
|
|
780
|
+
mockWalkthroughProviders = [
|
|
781
|
+
{ getWalkthroughs: () => [createDefinition({ title: 'First' })] },
|
|
782
|
+
{ getWalkthroughs: () => [createDefinition({ title: 'Second' })] }
|
|
783
|
+
];
|
|
784
|
+
service.syncWalkthroughs();
|
|
785
|
+
(0, chai_1.expect)(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
786
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId).title).to.equal('First');
|
|
787
|
+
});
|
|
788
|
+
it('should re-sync when a provider signals a change', async () => {
|
|
789
|
+
const onDidChangeEmitter = new event_1.Emitter();
|
|
790
|
+
let definitions = [];
|
|
791
|
+
mockWalkthroughProviders = [{
|
|
792
|
+
getWalkthroughs: () => definitions,
|
|
793
|
+
onDidChange: onDidChangeEmitter.event
|
|
794
|
+
}];
|
|
795
|
+
service.init();
|
|
796
|
+
await service.progressReady;
|
|
797
|
+
(0, chai_1.expect)(service.getWalkthroughs()).to.be.empty;
|
|
798
|
+
definitions = [createDefinition()];
|
|
799
|
+
onDidChangeEmitter.fire();
|
|
800
|
+
await service.progressReady;
|
|
801
|
+
(0, chai_1.expect)(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
802
|
+
onDidChangeEmitter.dispose();
|
|
803
|
+
});
|
|
804
|
+
});
|
|
689
805
|
describe('extensionInstalled completion event', () => {
|
|
690
806
|
const walkthroughContribution = createContribution({
|
|
691
807
|
steps: [
|
|
@@ -705,13 +821,13 @@ describe('WalkthroughService', () => {
|
|
|
705
821
|
});
|
|
706
822
|
}
|
|
707
823
|
beforeEach(() => {
|
|
708
|
-
// Set up the plugin so the walkthrough is discovered via
|
|
824
|
+
// Set up the plugin so the walkthrough is discovered via syncWalkthroughs
|
|
709
825
|
setupPluginWithWalkthrough();
|
|
710
|
-
service.
|
|
826
|
+
service.syncWalkthroughs();
|
|
711
827
|
// Wire up the onDidChangePlugins handler manually (simulating @postConstruct)
|
|
712
828
|
service.toDispose.push(service.pluginSupport.onDidChangePlugins(() => {
|
|
713
829
|
const previousIds = new Set(service.knownPluginIds);
|
|
714
|
-
service.
|
|
830
|
+
service.syncWalkthroughs();
|
|
715
831
|
const newIds = new Set(service.pluginSupport.plugins.map((p) => p.model.id));
|
|
716
832
|
for (const newId of newIds) {
|
|
717
833
|
if (!previousIds.has(newId)) {
|
|
@@ -764,7 +880,7 @@ describe('WalkthroughService', () => {
|
|
|
764
880
|
});
|
|
765
881
|
describe('onContext completion event', () => {
|
|
766
882
|
beforeEach(() => {
|
|
767
|
-
|
|
883
|
+
registerContribution(createContribution({
|
|
768
884
|
steps: [
|
|
769
885
|
{
|
|
770
886
|
id: 'context-step',
|
|
@@ -827,14 +943,14 @@ describe('WalkthroughService', () => {
|
|
|
827
943
|
describe('onContext expressions', () => {
|
|
828
944
|
it('should complete a step whose context expression already holds at registration', () => {
|
|
829
945
|
mockContextKeyMatchResult = true;
|
|
830
|
-
|
|
946
|
+
registerContribution(createContribution({
|
|
831
947
|
steps: [{ id: 'static', title: 'Static', description: 'd', completionEvents: ['onContext:isLinux'] }]
|
|
832
948
|
}));
|
|
833
949
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
834
950
|
(0, chai_1.expect)(service.getWalkthrough(wtId).steps[0].isComplete).to.be.true;
|
|
835
951
|
});
|
|
836
952
|
it('should react to a context expression rather than treating it as a single key', () => {
|
|
837
|
-
|
|
953
|
+
registerContribution(createContribution({
|
|
838
954
|
steps: [{ id: 'expr', title: 'Expression', description: 'd', completionEvents: ['onContext:foo && bar'] }]
|
|
839
955
|
}));
|
|
840
956
|
// The keys of the expression have to be recognised, not the expression string itself.
|
|
@@ -848,7 +964,7 @@ describe('WalkthroughService', () => {
|
|
|
848
964
|
});
|
|
849
965
|
describe('onView completion event', () => {
|
|
850
966
|
beforeEach(() => {
|
|
851
|
-
|
|
967
|
+
registerContribution(createContribution({
|
|
852
968
|
steps: [
|
|
853
969
|
{
|
|
854
970
|
id: 'view-step',
|
|
@@ -879,7 +995,7 @@ describe('WalkthroughService', () => {
|
|
|
879
995
|
});
|
|
880
996
|
it('should handle multiple onView completion events on different steps', async () => {
|
|
881
997
|
// Register a second walkthrough with a different view event
|
|
882
|
-
|
|
998
|
+
registerContribution(createContribution({
|
|
883
999
|
id: 'multi-view-walkthrough',
|
|
884
1000
|
steps: [
|
|
885
1001
|
{
|
|
@@ -911,7 +1027,7 @@ describe('WalkthroughService', () => {
|
|
|
911
1027
|
});
|
|
912
1028
|
describe('onLink completion event', () => {
|
|
913
1029
|
beforeEach(() => {
|
|
914
|
-
|
|
1030
|
+
registerContribution(createContribution({
|
|
915
1031
|
steps: [
|
|
916
1032
|
{
|
|
917
1033
|
id: 'link-step',
|
|
@@ -939,7 +1055,7 @@ describe('WalkthroughService', () => {
|
|
|
939
1055
|
(0, chai_1.expect)(mockOpenerOpenCalls).to.have.lengthOf(1);
|
|
940
1056
|
});
|
|
941
1057
|
it('should complete step with command: URI', async () => {
|
|
942
|
-
|
|
1058
|
+
registerContribution(createContribution({
|
|
943
1059
|
id: 'cmd-link-walkthrough',
|
|
944
1060
|
steps: [
|
|
945
1061
|
{
|
|
@@ -989,7 +1105,7 @@ describe('WalkthroughService', () => {
|
|
|
989
1105
|
// Wire up the onDidChangePlugins handler manually
|
|
990
1106
|
service.toDispose.push(service.pluginSupport.onDidChangePlugins(() => {
|
|
991
1107
|
const previousIds = new Set(service.knownPluginIds);
|
|
992
|
-
service.
|
|
1108
|
+
service.syncWalkthroughs();
|
|
993
1109
|
const newIds = new Set(service.pluginSupport.plugins.map((p) => p.model.id));
|
|
994
1110
|
for (const newId of newIds) {
|
|
995
1111
|
if (!previousIds.has(newId)) {
|