Skip to content

Commit a9c743e

Browse files
committed
test(notifications): fix and improve
- Fix async tests broken by recent commits. - Add setContext and telemetry verification
1 parent 860b441 commit a9c743e

File tree

4 files changed

+47
-37
lines changed

4 files changed

+47
-37
lines changed

packages/core/src/notifications/controller.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,22 @@ import { telemetry } from '../shared/telemetry/telemetry'
4040
export class NotificationsController {
4141
public static readonly suggestedPollIntervalMs = 1000 * 60 * 10 // 10 minutes
4242

43-
public readonly storageKey: globalKey
44-
4543
/** Internal memory state that is written to global state upon modification. */
4644
private readonly state: NotificationsState
4745

4846
static #instance: NotificationsController | undefined
4947

5048
constructor(
5149
private readonly notificationsNode: NotificationsNode,
52-
private readonly fetcher: NotificationFetcher = new RemoteFetcher()
50+
private readonly fetcher: NotificationFetcher = new RemoteFetcher(),
51+
public readonly storageKey: globalKey = 'aws.notifications'
5352
) {
5453
if (!NotificationsController.#instance) {
5554
// Register on first creation only.
5655
registerDismissCommand()
5756
}
5857
NotificationsController.#instance = this
5958

60-
this.storageKey = 'aws.notifications'
6159
this.state = globals.globalState.tryGet<NotificationsState>(this.storageKey, NotificationsStateConstructor, {
6260
startUp: {},
6361
emergency: {},

packages/core/src/notifications/panelNode.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,24 +78,23 @@ export class NotificationsNode implements TreeNode {
7878
}
7979

8080
public refresh(): void {
81-
if (!this.view) {
82-
throw new ToolkitError('NotificationsNode: TreeView accessed without being registered.')
83-
}
84-
8581
const totalNotifications = this.notificationCount()
86-
if (totalNotifications > 0) {
87-
this.view.badge = {
88-
tooltip: `${totalNotifications} notification${totalNotifications > 1 ? 's' : ''}`,
89-
value: totalNotifications,
82+
if (this.view) {
83+
if (totalNotifications > 0) {
84+
this.view.badge = {
85+
tooltip: `${totalNotifications} notification${totalNotifications > 1 ? 's' : ''}`,
86+
value: totalNotifications,
87+
}
88+
this.view.title = `${NotificationsNode.title} (${totalNotifications})`
89+
} else {
90+
this.view.badge = undefined
91+
this.view.title = NotificationsNode.title
9092
}
91-
this.view.title = `${NotificationsNode.title} (${totalNotifications})`
92-
void setContext(this.showContextStr, true)
9393
} else {
94-
this.view.badge = undefined
95-
this.view.title = NotificationsNode.title
96-
void setContext(this.showContextStr, false)
94+
logger.warn('NotificationsNode was refreshed but the view was not initialized!')
9795
}
9896

97+
void setContext(this.showContextStr, totalNotifications > 0)
9998
this.provider?.refresh()
10099
}
101100

@@ -240,7 +239,7 @@ export class NotificationsNode implements TreeNode {
240239
case 'updateAndReload':
241240
// Give things time to finish executing.
242241
globals.clock.setTimeout(() => {
243-
void this.updateAndReload(notification.displayIf.extensionId)
242+
return this.updateAndReload(notification.displayIf.extensionId)
244243
}, 1000)
245244
break
246245
case 'openUrl':

packages/core/src/test/notifications/controller.test.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import assert from 'assert'
99
import sinon from 'sinon'
1010
import globals from '../../shared/extensionGlobals'
1111
import { randomUUID } from '../../shared'
12+
import * as setContext from '../../shared/vscode/setContext'
1213
import { assertTelemetry, installFakeClock } from '../testUtil'
1314
import {
1415
NotificationFetcher,
@@ -45,8 +46,9 @@ describe('Notifications Controller', function () {
4546
let controller: NotificationsController
4647
let fetcher: TestFetcher
4748

48-
let ruleEngineSpy: sinon.SinonSpy
49-
let focusPanelSpy: sinon.SinonSpy
49+
const ruleEngineSpy = sinon.spy(ruleEngine, 'shouldDisplayNotification')
50+
const focusPanelSpy = sinon.spy(panelNode, 'focusPanel')
51+
const setContextSpy = sinon.spy(setContext, 'setContext')
5052

5153
function dismissNotification(notification: ToolkitNotification) {
5254
// We could call `controller.dismissNotification()`, but this emulates a call
@@ -89,10 +91,7 @@ describe('Notifications Controller', function () {
8991
beforeEach(async function () {
9092
panelNode.setNotifications([], [])
9193
fetcher = new TestFetcher()
92-
controller = new NotificationsController(panelNode, fetcher)
93-
94-
ruleEngineSpy = sinon.spy(ruleEngine, 'shouldDisplayNotification')
95-
focusPanelSpy = sinon.spy(panelNode, 'focusPanel')
94+
controller = new NotificationsController(panelNode, fetcher, '_aws.test.notification' as any)
9695

9796
await globals.globalState.update(controller.storageKey, {
9897
startUp: {} as NotificationData,
@@ -102,8 +101,14 @@ describe('Notifications Controller', function () {
102101
})
103102

104103
afterEach(function () {
105-
ruleEngineSpy.restore()
104+
ruleEngineSpy.resetHistory()
105+
focusPanelSpy.resetHistory()
106+
setContextSpy.resetHistory()
107+
})
108+
109+
after(function () {
106110
focusPanelSpy.restore()
111+
setContextSpy.restore()
107112
})
108113

109114
it('can fetch and store startup notifications', async function () {
@@ -135,6 +140,7 @@ describe('Notifications Controller', function () {
135140
assert.deepStrictEqual(panelNode.startUpNotifications, [content.notifications[0]])
136141
assert.equal(panelNode.getChildren().length, 1)
137142
assert.equal(focusPanelSpy.callCount, 0)
143+
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
138144
})
139145

140146
it('can fetch and store emergency notifications', async function () {
@@ -166,6 +172,7 @@ describe('Notifications Controller', function () {
166172
assert.deepStrictEqual(panelNode.emergencyNotifications, [content.notifications[0]])
167173
assert.equal(panelNode.getChildren().length, 1)
168174
assert.equal(focusPanelSpy.callCount, 1)
175+
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
169176
})
170177

171178
it('can fetch and store both startup and emergency notifications', async function () {
@@ -224,6 +231,7 @@ describe('Notifications Controller', function () {
224231
assert.deepStrictEqual(panelNode.emergencyNotifications, [emergencyContent.notifications[0]])
225232
assert.equal(panelNode.getChildren().length, 2)
226233
assert.equal(focusPanelSpy.callCount, 1)
234+
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
227235
})
228236

229237
it('dismisses a startup notification', async function () {
@@ -241,6 +249,7 @@ describe('Notifications Controller', function () {
241249

242250
assert.equal(panelNode.getChildren().length, 2)
243251
assert.equal(panelNode.startUpNotifications.length, 2)
252+
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
244253

245254
assert.deepStrictEqual(await globals.globalState.get(controller.storageKey), {
246255
startUp: {
@@ -281,9 +290,11 @@ describe('Notifications Controller', function () {
281290

282291
await controller.pollForStartUp(ruleEngine)
283292
assert.equal(panelNode.getChildren().length, 1)
293+
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
284294

285295
await dismissNotification(content.notifications[0])
286296
assert.equal(panelNode.getChildren().length, 0)
297+
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', false])
287298

288299
content.notifications.push(getValidTestNotification('id:startup2'))
289300
fetcher.setStartUpContent({
@@ -305,6 +316,7 @@ describe('Notifications Controller', function () {
305316
})
306317

307318
assert.equal(panelNode.getChildren().length, 1)
319+
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
308320
})
309321

310322
it('does not refocus emergency notifications', async function () {
@@ -434,6 +446,7 @@ describe('Notifications Controller', function () {
434446
newlyReceived: [],
435447
})
436448
assert.equal(panelNode.getChildren().length, 1)
449+
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
437450

438451
fetcher.setEmergencyContent({
439452
eTag: '1',
@@ -455,6 +468,7 @@ describe('Notifications Controller', function () {
455468
})
456469

457470
assert.equal(panelNode.getChildren().length, 0)
471+
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', false])
458472
})
459473

460474
it('does not rethrow errors when fetching', async function () {

packages/core/src/test/notifications/rendering.test.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,20 @@ import { panelNode } from './controller.test'
1212
import { getTestWindow } from '../shared/vscode/window'
1313
import * as VsCodeUtils from '../../shared/utilities/vsCodeUtils'
1414
import { assertTextEditorContains, installFakeClock } from '../testUtil'
15+
import { waitUntil } from '../../shared/utilities/timeoutUtils'
16+
import globals from '../../shared/extensionGlobals'
1517

1618
describe('Notifications Rendering', function () {
1719
let sandbox: sinon.SinonSandbox
18-
let clock: FakeTimers.InstalledClock
19-
20-
before(function () {
21-
clock = installFakeClock()
22-
})
2320

2421
beforeEach(function () {
2522
sandbox = sinon.createSandbox()
2623
})
2724

2825
afterEach(function () {
29-
clock.reset()
3026
sandbox.restore()
3127
})
3228

33-
after(function () {
34-
clock.uninstall()
35-
})
36-
3729
// util to test txt pop-up under different senarios
3830
async function verifyTxtNotification(notification: ToolkitNotification) {
3931
const expectedContent = notification.uiRenderInstructions.content['en-US'].description
@@ -103,14 +95,21 @@ describe('Notifications Rendering', function () {
10395
message.selectItem('Update and Reload')
10496
})
10597
const excuteCommandStub = sandbox.stub(vscode.commands, 'executeCommand').resolves()
98+
const telemetrySpy = sandbox.spy(globals.telemetry, 'flushRecords')
10699
const notification = getModalNotification()
107-
await panelNode.openNotification(notification)
108100

109101
// Update and Reload is put on a timer so that other methods (e.g. telemetry) can finish.
110-
await clock.tickAsync(2000)
102+
const clock: FakeTimers.InstalledClock = installFakeClock()
103+
await panelNode.openNotification(notification)
104+
105+
await clock.tickAsync(1000)
106+
clock.uninstall()
107+
108+
await waitUntil(async () => excuteCommandStub.called, { interval: 5, timeout: 5000 })
111109

112110
assert.ok(excuteCommandStub.calledWith('workbench.extensions.installExtension', 'aws.toolkit.fake.extension'))
113111
assert.ok(excuteCommandStub.calledWith('workbench.action.reloadWindow'))
112+
assert.ok(telemetrySpy.calledOnce)
114113
})
115114

116115
it('executes openURL type button', async function () {

0 commit comments

Comments
 (0)