1+ /**
2+ * ========================================
3+ * React Native Testing Library Tutorial
4+ * Chapter 4: Testing Events
5+ * ========================================
6+ *
7+ * This chapter covers how to simulate and test user interactions in React Native
8+ * applications using React Native Testing Library's userEvent API.
9+ *
10+ * Key concepts covered:
11+ * - Setting up userEvent for realistic user interactions
12+ * - Testing button press events
13+ * - Testing text input events
14+ * - Testing form submissions
15+ * - Testing state changes triggered by events
16+ * - Best practices for event testing
17+ *
18+ * Note: This example uses React Strict DOM (react-strict-dom) which provides
19+ * HTML-like components that work across React Native and web platforms.
20+ */
21+
122import * as React from 'react' ;
223import { html } from 'react-strict-dom' ;
324import { render , screen , userEvent } from '@testing-library/react-native' ;
425
26+ /**
27+ * ========================================
28+ * Example 1: Basic Button Press Events
29+ * ========================================
30+ *
31+ * This example demonstrates how to test button press events that trigger
32+ * state changes in a component.
33+ */
34+
535function Counter ( ) {
636 const [ count , setCount ] = React . useState ( 0 ) ;
737
@@ -15,19 +45,53 @@ function Counter() {
1545 ) ;
1646}
1747
48+ /**
49+ * Testing button press events:
50+ *
51+ * 1. Setup userEvent - creates a user session for realistic interactions
52+ * 2. Find the button element using queries
53+ * 3. Simulate the press event using user.press()
54+ * 4. Assert the expected state change occurred
55+ *
56+ * Key points:
57+ * - userEvent.setup() creates a user session for the test
58+ * - user.press() simulates a realistic button press (including focus, press, release)
59+ * - Always use await when calling userEvent methods (they return promises)
60+ * - Test both the initial state and the state after the event
61+ */
1862test ( 'Counter should increment the count when the button is pressed' , async ( ) => {
63+ // Setup userEvent - this creates a user session for the test
1964 const user = userEvent . setup ( ) ;
2065
66+ // Render the component
2167 render ( < Counter /> ) ;
68+
69+ // Verify initial state
2270 expect ( screen . getByText ( '0' ) ) . toBeOnTheScreen ( ) ;
2371
72+ // Find the button element using role and accessible name
2473 const button = screen . getByRole ( 'button' , { name : 'Increment' } ) ;
2574 expect ( button ) . toBeOnTheScreen ( ) ;
2675
76+ // Simulate a button press event
2777 await user . press ( button ) ;
78+
79+ // Verify the state change occurred
2880 expect ( screen . getByText ( '1' ) ) . toBeOnTheScreen ( ) ;
2981} ) ;
3082
83+ /**
84+ * ========================================
85+ * Example 2: Text Input and Form Events
86+ * ========================================
87+ *
88+ * This example demonstrates testing more complex user interactions including:
89+ * - Text input events
90+ * - Form submission events
91+ * - Conditional rendering based on events
92+ * - Error handling scenarios
93+ */
94+
3195function LoginForm ( ) {
3296 const [ email , setEmail ] = React . useState ( '' ) ;
3397 const [ password , setPassword ] = React . useState ( '' ) ;
@@ -69,24 +133,90 @@ function LoginForm() {
69133 ) ;
70134}
71135
136+ /**
137+ * Testing text input events and successful form submission:
138+ *
139+ * This test demonstrates:
140+ * - Using user.type() to simulate realistic text input
141+ * - Finding input elements by placeholder text
142+ * - Testing form submission with valid data
143+ * - Verifying conditional rendering after successful submission
144+ *
145+ * Key points:
146+ * - user.type() simulates realistic typing (including focus, keystrokes, blur)
147+ * - Always await user.type() calls
148+ * - Use placeholder text, labels, or roles to find input elements
149+ * - Test the complete user flow from input to submission to result
150+ */
72151test ( 'should login with valid credentials' , async ( ) => {
73152 const user = userEvent . setup ( ) ;
74153 render ( < LoginForm /> ) ;
75154
155+ // Simulate typing in the email field
76156 await user . type ( screen . getByPlaceholderText ( 'Email' ) , 'test@test.com' ) ;
157+
158+ // Simulate typing in the password field
77159 await user . type ( screen . getByPlaceholderText ( 'Password' ) , 'password' ) ;
160+
161+ // Simulate clicking the login button
78162 await user . press ( screen . getByRole ( 'button' , { name : 'Login' } ) ) ;
79163
164+ // Verify successful login redirects to success page
80165 expect ( screen . getByRole ( 'heading' , { name : 'Login successful' } ) ) . toBeOnTheScreen ( ) ;
81166} ) ;
82167
168+ /**
169+ * Testing error scenarios:
170+ *
171+ * This test demonstrates:
172+ * - Testing error handling with invalid inputs
173+ * - Verifying error messages are displayed correctly
174+ * - Using role="alert" for error messages (accessibility best practice)
175+ *
176+ * Key points:
177+ * - Always test both success and error scenarios
178+ * - Use role="alert" for error messages to ensure accessibility
179+ * - Test that error messages have appropriate accessible names
180+ * - Verify error states don't accidentally trigger success states
181+ */
83182test ( 'should show error message with invalid credentials' , async ( ) => {
84183 const user = userEvent . setup ( ) ;
85184 render ( < LoginForm /> ) ;
86185
186+ // Enter valid email but invalid password
87187 await user . type ( screen . getByPlaceholderText ( 'Email' ) , 'test@test.com' ) ;
88188 await user . type ( screen . getByPlaceholderText ( 'Password' ) , 'wrong-password' ) ;
189+
190+ // Attempt to login
89191 await user . press ( screen . getByRole ( 'button' , { name : 'Login' } ) ) ;
90192
193+ // Verify error message is displayed
91194 expect ( screen . getByRole ( 'alert' , { name : 'Invalid credentials' } ) ) . toBeOnTheScreen ( ) ;
92195} ) ;
196+
197+ /**
198+ * ========================================
199+ * Best Practices for Event Testing
200+ * ========================================
201+ *
202+ * 1. Always use userEvent.setup() to create a user session
203+ * 2. Always await userEvent method calls (they return promises)
204+ * 3. Use realistic user interactions (user.press, user.type) over fireEvent
205+ * 4. Test both success and error scenarios
206+ * 5. Find elements using accessible queries (role, label, placeholder)
207+ * 6. Test the complete user flow, not just individual events
208+ * 7. Verify state changes and side effects after events
209+ * 8. Use role="alert" for error messages and test them appropriately
210+ *
211+ * ========================================
212+ * Common userEvent Methods
213+ * ========================================
214+ *
215+ * - user.press(element) - Simulates pressing a button or touchable element
216+ * - user.type(element, text) - Simulates typing text into an input
217+ * - user.clear(element) - Clears text from an input
218+ * - user.selectText(element, options) - Selects text in an input
219+ * - user.scroll(element, options) - Simulates scrolling gestures
220+ *
221+ * For more advanced event testing, see the userEvent documentation.
222+ */
0 commit comments