-
Notifications
You must be signed in to change notification settings - Fork 0
HOC - Higher order components #24
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
base: develop
Are you sure you want to change the base?
Conversation
Removed lodash omit from components fixed a bug un userActions tests changed actions with more than 1 parameter to payload created utils functions to replace lodash utilites
| static propTypes = { | ||
| username: PropTypes.string.isRequired, | ||
| password: PropTypes.string.isRequired, | ||
| handleOnChange: PropTypes.func.isRequired, |
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.
handleOnChange should not be required, rather a default prop value with a noop
static defaultProps = {
handleOnChange: () => {}
}
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.
Done!
| username: PropTypes.string.isRequired, | ||
| password: PropTypes.string.isRequired, | ||
| handleOnChange: PropTypes.func.isRequired, | ||
| handleOnSubmit: PropTypes.func.isRequired |
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.
handleOnSubmit should not be required, rather a default prop value with a noop
static defaultProps = {
handleOnSubmit: () => {}
}
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.
Done!
| const LoginHOC = (LoginChild) => { | ||
| class LoginParent extends React.Component { | ||
| static propTypes = { | ||
| actions: PropTypes.object.isRequired |
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.
we could use PropTypes.shape instead of PropTypes.object
actions: PropTypes.shape({
foo: PropTypes.func,
bar: PropTypes.func
})
actions should not be a required prop, maybe using defaults with no operations for expected actions
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.
Good catch, good practice to do.
|
|
||
| const { username, password } = this.state; | ||
|
|
||
| this.props.actions.login({ |
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.
if a variable has the same name as a key, it can be assigned in the following way instead
this.props.login({ username, password });
otherwise the state destructuring into { username, password } creating intermediate variables would be unnecessary since we could just do the following and avoid the intermediate variable creation. The shorthand version stated above should be preferred though.
({ username: this.state.username, password: this.state.password })
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.
Done!
| handleOnChange = (e) => { | ||
| const { name, value } = e.target; | ||
|
|
||
| this.setState({ |
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.
we should add at least a couple of basic checks, at least if name is not falsy, and if the value is different than the prior state value for that name key, only then updat ethe state for that key with setState,
otherwise we endup updating unecesarily a key with the same exact value in the state,
and in the unlickely case the name is undefined or empty, we endup invoking setStat e with invalid keys or causing exceptions.
Perhaps the use of something along these lines would be more efficient
if (name && (this.state[name] !== value || !this.state[name])) {
this.setState({
[name]: value
});
}
|
|
||
| const mapStateToProps = state => { | ||
| return { | ||
| auth: state.auth |
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.
we could rewrite this using destructuring and shorthand object assignment
const mapStateToProps = ({ auth }) => ({ auth });
| @@ -0,0 +1,27 @@ | |||
| .card-container.card { | |||
| max-width: 350px; | |||
| padding: 40px 40px; | |||
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.
if the outer padding is the same value (vertical == horizontal),
there would be no need to specify them separately.
padding: [vertical] [horizontal];
rather please use
padding: 40px;
| background-color: #F7F7F7; | ||
| padding: 20px 25px 30px; | ||
| margin: 0 auto 25px; | ||
| margin-top: 50px; |
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.
no need to override margin-top separately, it could be defined directly like so
margin: [top] [horizontal] [bottom];
Please replace the following
margin: 0 auto 25px;
margin-top: 50px;
with the appropriate definition
margin: 50px auto 25px;
|
|
||
| expect(keys(props.actions)).toEqual(expectedActions); | ||
| }); | ||
| expect(wrapper.find('section')).toHaveLength(1); |
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.
Please add missing tests to make this one and all other new tests valid and more robust,
Testing we have a section element is valid, but alongside all other components and elements we are expecting to have in the rendered component.
We should test against functionality rather than implementation.
otherwise testing we just have a section expect(wrapper.find('section')).toHaveLength(1);
is fragile since the section element could be completely empty and the unit test will still pass. but in fact the application will be broken to the user.
The more robust way to test here would be to check against the components we are expecting and the actual output rendered.
There are at least 5 required checks missing here.
let section;
beforeAll(() => {
section = wrapper.find('section');
});
LoginNavigation
it('should have one <LoginNavigation>', () => {
expect(section.find('LoginNavigation').length).toBe(1);
});
Container
it('should have one `div` with class `container`', () => {
expect(section.find('div.container').length).toBe(1);
});
Card
it('should have one card `div` with class `card-container`', () => {
expect(section.find('div.card.card-container').length).toBe(1);
});
Profile Image
it('should have one `img` with class `profile-img`', () => {
// optionaly we could also check against the image url
expect(section.find('img.profile-img').length).toBe(1);
});
LoginFormMain
it('should have one `<LoginFormMain>` ', () => {
expect(section.find('LoginFormMain').length).toBe(1);
});
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.
I put a comment in the initial PR when was created:
Tests and clean code are pending
I'm working on this, base PR.
| @@ -0,0 +1,64 @@ | |||
| import React from 'react'; | |||
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.
I could not find the test for this component, does it have one?
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.
Done!
| @@ -0,0 +1,72 @@ | |||
| import React from 'react'; | |||
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.
Could not find the test for this component, does it have one?
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.
Done!
| @@ -0,0 +1,55 @@ | |||
|
|
|||
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.
Could not find corresponding test
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.
Done!
| @@ -0,0 +1,54 @@ | |||
| import React from 'react'; | |||
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.
Could not find test
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.
Done!
| } = this.props; | ||
| let dataToRender = null; | ||
|
|
||
| if (this.props.showFooter) { |
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.
Could not find the added test case for this newly added if (this.props.showFooter) branch, this will lower our branches coverage.
We should make sure to test all newly intoduced modifications and functionality, and as a rule of thumb always bring our coverage up or at least keep it the same after modifications or additions.
We should add the corresponding test, thanks
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.
Done!
Higher order components
Ready to review
Description
Here we have 2 forms with the same structure from form data username and password, to manage the same setState and use the same action from login (HOC). But we can see two ways to show the form information LoginFormMain and LoginFormTop both wrapper by the HOC