1
1
import type { Meta , StoryObj } from "@storybook/react" ;
2
- import { spyOn , userEvent , waitFor , within } from "@storybook/test" ;
2
+ import { spyOn , userEvent , waitFor , within , expect } from "@storybook/test" ;
3
3
import { API } from "api/api" ;
4
4
import {
5
5
notificationDispatchMethodsKey ,
@@ -19,8 +19,9 @@ import {
19
19
withGlobalSnackbar ,
20
20
} from "testHelpers/storybook" ;
21
21
import { NotificationsPage } from "./NotificationsPage" ;
22
+ import { reactRouterParameters } from "storybook-addon-remix-react-router" ;
22
23
23
- const meta : Meta < typeof NotificationsPage > = {
24
+ const meta = {
24
25
title : "pages/UserSettingsPage/NotificationsPage" ,
25
26
component : NotificationsPage ,
26
27
parameters : {
@@ -43,7 +44,7 @@ const meta: Meta<typeof NotificationsPage> = {
43
44
permissions : { viewDeploymentValues : true } ,
44
45
} ,
45
46
decorators : [ withGlobalSnackbar , withAuthProvider , withDashboardProvider ] ,
46
- } ;
47
+ } satisfies Meta < typeof NotificationsPage > ;
47
48
48
49
export default meta ;
49
50
type Story = StoryObj < typeof NotificationsPage > ;
@@ -78,72 +79,77 @@ export const NonAdmin: Story = {
78
79
} ,
79
80
} ;
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
+
81
99
export const DisableValidTemplate : Story = {
82
100
parameters : {
83
- msw : {
84
- handlers : [
85
- http . put ( "/api/v2/users/:userId/notifications/preferences" , ( ) => {
86
- return HttpResponse . json ( [
87
- { id : "valid-template-id" , disabled : true } ,
88
- ] ) ;
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 ;
89
121
} ) ,
90
- ] ,
122
+ ) ;
123
+ return < Story /> ;
91
124
} ,
92
- } ,
125
+ ] ,
93
126
play : async ( { canvasElement } ) => {
94
- const canvas = within ( canvasElement ) ;
95
-
96
- const validTemplateId = "valid-template-id" ;
97
- const validTemplateName = "Valid Template Name" ;
98
-
99
- window . history . pushState ( { } , "" , `?disabled=${ validTemplateId } ` ) ;
100
-
101
- await waitFor (
102
- async ( ) => {
103
- const successMessage = await canvas . findByText (
104
- `${ validTemplateName } notification has been disabled` ,
105
- ) ;
106
- expect ( successMessage ) . toBeInTheDocument ( ) ;
107
- } ,
108
- { timeout : 10000 } ,
109
- ) ;
110
-
111
- await waitFor (
112
- async ( ) => {
113
- const templateSwitch = await canvas . findByLabelText ( validTemplateName ) ;
114
- expect ( templateSwitch ) . not . toBeChecked ( ) ;
115
- } ,
116
- { timeout : 10000 } ,
127
+ await within ( document . body ) . findByText ( "Notification has been disabled" ) ;
128
+ const switchEl = await within ( canvasElement ) . findByLabelText (
129
+ templateToDisable . name ,
117
130
) ;
131
+ expect ( switchEl ) . not . toBeChecked ( ) ;
118
132
} ,
119
133
} ;
120
134
121
135
export const DisableInvalidTemplate : Story = {
122
136
parameters : {
123
- msw : {
124
- handlers : [
125
- http . put ( "/api/v2/users/:userId/notifications/preferences" , ( ) => {
126
- // Mock failed API response
127
- return new HttpResponse ( null , { status : 400 } ) ;
128
- } ) ,
129
- ] ,
130
- } ,
131
- } ,
132
- play : async ( { canvasElement } ) => {
133
- const canvas = within ( canvasElement ) ;
134
-
135
- const invalidTemplateId = "invalid-template-id" ;
136
-
137
- window . history . pushState ( { } , "" , `?disabled=${ invalidTemplateId } ` ) ;
138
-
139
- await waitFor (
140
- async ( ) => {
141
- const errorMessage = await canvas . findByText (
142
- "An error occurred when attempting to disable the requested notification" ,
143
- ) ;
144
- expect ( errorMessage ) . toBeInTheDocument ( ) ;
137
+ reactRouter : reactRouterParameters ( {
138
+ location : {
139
+ searchParams : { disabled : "invalid-template-id" } ,
145
140
} ,
146
- { timeout : 10000 } ,
147
- ) ;
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" ) ;
148
154
} ,
149
155
} ;
0 commit comments