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

Break apart workshop.jsx #31990

Merged
merged 41 commits into from
Dec 19, 2019
Merged

Break apart workshop.jsx #31990

merged 41 commits into from
Dec 19, 2019

Conversation

islemaster
Copy link
Contributor

@islemaster islemaster commented Nov 19, 2019

Break the large and fairly entangled Workshop component in workshop.jsx out into many small components. I'm doing this cleanup work in preparation for a behavior change that we haven't scheduled yet but is certainly badly needed: Letting workshop admins change names on enrollments (Jira). We're up to at least five requests for engineers to do this manually, so it's time to make some progress on it.

This change should be a pure refactor.

One benefit of breaking the components apart this way is that they show up with useful names in the React devtools for Chrome:
image

Testing story

There was very little existing coverage of this code. I only found the eyes test workshop_dashboard.feature.

I've added enough unit tests to achieve at least 70% coverage for every extracted component, which should be a big improvement since this is all code that had zero coverage before. Here's unit test coverage for this directory before (Notice that workshop.jsx isn't even on the list):

coverage_before

And here's coverage after:

coverage_after

I've also been doing manual testing of key behaviors on the workshop view throughout the process.

Reviewer Checklist:

  • Tests provide adequate coverage
  • Code is well-commented
  • New features are translatable or updates will not break translations
  • Relevant documentation has been added or updated
  • User impact is well-understood and desirable
  • Pull Request is labeled appropriately
  • Follow-up work items (including potential tech debt) are tracked and linked

.attr('first_name', 'George')
.attr('last_name', 'Dragon')
.attr('school', 'Academy')
.attr('attended', false);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@madelynkasula I ❤️ rosie so far. Thank you for adding this!

Copy link
Contributor

Choose a reason for hiding this comment

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

yayy -- thank you for recommending it!

@@ -9,37 +9,15 @@ import _ from 'lodash';
import PropTypes from 'prop-types';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

GitHub wants to hide this diff because it's too large, but please take a look - simplifying this component is why I think this change is worthwhile.

/**
* View and manage the list of teachers enrolled in a workshop.
*/
export default class EnrollmentsPanel extends React.Component {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: I'm especially excited about extracting EnrollmentsPanel because this is where we'll give admins the ability to change enrollment details in the near future. There's definitely some further simplification that could happen in this component but I picked this as a stopping point since we'll be coming back to it soon anyway.

@islemaster
Copy link
Contributor Author

Note to reviewers: There's no timeline on this and it's a large review, so don't feel a need to look at this right away.

@islemaster islemaster added refactor Better code, no behavior change code-hygiene labels Nov 20, 2019
@islemaster islemaster marked this pull request as ready for review November 22, 2019 16:51
@islemaster islemaster changed the base branch from staging to staging-next November 25, 2019 18:22
@bencodeorg
Copy link
Contributor

bencodeorg commented Dec 7, 2019

This is potentially obvious to PLC people or to people with more React experience (and I think is much more clear in the refactored version), but in case helpful to others here's a table of how I think each of these components get used depending on the status of the workshop:

image

@islemaster islemaster changed the base branch from staging-next to staging December 18, 2019 01:14
const {view, workshop, isWorkshopAdmin, onWorkshopSaved} = this.props;

if (view === 'edit') {
const header = <EditHeader handleSave={this.handleSaveClick} />;
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker. These headers, EditHeader, NotStartedHeader, AdminHeader, DetailsPanelHeader, have multiple nested layers to display a simple text + a button. And what really changes is the button name and its callback function. In this case, I would prefer a flatter component structure (maybe more verbose code) but easier to reason.

/**
* Provides controls for taking attendance in a workshop session.
*/
export default class AttendancePanel extends React.Component {
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that we change file name style, for example AttendancePanel.jsx (new) vs. workshop_enrollment.jsx (old). What is the convention to follow?

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'd like us to move to PascalCase instead of snake_case for JavaScript filenames, as this is the convention other cabals are using.

Copy link
Contributor

@hacodeorg hacodeorg left a comment

Choose a reason for hiding this comment

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

I've just reviewed half of the changes, so far so good :)

* Simple wrapper component for a chunk of related content when
* viewing a workshop.
*/
export default class WorkshopPanel extends React.Component {
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 a great UI abstraction!

Copy link
Contributor

@hacodeorg hacodeorg left a comment

Choose a reason for hiding this comment

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

Phew, done, this PR is a good read. I learn a lot more about workshop page now.

server = null;
});

it('when ready to close', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the purpose of this test and the one below it? Do they test if a component can mount or if a component can be rendered?

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 a quick check that the component renders without errors when given a certain set of props. (By default, our tests fail when console.warn or console.error is called. One common way this happens for React components is PropType failures.) While these definitely are not robust in terms of checking a behavior for the component, I wanted to make sure all possible render paths were covered.

loadEnrollments={loadEnrollments}
/>
);
assert(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: To be symmetrical to the test above, you can assert that spinner is not rendered here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great point! I'll do that.

@@ -385,3 +385,45 @@ export function enforceDocumentBodyCleanup(
describe('', runTestCases);
});
}

/**
* Call in the `describe` block for a group of tests to stub the value of window.dashboard safely.
Copy link
Contributor

Choose a reason for hiding this comment

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

🥇 for the comments!

@islemaster islemaster force-pushed the change-your-own-darn-enrollment branch from 8919629 to 9d647cb Compare December 19, 2019 02:22
Copy link
Contributor

@hacodeorg hacodeorg left a comment

Choose a reason for hiding this comment

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

🎉

@islemaster islemaster merged commit ebc2633 into staging Dec 19, 2019
@islemaster islemaster deleted the change-your-own-darn-enrollment branch December 19, 2019 21:06
islemaster added a commit that referenced this pull request Dec 20, 2019
Restores behavior introduced in
#32453 and regressed
during a complicated rebase in
#31990.  Most of the
change was preserved, but the JSX that actually renders the new
component was accidentally dropped.

I mentioned in the previous PR that I wasn't adding a test for the UI
because I was adding so many tests in the other PR (that regressed
this!) and it would be covered.  Turns out I was wrong!  So now I'm
adding a unit test for the Workshop component that verifies that we show
the created_at date as expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code-hygiene refactor Better code, no behavior change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants