Skip to content

Commit ba67352

Browse files
test: unreliable ExtensionUserActivity test #3690
This fixes a flaky test due to the timeout delays not being properly spaced. Because of this the vscode Event Emitter would fire in the same throttle interval. This caused the throttled function to treat all calls to it to be in the same interval, such that it only triggered once. This fixes the delay of when the second set of event firing goes off so that those are triggered when we are in the next throttle interval, instead of the first. Signed-off-by: Nikolas Komonen <[email protected]>
1 parent fc38958 commit ba67352

File tree

1 file changed

+60
-52
lines changed

1 file changed

+60
-52
lines changed

src/test/shared/extensionUtilities.test.ts

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { FakeExtensionContext } from '../fakeExtensionContext'
2828
import { InstanceIdentity } from '../../shared/clients/ec2MetadataClient'
2929
import { extensionVersion } from '../../shared/vscode/env'
3030
import { sleep } from '../../shared/utilities/timeoutUtils'
31+
import globals from '../../shared/extensionGlobals'
3132

3233
describe('extensionUtilities', function () {
3334
describe('safeGet', function () {
@@ -205,102 +206,112 @@ describe('ExtensionUserActivity', function () {
205206
})
206207

207208
it('triggers twice when multiple user activities are fired in separate intervals', async function () {
208-
const throttleDelay = 2000
209-
const middleOfInterval = Math.floor(throttleDelay / 2)
210-
const waitFor = throttleDelay * 3 // delay * (2 event intervals + test buffer)
211-
212-
const eventsFirst = [
213-
delayedFiringEvent(middleOfInterval + 1),
214-
delayedFiringEvent(middleOfInterval + 2),
215-
delayedFiringEvent(middleOfInterval + 3),
216-
delayedFiringEvent(middleOfInterval + 4),
217-
]
218-
const eventsSecond = [
219-
delayedFiringEvent(throttleDelay + middleOfInterval + 1),
220-
delayedFiringEvent(throttleDelay + middleOfInterval + 2),
221-
delayedFiringEvent(throttleDelay + middleOfInterval + 2),
222-
delayedFiringEvent(throttleDelay + middleOfInterval + 3),
209+
const throttleDelay = 200
210+
211+
const firstInvervalMillisUntilFire = [51, 52, 53, 54]
212+
213+
const secondIntervalStart = firstInvervalMillisUntilFire[0] + throttleDelay + 1
214+
const secondIntervalMillisUntilFire = [
215+
secondIntervalStart + 10,
216+
secondIntervalStart + 11,
217+
secondIntervalStart + 11,
218+
secondIntervalStart + 12,
223219
]
224-
225-
const instance = new ExtensionUserActivity(throttleDelay, [...eventsFirst, ...eventsSecond])
220+
221+
const instance = new ExtensionUserActivity(throttleDelay, [
222+
...firstInvervalMillisUntilFire.map(delayedTriggeredEvent),
223+
...secondIntervalMillisUntilFire.map(delayedTriggeredEvent),
224+
])
226225
instance.onUserActivity(onEventTriggered)
227-
await sleep(waitFor)
226+
await sleep(secondIntervalStart + throttleDelay + 1)
228227

229-
assert.strictEqual(count, 2, 'This may be flaky in CI, so we may need to increase the intervals for better tolerance')
228+
assert.strictEqual(count, 2)
230229
})
231230

232-
describe('does not fire user activity events in specific scenarios', function() {
231+
describe('does not fire user activity events in specific scenarios', function () {
233232
let userActivitySubscriber: sinon.SinonStubbedMember<() => void>
234233
let _triggerUserActivity: (obj: any) => void
235234
let instance: ExtensionUserActivity
236235

237236
beforeEach(function () {
238237
userActivitySubscriber = sandbox.stub()
239-
_triggerUserActivity = () => { throw Error('Called before ExtensionUserActivity was instantiated')}
238+
_triggerUserActivity = () => {
239+
throw Error('Called before ExtensionUserActivity was instantiated')
240+
}
240241
})
241242

242243
afterEach(function () {
243244
instance.dispose()
244245
sandbox.restore()
245246
})
246247

247-
it('does not fire onDidChangeWindowState when not active', function() {
248+
it('does not fire onDidChangeWindowState when not active', function () {
248249
stubUserActivityEvent(vscode.window, 'onDidChangeWindowState')
249-
250+
250251
const triggerUserActivity = createTriggerActivityFunc()
251252

252-
triggerUserActivity({active: false})
253+
triggerUserActivity({ active: false })
253254
assert.strictEqual(userActivitySubscriber.callCount, 0)
254255

255-
triggerUserActivity({active: true})
256+
triggerUserActivity({ active: true })
256257
assert.strictEqual(userActivitySubscriber.callCount, 1)
257258
})
258259

259-
it('does not fire onDidChangeTextEditorSelection when editor is `Output` panel', function() {
260+
it('does not fire onDidChangeTextEditorSelection when editor is `Output` panel', function () {
260261
stubUserActivityEvent(vscode.window, 'onDidChangeTextEditorSelection')
261-
262+
262263
const triggerUserActivity = createTriggerActivityFunc()
263264

264-
triggerUserActivity({textEditor: {document: {uri: {scheme: 'output'}}}})
265+
triggerUserActivity({ textEditor: { document: { uri: { scheme: 'output' } } } })
265266
assert.strictEqual(userActivitySubscriber.callCount, 0)
266267

267-
triggerUserActivity({textEditor: {document: {uri: {scheme: 'NOToutput'}}}})
268+
triggerUserActivity({ textEditor: { document: { uri: { scheme: 'NOToutput' } } } })
268269
assert.strictEqual(userActivitySubscriber.callCount, 1)
269270
})
270271

271-
it('does not fire onDidChangeTextEditorVisibleRanges when when editor is `Output` panel', function() {
272+
it('does not fire onDidChangeTextEditorVisibleRanges when when editor is `Output` panel', function () {
272273
stubUserActivityEvent(vscode.window, 'onDidChangeTextEditorVisibleRanges')
273-
274+
274275
const triggerUserActivity = createTriggerActivityFunc()
275276

276-
triggerUserActivity({textEditor: {document: {uri: {scheme: 'output'}}}})
277+
triggerUserActivity({ textEditor: { document: { uri: { scheme: 'output' } } } })
277278
assert.strictEqual(userActivitySubscriber.callCount, 0)
278279

279-
triggerUserActivity({textEditor: {document: {uri: {scheme: 'NOToutput'}}}})
280+
triggerUserActivity({ textEditor: { document: { uri: { scheme: 'NOToutput' } } } })
280281
assert.strictEqual(userActivitySubscriber.callCount, 1)
281282
})
282283

283-
it('does not fire onDidChangeTextDocument when not the active user document', function() {
284+
it('does not fire onDidChangeTextDocument when not the active user document', function () {
284285
stubUserActivityEvent(vscode.workspace, 'onDidChangeTextDocument')
285286
const activeEditorStub = sandbox.stub(vscode.window, 'activeTextEditor')
286-
287+
287288
const triggerUserActivity = createTriggerActivityFunc()
288289

289290
activeEditorStub.get(() => undefined)
290291
triggerUserActivity({})
291292
assert.strictEqual(userActivitySubscriber.callCount, 0, 'Was not ignored when no active editor')
292293

293-
activeEditorStub.get(() => {return {document: {uri: 'myUri'}}})
294-
triggerUserActivity({document: {uri: 'myOtherUri'}})
295-
assert.strictEqual(userActivitySubscriber.callCount, 0, 'Was not ignored when active editor document was different from the event')
294+
activeEditorStub.get(() => {
295+
return { document: { uri: 'myUri' } }
296+
})
297+
triggerUserActivity({ document: { uri: 'myOtherUri' } })
298+
assert.strictEqual(
299+
userActivitySubscriber.callCount,
300+
0,
301+
'Was not ignored when active editor document was different from the event'
302+
)
296303

297-
triggerUserActivity({document: {uri: 'myUri'}})
298-
assert.strictEqual(userActivitySubscriber.callCount, 1, 'Was ignored when the active editor document was the same as the event')
304+
triggerUserActivity({ document: { uri: 'myUri' } })
305+
assert.strictEqual(
306+
userActivitySubscriber.callCount,
307+
1,
308+
'Was ignored when the active editor document was the same as the event'
309+
)
299310
})
300311

301312
it('fires for onDidChangeActiveColorTheme (sanity check)', function () {
302313
stubUserActivityEvent(vscode.window, 'onDidChangeActiveColorTheme')
303-
314+
304315
const triggerUserActivity = createTriggerActivityFunc()
305316

306317
triggerUserActivity({})
@@ -309,23 +320,20 @@ describe('ExtensionUserActivity', function () {
309320

310321
/**
311322
* Helper to stub a vscode event object.
312-
*
323+
*
313324
* Once stubbed, you can call {@link _triggerUserActivity} to fire
314325
* the event.
315326
*/
316-
function stubUserActivityEvent<T, K extends keyof T>(vscodeObj: T, eventName: K){
317-
const eventStub = sandbox.stub(
318-
vscodeObj,
319-
eventName
320-
)
321-
327+
function stubUserActivityEvent<T, K extends keyof T>(vscodeObj: T, eventName: K) {
328+
const eventStub = sandbox.stub(vscodeObj, eventName)
329+
322330
eventStub.callsFake((callback: any) => {
323331
_triggerUserActivity = callback
324332
return {
325-
dispose: sandbox.stub()
333+
dispose: sandbox.stub(),
326334
}
327335
})
328-
336+
329337
return eventStub
330338
}
331339

@@ -339,9 +347,9 @@ describe('ExtensionUserActivity', function () {
339347
}
340348
})
341349

342-
function delayedFiringEvent(fireInMillis: number): vscode.Event<any> {
350+
function delayedTriggeredEvent(millisUntilFire: number): vscode.Event<any> {
343351
const event = new vscode.EventEmitter<void>()
344-
setTimeout(() => event.fire(), fireInMillis)
352+
globals.clock.setTimeout(() => event.fire(), millisUntilFire)
345353
return event.event
346354
}
347355
})

0 commit comments

Comments
 (0)