Skip to content

Commit bc17eca

Browse files
author
Kartik Raj
authored
Populate survey links with variables (microsoft#8802)
* Populate survey links with variables * Use node's querystring module Co-Authored-By: Eric Snow <ericsnowcurrently@gmail.com> * Mock vscode version out
1 parent 817199b commit bc17eca

File tree

5 files changed

+86
-11
lines changed

5 files changed

+86
-11
lines changed

news/1 Enhancements/8484.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Populate survey links with variables

src/client/activation/extensionSurvey.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
'use strict';
55

66
import { inject, injectable, optional } from 'inversify';
7-
import { IApplicationShell } from '../common/application/types';
7+
import * as querystring from 'querystring';
8+
import { IApplicationEnvironment, IApplicationShell } from '../common/application/types';
89
import { ShowExtensionSurveyPrompt } from '../common/experimentGroups';
910
import '../common/extensions';
1011
import { traceDecorators } from '../common/logger';
12+
import { IPlatformService } from '../common/platform/types';
1113
import {
1214
IBrowserService, IExperimentsManager, IPersistentStateFactory, IRandom
1315
} from '../common/types';
@@ -33,6 +35,8 @@ export class ExtensionSurveyPrompt implements IExtensionSingleActivationService
3335
@inject(IPersistentStateFactory) private persistentState: IPersistentStateFactory,
3436
@inject(IRandom) private random: IRandom,
3537
@inject(IExperimentsManager) private experiments: IExperimentsManager,
38+
@inject(IApplicationEnvironment) private appEnvironment: IApplicationEnvironment,
39+
@inject(IPlatformService) private platformService: IPlatformService,
3640
@optional() private sampleSizePerOneHundredUsers: number = 10,
3741
@optional() private waitTimeToShowSurvey: number = WAIT_TIME_TO_SHOW_SURVEY) { }
3842

@@ -86,6 +90,13 @@ export class ExtensionSurveyPrompt implements IExtensionSingleActivationService
8690
}
8791

8892
private launchSurvey() {
89-
this.browserService.launch('https://aka.ms/AA5rjx5');
93+
const query = querystring.stringify({
94+
o: encodeURIComponent(this.platformService.osType), // platform
95+
v: encodeURIComponent(this.appEnvironment.vscodeVersion),
96+
e: encodeURIComponent(this.appEnvironment.packageJson.version), // extension version
97+
m: encodeURIComponent(this.appEnvironment.machineId)
98+
});
99+
const url = `https://aka.ms/AA5rjx5?${query}`;
100+
this.browserService.launch(url);
90101
}
91102
}

