From 8966edc82a33c5b7f00d45477941bcc333a10318 Mon Sep 17 00:00:00 2001 From: Tom Zu <138054255+tomcat323@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:30:20 -0500 Subject: [PATCH] test(notifications): unit tests for notification rendering (#5947) Unit testing for notifications rendering Using locally generated notifications, test covers: - new notification on-receive modal/toast windows - panel on-click txt/url pop up - modal button actions (update&restart, txt, url) --- packages/core/src/notifications/panelNode.ts | 2 +- .../shared/utilities/textDocumentUtilities.ts | 12 +- .../src/test/notifications/rendering.test.ts | 208 ++++++++++++++++++ 3 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/test/notifications/rendering.test.ts diff --git a/packages/core/src/notifications/panelNode.ts b/packages/core/src/notifications/panelNode.ts index b3478f7bb4f..87ef872c59a 100644 --- a/packages/core/src/notifications/panelNode.ts +++ b/packages/core/src/notifications/panelNode.ts @@ -128,7 +128,7 @@ export class NotificationsNode implements TreeNode { * Fired when a notification is clicked on in the panel. It will run any rendering * instructions included in the notification. See {@link ToolkitNotification.uiRenderInstructions}. */ - private async openNotification(notification: ToolkitNotification) { + public async openNotification(notification: ToolkitNotification) { switch (notification.uiRenderInstructions.onClick.type) { case 'modal': // Render blocking modal diff --git a/packages/core/src/shared/utilities/textDocumentUtilities.ts b/packages/core/src/shared/utilities/textDocumentUtilities.ts index 20222a84f7d..1f2fb7aa1da 100644 --- a/packages/core/src/shared/utilities/textDocumentUtilities.ts +++ b/packages/core/src/shared/utilities/textDocumentUtilities.ts @@ -5,7 +5,7 @@ import * as _path from 'path' import * as vscode from 'vscode' -import { getTabSizeSetting } from './editorUtilities' +import { disposeOnEditorClose, getTabSizeSetting } from './editorUtilities' import { tempDirPath } from '../filesystemUtilities' import { getLogger } from '../logger' import fs from '../fs/fs' @@ -247,22 +247,22 @@ class ReadonlyDocument { private readonly scheme = 'AWStoolkit-readonly' private readonly provider = new ReadonlyTextDocumentProvider() - constructor() { - vscode.workspace.registerTextDocumentContentProvider(this.scheme, this.provider) - } - public async show(content: string, filename: string) { + const disposableProvider = vscode.workspace.registerTextDocumentContentProvider(this.scheme, this.provider) this.provider.setContent(content) const uri = vscode.Uri.parse(`${this.scheme}:/${filename}.txt`) + // txt document on side column, in focus and preview const options: vscode.TextDocumentShowOptions = { viewColumn: vscode.ViewColumn.Beside, - preserveFocus: true, + preserveFocus: false, preview: true, } // Open the document with the updated content const document = await vscode.workspace.openTextDocument(uri) await vscode.window.showTextDocument(document, options) + + disposeOnEditorClose(uri, disposableProvider) } } diff --git a/packages/core/src/test/notifications/rendering.test.ts b/packages/core/src/test/notifications/rendering.test.ts new file mode 100644 index 00000000000..ada48c2c64b --- /dev/null +++ b/packages/core/src/test/notifications/rendering.test.ts @@ -0,0 +1,208 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import * as sinon from 'sinon' +import assert from 'assert' +import { ToolkitNotification } from '../../notifications/types' +import { panelNode } from './controller.test' +import { getTestWindow } from '../shared/vscode/window' +import * as VsCodeUtils from '../../shared/utilities/vsCodeUtils' +import { assertTextEditorContains } from '../testUtil' + +describe('Notifications Rendering', function () { + let sandbox: sinon.SinonSandbox + + beforeEach(function () { + sandbox = sinon.createSandbox() + }) + + afterEach(function () { + sandbox.restore() + }) + + // util to test txt pop-up under different senarios + async function verifyTxtNotification(notification: ToolkitNotification) { + const expectedContent = notification.uiRenderInstructions.content['en-US'].description + void panelNode.openNotification(notification) + + await assertTextEditorContains(expectedContent) + } + + // util to test open url under different senarios + async function verifyOpenExternalUrl(notification: ToolkitNotification) { + const openUrlStub = sandbox.stub(VsCodeUtils, 'openUrl') + await panelNode.openNotification(notification) + + assert.ok(openUrlStub.calledWith(vscode.Uri.parse('https://aws.amazon.com/visualstudiocode/'))) + } + + // test on-receive behaviors + it('displays a toast with correct message on receive', async function () { + const testWindow = getTestWindow() + testWindow.onDidShowMessage((message) => {}) + + const notification = getToastURLTestNotification() + await panelNode.onReceiveNotifications([notification]) + + const expectedMessage = + notification.uiRenderInstructions.content['en-US'].toastPreview ?? + notification.uiRenderInstructions.content['en-US'].title + + const shownMessages = testWindow.shownMessages + assert.ok(shownMessages.some((msg) => msg.message === expectedMessage)) + }) + + it('displays a modal with correct buttons on receive', async function () { + const testWindow = getTestWindow() + const notification = getModalNotification() + + testWindow.onDidShowMessage((message) => { + const expectedButtons = + notification.uiRenderInstructions.actions?.map((actions) => actions.displayText['en-US']) ?? [] + expectedButtons.forEach((buttonText) => { + assert.ok( + message.items.some((item) => item.title === buttonText), + `Button "${buttonText}" is missing` + ) + }) + }) + + await panelNode.onReceiveNotifications([notification]) + }) + + // test on-lick behaviors + it('open a txt with correct content on-click', async function () { + const notification = getTxtNotification() + await verifyTxtNotification(notification) + }) + + it('opens a URL with correct link on-click', async function () { + const notification = getToastURLTestNotification() + await verifyOpenExternalUrl(notification) + }) + + // test modal buttons behavior + it('executes updateAndReload type button', async function () { + const testWindow = getTestWindow() + testWindow.onDidShowMessage((message) => { + // Simulate user clicking update and reload type + message.selectItem('Update and Reload') + }) + const excuteCommandStub = sandbox.stub(vscode.commands, 'executeCommand').resolves() + const notification = getModalNotification() + await panelNode.openNotification(notification) + + assert.ok(excuteCommandStub.calledWith('workbench.extensions.installExtension', 'aws.toolkit.fake.extension')) + assert.ok(excuteCommandStub.calledWith('workbench.action.reloadWindow')) + }) + + it('executes openURL type button', async function () { + const testWindow = getTestWindow() + testWindow.onDidShowMessage((message) => { + // Simulate user clicking open URL type + message.selectItem('Proceed to Wiki') + }) + const notification = getModalNotification() + await verifyOpenExternalUrl(notification) + }) + + it('executes openTxt type button', async function () { + const testWindow = getTestWindow() + testWindow.onDidShowMessage((message) => { + // Simulate user clicking open txt type + message.selectItem('Read More') + }) + const notification = getModalNotification() + await verifyTxtNotification(notification) + }) +}) + +// generate test notifications +function getToastURLTestNotification(): ToolkitNotification { + return { + id: 'test notification 1', + displayIf: { + extensionId: 'aws.toolkit.fake.extension', + }, + uiRenderInstructions: { + content: { + [`en-US`]: { + title: 'test', + description: 'This is a url notification.', + toastPreview: 'test toast preview', + }, + }, + onRecieve: 'toast', + onClick: { + type: 'openUrl', + url: 'https://aws.amazon.com/visualstudiocode/', + }, + }, + } +} + +function getTxtNotification(): ToolkitNotification { + return { + id: 'test notification 2', + displayIf: { + extensionId: 'aws.toolkit.fake.extension', + }, + uiRenderInstructions: { + content: { + [`en-US`]: { + title: 'test', + description: 'This is a text document notification.', + }, + }, + onRecieve: 'toast', + onClick: { + type: 'openTextDocument', + }, + }, + } +} + +function getModalNotification(): ToolkitNotification { + return { + id: 'test notification 3', + displayIf: { + extensionId: 'aws.toolkit.fake.extension', + }, + uiRenderInstructions: { + content: { + [`en-US`]: { + title: 'test', + description: 'This is a modal notification.', + }, + }, + onRecieve: 'modal', + onClick: { + type: 'modal', + }, + actions: [ + { + type: 'updateAndReload', + displayText: { + 'en-US': 'Update and Reload', + }, + }, + { + type: 'openUrl', + url: 'https://aws.amazon.com/visualstudiocode/', + displayText: { + 'en-US': 'Proceed to Wiki', + }, + }, + { + type: 'openTxt', + displayText: { + 'en-US': 'Read More', + }, + }, + ], + }, + } +}