Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[No QA] Add sanitizeStringForJSONParse and use it in getMergeLogsAsJSON #14351

Merged
merged 15 commits into from
Jan 18, 2023

Conversation

yuwenmemon
Copy link
Contributor

@yuwenmemon yuwenmemon commented Jan 17, 2023

@roryabraham please review
cc @francoisl @chiragsalian @AndrewGable

Details

Fix discussed here: https://expensify.slack.com/archives/C07J32337/p1670871959612579

Create a function to make strings safe for getMergeLogsAsJSON's JSON.parse call. Add unit test guardrails around it so we can make it more robust looking forward into the future.

Fixed Issues

$ #13649

Tests/QA

  • Added unit tests
  • Will be tested as part of the Deploy process

Offline tests

  • N/A

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android / native
    • Android / Chrome
    • iOS / native
    • iOS / Safari
    • MacOS / Chrome / Safari
    • MacOS / Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is correct English and approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.

Screenshots/Videos

Web

-N/A

Mobile Web - Chrome

-N/A

Mobile Web - Safari

-N/A

Desktop

-N/A

iOS

-N/A

Android

-N/A

@yuwenmemon yuwenmemon self-assigned this Jan 17, 2023
@yuwenmemon yuwenmemon requested a review from a team as a code owner January 17, 2023 01:11
@melvin-bot melvin-bot bot requested review from amyevans and sobitneupane and removed request for a team January 17, 2023 01:12
@melvin-bot
Copy link

melvin-bot bot commented Jan 17, 2023

@sobitneupane @amyevans 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]

