-
Notifications
You must be signed in to change notification settings - Fork 123
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
Please add instructions how to test decorated methods #112
Comments
looks like a setter is missing in |
I haven’t had a use case for testing these methods as they’re mostly a simple function of props. Happy to explore a PR if you have an approach to make these more testable. |
@tizmagik A use case might be to test that the method called track with data? How would we test that? |
Also, if we can’t stub the decorators then won’t react-tracking get called on every test assertion that uses it? Ideally I don’t want this to be called as part of my component tests. |
Ah yea, so for the tests we actually just mock out react-tracking. If you're using Jest, you can define a shared mock in /* __mocks__/react-tracking.js */
module.exports = () => c => c; If you wanted to assert that react-tracking is called with a particular object (or, at all) you could do something like: // UNTESTED, but you get the idea...
const reactTrackingMock = jest.fn(c => c);
jest.setMock('react-tracking', reactTrackingMock);
it('calls track', () => {
mount(<MyComponent />)
expect(reactTrackingMock).toHaveBeenCalled();
}); To your point, this should be something we go over in the docs. If the above works for you, and you're up for it, a PR would be great! |
Yes, this might work. I’ll test the idea and do a PR to update the docs. |
@saidkholov @tizmagik in the end my team used another tracking provider to mock the dispatch call. This was simple to do plus you don't mock out the entire library. I've created a PR if this is something that works for everyone: |
The PR looks great, thanks @robmojosix . I'll give this approach a try.
Works wether decorators are used or tracking is dispatched via props. P.S. If one is testing a fully wrapped component( |
The only problem that I'm still having is coverage within function passed to a decorator. Istanbul seems to ignore it. Looks like it is an issue for istanbul repository.
Exporting the function and testing it separately doesn't look good. |
Thanks very much for the PR @robmojosix -- I'll take a look! @saidkholov I like the approach of passing in a |
@saidkholov if you can assert that your mock was called with args doesn’t this cover your decorated methods? Checking it was called means the decorator fired and checking the args means you are testing the logic of the decorator. |
Sorry my bad, I didn't check coverage stats after I mocked tracking object the way I mentioned. It is looking good now. Created a PR #115 |
Cool, @saidkholov I've just looked over the PR :) As you mentioned before; I'm not sure this will cover your decorated class methods - these won't call your stub. Another thought is that this will bypass react-tracking's use of the context API which will only matter if you need to test accumulative tracking over multiple components. However, you might reserve this for feature or more e2e style tests. Lastly, this pattern means user's code has react-tracking's props mapped within every file we need to test. If react-tracking change their API we have to change every test file where this pattern is used. These are only minor points. If this pattern works for you and your team you should definitely use it. |
All good points @robmojosix -- thank you very much for your input. And thanks @saidketchman for the PR. I'm hesitating about #114 because I don't want to increase the surface of react-tracking, especially since this can be implemented in userland relatively easily. And I think #115 is a good start but @robmojosix raised some good points there. I think the right solution may be some combination of these two approaches. So if we take Jest as the assumed test framework, maybe there's a recipe there for how to mock out react-tracking when a particular test doesn't care to assert about its tracking concerns, but then also a provide a clean way to assert on tracking concerns a la #114 in the case where the test does want to. I'm kind of swamped with things at work right now but hope to get to this soon. In the mean time, if you all have any other ideas or approaches, by all means please chime in or add to your PRs. Thanks again for your thoughts here everyone, I really appreciate it! |
Completely agree @tizmagik |
@tizmagik getting credit for something I didn't do hahaha. Wrong Said :P |
Thanks for your feedback, everyone. |
How do I test my decorated functions? I have /* __mocks__/react-tracking.js */
module.exports = () => c => c; But I have been getting Example: @track({ component: "Sample" })
class Sample extends Component {
// most of the component left out
@track((_, state) => ({action: "handleClick", state: state})))
handleClick = () => {
// do something
};
} it("should do a thing", () => {
const wrapper = shallow(
<Sample />,
{
disableLifecycleMethods: true
}
);
const dive = wrapper.dive();
// TypeError
dive.instance().clear();
}); Works perfectly fine with the |
Ah, this is because that simplified mock ( Here's a slightly more sophisticated mock that should work for what you're trying to do @carterthayer const PropTypes = require('prop-types');
const mockTrackEvent = jest.fn();
module.exports.TrackingPropType = PropTypes.shape();
module.exports = () => (...clsOrMethod) => {
if (clsOrMethod.length === 1) {
// decorating a class
const [cls] = clsOrMethod;
cls.defaultProps = {
...cls.defaultProps,
tracking: {
trackEvent: mockTrackEvent,
},
};
return cls;
}
// decorating a method
return clsOrMethod[1].initializer;
};
module.exports.mockTrackEvent = mockTrackEvent; I've been meaning to provide this as importable within react-tracking via something like: |
Closing this issue in favor of #134 |
Example 1:
The only way to test this decorator is to extract the callback function.
Example 2:
There is no way to
jest.spyOn()
on the decorated method or override a decorated method.The text was updated successfully, but these errors were encountered: