Skip to content

Commit 27dad6e

Browse files
committed
feat(context): add getContext, update notifications tests
Add counterpart to setContext wrapper.
1 parent 29dd9c2 commit 27dad6e

File tree

4 files changed

+35
-49
lines changed

4 files changed

+35
-49
lines changed

packages/core/src/notifications/controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class NotificationsController {
9292
ruleEngine.shouldDisplayNotification(n)
9393
)
9494

95-
NotificationsNode.instance.setNotifications(startUp, emergency)
95+
await NotificationsNode.instance.setNotifications(startUp, emergency)
9696

9797
// Emergency notifications can't be dismissed, but if the user minimizes the panel then
9898
// we don't want to focus it each time we set the notification nodes.
@@ -126,7 +126,7 @@ export class NotificationsController {
126126
this.state.dismissed.push(notificationId)
127127
await this.writeState()
128128

129-
NotificationsNode.instance.dismissStartUpNotification(notificationId)
129+
await NotificationsNode.instance.dismissStartUpNotification(notificationId)
130130
}
131131

132132
/**

packages/core/src/notifications/panelNode.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class NotificationsNode implements TreeNode {
7777
return item
7878
}
7979

80-
public refresh(): void {
80+
public refresh() {
8181
const totalNotifications = this.notificationCount()
8282
if (this.view) {
8383
if (totalNotifications > 0) {
@@ -94,8 +94,8 @@ export class NotificationsNode implements TreeNode {
9494
logger.warn('NotificationsNode was refreshed but the view was not initialized!')
9595
}
9696

97-
void setContext(this.showContextStr, totalNotifications > 0)
9897
this.provider?.refresh()
98+
return setContext(this.showContextStr, totalNotifications > 0)
9999
}
100100

101101
public getChildren() {
@@ -126,10 +126,10 @@ export class NotificationsNode implements TreeNode {
126126
* Sets the current list of notifications. Nodes are generated for each notification.
127127
* No other processing is done, see NotificationController.
128128
*/
129-
public setNotifications(startUp: ToolkitNotification[], emergency: ToolkitNotification[]) {
129+
public async setNotifications(startUp: ToolkitNotification[], emergency: ToolkitNotification[]) {
130130
this.startUpNotifications = startUp
131131
this.emergencyNotifications = emergency
132-
this.refresh()
132+
await this.refresh()
133133
}
134134

135135
/**
@@ -138,9 +138,9 @@ export class NotificationsNode implements TreeNode {
138138
*
139139
* Only dismisses startup notifications.
140140
*/
141-
public dismissStartUpNotification(id: string) {
141+
public async dismissStartUpNotification(id: string) {
142142
this.startUpNotifications = this.startUpNotifications.filter((n) => n.id !== id)
143-
this.refresh()
143+
await this.refresh()
144144
}
145145

146146
/**

packages/core/src/shared/vscode/setContext.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,34 @@ export type contextKey =
3636
| 'amazonq.inline.codelensShortcutEnabled'
3737
| 'aws.toolkit.lambda.walkthroughSelected'
3838

39+
const contextMap: Partial<Record<contextKey, any>> = {}
40+
3941
/**
4042
* Calls the vscode "setContext" command.
4143
*
4244
* This wrapper adds structure and traceability to the vscode "setContext". It also opens the door
43-
* for:
44-
* - validation
45-
* - getContext() (see also https://github.com/microsoft/vscode/issues/10471)
45+
* for validation.
4646
*
4747
* Use "setContext" only as a last resort, to set flags that are detectable in package.json
4848
* declarations. Do not use it as a general way to store global state (which should be avoided
4949
* anyway).
5050
*
5151
* Warning: vscode context keys/values are NOT isolated to individual extensions. Other extensions
52-
* can read and modify them.
52+
* can read and modify them. See also https://github.com/microsoft/vscode/issues/10471
5353
*/
5454
export async function setContext(key: contextKey, val: any): Promise<void> {
5555
// eslint-disable-next-line aws-toolkits/no-banned-usages
5656
await vscode.commands.executeCommand('setContext', key, val)
57+
contextMap[key] = val
58+
}
59+
60+
/**
61+
* Returns the value of a context key set via {@link setContext} wrapper for this session.
62+
*
63+
* Warning: this does not gaurantee the state of the context key in vscode because it may have
64+
* been set via `vscode.commands.executeCommand('setContext')`. It has no connection the
65+
* context keys stored in vscode itself because an API for this is not exposed.
66+
*/
67+
export function getContext(key: contextKey): any {
68+
return contextMap[key]
5769
}

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

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import assert from 'assert'
99
import sinon from 'sinon'
1010
import globals from '../../shared/extensionGlobals'
1111
import { randomUUID } from '../../shared/crypto'
12-
import * as setContext from '../../shared/vscode/setContext'
12+
import { getContext } from '../../shared/vscode/setContext'
1313
import { assertTelemetry, installFakeClock } from '../testUtil'
1414
import {
1515
NotificationFetcher,
@@ -88,7 +88,7 @@ describe('Notifications Controller', function () {
8888
}
8989

9090
beforeEach(async function () {
91-
panelNode.setNotifications([], [])
91+
await panelNode.setNotifications([], [])
9292
fetcher = new TestFetcher()
9393
controller = new NotificationsController(panelNode, fetcher, '_aws.test.notification' as any)
9494

@@ -108,10 +108,6 @@ describe('Notifications Controller', function () {
108108
})
109109

110110
it('can fetch and store startup notifications', async function () {
111-
// There seems to be a race condition with having a global spy object that is reset after each
112-
// test. Doesn't seem to affect the other ones, for some reason.
113-
const setContextSpy = sinon.spy(setContext, 'setContext')
114-
115111
const eTag = randomUUID()
116112
const content = {
117113
schemaVersion: '1.x',
@@ -140,14 +136,10 @@ describe('Notifications Controller', function () {
140136
assert.deepStrictEqual(panelNode.startUpNotifications, [content.notifications[0]])
141137
assert.equal(panelNode.getChildren().length, 1)
142138
assert.equal(focusPanelSpy.callCount, 0)
143-
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
144-
145-
setContextSpy.restore()
139+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
146140
})
147141

148142
it('can fetch and store emergency notifications', async function () {
149-
const setContextSpy = sinon.spy(setContext, 'setContext')
150-
151143
const eTag = randomUUID()
152144
const content = {
153145
schemaVersion: '1.x',
@@ -176,14 +168,10 @@ describe('Notifications Controller', function () {
176168
assert.deepStrictEqual(panelNode.emergencyNotifications, [content.notifications[0]])
177169
assert.equal(panelNode.getChildren().length, 1)
178170
assert.equal(focusPanelSpy.callCount, 1)
179-
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
180-
181-
setContextSpy.restore()
171+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
182172
})
183173

184174
it('can fetch and store both startup and emergency notifications', async function () {
185-
const setContextSpy = sinon.spy(setContext, 'setContext')
186-
187175
const eTag1 = randomUUID()
188176
const eTag2 = randomUUID()
189177
const startUpContent = {
@@ -239,14 +227,10 @@ describe('Notifications Controller', function () {
239227
assert.deepStrictEqual(panelNode.emergencyNotifications, [emergencyContent.notifications[0]])
240228
assert.equal(panelNode.getChildren().length, 2)
241229
assert.equal(focusPanelSpy.callCount, 1)
242-
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
243-
244-
setContextSpy.restore()
230+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
245231
})
246232

247233
it('dismisses a startup notification', async function () {
248-
const setContextSpy = sinon.spy(setContext, 'setContext')
249-
250234
const eTag = randomUUID()
251235
const content = {
252236
schemaVersion: '1.x',
@@ -261,7 +245,7 @@ describe('Notifications Controller', function () {
261245

262246
assert.equal(panelNode.getChildren().length, 2)
263247
assert.equal(panelNode.startUpNotifications.length, 2)
264-
assert.ok(setContextSpy.calledWithExactly('aws.toolkit.notifications.show', true))
248+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
265249

266250
assert.deepStrictEqual(await globals.globalState.get(controller.storageKey), {
267251
startUp: {
@@ -288,13 +272,9 @@ describe('Notifications Controller', function () {
288272

289273
assert.equal(panelNode.getChildren().length, 1)
290274
assert.equal(panelNode.startUpNotifications.length, 1)
291-
292-
setContextSpy.restore()
293275
})
294276

295277
it('does not redisplay dismissed notifications', async function () {
296-
const setContextSpy = sinon.spy(setContext, 'setContext')
297-
298278
const content = {
299279
schemaVersion: '1.x',
300280
notifications: [getValidTestNotification('id:startup1')],
@@ -306,11 +286,11 @@ describe('Notifications Controller', function () {
306286

307287
await controller.pollForStartUp(ruleEngine)
308288
assert.equal(panelNode.getChildren().length, 1)
309-
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
289+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
310290

311291
await dismissNotification(content.notifications[0])
312292
assert.equal(panelNode.getChildren().length, 0)
313-
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', false])
293+
assert.equal(getContext('aws.toolkit.notifications.show'), false)
314294

315295
content.notifications.push(getValidTestNotification('id:startup2'))
316296
fetcher.setStartUpContent({
@@ -332,9 +312,7 @@ describe('Notifications Controller', function () {
332312
})
333313

334314
assert.equal(panelNode.getChildren().length, 1)
335-
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
336-
337-
setContextSpy.restore()
315+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
338316
})
339317

340318
it('does not refocus emergency notifications', async function () {
@@ -406,8 +384,6 @@ describe('Notifications Controller', function () {
406384
})
407385

408386
it('cleans out dismissed state', async function () {
409-
const setContextSpy = sinon.spy(setContext, 'setContext')
410-
411387
const startUpContent = {
412388
schemaVersion: '1.x',
413389
notifications: [getValidTestNotification('id:startup1')],
@@ -466,7 +442,7 @@ describe('Notifications Controller', function () {
466442
newlyReceived: [],
467443
})
468444
assert.equal(panelNode.getChildren().length, 1)
469-
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', true])
445+
assert.equal(getContext('aws.toolkit.notifications.show'), true)
470446

471447
fetcher.setEmergencyContent({
472448
eTag: '1',
@@ -488,9 +464,7 @@ describe('Notifications Controller', function () {
488464
})
489465

490466
assert.equal(panelNode.getChildren().length, 0)
491-
assert.deepStrictEqual(setContextSpy.lastCall.args, ['aws.toolkit.notifications.show', false])
492-
493-
setContextSpy.restore()
467+
assert.equal(getContext('aws.toolkit.notifications.show'), false)
494468
})
495469

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

0 commit comments

Comments
 (0)