Conversation
|
|
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Pass CONST.MAX_MARKUP_LENGTH to all emoji-related parseExpensiMark calls
Add regression coverage for emoji reversion, shortcode replacement, and suggestion detection at the 10,000-character markup limit.
|
There are couple of things I wanna mention:
|
|
@linhvovan29546 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-09-28.at.20.24.51.movAndroid: mWeb ChromeScreen.Recording.2026-09-28.at.20.21.55.moviOS: HybridAppScreen.Recording.2026-09-28.at.20.27.34.moviOS: mWeb SafariScreen.Recording.2026-09-28.at.20.21.19.movMacOS: Chrome / SafariScreen.Recording.2026-09-28.at.20.18.49.mov |
I’m not sure. Since the change only updates the JS, and the Podfile.lock isn’t included in this PR.
Yes. |
When I built the iOS native app locally then the Podfile was updated locally, it might happen because the fingerprint was changed as the
What about this? ccing: @JS00001 for helping on the above
Sure, I'll raise a PR in |
|
I DMd @roryabraham to ask, I'm not sure if mobile needs to be updated or not |
|
@linhvovan29546 do you have access to mobile-expensify? |
Yes |
|
@linhvovan29546 can you please |
We have the diff, but I don’t think it’s related to the issue because the diff I see locally doesn’t involve |
|
Yeah I think these changes would be js only, so we may not need a mobile-e change |
|
@JS00001 What about
I strongly believe to update the
cc: @linhvovan29546 |
|
@Uzaifm127 Ah, it looks like the |
|
@JS00001 The PR update |
|
@linhvovan29546 Yes, doing... |
…0-preserve-markdown-in-long-messages
|
Nice, we'll need to merge this and the mobile-expensify PR together. so lmk when this is ready and I'll merge both |
|
@linhvovan29546 Done with the |
|
merged both PRs, this and mobile-e |
|
🚧 JS00001 has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/JS00001 in version: 9.4.95-0 🚀
|
|
No help site changes are needed for this PR, so I didn't create a docs PR. This PR fixes [$250] Chat - Live markdown in composer is removed if the text exceeds 4000 characters. It changes how the composer parses Markdown internally and raises the live-formatting limit from 4,000 to 10,000 characters. It doesn't add or rename any feature, setting, or button. What I checked
@Uzaifm127, no help site PR was needed, so there is nothing to review or mark |
|
@kavimuru I saw all three recordings. These recordings are from Android native, and they don't reproduce the original issue where live Markdown formatting disappears after 4,000 characters.
I didn't get how the PR is failing with original native bug? TY! cc: @linhvovan29546 |
|
Deploy Blocker #102487 was identified to be related to this PR. |
|
This PR failing because of the issue #102487 |
|
Hi @Uzaifm127. QA team failed test 1 on Native apps with an original issue 1790639298969.14-and-test1.mp4 |
|
@IuliiaHerets Could you please confirm which step in Test 1 is failing? Thanks
|
|
@Uzaifm127 https://applause.enterprise.slack.com/files/WC42FV8MT/F0C4U12LYQ7/14-and-test1.mp4 |
|
@kavimuru I'm still not getting how the PR is failing with the original issue. I've tested on the adhoc build on a real device and I didn't get any issue: PR-test-on-adhoc.mp4I don't have access to the video you shared. Is the QA team copying the text from another application or another application sent message? cc: @linhvovan29546 |
in the meantime, checking it off as the original bug already I'm still not getting how the PR is failing with the original issue on production. |
|
🚀 Deployed to production by https://github.com/Julesssss in version: 9.4.95-4 🚀
|

