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

ERA-7998: List activity for an incident #813

Merged
merged 24 commits into from
Dec 21, 2022
Merged

ERA-7998: List activity for an incident #813

merged 24 commits into from
Dec 21, 2022

Conversation

luixlive
Copy link
Contributor

@luixlive luixlive commented Dec 13, 2022

@luixlive luixlive marked this pull request as draft December 13, 2022 22:14
@luixlive luixlive marked this pull request as ready for review December 14, 2022 22:24
Copy link
Collaborator

@JoshuaVulcan JoshuaVulcan left a comment

Choose a reason for hiding this comment

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

Overall, looks amazing and will be very very useful!

I left a few questions/comments/bits of feedback to address.

@@ -0,0 +1,167 @@
import React, { memo, useCallback, useEffect, useMemo } from 'react';
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's already a ReportListItem component, do we feel like this is going to be confusing?
And/or is this different enough, functionality-wise, to justify its own component as opposed to just reconciling it into the main ReportListItem instead? Then we could explore fun things like injecting the report preview accordion in other places as well...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm I would say this is different enough, specially because of the accordion, but Idk, if you think that may be reused I can merge those two components. I fear we will end up with a pretty big ugly file and don't even take advantage of having merged them.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd personally recommend having the accordion panel content as a separate component, affiliated with the ReportListItem, and reconcile the two together.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds nice, I'm creating a new global ReportFormSummary that receives report and schema as props, so we can reuse this new way of reading the form values 👍 So now this file is only the "reconciliator" that puts the existing ReportListItem within an accordion header and the new ReportFormSummary in its panel content


.nonSchemaField {
width: 50%;
display: flex;
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: alphabetical order is neat for CSS properties

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixing this PR and doing that from now on. I'm really into alphabetical ordering stuff haha

@@ -13,38 +18,55 @@ jest.mock('../../utils/file', () => ({
fetchImageAsBase64FromUrl: jest.fn(),
}));

const server = setupServer(
rest.get(
Copy link
Collaborator

Choose a reason for hiding this comment

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

How are you feeling about our use of msw?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

100 times better than mocking redux actions. However, Redux is still a pain because in our tests we don't mock our entire redux store, so even though msw mocks the response, we don't have the full store funcitonality of storing the backend data in redux and providing it to the component. This is a limitation to do a full test of certain flows. Anyway, is not a big issue, we can still divide that in two tests: one with the mocked store without data and one with the data preloaded in the test.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I'm thinking we'll want to make a slow transition away from mockStore and to just use our real store instead. We honestly don't even use mockStore much for its purpose as intended (checking which actions were dispatched etc), just as a bad placeholder for a store.

Once we're using a real store, the full and actual in situ behavior of a live component can be tested in our test suites, which is awesome.


expect(reportCollapse).toHaveClass('collapse');

const expandButton = (await screen.findAllByText('arrow-down-simple.svg'))[2];
Copy link
Collaborator

Choose a reason for hiding this comment

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

A couple things:

  1. This should just be a single arrow, rotated with CSS.
  2. You'll need to find a different selector for that element once you've done Develop #1. This is a pretty meh selector anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you referenced the wrong PR there. Hmm how would you select the icon? I could add a data-testid. That would make it unique, so I won't have an array, but still feels meh to me 😂

Copy link
Collaborator

@JoshuaVulcan JoshuaVulcan Dec 15, 2022

Choose a reason for hiding this comment

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

lol that was just me typing # 1 and GitHub trying to be smart about it

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think something more closely following the ARIA guidelines for accordions would yield a number of healthy test selectors.

https://www.w3.org/WAI/ARIA/apg/example-index/accordion/accordion.html

@@ -133,7 +181,7 @@ describe('ReportManager - ActivitySection', () => {

expect(noteCollapse).toHaveClass('collapse');

const expandButton = (await screen.findAllByText('arrow-down-simple.svg'))[3];
const expandButton = (await screen.findAllByText('arrow-down-simple.svg'))[4];
Copy link
Collaborator

Choose a reason for hiding this comment

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

These indexed selectors (findAllByWhatever('hi')[3], findAllByWhatever('hi')[4] etc) have an extremely weak contract as being accurate representations of their elements. We need a better selection pattern.

@@ -127,6 +127,22 @@
height: 1.375rem;
width: 1.375rem;
}

&.priority-300 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any way to steal this from the other places it's defined in the project?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm I could take a look on how to reuse that CSS. Not an expert with SCSS honestly but I see we already have some mixins for buttons and stuff.

schema={reportSchemas?.schema}
showErrorList={false}
templates={{
ArrayFieldItemTemplate,
Copy link
Collaborator

Choose a reason for hiding this comment

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

So much of this form definition is recycled from elsewhere. Any way to componentize it for regular reuse?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think it's worth it? We can define a CustomForm that is simply the Form implementing the custom components and spreading the ...rest props. It won't do a lot, it's another file to mantain, but we will hide this repetitiveness you mention.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That, or capturing the form defaults in a constant which are spread into this form where it's invoked. Or a combination of the two: define the defaults, give them to a component, use that component as the default form component with overrides available.

</div>
</div>

{reportSchemas?.schema && <Form
Copy link
Collaborator

Choose a reason for hiding this comment

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

What would the level of effort be on concealing empty fields? It seems like we'd need to pass custom input components which are self-concealing when empty, which is kind of a PITA but maybe worth it to avoid things like this:
Screen Shot 2022-12-14 at 3 47 59 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's tricky. Hiding it through CSS, if possible, would require a lot of rules. Doing it through the custom components, we would need some new flag that tells the custom component if it is a non editable form print like this, so we can decide not to render the field vs the normal form where eve if it is empty we want the field to show up so the user can edit its value.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hiding it through CSS, if possible, would require a lot of rules

Funny, that seems like the lazy/cheap way to me. Add an "empty" class to field templates with no values, then select and style those specifically in the context of this panel

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this but it's not that simple 😢 I can add the class and try to hide it, display none, etc... But since react-jsonschema-form injects several divs with different grid classes and other stuff, it's really hard to rearrange the form ignoring the empty fields. There's actually an on-going conversation on their repo about this. It is possible to ui:widget: hidden but custom components don't override their uiSchema: rjsf-team/react-jsonschema-form#1236

…omponents, for re-use throughout the new report UI .🤷
…e to refactor them appropriately. minor tweaks to de-anonymize the return values of the useListSortWithButton hook, thus preventing excess renders.
Copy link
Contributor

@Alcoto95 Alcoto95 left a comment

Choose a reason for hiding this comment

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

LGTM 🎉

@JoshuaVulcan
Copy link
Collaborator

@luixlive just want to call out this ticket comment as something we need to get solid before proceeding

@JoshuaVulcan
Copy link
Collaborator

choppy-collapse-animation

Looks like a little chop at the end of the collapse animation

@Alcoto95
Copy link
Contributor

@luixlive
Just a comment, will revisit this. I see that the issue for editing just Longitude in events location is happening again:

It is sending only the longitude in the location object. I guess this is more of a question as I don't see the issue in develop (2-64-1 right now), nor Stage (2-63-1 right now). In case you can have a look.

If it can't be solved in this ticket please let me know so that I can reopen the bug 🙌

Screen Shot 2022-12-16 at 11 53 44

Screen Shot 2022-12-16 at 11 53 53

@JoshuaVulcan
Copy link
Collaborator

JoshuaVulcan commented Dec 16, 2022

@luixlive Just a comment, will revisit this. I see that the issue for editing just Longitude in events location is happening again:

It is sending only the longitude in the location object. I guess this is more of a question as I don't see the issue in develop (2-64-1 right now), nor Stage (2-63-1 right now). In case you can have a look.

If it can't be solved in this ticket please let me know so that I can reopen the bug 🙌

Screen Shot 2022-12-16 at 11 53 44 Screen Shot 2022-12-16 at 11 53 53

@Alcoto95 Don't worry about this for now, the hotfix for the location prop currently going into 2.62 (which will then go down into develop and thus up into this branch) includes fixing this.

@luixlive
Copy link
Contributor Author

Ready for new review. But:
1- The pipeline failed. I see you sent a commit fixing the pipeline in another PR, could it be the same thing here @JoshuaVulcan ?
2- @Alcoto95 comment hasn't been addressed. Should we fix that here? Seems out of the scope and I doubt it was injected here.

@Alcoto95
Copy link
Contributor

Alright! Thanks!

Copy link
Collaborator

@JoshuaVulcan JoshuaVulcan left a comment

Choose a reason for hiding this comment

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

Some more feedback about test quality+structure

userEvent.click(expandButton);

await waitFor(() => {
expect(reportCollapse).toHaveClass('show');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Testing this css class has no intrinsic link to testing visibility, you just have to take it on faith that a "show" class means something is visible.

We need to assert something something like expect(whatever).toBeVisible()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know how toBeVisible does the validation, but it's not working for this test. Following your suggestions, I should change:
expect(reportCollapse).toHaveClass('collapse'); for expect(reportCollapse).not.toBeVisible();
and
expect(reportCollapse).toHaveClass('show'); for expect(reportCollapse).toBeVisible();
But that doesn't work, even tho I know the test is doing the right thing and the feature works properly 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

For reference (even though we already Slacked about it 🙂 )
Need to add the bootstrap styles to your jsdom rendering by either importing the stylesheet in your test file or adding a jest css plugin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for your answer. Actually, there is an open issue in CRA about this exact scenario (test React Bootstrap Accordion with toBeVisible): facebook/create-react-app#10483 😞

const reportCollapse = await screen.findByTestId('reportManager-activitySection-collapse-d45cb504-4612-41fe-9ea5-f1b423ac3ba4');

await waitFor(() => {
expect(reportCollapse).toHaveClass('collapse');
Copy link
Collaborator

Choose a reason for hiding this comment

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

ditto as above

@@ -181,15 +229,17 @@ describe('ReportManager - ActivitySection', () => {
const itemsText = (await screen.findAllByRole('listitem')).map((item) => item.textContent.split(' ')[0]);

expect(itemsText).toEqual([
'note.svgNew',
Copy link
Collaborator

Choose a reason for hiding this comment

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

These matchers are not great. Each list item has the text of their icon's name, the name of the file etc, their "new" indicator, etc, all squished together in a weird string. They're also unnecessarily long for showing a basic sort. Can we clean this up to be more legible? Take some known quantities, select for them more cleanly, and assert their position in the list.

@@ -25,6 +25,7 @@ describe('useReport', () => {
</Provider>
);

expect((await screen.findByTestId('report-data'))).toHaveTextContent('{"displayTitle":"Light","eventTypeTitle":"Light"}');
expect((await screen.findByTestId('report-data')))
.toHaveTextContent('{"coordinates":[-104.19557197413907,20.75709101172957],"displayPriority":300,"displayTitle":"Light","eventTypeTitle":"Light"}');
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test should really be rewritten using renderHook

Copy link
Collaborator

@JoshuaVulcan JoshuaVulcan left a comment

Choose a reason for hiding this comment

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

Looking good. nice work


expect((await screen.findByTestId('report-data'))).toHaveTextContent('{"displayTitle":"Light","eventTypeTitle":"Light"}');
expect(result.current).toEqual({
coordinates: [-104.19557197413907, 20.75709101172957],
Copy link
Collaborator

Choose a reason for hiding this comment

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

So much better!

@luixlive luixlive merged commit 26710da into develop Dec 21, 2022
@luixlive luixlive deleted the ERA-7998 branch December 21, 2022 17:26
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.

3 participants