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

chore(warnings): Fix warnings in Form and Modal #626

Merged
merged 3 commits into from
Oct 5, 2016

Conversation

jeffcarbs
Copy link
Member

Fixes warnings in two of the components referenced here: #599

@codecov-io
Copy link

codecov-io commented Oct 5, 2016

Current coverage is 100% (diff: 100%)

Merging #626 into master will not change coverage

@@           master   #626   diff @@
====================================
  Files         119    119          
  Lines        1881   1884     +3   
  Methods         0      0          
  Messages        0      0          
  Branches        0      0          
====================================
+ Hits         1881   1884     +3   
  Misses          0      0          
  Partials        0      0          

Powered by Codecov. Last update ddb6349...1f3eebe

@layershifter
Copy link
Member

Note, I added tests for Form's bool props in #584.

const portalProps = _.pick(rest, _.keys(Portal.propTypes))

// Remove portal-handled props from 'rest' and pass them through to Portal
const portalProps = _.reduce(rest, (memo, value, key) => {
Copy link
Member

@levithomason levithomason Oct 5, 2016

Choose a reason for hiding this comment

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

Just a suggestion here. This adds another loop, but is a little clearer (at least to my eyes) and does not mutate any objects:

const unhandled = getUnhandledProps(Modal, this.props)

const portalPropKeys = _.keys(Portal.propTypes)
const portalProps = _.pick(unhandled, portalPropKeys)
const rest = _.omit(unhandled, portalPropKeys)

@@ -62,4 +63,23 @@ describe('Input', () => {
})
})
})

describe('onChange', () => {
it('handles onChange', () => {
Copy link
Member

Choose a reason for hiding this comment

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

This should be covered by the conformance test for events. It runs every component through every event handler and asserts that it was called, and was called with the appropriate event shape as the first arg.

// React gives a warning if no onChange is given to a controlled input. We
// handle the onChange on the wrapping element, so we don't actually need
// onChange on the input itself but let's pass a noop to suppress the warning.
onChange: _.noop,
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we instead add onChange to the htmlInputPropNames? This way, it is applied to the correct place and suppresses the warning only when it should be suppressed (user passed value/onChange). My concern is that we're swallowing the warning. If the user adds <Input value='' />, they should see the warning but they won't with the current change here.

Copy link
Member Author

@jeffcarbs jeffcarbs Oct 5, 2016

Choose a reason for hiding this comment

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

That makes sense, although adding it to the htmlInputPropNames actually causes it to be called twice. I think we need to do a similar thing here as the portalProps, where any prop we pass through to the input isn't included in the rest. e.g.

// Currently:
const rest = getUnhandledProps(Input, props)
const inputProps = _.pick(props, htmlInputPropNames)

// Change to:
const unhandled = getUnhandledProps(Input, props)

const htmlInputProps = _.pick(unhandled, htmlInputPropNames)
const rest = _.omit(unhandled, htmlInputPropNames)

Copy link
Member

Choose a reason for hiding this comment

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

I think that is true? Just make sure all the examples work/look how they should. SUI relies partially on the classNames and partially on the input props to do what it does for the Input component.

There are gonna be some exceptions for things like disabled, which adds opacity to the input. It can't be both a class and an attribute or it is doubly transparent. Also, readOnly I believe must be on the input to prevent entries, but not required as a className.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, this causes the handles events transparently test to fail. I think that test tries to call the event (onChange in this case) on the top-level component (the Input in this case). Since the onChange is now actually being passed as a prop to the htmlInput, it's not being called when simulated on the Input.

Thoughts on how to handle this? I agree it would be better to not suppress the warning, so ideally we can improve the test, assuming I'm understanding the issue correctly.

Copy link
Member

Choose a reason for hiding this comment

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

Ugh, yep. That test is a little to naive. We could teach it where to put the handler (pass an argument somehow), but that would be pretty ugly I think.

I'll give this more thought and see what I can come up with.

@@ -104,6 +104,12 @@ describe('Modal', () => {
shallow(<Modal open={false} />)
.find('Portal')
.should.have.prop('open', false)

// Does not pass this prop to the portal child
Copy link
Member

Choose a reason for hiding this comment

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

Suggest pulling this into it's own it() block to keep assertions isolated.

@jeffcarbs
Copy link
Member Author

Regarding my comment about the "handles events transparently" above, I updated the test slightly to account for this situation. I think it makes sense but let me know if not.

The idea behind the test (imho) is to ensure that if a user passes an event handler as a prop to the top-level component it is fired when that event takes place within that component. In this case, we're binding the event to a more appropriate sub-component that is the only element that will actually cause the event to be fired in an actual browser. So this test now is able to simulate a more real-world scenario.

The only negative is that within other tests if you did .find(Input).simulate('change') it wouldn't trigger the onChange for the component as one might expect because the event needs to be simulated on the html input within.

Thoughts?

@@ -295,7 +298,7 @@ export const isConformant = (Component, options = {}) => {
// ^ was not called on "blur"
const leftPad = ' '.repeat(constructorName.length + listenerName.length + 3)

handlerSpy.called.should.equal(true,
handlerSpy.calledOnce.should.equal(true,
`<${constructorName} ${listenerName}={${handlerName}} />\n` +
`${leftPad} ^ was not called on "${eventName}".` +
Copy link
Member

Choose a reason for hiding this comment

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

Update required: "was not called on once"

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👍

@levithomason
Copy link
Member

Test changes look good to me! I think if someone is writing tests for a component, they should be responsible for find()ing the correct component to fire the event on. Seems sane.

I added one last request to update the event assertion error to match the updated calledOnce assertion. Other than this, I think we're there!

@levithomason
Copy link
Member

Looks good, will merge on pass

@levithomason levithomason merged commit 835dd0a into master Oct 5, 2016
@levithomason levithomason deleted the feature/warnings branch October 5, 2016 19:21
@layershifter layershifter mentioned this pull request Oct 6, 2016
17 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants