You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: guides/navigation-timing/readme.md
+38-10Lines changed: 38 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,13 +25,33 @@ If any navigation operation is triggered during steps 1-4, it **interrupts** thi
25
25
- The intended navigation never finishes.
26
26
- Your test ends up in an unexpected state.
27
27
28
+
## The Redirect Race Condition
29
+
30
+
A particularly common variant of this race condition occurs with **HTTP redirects** (302, 301, etc.). When a form submission or other action triggers a redirect:
31
+
32
+
1.**Form Submission**: Browser sends POST request to `/submit`.
33
+
2.**Server Response**: Server returns `302 Found` with `Location: /success` header.
34
+
3.**Redirect Processing**: Browser receives the 302 response (usually with empty body).
35
+
4.**Follow Redirect**: Browser automatically navigates to `/success`.
36
+
5.**Final Page Load**: Success page loads with actual content.
37
+
38
+
The race condition occurs because element-based waits can execute during step 3, when the browser has received the 302 response but hasn't yet loaded the target page:
39
+
40
+
```ruby
41
+
session.click_button("Submit") # Triggers POST -> 302 redirect
42
+
session.find_element(xpath:"//h1") # May execute on empty 302 page!
43
+
session.navigate_to("/other-page") # Interrupts redirect to /success
44
+
```
45
+
46
+
This explains why redirect-based workflows (login forms, contact forms, checkout processes) are particularly susceptible to race conditions.
47
+
28
48
## Problematic Code Examples
29
49
30
50
### Example 1: Login Form Race Condition
31
51
32
52
```ruby
33
53
# ❌ PROBLEMATIC: May interrupt login before authentication completes
34
-
session.click_button("Login") # Triggers form submission
54
+
session.click_button("Login") # Triggers form submission.
35
55
session.navigate_to("/dashboard") # May interrupt login process!
36
56
```
37
57
@@ -40,10 +60,19 @@ session.navigate_to("/dashboard") # May interrupt login process!
session.click_button("Subscribe") # Triggers form submission
63
+
session.click_button("Subscribe") # Triggers form submission.
44
64
session.navigate_to("/thank-you") # May interrupt subscription action on server!
45
65
```
46
66
67
+
### Example 3: Redirect Race Condition
68
+
69
+
```ruby
70
+
# ❌ PROBLEMATIC: May interrupt redirect before it completes
71
+
session.click_button("Submit") # POST -> 302 redirect.
72
+
session.find_element(xpath:"//h1") # May find element on 302 page and fail.
73
+
session.navigate_to("/dashboard") # Interrupts redirect to success page.
74
+
```
75
+
47
76
## Detection and Mitigation Strategies
48
77
49
78
⚠️ **Important**: Element-based waits (`find_element`) are **insufficient** for preventing race conditions because navigation can be interrupted before target elements ever appear on the page.
@@ -67,8 +96,7 @@ For critical operations like authentication, wait for server-side effects to com
@@ -79,20 +107,20 @@ These approaches are commonly used but **may still allow race conditions**:
79
107
80
108
#### Element-based Waits
81
109
82
-
Unfortunately, waiting for specific elements to appear does not always work when navigation operations are in progress. In some cases, the element isn't present before the navigation starts, which can cause hangs. However, sometimes it may work by chance, if the navigation completes before the find element call is invoked. It also appears to depend on which browser is being used, and perhaps even which version of that browser.
110
+
Unfortunately, waiting for specific elements to appear does not always work when navigation operations are in progress. This is especially problematic with redirects, where element waits can execute on the intermediate redirect response (which typically has no content) rather than the final destination page.
83
111
84
112
```ruby
85
113
# ❌ UNRELIABLE: Navigation can be interrupted before element appears
86
-
session.click_button("Submit")
114
+
session.click_button("Submit")# Triggers POST -> 302 redirect
87
115
88
116
# In principle, wait for the form submission to complete:
0 commit comments