@yuwenmemon yuwenmemon force-pushed the yuwen-sanitizeStringForJSONParse branch from 6cb62ff to ce5e791 Compare January 17, 2023 01:35
*/
function sanitizeStringForJSONParse(inputString) {
if (!inputString || typeof inputString !== 'string') {
return '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB but maybe it's better to just throw an error rather than returning an empty string

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

tests/unit/sanitizeStringForJSONParseTest.js Show resolved Hide resolved
.github/libs/GitUtils.js Outdated Show resolved Hide resolved
yuwenmemon and others added 2 commits January 16, 2023 17:39
Co-authored-by: Rory Abraham <47436092+roryabraham@users.noreply.github.com>
* @param {String} inputString
* @returns {String}
*/
export default function (inputString) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, that's annoying... Here's what I think is happening there:

  • src/libs/sanitizeStringForJSONParse.js is written as an ES6 module ("native JavaScript module", import/export).
  • Normally CommonJS (CJS) modules ("Node.js modules", require/module.exports) cannot understand ES6 modules. We can import ES6 modules in some cases (such as in the GitHub Actions) when the code importing that ES6 module is preprocessed by babel, ncc, or some other compile-time bundler.
  • Furthermore, newer versions of Node.js can understand ES6 modules if they're in a file ending with .mjs instead of just .js
  • The test you're looking at executes JavaScript via a Node.JS wrapper script here (note the file ending in MJS allows Node to understand ES6 modules, but only for that file)
  • Recall that when JavaScript files are imported, they are immediately evaluated. So when the .mjs file tries to import the .js file, it defaults back to reading in CJS and then barfs when it sees the export keyword

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always so confusing. I'm not sure the best way to make a javascript library reusable between ES6 and CJS, but I know there's a way to do it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for now the path-of-least resistance to fix this would be to:

  • Move src/libs/sanitizeStringForJSONParse.js to .github/libs/sanitizeStringForJSONParse.js
  • Convert .github/libs/sanitizeStringForJSONParse.js to a CJS module (replace export default ... with module.exports = ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecating .github/libs and providing a cleaner way to share JS code between the main application and the GitHub Actions could be a good future project.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @roryabraham approach sounds great at the moment! I think the github actions in general would deserve some clean up once we get a bit more time

Copy link
Contributor

@mountiny mountiny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank @yuwenmemon for doing this!

* @param {String} inputString
* @returns {String}
*/
export default function (inputString) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @roryabraham approach sounds great at the moment! I think the github actions in general would deserve some clean up once we get a bit more time

*/
function sanitizeStringForJSONParse(inputString) {
if (!inputString || typeof inputString !== 'string') {
return '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@yuwenmemon yuwenmemon force-pushed the yuwen-sanitizeStringForJSONParse branch 2 times, most recently from 5099e4e to 7ea43c3 Compare January 17, 2023 19:24
@yuwenmemon yuwenmemon force-pushed the yuwen-sanitizeStringForJSONParse branch from 7ea43c3 to 8dd8b30 Compare January 17, 2023 19:37
@yuwenmemon
Copy link
Contributor Author

Thanks folks! Updated!

Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

tests/unit/sanitizeStringForJSONParseTest.js Show resolved Hide resolved
@roryabraham
Copy link
Contributor

roryabraham commented Jan 18, 2023

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • Android / native
    • Android / Chrome
    • iOS / native
    • iOS / Safari
    • MacOS / Chrome / Safari
    • MacOS / Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is correct English and approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

No screenshots for this GitHub Actions change.

Web
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
Android

@roryabraham roryabraham merged commit e62a79f into main Jan 18, 2023
@roryabraham roryabraham deleted the yuwen-sanitizeStringForJSONParse branch January 18, 2023 02:33
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@github-actions
Copy link
Contributor

Performance Comparison Report 📊

Significant Changes To Duration

There are no entries

Meaningless Changes To Duration

Show entries
Name Duration
App start TTI 723.670 ms → 767.619 ms (+43.949 ms, +6.1%)
Open Search Page TTI 598.222 ms → 613.731 ms (+15.509 ms, +2.6%)
App start runJsBundle 201.563 ms → 208.719 ms (+7.156 ms, +3.6%)
App start nativeLaunch 19.871 ms → 20.806 ms (+0.935 ms, +4.7%)
App start regularAppStart 0.016 ms → 0.018 ms (+0.001 ms, +8.9%)
Show details
Name Duration
App start TTI Baseline
Mean: 723.670 ms
Stdev: 27.358 ms (3.8%)
Runs: 659.8702099998482 679.6202569999732 684.9619049998 693.5796500002034 695.3970769997686 697.7864620001055 705.4435180001892 706.307312999852 707.2849790002219 707.6792819998227 709.026783999987 717.6798249999993 720.6695730001666 724.1477979999036 725.48075899994 725.940810999833 726.2558889999054 727.5790079999715 734.0382840000093 737.0590070001781 737.402515000198 737.6690110000782 739.3471610001288 741.9133299998939 744.1360249998979 750.9654700001702 754.1084529999644 757.3213390000165 772.3010329999961 789.1221239999868

Current
Mean: 767.619 ms
Stdev: 28.852 ms (3.8%)
Runs: 724.3167489999905 725.3451350000687 726.196140000131 729.8403759999201 736.7550550000742 738.2602479998022 739.0822129999287 741.0187050001696 744.5641520000063 747.8901519998908 751.1559910001233 755.3468100000173 757.0593480002135 759.2951050000265 764.293835000135 770.1098219999112 770.2728510000743 771.2783459997736 771.9995989999734 772.6589330001734 774.1954069999047 779.6903530000709 785.9520879997872 786.0862900000066 787.6135209999047 789.3343670000322 794.6578700002283 795.3165440000594 796.7215060000308 807.8839420001023 825.8750629997812 843.7296330002137
Open Search Page TTI Baseline
Mean: 598.222 ms
Stdev: 26.379 ms (4.4%)
Runs: 548.3822429999709 555.3068450000137 557.0427649999037 559.6176760001108 560.2254640003666 562.8183590001427 577.2958979997784 580.4908050000668 581.6225589998066 582.2801109999418 582.4735520002432 590.9359949999489 591.3597820000723 594.1254079998471 595.6114920000546 602.9552409998141 603.3425700003281 604.1623140000738 607.2198489997536 607.7367759998888 611.8406980000436 613.7058919998817 615.9540199995972 618.7895909999497 619.2489419998601 620.6440840000287 622.0164390001446 622.2346189999953 623.6901449998841 638.087157999631 638.6840820000507 653.2048749998212

Current
Mean: 613.731 ms
Stdev: 17.465 ms (2.8%)
Runs: 574.1333830002695 582.0205899998546 593.2303069997579 595.1947440002114 596.1264240001328 596.5055749998428 600.0931800003164 600.8636470003985 601.8312180000357 603.2212740001269 604.3247480001301 605.6033939998597 609.3877770002 611.1812749998644 614.9498290000483 615.9768069996499 617.0603430001065 617.6016039997339 618.4546720003709 620.7228190000169 620.8396399999037 622.4871020000428 623.3881839998066 624.2510179998353 624.6709389998578 628.4385989997536 629.219768000301 636.1394460001029 637.4346930002794 649.5727949999273 650.7227380000986
App start runJsBundle Baseline
Mean: 201.563 ms
Stdev: 23.068 ms (11.4%)
Runs: 163 172 175 176 177 177 178 181 182 183 186 186 189 191 194 199 201 202 207 212 213 214 215 217 219 221 225 228 232 238 240 257

Current
Mean: 208.719 ms
Stdev: 13.998 ms (6.7%)
Runs: 186 190 192 193 194 194 194 197 198 199 199 201 202 204 205 206 206 210 211 213 213 215 218 218 219 220 221 225 225 232 236 243
App start nativeLaunch Baseline
Mean: 19.871 ms
Stdev: 1.581 ms (8.0%)
Runs: 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 20 20 20 20 20 20 20 20 21 21 21 22 22 23 23 24

Current
Mean: 20.806 ms
Stdev: 2.176 ms (10.5%)
Runs: 18 19 19 19 19 19 19 19 19 19 19 19 20 20 20 20 20 20 20 21 22 22 22 22 22 23 23 24 25 26 26
App start regularAppStart Baseline
Mean: 0.016 ms
Stdev: 0.001 ms (6.7%)
Runs: 0.013711999636143446 0.014688999857753515 0.014810999855399132 0.015177999623119831 0.015381000004708767 0.015381000004708767 0.015543000306934118 0.0157880000770092 0.015910000074654818 0.015950999688357115 0.016153999604284763 0.016276000067591667 0.016276000067591667 0.016276000067591667 0.016439000144600868 0.016439000144600868 0.016479999758303165 0.016642000060528517 0.016681999899446964 0.016805000137537718 0.01696799974888563 0.01696800021454692 0.017048999667167664 0.017292999662458897 0.017374999821186066 0.017659999895840883 0.017903000116348267 0.01794400019571185 0.018188000191003084 0.01887999987229705

Current
Mean: 0.018 ms
Stdev: 0.002 ms (10.3%)
Runs: 0.015665999613702297 0.015747999772429466 0.015787999611347914 0.015910000074654818 0.016112999990582466 0.016276000067591667 0.016316999681293964 0.016398000065237284 0.016561000142246485 0.01664199959486723 0.0167239997535944 0.016764000058174133 0.016805000137537718 0.016805000137537718 0.016927000135183334 0.017008000053465366 0.01725299982354045 0.017374999821186066 0.018066000193357468 0.0181470001116395 0.018554999958723783 0.019001999869942665 0.019002999644726515 0.019247000105679035 0.019328000023961067 0.01949000032618642 0.019857000093907118 0.019979000091552734 0.020223000086843967 0.020345000084489584 0.020589000079780817 0.023559999652206898

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by @roryabraham in version: 1.2.56-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@mvtglobally
Copy link

@yuwenmemon @roryabraham Can you QA this internally?

@yuwenmemon
Copy link
Contributor Author

Ah this [No QA] I guess. Feel free to check it off!

@yuwenmemon yuwenmemon changed the title Add sanitizeStringForJSONParse and use it in getMergeLogsAsJSON [No QA] Add sanitizeStringForJSONParse and use it in getMergeLogsAsJSON Jan 18, 2023
@OSBotify
Copy link
Contributor

🚀 Deployed to production by https://github.com/AndrewGable in version: 1.2.56-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants