-
Notifications
You must be signed in to change notification settings - Fork 19
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
feat: migrate enzyme to rtl #915
base: master
Are you sure you want to change the base?
Conversation
…al-enterprise into Ali-Abbas/enzyme-to-rtl
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #915 +/- ##
==========================================
- Coverage 84.87% 84.65% -0.22%
==========================================
Files 320 343 +23
Lines 6399 7520 +1121
Branches 1552 1849 +297
==========================================
+ Hits 5431 6366 +935
- Misses 941 1118 +177
- Partials 27 36 +9 ☔ View full report in Codecov by Sentry. |
…al-enterprise into Ali-Abbas/enzyme-to-rtl
…al-enterprise into Ali-Abbas/enzyme-to-rtl
…al-enterprise into Ali-Abbas/enzyme-to-rtl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR, @Syed-Ali-Abbas-Zaidi! I left some feedback/suggestions, primarily to ensure the updated tests more closely follow best practices with RTL. Thanks.
|
||
expect(buttonElement[buttonElement.length - 1].getAttribute('aria-disabled')).toEqual('true'); | ||
expect(buttonElement[buttonElement.length - 1].disabled).toEqual(false); | ||
expect(screen.getByText('Save')).toBeTruthy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When making assertions with .getByText
, it's recommended to use .toBeInTheDocument()
, not .toBeTruthy()
. This would be more consistent with other usages of getByText
throughout this repo and more aligned with the best practices recommended with RTL (e.g., https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-get-variants-as-assertions).
const defaultState = 'default'; | ||
expect(wrapper.find(StatefulButton).prop('state')).toEqual(defaultState); | ||
expect(wrapper.find(StatefulButton).prop('disabledStates')).toContain(defaultState); | ||
const buttonElement = screen.getAllByRole('button'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[curious/suggestion] Why use .getAllByRole
when you're only expecting/asserting on a single button? I would recommend making this query for the specific button in question, not all buttons...
For example, something like:
const buttonElement = screen.getByRole('button', { name: 'Save' });
Same feedback for similar usages in other test cases as well.
expect(buttonElement[buttonElement.length - 1].getAttribute('aria-disabled')).toEqual('true'); | ||
expect(buttonElement[buttonElement.length - 1].disabled).toEqual(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] Would .toBeDisabled()
simplify these lines?
expect(buttonElement).toBeDisabled();
wrapper.find('input[type="checkbox"]').simulate('change', { target: { checked: false } }); | ||
wrapper.find(StatefulButton).simulate('click'); | ||
expect(screen.getByText('Save')).toBeTruthy(); | ||
expect(screen.queryByText('Saved')).toBeFalsy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to using .toBeInTheDocument()
for such assertions, this should be using .not.toBeInTheDocument()
, not toBeFalsy()
.
expect(screen.getByText('Save')).toBeTruthy(); | ||
expect(screen.queryByText('Saved')).toBeFalsy(); | ||
|
||
fireEvent.click(screen.getByRole('checkbox')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
userEvent
is generally preferred over fireEvent
. userEvent
utilizes fireEvent
but userEvent
more closely mimics real user behavior (which is one of the overall benefits of RTL).
The only time fireEvent
should be called, per the following resources, is if the user interaction is not yet implemented in userEvent
.
There are, however, some user interactions or aspects of these that aren't yet implemented and thus can't yet be described with user-event. In these cases you can use fireEvent to dispatch the concrete events that your software relies on.
See these related resources for more details:
|
||
expect(buttonElement[1].getAttribute('aria-disabled')).not.toEqual('true'); | ||
expect(buttonElement[1].disabled).toEqual(false); | ||
expect(screen.getByText('Save')).toBeTruthy(); | ||
wrapper.unmount(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as above whether wrapper.unmount()
can be removed (question applies to the below test cases as well).
wrapper.find(StatefulButton).simulate('click'); | ||
wrapper.update(); | ||
|
||
fireEvent.change(screen.getByTestId('dropdown').children[0], { target: { value: 'Software Engineer' } }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] I believe it'd be more in line with RTL's philosophy/recommendations to not reach into the children
of the returned element from screen.getByTestId('dropdown')
but instead query for the input field directly (e.g., based on its role or label).
screen.getByRole('input', { name: 'Type to find a current job' })
@@ -61,16 +61,15 @@ | |||
}, | |||
"devDependencies": { | |||
"@edx/browserslist-config": "1.1.1", | |||
"@edx/react-unit-test-utils": "^2.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[inform/suggestion] Note, while @edx/react-unit-test-utils
is acceptable as a short-term replacement for previous Enzyme tests to minimize initial refactoring, we generally would prefer not to use this NPM package in favor of using React Testing Library (RTL) directly.
Rationale: RTL's testing philosophy is vastly different from Enzyme, and while @edx/react-unit-test-utils
is using RTL under-the-hood, it generally continues to propagate Enzyme's testing philosophy of asserting based on implementation details (no longer desired).
It does look like you're using RTL directly in all but 2 test cases, which is great. Perhaps considering refactoring those 2 test cases to also use RTL directly.
@@ -1,5 +1,5 @@ | |||
import { AppContext } from '@edx/frontend-platform/react'; | |||
import { shallow } from 'enzyme'; | |||
import { shallow } from '@edx/react-unit-test-utils'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] Would recommend not using @edx/react-unit-test-utils
here in favor of refactoring the one test using shallow
to use RTL directly instead;shallow
rendering is not something we want to continue as a paradigm in this MFE.
https://buttondown.email/kentcdodds/archive/76ce5bb1-0681-490b-9e1e-62f27e5cfa4d
wrapper.rerender(( | ||
<EmailSettingsModal | ||
onClose={() => {}} | ||
courseRunId="my+course+key" | ||
hasEmailsEnabled | ||
/> | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[note] It's unfortunate we will need to rerender()
here, but don't seem an immediate way around it without refactoring the underlying EmailSettingsModal
itself, which is likely out of scope for this particular work to replace Enzyme. Just wanted to leave a note that, while OK to leave as is, this generally seems to be a code smell.
For all changes
Only if submitting a visual change