From dbb57a9b8dce16ed41bf8ca179f5fcbce02a26d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 15:16:37 +0000 Subject: [PATCH] Add unit tests for addReleaseNotesNotification utility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 11 tests covering all branches in addReleaseNotesNotification: - dispatches notifications/add when not found and not previously read - skips notifications/add when current version already exists in store - skips notifications/add when version already read via preference - dispatches notifications/remove for older release-notes notification - dispatches both remove and add for correct transition - skips add when version was read even after removing old notification - ignores non-release-notes notifications (no remove, still adds) - verifies full notification structure (level, preference, primaryAction) - strips pre-release suffix from version string (e.g. 2.11.0-rc1 → 2.11.0) - handles co-existing old and current version notifications - makes no dispatch calls when list empty and version already read Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- shell/utils/__tests__/release-notes.test.ts | 133 ++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 shell/utils/__tests__/release-notes.test.ts diff --git a/shell/utils/__tests__/release-notes.test.ts b/shell/utils/__tests__/release-notes.test.ts new file mode 100644 index 00000000000..18d4d50489b --- /dev/null +++ b/shell/utils/__tests__/release-notes.test.ts @@ -0,0 +1,133 @@ +import { addReleaseNotesNotification } from '@shell/utils/release-notes'; +import * as versionModule from '@shell/config/version'; +import { NotificationLevel } from '@shell/types/notifications'; + +jest.mock('@shell/config/version', () => ({ getVersionData: jest.fn() })); +jest.mock('@shell/store/prefs', () => ({ READ_WHATS_NEW: 'read-whatsnew' })); + +const VERSION = '2.11.0'; +const NOTES_URL = 'https://release-notes.example.com'; +const mockT = (key: string, vars?: Record) => (vars ? `${ key }:${ JSON.stringify(vars) }` : key); + +describe('addReleaseNotesNotification', () => { + let dispatch: jest.Mock; + let getters: Record; + + beforeEach(() => { + (versionModule.getVersionData as jest.Mock).mockReturnValue({ Version: VERSION }); + dispatch = jest.fn().mockResolvedValue(undefined); + getters = { + 'notifications/all': [], + 'prefs/get': (_key: string) => '', + 'i18n/t': mockT, + releaseNotesUrl: NOTES_URL, + }; + }); + + it('dispatches notifications/add when not found and version not previously read', async() => { + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ + id: `release-notes-${ VERSION }`, + level: NotificationLevel.Info, + })); + }); + + it('does not dispatch notifications/add when current version notification already exists', async() => { + getters['notifications/all'] = [{ id: `release-notes-${ VERSION }` }]; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything()); + }); + + it('does not dispatch notifications/add when this version was already read via preference', async() => { + getters['prefs/get'] = (_key: string) => VERSION; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything()); + }); + + it('dispatches notifications/remove for an older release-notes notification', async() => { + const oldId = 'release-notes-2.10.0'; + + getters['notifications/all'] = [{ id: oldId }]; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId); + }); + + it('dispatches notifications/add after removing an older release-notes notification', async() => { + getters['notifications/all'] = [{ id: 'release-notes-2.10.0' }]; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: `release-notes-${ VERSION }` })); + }); + + it('removes old notification but skips notifications/add when version was already read', async() => { + const oldId = 'release-notes-2.10.0'; + + getters['notifications/all'] = [{ id: oldId }]; + getters['prefs/get'] = (_key: string) => VERSION; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId); + expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything()); + }); + + it('ignores notifications without the release-notes prefix', async() => { + getters['notifications/all'] = [{ id: 'some-other-notification' }]; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).not.toHaveBeenCalledWith('notifications/remove', 'some-other-notification'); + expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: `release-notes-${ VERSION }` })); + }); + + it('dispatches notifications/add with correct notification structure', async() => { + await addReleaseNotesNotification(dispatch, getters); + + const notification = dispatch.mock.calls.find((c) => c[0] === 'notifications/add')?.[1]; + + expect(notification.level).toStrictEqual(NotificationLevel.Info); + expect(notification.preference).toStrictEqual({ key: 'read-whatsnew', value: VERSION }); + expect(notification.primaryAction).toStrictEqual({ + label: 'landing.whatsNew.link', + target: NOTES_URL, + }); + }); + + it('strips the pre-release suffix from the version string', async() => { + (versionModule.getVersionData as jest.Mock).mockReturnValue({ Version: `${ VERSION }-rc1` }); + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/add', expect.objectContaining({ id: `release-notes-${ VERSION }` })); + }); + + it('removes old notification and does not add when both old and current exist', async() => { + const oldId = 'release-notes-2.10.0'; + + getters['notifications/all'] = [ + { id: oldId }, + { id: `release-notes-${ VERSION }` }, + ]; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).toHaveBeenCalledWith('notifications/remove', oldId); + expect(dispatch).not.toHaveBeenCalledWith('notifications/add', expect.anything()); + }); + + it('makes no dispatch calls when notifications list is empty and version already read', async() => { + getters['prefs/get'] = (_key: string) => VERSION; + + await addReleaseNotesNotification(dispatch, getters); + + expect(dispatch).not.toHaveBeenCalled(); + }); +});