Explanation of Change
ExpensiMark.replace()was optimized to avoid running the autolink, bold, and strikethrough regexes over the complete text on every change. The scanner first finds small possible URL and Markdown candidates, then the existing ExpensiMark regexes validate and replace only those candidates.This keeps the existing parsing behavior while reducing the work required for long composer messages.
react-native-live-markdownnow allowsparseExpensiMarkfunction callers to provide the maximum length passed toparseExpensiMark.App uses
CONST.MAX_MARKUP_LENGTH, which is10,000characters. This PR passes that value to all the locations in the App that useparseExpensiMarkfor composer Markdown parsing and selected-text formatting, instead of using the library default of4,000.Fixed Issues
$ #95210
PROPOSAL: #95210 (comment)
Tests
Note
The complete composer text, including the Markdown added during testing, must contain more than 4,000 and fewer than 10,000 characters.
Test 1 (All platforms)
Note
Android native has a separate known typing-delay issue with long text, which will be handled in a follow-up. Do not fail this PR because of that delay. For Android native, verify that Markdown remains preserved after 4,000 characters. On the other platforms, also verify that typing remains responsive.
Test 2 (Web)
bold, without selecting the stars (*).Cmd+Bon macOS orCtrl+Bon Windowsitalic, without underscores.Cmd+IorCtrl+I.boldon pressingcmd/ctrl + band becomesitalicon pressingcmd/ctrl + i.Test 3 (All platforms)
`😄`without selecting any existing text.`:smile:`.:smile: and `:wave:`without selecting any existing text.:smile:outside the backticks becomes 😄.:wave:inside the backticks remains unchanged.Test 4 (All platforms)
Note
There are no suggestions in the composer in iOS native app either we type in the code range or outside the code range and this issue also exist in existing main so this Test 4 can't reliably be performed on iOS native. This existing issue only reproducible after composer has 4000 characters.
:smi, for example:`:smi`.:smioutside the backticks.Offline tests
Same as Test
QA Steps
Note
Tests 1, 2, 3 and 4 are the same as the corresponding tests in the
Testssection above.Test 1: Malformed HTML and HTML-boundary parsing
Open the App on Web.
Open the Devtool by right clicking on the App and select a inspect or press
F12.In Chrome DevTools, select the Network tab.
Go to Workspaces > workspace > Members > Invite member.
Enter an email address that is not already a workspace member.
Continue to the invitation message step.
Replace the invitation message with:
Clear the Network panel in devtool.
Click Invite.
Open the
AddMembersToWorkspaceAPI request.Inspect the
welcomeNotein the payload of API.Verify that both
before.comandafter.comare converted into links.Repeat the same test with the following cases:
Case:
*bold* >expected:
*bold* >Case:
~strike~ >expected:
~strike~ >Case:
<unfinished example.com 😄expected:
<unfinished <a href="https://example.com" target="_blank" rel="noreferrer noopener">example.com</a> <emoji>😄</emoji>Test 2: Long invalid
.comxURL candidateaaaaaaaaaaa...... upto 8000 characters then .comx, for example:aaaaaaaa....8000.comxNote
Follow the following steps to copy the correct text to test:
1. Open Chrome DevTools and select the Console tab.
2. Run:
copy('a'.repeat(8496) + '.comx')Type several characters quickly at the end of the text.
Verify that:
.comxis not converted into a link.Repeat the test with:
copy('a'.repeat(8496) + '.com')but make sure to add a space after.comat the end of the text.Verify that the valid
.comtext becomes a link and that typing remains responsive after adding a space at the end.Test 3: Dot-heavy invalid URL candidate
a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.... up to 8000 characters.Note
Follow the following steps to copy the correct text to test:
1. Open Chrome DevTools and select the Console tab.
2. Run:
copy('a.'.repeat(4499) + 'a')Paste the text into the composer.
Type several characters quickly at the end.
Verify that:
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Test 1
Android-native.mov
Test 3
Test-3-Android-native.mp4
Test 4
Test-4-Android-native.mov
Android: mWeb Chrome
Test 1:
android.mweb.mp4
Test 3:
Test-3-Android-mweb.mp4
Test 4:
Test-4-Android-mweb.mov
iOS: Native
Test 1:
ios-native.mp4
Test 3:
Test-3-iOS-native.mov
iOS: mWeb Safari
Test 1:
ios-safari.mp4
Test 3:
Test-3-iOS-mweb.mp4
Test 4:
Test-4-iOS-mweb.mov
MacOS: Chrome / Safari
Test 1:
macOS.web.mp4
Test 2:
Test-2-macOS.mp4
Test 3 (Part 1):
Test-3-macOS-part-1.mp4
Test 3 (Part 2):
Test-3-macOS-part-2.mp4
Test 4:
Test-4-macOS.mp4