fix: prevent report field value from referencing itself#72375
Conversation
Codecov Report❌ Patch coverage is
... and 5 files with indirect coverage changes 🚀 New features to boost your workflow:
|
|
I'll add unit test soon |
|
@dubielzyk-expensify @DylanDylann One of you needs to 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] |
|
Videos are looking good to me 👍 |
|
I have bumped in Slack for a C+ review |
|
Reviewing ... |
|
@NJ-2020 I get this error in the second test. Do you also have it? Screen.Recording.2025-10-27.at.17.18.51.movCan you please merge from main? and see if you still have the issue? |
|
@DylanDylann Done, I've addressed all the comments ✅ |
| // If fieldList has only 1 item, it means only the default (undeletable) field exists, so fall back to a simple check (direct self-reference only) | ||
| if (isEmptyObject(fieldList) || Object.keys(fieldList ?? {}).length === 1) { | ||
| return formulaValues.some((formula) => { | ||
| const fieldPath = parsePart(formula).fieldPath; | ||
| return fieldPath.includes(fieldName); | ||
| }); | ||
| } |
There was a problem hiding this comment.
This if block is causing the issue below. I’m wondering if it’s actually necessary — should we consider removing it?
Screen.Recording.2025-11-04.at.19.04.21.mov
There was a problem hiding this comment.
Okay, removed the check condition ✅
Thank you
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2025-11-04.at.19.34.12.movAndroid: mWeb ChromeScreen.Recording.2025-11-04.at.19.20.17.moviOS: HybridAppiOS: mWeb SafariScreen.Recording.2025-11-04.at.19.21.42.movMacOS: Chrome / SafariScreen.Recording.2025-11-04.at.19.15.07.movMacOS: DesktopScreen.Recording.2025-11-04.at.19.24.03.mov |
|
@neil-marcellini I noticed a delay issue — we need to reload the page for the report fields that use formulas to display updated values Screen.Recording.2025-11-04.at.19.15.07.mov |
joekaufmanexpensify
left a comment
There was a problem hiding this comment.
Good from a product perspective
neil-marcellini
left a comment
There was a problem hiding this comment.
Looks great, thank you. There are a few things I would like to see changed, but they don't need to block this at the moment. Please fix them before we merge, or create a follow up PR for those items.
| * Check if the report field formula value is containing circular references, e.g example: A -> A, A->B->A, A->B->C->A, etc | ||
| */ | ||
| function hasCircularReferences(fieldValue: string, fieldName: string, fieldList?: FieldList): boolean { | ||
| const formulaValues = extract(fieldValue); |
There was a problem hiding this comment.
NAB: I would prefer to call these formulaParts because that's what we call them in the backend. Also, the value of a formula reportField is it's computed value, not it's default value / the definition of the formula, so that adds to the confusion with this variable name.
There was a problem hiding this comment.
I see we parse them into parts later, so maybe we call them something like formulaPartDefinitions instead?
| return false; | ||
| } | ||
|
|
||
| const visitedLists = new Set<string>(); |
There was a problem hiding this comment.
NAB: Can we please call this visitedFields instead?
| if (referencedField?.defaultValue) { | ||
| // Recursively check the referenced field | ||
| if (hasCircularReferencesRecursive(referencedField.defaultValue, referencedFieldName)) { | ||
| visitedLists.delete(currentFieldName); |
There was a problem hiding this comment.
I think we should remove this code as Dylan mentioned. It's unnecessary and therefore a little confusing.
| expect(hasCircularReferences('{field:test-o}', 'test-example', fieldList)).toBe(false); | ||
| }); | ||
|
|
||
| test('should return false when no references', () => { |
There was a problem hiding this comment.
What do you mean "no references"? I think you mean "no circular references".
|
I noticed the Reassure performance test timed out and had this message. |
|
@neil-marcellini looks like this was merged without a test passing. Please add a note explaining why this was done and remove the |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/neil-marcellini in version: 9.2.47-0 🚀
|
|
🚀 Deployed to production by https://github.com/cristipaval in version: 9.2.47-1 🚀
|
|
It looked to me like all the tests were passing when I merged it, so not sure what happened there. The tests are passing on more recent PRs so it's all good. |
Explanation of Change
Add validation to prevent formulas from referencing themselves
Fixed Issues
$ #70775
PROPOSAL: #70775 (comment)
Tests
Initial/Default value
Self Reference
Circular Reference
2 circular/references
{field:B} or field Bis not created yet)More than 2 circular/references
{field:B} or field Bis not created yet){field:C} or field Cis not created yet)No references
{field:B}is created and the default/initial value is set to empty >""or no formula circular field)Report field value / report expense
A, A > A, A > B > AOffline tests
Same as Tests
QA Steps
Same as Tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, 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.ScrollViewcomponent to make it scrollable when more elements are added to the page.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
Screen.Recording.2025-10-16.at.10.online-video-cutter.com.mp4
Android: mWeb Chrome
Screen.Recording.2025-10-16.at.09.49.55.mp4
iOS: Native
Screen.Recording.2025-10-16.at.10.44.52.mp4
iOS: mWeb Safari
Screen.Recording.2025-10-16.at.10.49.38.mp4
MacOS: Chrome / Safari
Screen.Recording.2025-10-16.at.09.25.18.mp4
MacOS: Desktop
Screen.Recording.2025-10-16.at.09.18.15.mp4