-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
breaking(Form|RatingIcon|Search|SearchResult): Pass data to event handlers #951
Conversation
2eba8e1
to
4e1df95
Compare
@levithomason - thoughts on this approach? The alternative would be to have a separate common test like: common.passesPropsToEventHandler(Component, 'onClick') The issue with the current approach is that non-built-in events (e.g. Also I know we try to avoid big refactors, but assuming we go with this approach (updating the 'handles events' spec) I think it makes sense to just fix all of the handlers at once. These files currently have failing specs:
|
4e1df95
to
c027f6c
Compare
Current coverage is 99.73% (diff: 100%)
|
I like the idea of doing these all at once as it makes for less breaking changes and a clear upgrade path for users. My idea for solving the handled/unhandled callbacks is precisely what you've done. Though, I we can't assert the |
|
c027f6c
to
5b2eeba
Compare
@levithomason - ready for review 👍 One question I had about getHandlerProps = () => {
return { ...this.props, value: this.state.value }
}
onChange = (e, value /* <- proposed value */) => {
// ...
props.onChange(e, { ...this.getHandlerProps(), value })
}
onClick = (e) => {
// ...
props.onClick(e, this.getHandlerProps())
} |
This is correct, however, the test would have failed because the value in the
Initially, I don't think this is necessary in this case. When the props change the ACC copies those values to state so the That aside, it is a good idea IMO to have a SSOT for the handler props so I still like this idea. It makes testing easier and the component stronger. |
For clarity, |
@@ -198,7 +198,12 @@ export default class Form extends Component { | |||
/** Automatically show a loading indicator */ | |||
loading: PropTypes.bool, | |||
|
|||
/** Called with (event, jsonSerializedForm) on submit */ | |||
/** | |||
* Called with (event, jsonSerializedForm) on submit |
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.
Probably an oversight here, let's remove the signature from the description.
@@ -68,7 +68,13 @@ export default class MenuItem extends Component { | |||
/** Internal name of the MenuItem. */ | |||
name: PropTypes.string, | |||
|
|||
/** Render as an `a` tag instead of a `div` and called with event on MenuItem click. */ | |||
/** | |||
* Called on click. When passed, the component render as an `a` |
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.
Might be missing a word in here: "the component render as an a
"
the component will render as an a
the component renders as an a
@@ -101,10 +101,20 @@ export default class Label extends Component { | |||
PropTypes.oneOf(_meta.props.pointing), | |||
]), | |||
|
|||
/** Adds the link style when present, called with (event, props). */ | |||
/** | |||
* Adds the link style when present, called with (event, props). |
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.
Let's remove the signature here as well.
onClick: PropTypes.func, | ||
|
||
/** Adds an "x" icon, called with (event, props) when "x" is clicked. */ | ||
/** | ||
* Adds an "x" icon, called with (event, props) when "x" is clicked. |
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.
Another signature we can drop.
@@ -50,7 +50,13 @@ export default class Step extends Component { | |||
/** Render as an `a` tag instead of a `div` and adds the href attribute. */ | |||
href: PropTypes.string, | |||
|
|||
/** Render as an `a` tag instead of a `div` and called with event on Step click. */ | |||
/** | |||
* Called on click. When passed, the component render as an `a` |
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 comment regarding phrasing here: "the component render as an a
"
onOpen: PropTypes.func, | ||
|
||
/** Called with the React Synthetic Event and current value on search input change. */ | ||
/** | ||
* Called with the React Synthetic Event and current value on search input change. |
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.
Let's drop the signature info from the description here as well.
@@ -86,7 +86,12 @@ export default class Embed extends Component { | |||
/** Specifies an icon to use with placeholder content. */ | |||
icon: customPropTypes.itemShorthand, | |||
|
|||
/** Сalled with event on Embed click with (event, props). */ | |||
/** | |||
* Сalled with event on Embed click with (event, props). |
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.
Let's drop the signature info from the description here as well.
@@ -71,7 +71,12 @@ export default class Rating extends Component { | |||
PropTypes.number, | |||
]), | |||
|
|||
/** Called with (event, { rating, maxRating }) after user selects a new rating. */ | |||
/** | |||
* Called with (event, { rating, maxRating }) after user selects a new rating. |
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.
Let's drop the signature info from the description here as well.
|
||
/** Called with the React Synthetic Event and current value on search input change. */ | ||
/** | ||
* Called with the React Synthetic Event and current value on search input change. |
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.
Let's drop the signature info from the description here as well.
import AccordionTitle from 'src/modules/Accordion/AccordionTitle' | ||
|
||
describe('AccordionTitle', () => { | ||
common.isConformant(AccordionTitle) | ||
common.rendersChildren(AccordionTitle) | ||
common.propKeyOnlyToClassName(AccordionTitle, 'active') | ||
|
||
describe('onClick', () => { |
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.
Did we intend to drop these tests or update them?
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.
Intentional given that all the functionality is already being tested by the event-related tests within isConformant
Doc ExamplesI'm guessing there are several doc site examples that need to be updated to reflect the new changes as well. Would finding handler prop names in the docs, RatingIcon
@layershifter Good call. We should make this a private component in this case. Simply prefixing its name with |
let errorMessage = 'was not called with (event)' | ||
|
||
if (_.has(Component.propTypes, listenerName)) { | ||
expectedArgs = [eventShape, props] |
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 see all tests are passing, but how does this work for things like the Input onChange where the data
arg's value
key != to the props
value key? Same for Checkbox's checked
prop.
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.
props
here isn't the Component's full props object, it's just:
const props = {
...requiredProps,
[listenerName]: handlerSpy,
'data-simulate-event-here': true,
}
So we're really just testing that arbitrary props get passed through (e.g. that data-simulate-event-here
prop). Tests for additional data, like checked
of a Checkbox
, should be handled in that Component's test file.
b6c0fca
to
9f50d8e
Compare
I started looking into making
|
That logic makes sense to me, thanks @jcarbo. |
Released in |
Breaking Changes!
The following components have breaking changes in their event handler props.
Form
RatingIcon
Search
NOTE: The handler name changed from
onChange
toonResultSelect
. The change was made because:onSelect
). The reason to not useonSelect
is because that's a built-in html event type for when a user selects text.SearchResult
Fixes #623
This updates the common tests for event handling to ensure any handlers that we wrap are called with
(event, data)
as arguments.