Repository navigation
[HOLD for payment 2024-04-15] [$500] Characters missing when typing message in compose box #37356
Description
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Coming from here where we were able to document reliable reproduction steps.
Version Number:
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL:
Issue reported by: @mallenexpensify
Slack conversation: here
Reproduction Steps
- Open Script Editor (Mac)
- New Document > Paste the following script
on run
set textToType to "JUMP "
repeat
emulateTyping(textToType)
delay 1
end repeat
end run
on emulateTyping(textToType)
tell application "System Events"
repeat with i from 1 to count of characters of textToType
set currentChar to character i of textToType
keystroke currentChar
delay 1
end repeat
end tell
end emulateTyping- Press the play button (run the script)
- Focus the desktop newDot app composer
- Wait until you observe that a letter from the word 'JUMP' is being omitted after being typed.
Expected result:
The word 'JUMP' needs to be typed with consistency in the composer. ignore the first word it is because we had a delay when focusing the input.
Actual result:
After a few tries character gets omitted and the word becomes inconsistent. i.e. JUMP JUMP JMP
Screen.Recording.2024-02-22.at.11.35.41.AM.mov
Platforms:
Which of our officially supported platforms is this issue occurring on?
- Android: Native
- Android: mWeb Chrome
- iOS: Native
- iOS: mWeb Safari
- MacOS: Chrome / Safari
- MacOS: Desktop
Screenshots/Videos
View the other issue.
Additional Deliverable
From here
FWIW the issue also occurred when editing the message, I think that should also be fixed in this post.
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~0104493dfd4225a65e
- Upwork Job ID: 1763648489851805696
- Last Price Increase: 2024-03-13
- Automatic offers:
- getusha | Reviewer | 0
- tienifr | Contributor | 0
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsCRITICAL
Activity
melvin-bot commentedon Feb 27, 2024
Triggered auto assignment to @johncschuster (
Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.mallenexpensify commentedon Feb 27, 2024
@johncschuster, I'll take this, I have context from the issue this came form, and the bug.
wildan-m commentedon Feb 29, 2024
Proposal
Please re-state the problem that we are trying to solve in this issue.
Characters missing when typing message in compose box
What is the root cause of that problem?
Race conditions occur when updating the composer value by typing and updating the value from the Onyx draft.
In the main composer, the
SilentCommentUpdaterupdate can be triggered when the user types at a debounce interval.App/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx
Lines 34 to 36 in b7a230e
When editing chat, this is the culprit that causes it to behave similarly to the main composer.
App/src/pages/home/report/ReportActionItemMessageEdit.tsx
Lines 129 to 131 in b7a230e
The problem is that when typing a comment, the value from the composer will be more recent than the updates above, which means the above updates might use outdated value.
What changes do you think we should make in order to solve the problem?
Ensure the updated value is not outdated by using Composer's most recent value when the user is actively typing.
Track the current user's typing status with the
useTypingStatushook:In
ComposerWithSuggestion, we can initiate track typing withinonChangeTextPass the
isTypingRefto theSilentCommentUpdater.and use
commentRef.currentwhen the user is typingWhen editing
ReportActionItemMessageEdit.tsx, we can update this code to utilizetextInputRef.current?.valueduring active typing.Trigger the typing tracking here.
Or perform early return when isTypingRef.current === true
Branch to test
What alternative solutions did you explore? (Optional)
Alternative 1
We can remove the
shouldDebounceSaveCommentfeature and its functiondebouncedSaveReportComment. Though it functions, it will revert us to the pre-optimized state, resulting in noticeable lag as the method will be executed for each character.GMT20240229-024116_Clip_Wildan.M.s.Clip.02_29_2024.mp4
Alternative 2
What if we set the
trailingtofalseandleadingtotrue?It means the debounced function will be invoked immediately when the event occurs, and then it will be debounced for subsequent calls.
It will not miss a keystroke, but the onyx
saveReportCommentdata will not be properly updated, as it will not call the method at the end of the debounce trailing phase.The issue illustrated in this video
GMT20240229-031351_Clip_Wildan.M.s.Clip.02_29_2024.mp4
Better solution
We can trigger the
saveReportCommentfunction in both theleadingandtrailingphases to ensure setState doesn't missed important invocation.Change this lines:
App/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx
Lines 322 to 328 in 3e74ddf
To
Also implement this modification in src/pages/home/report/ReportActionItemMessageEdit.tsx for
debouncedSaveDraftTest with 'JUMP' at 1-second typing interval.
GMT20240229-023310_Clip_Wildan.M.s.Clip.02_29_2024.mp4
Test with paragraph at 100 millisecond typing interval
GMT20240229-022734_Clip_Wildan.M.s.Clip.02_29_2024.mp4
jeremy-croff commentedon Feb 29, 2024
I would like to explain why your solution seems fail to reproduce, but not mitigate the bug:
Specifically note from the docs the following:
If leading and trailing options are true, func is invoked on the trailing edge of the timeout only if the debounced function is invoked more than once during the wait timeout.If you type 1 character per second, and the wait is 1 second, it will now never call the debounce. I think we see a few of those occurrences in your video.
If we review this report https://ellenaua.medium.com/throttle-debounce-behavior-lodash-6bcae1494e03 it shows how the debounce also now no longer reliable runs at the 1 second interval as is required to actually reproduce the bug with the script.
wildan-m commentedon Feb 29, 2024
@jeremy-croff Thanks for your comment. To help readers stay focused, I filter my console log with the 'wildebug' keyword. This is my personal debug code.
jeremy-croff commentedon Feb 29, 2024
Thank you and my apologies, I edited my wording a bit in the same train of thought. I also deleted my original proposal and have a new one to consider:
Proposal
Please re-state the problem that we are trying to solve in this issue.
We are missing characters when typing
What is the root cause of that problem?
These three compete with what's on the screen, what should get debounced, and what's in the store.
To reproduce the bug, we we maximize the draft saving lifecycles, to trigger rerenders, which occur each time you wait >1 sec because the debounce, Let's say you type a character before that change is reflected on the input 1. a debounce will save it, but it gets wiped while it repaints from onyx. And after the repaint 2. changeText is detected and now the debounce will just simply save the text with the missing character.
I was able to isolate the related code early on here in the original thread.
What changes do you think we should make in order to solve the problem?
When reviewing a solution, I wanted to decouples these 3 factors,
I came up with the following:
useEffect(() => _.debounce((selectedReportID) => Report.saveReportComment(selectedReportID, value || ''), 1000), [value]);note: value is the existing state variable that we set on text update here or directly from the onyx store here
melvin-bot commentedon Mar 1, 2024
Job added to Upwork: https://www.upwork.com/jobs/~0104493dfd4225a65e
76 remaining items
melvin-bot commentedon Apr 8, 2024
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
mallenexpensify commentedon Apr 17, 2024
Contributor: @tienifr paid $500 via Upwork
Contributor+: @getusha paid $500 via Upwork
I created the TestRail GH with the test steps below from the PR, comment if there are better steps.
@getusha, please complete the rest of the BZ checklist above. thx
Tests
getusha commentedon Apr 21, 2024
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
[@getusha] The PR that introduced the bug has been identified. Link to the PR: #25758
[@getusha] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment: https://github.com/Expensify/App/pull/25758/files#r1573699887
[@getusha] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion: N/a, this is hard to reproduce and catch. i don't think we need other actions to be taken other than adding the tests steps.