fix(twitter): use search input for SPA navigation instead of pushState#695
Conversation
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks for the PR and for reproducing the issue. The dual-strategy approach is a good idea, but I have a few concerns after investigating this:
1. Root cause analysis may not be accurate
The PR states that pushState + popstate no longer works after Twitter's React Router update. However, I ran twitter search locally 5 times in a row and all succeeded. If the router change completely broke this approach, it should fail consistently. The issue reporter's Final path: (empty) suggests a timing race condition (pathname hasn't updated yet when checked) rather than complete failure. It's more likely that Twitter is running an A/B test, or behavior varies by browser version / login state.
2. The legacy fallback has a regression
The PR replaces wait({ selector: '[data-testid="primaryColumn"]' }) with wait(3) (fixed 3-second wait). This is a step back — it wastes time on fast networks and may still be insufficient on slow ones. The selector-based wait is the right approach; if anything, we should keep it or increase the timeout rather than switch to a fixed delay.
3. The search input approach was already tried and abandoned
Commit d1986f0 (#105) switched away from the search input + Enter keydown approach because "the synthetic KeyboardEvent is ignored by React, leaving the page on /explore with zero API calls captured." The code in this PR is nearly identical to the old approach. It would be helpful to explain what changed on Twitter's side that would make this work now when it didn't before.
Suggested direction:
- Keep
pushState + popstateas the primary strategy (it works in most environments) - Add more retries or a longer backoff for slow networks
- If keeping the search input as fallback, add a note about why it works now despite #105
- Fix the fallback to use selector-based waiting instead of fixed delay
…on failures The pushState + popstate approach works in most environments but fails intermittently for some users (see jackwener#690), likely due to Twitter A/B tests or timing race conditions where the pathname hasn't updated when checked. This commit adds a fallback strategy: when pushState fails after 2 retries, we type the query into the search input on /explore and press Enter. This triggers Twitter's own form handler, performing SPA navigation without a full page reload (keeping the fetch interceptor alive). Both strategies use selector-based waiting ([data-testid="primaryColumn"]) rather than fixed delays, with graceful fallthrough on timeout. Fixes jackwener#690
0505cee to
597eaf7
Compare
|
Thanks @Astro-Han for the thorough review, and @jackwener for testing. You were both right — I've updated the PR based on your feedback. What changed in v2:
The net effect: existing behavior is preserved for the majority of users, and the fallback covers the intermittent failures reported in #690. |
The search input fallback adds one extra evaluate() call when pushState fails. Update the mock chain and assertion count accordingly.
|
Thanks for the update — v2 is much cleaner. Root cause correction, selector-based wait restored, pushState kept as primary — all good. One thing I'm still curious about: commit d1986f0 (#105) moved away from the search input + Enter approach because the synthetic KeyboardEvent was ignored by React. The code here looks similar. Do you know what changed on Twitter's side that makes this work now? Even a brief note in the comment would help future maintainers understand why the fallback is expected to be reliable. Not a blocker since the fallback can't break existing behavior, but worth documenting. |
- Add optional chaining on getOwnPropertyDescriptor().set to handle edge cases where Twitter's sandbox overrides the HTMLInputElement prototype. - Add test case covering the full fallback path: pushState fails twice, search input fallback succeeds, results are returned correctly.
|
@0xsline can you contact me with Wechat? My email is jakevingoo@gmail.com. |
Summary
pushState + popstateapproach works in most environments but fails intermittently for some users ([Bug]: SPA navigation to /search failed. Final path: (empty). Twitter may have changed its routing. Add --verbose for details, or report: https://github.com/jackwener/opencli/issues #690)/exploreand press Enter[data-testid="primaryColumn"]) with graceful fallthrough on timeoutRoot Cause
The failure is intermittent, not permanent. Likely causes include Twitter A/B tests, timing race conditions (pathname not updated when checked), or browser/session state differences. In my testing, pushState failed consistently at first, then succeeded consistently later — consistent with server-side variation.
Changes
primaryColumnselector wait in a try/catch so a timeout doesn't throw immediately — it falls through to the path checklivefilter with the fallback path, click the "Latest" tab after navigationTesting
Fixes #690