@@ -4,13 +4,16 @@ import {
44 setupPriceAlertsApiMock ,
55 setupPriceAlertsPostMock ,
66 setupPriceAlertsPatchMock ,
7+ setupPercentPriceAlertsPostMock ,
8+ setupPercentPriceAlertsPatchMock ,
79 clearPriceAlertsApiMocks ,
810} from '../../../../../../../tests/component-view/api-mocking/priceAlerts' ;
911import { describeForPlatforms } from '../../../../../../../tests/component-view/platform' ;
1012import { act , fireEvent , waitFor } from '@testing-library/react-native' ;
1113import {
1214 type AbsolutePriceAlert ,
1315 CreatePriceAlertTestIds ,
16+ type PercentChangeAlert ,
1417} from '../../constants' ;
1518
1619beforeEach ( ( ) => {
@@ -32,6 +35,19 @@ const editingAlert: AbsolutePriceAlert = {
3235 createdAt : '2025-01-01T00:00:00.000Z' ,
3336} ;
3437
38+ const editingPercentAlert : PercentChangeAlert = {
39+ id : 'percent-alert-1' ,
40+ userId : 'user-1' ,
41+ asset : 'eip155:1/slip44:60' ,
42+ type : 'percent_change' ,
43+ threshold : 10.5 ,
44+ period : '1h' ,
45+ direction : 'down' ,
46+ recurring : true ,
47+ active : true ,
48+ createdAt : '2025-01-01T00:00:00.000Z' ,
49+ } ;
50+
3551describeForPlatforms ( 'CreatePriceAlertView' , ( ) => {
3652 it ( 'renders the Price Reaches form with keypad and quick-percentage pills' , async ( ) => {
3753 const { getByTestId, getByText } = renderCreatePriceAlertViewWithRoutes ( ) ;
@@ -176,4 +192,128 @@ describeForPlatforms('CreatePriceAlertView', () => {
176192
177193 await waitFor ( ( ) => expect ( scope . isDone ( ) ) . toBe ( true ) ) ;
178194 } ) ;
195+
196+ describe ( 'percent-change alerts' , ( ) => {
197+ it ( 'switches to the percent form and updates direction and period' , async ( ) => {
198+ const { getByTestId, getByText, queryByTestId } =
199+ renderCreatePriceAlertViewWithRoutes ( ) ;
200+
201+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . TYPE_SEGMENT_CHANGE ) ) ;
202+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . DIRECTION_TOGGLE ) ) ;
203+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . PERIOD_SEGMENT_1H ) ) ;
204+
205+ await waitFor ( ( ) => {
206+ expect (
207+ getByTestId ( CreatePriceAlertTestIds . PERCENT_INPUT ) ,
208+ ) . toBeOnTheScreen ( ) ;
209+ expect (
210+ queryByTestId ( CreatePriceAlertTestIds . TARGET_PRICE_INPUT ) ,
211+ ) . not . toBeOnTheScreen ( ) ;
212+ expect ( getByText ( 'When price moves down' ) ) . toBeOnTheScreen ( ) ;
213+ expect (
214+ getByTestId ( CreatePriceAlertTestIds . PERIOD_SEGMENT_1H ) ,
215+ ) . toHaveProp (
216+ 'accessibilityState' ,
217+ expect . objectContaining ( { selected : true } ) ,
218+ ) ;
219+ } ) ;
220+ } ) ;
221+
222+ it ( 'submits the selected percent configuration to the percent endpoint' , async ( ) => {
223+ const scope = setupPercentPriceAlertsPostMock ( {
224+ asset : 'eip155:1/slip44:60' ,
225+ threshold : 10 ,
226+ period : '1h' ,
227+ direction : 'down' ,
228+ recurring : false ,
229+ } ) ;
230+ const { getByTestId, getByText } = renderCreatePriceAlertViewWithRoutes ( {
231+ routeParams : { initialType : 'percent_change' } ,
232+ } ) ;
233+
234+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . DIRECTION_TOGGLE ) ) ;
235+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . PERIOD_SEGMENT_1H ) ) ;
236+ fireEvent . press ( getByText ( '1' ) ) ;
237+ fireEvent . press ( getByText ( '0' ) ) ;
238+ fireEvent (
239+ getByTestId ( CreatePriceAlertTestIds . RECURRING_TOGGLE ) ,
240+ 'valueChange' ,
241+ false ,
242+ ) ;
243+
244+ await act ( async ( ) => {
245+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . SET_ALERT_BUTTON ) ) ;
246+ } ) ;
247+
248+ await waitFor ( ( ) => expect ( scope . isDone ( ) ) . toBe ( true ) ) ;
249+ } ) ;
250+
251+ it ( 'prevents saving a duplicate percent configuration' , async ( ) => {
252+ const { getByTestId, getByText, findByText } =
253+ renderCreatePriceAlertViewWithRoutes ( {
254+ routeParams : {
255+ initialType : 'percent_change' ,
256+ existingPercentAlerts : [
257+ {
258+ ...editingPercentAlert ,
259+ threshold : 10 ,
260+ period : '24h' ,
261+ direction : 'up' ,
262+ } ,
263+ ] ,
264+ } ,
265+ } ) ;
266+
267+ fireEvent . press ( getByText ( '1' ) ) ;
268+ fireEvent . press ( getByText ( '0' ) ) ;
269+
270+ expect (
271+ await findByText ( 'An alert with this configuration already exists.' ) ,
272+ ) . toBeOnTheScreen ( ) ;
273+ expect (
274+ getByTestId ( CreatePriceAlertTestIds . SET_ALERT_BUTTON ) ,
275+ ) . toBeDisabled ( ) ;
276+ } ) ;
277+
278+ it ( 'locks immutable controls and PATCHes editable percent fields' , async ( ) => {
279+ const scope = setupPercentPriceAlertsPatchMock ( editingPercentAlert . id , {
280+ threshold : 10.5 ,
281+ recurring : false ,
282+ } ) ;
283+ const { getByTestId } = renderCreatePriceAlertViewWithRoutes ( {
284+ routeParams : {
285+ editingAlert : editingPercentAlert ,
286+ existingPercentAlerts : [ editingPercentAlert ] ,
287+ } ,
288+ } ) ;
289+
290+ fireEvent (
291+ getByTestId ( CreatePriceAlertTestIds . RECURRING_TOGGLE ) ,
292+ 'valueChange' ,
293+ false ,
294+ ) ;
295+
296+ expect (
297+ getByTestId ( CreatePriceAlertTestIds . TYPE_SEGMENT_TARGET ) ,
298+ ) . toBeDisabled ( ) ;
299+ expect (
300+ getByTestId ( CreatePriceAlertTestIds . TYPE_SEGMENT_CHANGE ) ,
301+ ) . toBeDisabled ( ) ;
302+ expect (
303+ getByTestId ( CreatePriceAlertTestIds . PERIOD_SEGMENT_1H ) ,
304+ ) . toBeDisabled ( ) ;
305+ expect (
306+ getByTestId ( CreatePriceAlertTestIds . PERIOD_SEGMENT_24H ) ,
307+ ) . toBeDisabled ( ) ;
308+ expect (
309+ getByTestId ( CreatePriceAlertTestIds . DIRECTION_TOGGLE ) ,
310+ ) . toBeDisabled ( ) ;
311+
312+ await act ( async ( ) => {
313+ fireEvent . press ( getByTestId ( CreatePriceAlertTestIds . SET_ALERT_BUTTON ) ) ;
314+ } ) ;
315+
316+ await waitFor ( ( ) => expect ( scope . isDone ( ) ) . toBe ( true ) ) ;
317+ } ) ;
318+ } ) ;
179319} ) ;
0 commit comments