1
1
import type { Meta , StoryObj } from "@storybook/react" ;
2
- import { spyOn , userEvent , within } from "@storybook/test" ;
2
+ import { expect , spyOn , userEvent , waitFor , within } from "@storybook/test" ;
3
3
import { API } from "api/api" ;
4
4
import {
5
5
notificationDispatchMethodsKey ,
6
6
systemNotificationTemplatesKey ,
7
7
userNotificationPreferencesKey ,
8
8
} from "api/queries/notifications" ;
9
+ import { http , HttpResponse } from "msw" ;
10
+ import { reactRouterParameters } from "storybook-addon-remix-react-router" ;
9
11
import {
10
12
MockNotificationMethodsResponse ,
11
13
MockNotificationPreferences ,
@@ -19,7 +21,7 @@ import {
19
21
} from "testHelpers/storybook" ;
20
22
import { NotificationsPage } from "./NotificationsPage" ;
21
23
22
- const meta : Meta < typeof NotificationsPage > = {
24
+ const meta = {
23
25
title : "pages/UserSettingsPage/NotificationsPage" ,
24
26
component : NotificationsPage ,
25
27
parameters : {
@@ -42,7 +44,7 @@ const meta: Meta<typeof NotificationsPage> = {
42
44
permissions : { viewDeploymentValues : true } ,
43
45
} ,
44
46
decorators : [ withGlobalSnackbar , withAuthProvider , withDashboardProvider ] ,
45
- } ;
47
+ } satisfies Meta < typeof NotificationsPage > ;
46
48
47
49
export default meta ;
48
50
type Story = StoryObj < typeof NotificationsPage > ;
@@ -76,3 +78,78 @@ export const NonAdmin: Story = {
76
78
permissions : { viewDeploymentValues : false } ,
77
79
} ,
78
80
} ;
81
+
82
+ // Ensure the selected notification template is enabled before attempting to
83
+ // disable it.
84
+ const enabledPreference = MockNotificationPreferences . find (
85
+ ( pref ) => pref . disabled === false ,
86
+ ) ;
87
+ if ( ! enabledPreference ) {
88
+ throw new Error (
89
+ "No enabled notification preference available to test the disabling action." ,
90
+ ) ;
91
+ }
92
+ const templateToDisable = MockNotificationTemplates . find (
93
+ ( tpl ) => tpl . id === enabledPreference . id ,
94
+ ) ;
95
+ if ( ! templateToDisable ) {
96
+ throw new Error ( " No notification template matches the enabled preference." ) ;
97
+ }
98
+
99
+ export const DisableValidTemplate : Story = {
100
+ parameters : {
101
+ reactRouter : reactRouterParameters ( {
102
+ location : {
103
+ searchParams : { disabled : templateToDisable . id } ,
104
+ } ,
105
+ } ) ,
106
+ } ,
107
+ decorators : [
108
+ ( Story ) => {
109
+ // Since the action occurs during the initial render, we need to spy on
110
+ // the API call before the story is rendered. This is done using a
111
+ // decorator to ensure the spy is set up in time.
112
+ spyOn ( API , "putUserNotificationPreferences" ) . mockResolvedValue (
113
+ MockNotificationPreferences . map ( ( pref ) => {
114
+ if ( pref . id === templateToDisable . id ) {
115
+ return {
116
+ ...pref ,
117
+ disabled : true ,
118
+ } ;
119
+ }
120
+ return pref ;
121
+ } ) ,
122
+ ) ;
123
+ return < Story /> ;
124
+ } ,
125
+ ] ,
126
+ play : async ( { canvasElement } ) => {
127
+ await within ( document . body ) . findByText ( "Notification has been disabled" ) ;
128
+ const switchEl = await within ( canvasElement ) . findByLabelText (
129
+ templateToDisable . name ,
130
+ ) ;
131
+ expect ( switchEl ) . not . toBeChecked ( ) ;
132
+ } ,
133
+ } ;
134
+
135
+ export const DisableInvalidTemplate : Story = {
136
+ parameters : {
137
+ reactRouter : reactRouterParameters ( {
138
+ location : {
139
+ searchParams : { disabled : "invalid-template-id" } ,
140
+ } ,
141
+ } ) ,
142
+ } ,
143
+ decorators : [
144
+ ( Story ) => {
145
+ // Since the action occurs during the initial render, we need to spy on
146
+ // the API call before the story is rendered. This is done using a
147
+ // decorator to ensure the spy is set up in time.
148
+ spyOn ( API , "putUserNotificationPreferences" ) . mockRejectedValue ( { } ) ;
149
+ return < Story /> ;
150
+ } ,
151
+ ] ,
152
+ play : async ( ) => {
153
+ await within ( document . body ) . findByText ( "Error disabling notification" ) ;
154
+ } ,
155
+ } ;
0 commit comments