src/client/common/application/applicationEnvironment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export class ApplicationEnvironment implements IApplicationEnvironment {
3434
public get appName(): string {
3535
return vscode.env.appName;
3636
}
37+
public get vscodeVersion(): string {
38+
return vscode.version;
39+
}
3740
public get appRoot(): string {
3841
return vscode.env.appRoot;
3942
}

src/client/common/application/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,10 @@ export interface IApplicationEnvironment {
903903
* @memberof IApplicationShell
904904
*/
905905
readonly extensionChannel: Channel;
906+
/**
907+
* The version of the editor.
908+
*/
909+
readonly vscodeVersion: string;
906910
}
907911

908912
export const IWebPanelMessageListener = Symbol('IWebPanelMessageListener');

src/test/activation/extensionSurvey.unit.test.ts

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import * as sinon from 'sinon';
88
import { anything, instance, mock, verify, when } from 'ts-mockito';
99
import * as TypeMoq from 'typemoq';
1010
import { ExtensionSurveyPrompt, extensionSurveyStateKeys } from '../../client/activation/extensionSurvey';
11-
import { IApplicationShell } from '../../client/common/application/types';
11+
import { IApplicationEnvironment, IApplicationShell } from '../../client/common/application/types';
1212
import { ShowExtensionSurveyPrompt } from '../../client/common/experimentGroups';
1313
import { PersistentStateFactory } from '../../client/common/persistentState';
14+
import { IPlatformService } from '../../client/common/platform/types';
1415
import { IBrowserService, IExperimentsManager, IPersistentState, IPersistentStateFactory, IRandom } from '../../client/common/types';
1516
import { createDeferred } from '../../client/common/utils/async';
1617
import { Common, ExtensionSurveyBanner, LanguageService } from '../../client/common/utils/localize';
18+
import { OSType } from '../../client/common/utils/platform';
1719
import { sleep } from '../core';
1820

1921
// tslint:disable:no-any
@@ -25,6 +27,8 @@ suite('Extension survey prompt - shouldShowBanner()', () => {
2527
let random: TypeMoq.IMock<IRandom>;
2628
let persistentStateFactory: IPersistentStateFactory;
2729
let experiments: TypeMoq.IMock<IExperimentsManager>;
30+
let platformService: TypeMoq.IMock<IPlatformService>;
31+
let appEnvironment: TypeMoq.IMock<IApplicationEnvironment>;
2832
let disableSurveyForTime: TypeMoq.IMock<IPersistentState<any>>;
2933
let doNotShowAgain: TypeMoq.IMock<IPersistentState<any>>;
3034
let extensionSurveyPrompt: ExtensionSurveyPrompt;
@@ -36,9 +40,11 @@ suite('Extension survey prompt - shouldShowBanner()', () => {
3640
persistentStateFactory = mock(PersistentStateFactory);
3741
disableSurveyForTime = TypeMoq.Mock.ofType<IPersistentState<any>>();
3842
doNotShowAgain = TypeMoq.Mock.ofType<IPersistentState<any>>();
43+
platformService = TypeMoq.Mock.ofType<IPlatformService>();
44+
appEnvironment = TypeMoq.Mock.ofType<IApplicationEnvironment>();
3945
when(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).thenReturn(disableSurveyForTime.object);
4046
when(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).thenReturn(doNotShowAgain.object);
41-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 10);
47+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 10);
4248
});
4349
test('Returns false if do not show again is clicked', async () => {
4450
random
@@ -110,7 +116,7 @@ suite('Extension survey prompt - shouldShowBanner()', () => {
110116
});
111117

112118
test('Always return true if sample size is 100', async () => {
113-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 100);
119+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 100);
114120
disableSurveyForTime
115121
.setup(d => d.value)
116122
.returns(() => false);
@@ -127,7 +133,7 @@ suite('Extension survey prompt - shouldShowBanner()', () => {
127133
});
128134

129135
test('Always return false if sample size is 0', async () => {
130-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 0);
136+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 0);
131137
disableSurveyForTime
132138
.setup(d => d.value)
133139
.returns(() => false);
@@ -154,6 +160,8 @@ suite('Extension survey prompt - showSurvey()', () => {
154160
let persistentStateFactory: IPersistentStateFactory;
155161
let disableSurveyForTime: TypeMoq.IMock<IPersistentState<any>>;
156162
let doNotShowAgain: TypeMoq.IMock<IPersistentState<any>>;
163+
let platformService: TypeMoq.IMock<IPlatformService>;
164+
let appEnvironment: TypeMoq.IMock<IApplicationEnvironment>;
157165
let extensionSurveyPrompt: ExtensionSurveyPrompt;
158166
setup(() => {
159167
appShell = TypeMoq.Mock.ofType<IApplicationShell>();
@@ -162,20 +170,42 @@ suite('Extension survey prompt - showSurvey()', () => {
162170
persistentStateFactory = mock(PersistentStateFactory);
163171
disableSurveyForTime = TypeMoq.Mock.ofType<IPersistentState<any>>();
164172
doNotShowAgain = TypeMoq.Mock.ofType<IPersistentState<any>>();
173+
platformService = TypeMoq.Mock.ofType<IPlatformService>();
174+
appEnvironment = TypeMoq.Mock.ofType<IApplicationEnvironment>();
165175
when(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).thenReturn(disableSurveyForTime.object);
166176
when(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).thenReturn(doNotShowAgain.object);
167177
experiments = TypeMoq.Mock.ofType<IExperimentsManager>();
168-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 10);
178+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 10);
169179
});
170180

171181
test('Launch survey if \'Yes\' option is clicked', async () => {
182+
const packageJson = {
183+
version: 'extensionVersion'
184+
};
172185
const prompts = [LanguageService.bannerLabelYes(), ExtensionSurveyBanner.maybeLater(), Common.doNotShowAgain()];
186+
const expectedUrl = `https://aka.ms/AA5rjx5?o=Windows&v=vscodeVersion&e=extensionVersion&m=machineId`;
187+
appEnvironment
188+
.setup(a => a.packageJson)
189+
.returns(() => packageJson)
190+
.verifiable(TypeMoq.Times.once());
191+
appEnvironment
192+
.setup(a => a.vscodeVersion)
193+
.returns(() => 'vscodeVersion')
194+
.verifiable(TypeMoq.Times.once());
195+
appEnvironment
196+
.setup(a => a.machineId)
197+
.returns(() => 'machineId')
198+
.verifiable(TypeMoq.Times.once());
199+
platformService
200+
.setup(a => a.osType)
201+
.returns(() => OSType.Windows)
202+
.verifiable(TypeMoq.Times.once());
173203
appShell
174204
.setup(a => a.showInformationMessage(ExtensionSurveyBanner.bannerMessage(), ...prompts))
175205
.returns(() => Promise.resolve(LanguageService.bannerLabelYes()))
176206
.verifiable(TypeMoq.Times.once());
177207
browserService
178-
.setup(s => s.launch(TypeMoq.It.isAny()))
208+
.setup(s => s.launch(expectedUrl))
179209
.returns(() => Promise.resolve())
180210
.verifiable(TypeMoq.Times.once());
181211
disableSurveyForTime
@@ -186,17 +216,24 @@ suite('Extension survey prompt - showSurvey()', () => {
186216
.setup(d => d.updateValue(true))
187217
.returns(() => Promise.resolve())
188218
.verifiable(TypeMoq.Times.never());
219+
189220
await extensionSurveyPrompt.showSurvey();
221+
190222
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).once();
191223
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).never();
192224
appShell.verifyAll();
193225
browserService.verifyAll();
194226
disableSurveyForTime.verifyAll();
195227
doNotShowAgain.verifyAll();
228+
appEnvironment.verifyAll();
229+
platformService.verifyAll();
196230
});
197231

198232
test('Do nothing if \'Maybe later\' option is clicked', async () => {
199233
const prompts = [LanguageService.bannerLabelYes(), ExtensionSurveyBanner.maybeLater(), Common.doNotShowAgain()];
234+
platformService
235+
.setup(p => p.osType)
236+
.verifiable(TypeMoq.Times.never());
200237
appShell
201238
.setup(a => a.showInformationMessage(ExtensionSurveyBanner.bannerMessage(), ...prompts))
202239
.returns(() => Promise.resolve(ExtensionSurveyBanner.maybeLater()))
@@ -213,17 +250,23 @@ suite('Extension survey prompt - showSurvey()', () => {
213250
.setup(d => d.updateValue(true))
214251
.returns(() => Promise.resolve())
215252
.verifiable(TypeMoq.Times.never());
253+
216254
await extensionSurveyPrompt.showSurvey();
255+
217256
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).never();
218257
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).never();
219258
appShell.verifyAll();
220259
browserService.verifyAll();
221260
disableSurveyForTime.verifyAll();
222261
doNotShowAgain.verifyAll();
262+
platformService.verifyAll();
223263
});
224264

225265
test('Do nothing if no option is clicked', async () => {
226266
const prompts = [LanguageService.bannerLabelYes(), ExtensionSurveyBanner.maybeLater(), Common.doNotShowAgain()];
267+
platformService
268+
.setup(p => p.osType)
269+
.verifiable(TypeMoq.Times.never());
227270
appShell
228271
.setup(a => a.showInformationMessage(ExtensionSurveyBanner.bannerMessage(), ...prompts))
229272
.returns(() => Promise.resolve(undefined))
@@ -240,17 +283,23 @@ suite('Extension survey prompt - showSurvey()', () => {
240283
.setup(d => d.updateValue(true))
241284
.returns(() => Promise.resolve())
242285
.verifiable(TypeMoq.Times.never());
286+
243287
await extensionSurveyPrompt.showSurvey();
288+
244289
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).never();
245290
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).never();
246291
appShell.verifyAll();
247292
browserService.verifyAll();
248293
disableSurveyForTime.verifyAll();
249294
doNotShowAgain.verifyAll();
295+
platformService.verifyAll();
250296
});
251297

252298
test('Disable prompt if \'Do not show again\' option is clicked', async () => {
253299
const prompts = [LanguageService.bannerLabelYes(), ExtensionSurveyBanner.maybeLater(), Common.doNotShowAgain()];
300+
platformService
301+
.setup(p => p.osType)
302+
.verifiable(TypeMoq.Times.never());
254303
appShell
255304
.setup(a => a.showInformationMessage(ExtensionSurveyBanner.bannerMessage(), ...prompts))
256305
.returns(() => Promise.resolve(Common.doNotShowAgain()))
@@ -267,13 +316,16 @@ suite('Extension survey prompt - showSurvey()', () => {
267316
.setup(d => d.updateValue(true))
268317
.returns(() => Promise.resolve())
269318
.verifiable(TypeMoq.Times.once());
319+
270320
await extensionSurveyPrompt.showSurvey();
321+
271322
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.disableSurveyForTime, false, anything())).never();
272323
verify(persistentStateFactory.createGlobalPersistentState(extensionSurveyStateKeys.doNotShowAgain, false)).once();
273324
appShell.verifyAll();
274325
browserService.verifyAll();
275326
disableSurveyForTime.verifyAll();
276327
doNotShowAgain.verifyAll();
328+
platformService.verifyAll();
277329
});
278330
});
279331

@@ -287,12 +339,16 @@ suite('Extension survey prompt - activate()', () => {
287339
let showSurvey: sinon.SinonStub<any>;
288340
let experiments: TypeMoq.IMock<IExperimentsManager>;
289341
let extensionSurveyPrompt: ExtensionSurveyPrompt;
342+
let platformService: TypeMoq.IMock<IPlatformService>;
343+
let appEnvironment: TypeMoq.IMock<IApplicationEnvironment>;
290344
setup(() => {
291345
appShell = TypeMoq.Mock.ofType<IApplicationShell>();
292346
browserService = TypeMoq.Mock.ofType<IBrowserService>();
293347
random = TypeMoq.Mock.ofType<IRandom>();
294348
persistentStateFactory = mock(PersistentStateFactory);
295349
experiments = TypeMoq.Mock.ofType<IExperimentsManager>();
350+
platformService = TypeMoq.Mock.ofType<IPlatformService>();
351+
appEnvironment = TypeMoq.Mock.ofType<IApplicationEnvironment>();
296352
});
297353

298354
teardown(() => {
@@ -303,7 +359,7 @@ suite('Extension survey prompt - activate()', () => {
303359
shouldShowBanner = sinon.stub(ExtensionSurveyPrompt.prototype, 'shouldShowBanner');
304360
shouldShowBanner.callsFake(() => false);
305361
showSurvey = sinon.stub(ExtensionSurveyPrompt.prototype, 'showSurvey');
306-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 10);
362+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 10);
307363
experiments
308364
.setup(exp => exp.inExperiment(ShowExtensionSurveyPrompt.enabled))
309365
.returns(() => false)
@@ -327,7 +383,7 @@ suite('Extension survey prompt - activate()', () => {
327383
return Promise.resolve();
328384
});
329385
// waitTimeToShowSurvey = 50 ms
330-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 10, 50);
386+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 10, 50);
331387
experiments
332388
.setup(exp => exp.inExperiment(ShowExtensionSurveyPrompt.enabled))
333389
.returns(() => true)
@@ -355,7 +411,7 @@ suite('Extension survey prompt - activate()', () => {
355411
return Promise.resolve();
356412
});
357413
// waitTimeToShowSurvey = 50 ms
358-
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, 10, 50);
414+
extensionSurveyPrompt = new ExtensionSurveyPrompt(appShell.object, browserService.object, instance(persistentStateFactory), random.object, experiments.object, appEnvironment.object, platformService.object, 10, 50);
359415
experiments
360416
.setup(exp => exp.inExperiment(ShowExtensionSurveyPrompt.enabled))
361417
.returns(() => true)

0 commit comments

Comments
 (0)