chore: refactor observation fields#1903
Conversation
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
|
im not sure why, but the front end integration test is failing on CI, but is not faiing locally. Can you try running the tests locally @cimigree
|
Yes they pass for me too. I can look into it as I review |
OK! I think the problem is because we mock/create individual instances of the entire backend in our tests. Since we are doing that, we never install the the backend packages when running the front end CI tests. I was importing the categories for the tests via the backend packages. That is also why it was working locally, because we both have those packages installed locally. To fix this, i just added the default categories as a dev dep to the front end, and updated the import in the tests |
cimigree
left a comment
There was a problem hiding this comment.
Nice refactor!
Applies the guidelines, as you said.
Sub-components now take agnostic props, logic lives at the top level,
<Question> confusion is gone
Lots of great new integration tests.
Cautions
We will need to make sure that if the default-categories update, we update them in our frontend, i.e., keep them in sync manually.
The tests rely on real categories, which is probably fine, but if they change, the test will need to change.
Questions/ Cautions
The Android hardware back button goes back to the Observation screen instead of the previous question. Is that intentional?
Number now stores a float instead of a string. Are you sure that is merited?
Must Change
I am worried about someone entering incomplete info in the number field accidentally. Just a negative sign, or just a point (.) or -0. and it will be not a number. I can't test what actually happens because we don't have any number fields in the default categories, but will it crash the app? It definitely fails an integration test. It can be easily guarded against with isFinite(and check the input).
And then you can add a test to check those inputs.
And other little changes, see below.
| const field = fields.find(val => val.docId === fieldIds[current - 1]); | ||
|
|
||
| if (!field) { | ||
| // should throw error here |
There was a problem hiding this comment.
probably should remove comment and throw error
| <HeaderText variant="header3"> | ||
| <FormattedFieldProp field={field} propName="label" /> | ||
| </HeaderText> | ||
| {<HeaderText variant="header5">{field.helperText}</HeaderText>} |
There was a problem hiding this comment.
You know what...i didn't realize that these were superflous wrapper. I think they were created in legacy mapeo with an attempt to guarantee a label, when labels were optional. but now labels are mandatory, so i think i can just get rid of the wrapper completely
There was a problem hiding this comment.
i removed all the wrappers entirely, which means i had to refactor a couple more pages. They were a remnant of the mapeo and they were really convoluted.
I also wrote several tests related to showing these details in an observation
| headerTitle: formatMessage(m.title, {current, total: fieldIds.length}), | ||
| headerLeft: props => ( | ||
| <CustomHeaderLeft headerBackButtonProps={props} onPress={onBackPress} /> | ||
| <CustomHeaderLeft |
There was a problem hiding this comment.
So now the android back button goes away from the details and back to the Observation screen (as far as I can tell) when it used to do the same thing as the header back button, that is go back one question. Is this your intention?
| .replace(/[^0-9.-]/g, '') // Allow digits, decimal, and negative sign | ||
| .replace(/(?!^)-/g, '') // Remove any minus sign that is not at the start | ||
| .replace(/(\..*?)\./g, '$1'), // Remove additional decimal points | ||
| parseFloat( |
There was a problem hiding this comment.
parseFloat('-'), parseFloat('.'), and parseFloat('-0.') all return NaN It would be good to put something here so incomplete input doesn't save NaN into the observation tags
There was a problem hiding this comment.
Wow number are annoying. I added so many tests to catch the edge cases! But also the tests made it really easy to find edge cases and determine if it breaks things!
| testID="OBS.details-inp" | ||
| value={typeof value === 'string' ? value : ''} | ||
| testID="OBS.number-inp" | ||
| value={typeof tagValue === 'number' ? String(tagValue) : ''} |
There was a problem hiding this comment.
If someone is editing an existing observation that has a number field, it will show a blank field because this value used to be saved as a string.
| .replace(/[^0-9.-]/g, '') // Allow digits, decimal, and negative sign | ||
| .replace(/(?!^)-/g, '') // Remove any minus sign that is not at the start | ||
| .replace(/(\..*?)\./g, '$1'), // Remove additional decimal points | ||
| parseFloat( |
There was a problem hiding this comment.
This field used to be stored as a string but now it will be stored as a float. That does make sense, but it is a change. Is that for sure intentional?
There was a problem hiding this comment.
handled now. if the value is a string (that can be parsed as a number) it will show the value. and then if they update the value, that string will be updated to a number. 33d8f7d
| const details = await screen.findByText('Details'); | ||
| await user.press(details); | ||
|
|
||
| // through manually clicking through the app, I know that this should be a text input |
There was a problem hiding this comment.
This code comment should be a little less conversational for posterity...Maybe something like the category type Animal's first field is a text input (animal-notes).
| fireEvent.changeText(screen.getByDisplayValue(''), '1.2.3'); | ||
|
|
||
| expect(updateTag).toHaveBeenCalledWith(1.23); | ||
| }); |
There was a problem hiding this comment.
If you had added fireEvent.changeText(screen.getByDisplayValue(''), '-');
fireEvent.changeText(screen.getByDisplayValue(''), '.');
It would fail... Once you fix that, you can add that test!
There was a problem hiding this comment.
Wow this is quite a refactor!
With the new config I was able to test numbers!
One thing that worked was using the old version of a number (that was a string) and then switching branches to this new version of number (that is a number). I couldn't even tell it was processing. All worked as expected.
BUT,
I am having 2 issues with numbers.
- is that I cannot enter negative numbers using the keyboard given. Not sure if that is a problem. I can paste them in... Not sure if that is expected. So regex makes sense to keep but wondering about use case and needing negative numbers. It may be related to the numeric keyboard type. But I am not sure.
- If I have a number in place and then I erase it so that there is no number (because I want to have "no answer") then it doesn't work. The first digit from the previous entry is kept and cannot be cleared. I can type 0 as a work around but I am not sure how intuitive that is and may be misleading or not what a user wants. See video.
Screen_Recording_20260528_180406_CoMapeo.Dev.mp4
Also, my local jest tests are failing.
FAIL src/frontend/screens/ComapeoSettings/index.test.tsx (5.355 s)
● CoMapeo Settings Screen › opens drawer when header button is pressed
TypeError: (0 , _reactNative.renderAsync) is not a function
49 | onTeardown.push(appProviders.teardown);
And
FAIL src/frontend/screens/ObservationFields/index.test.tsx
● Test suite failed to run
Cannot find module '@comapeo/default-categories/package.json' from 'src/frontend/screens/ObservationFields/index.test.tsx'
4 |
5 | const DEFAULT_CONFIG_PATH = path.join(
> 6 | path.dirname(require.resolve('@comapeo/default-categories/package.json')),
| ^
7 | 'dist/comapeo-default-categories.comapeocat',
8 | );
9 |
at Resolver._throwModNotFoundError (node_modules/jest-resolve/build/resolver.js:427:11)
at Object.resolve (src/frontend/screens/ObservationFields/index.test.tsx:6:24)
And a bunch of tests on Browserstack are failing. Not sure if that is flakiness or the tests because it is Observations that are failing.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
@cimigree this number issue seems device specific. I have updated the pr to be similar to the previous implementation. Can you try using numbers on |
cimigree
left a comment
There was a problem hiding this comment.
It actually works fine on develop and on Samsung. Seems like all is fixed. I tested all manually though I see there are so many new and thorough tests. Way to go!
One non blocking comment!
| .replace(/[^0-9.-]/g, '') // Allow digits, decimal, and negative sign | ||
| .replace(/(?!^)-/g, '') // Remove any minus sign that is not at the start | ||
| .replace(/(\..*?)\./g, '$1') // Remove additional decimal points | ||
| // .replace(/^(-?)\./, '$10.') // Prefix bare decimal with 0 |
There was a problem hiding this comment.
I think this line that you commented out was the one that was breaking the functionality on the Samsung. Can you just delete it instead of leaving it commented out?



closes: #1882
I refactored the Observation Fields to follow our new guidelines.
Previously the ObservationField screen had several nested components. Those nested components had several unnecessary props.
This refactors introduces only one level of nesting, and the nested components have agnostic props instead of passing the entire
fieldobject.I also created several tests. A general integration test that mounts the entire navigation, and tests the observation fields in a normal user interaction. As well as individual tests for each of the smaller components