react-tracking
react-tracking copied to clipboard
Provide testing/mocking instructions and export react-tracking/mock
I've been meaning to provide this as importable within react-tracking via something like: import track, { mockTrackEvent, TrackingPropType } from 'react-tracking/mock';
but haven't had a chance yet. PRs welcome! 😁
/* __mocks__/react-tracking.js */
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;
Originally posted by @tizmagik in https://github.com/nytimes/react-tracking/issues/112#issuecomment-522647123
Hi team,
We've been integrating this wonderful package into our own application but have faced some issues with fixing broken unit tests as a result. We tried using the mock above to set the tracking
default prop for our class components but it didn't work. I'm almost certain that the issue is that the defaultProps
for our components are defined outside of the class definition, a common pattern for React developers.
Here's an example:
@track({ module: 'MyComponent' })
export class MyComponent extends Component {
render() {
...
}
}
MyComponent.propTypes = {
tracking: TrackingPropType,
};
MyComponent.defaultProps = {
tracking: null,
};
export default connect(mapStateToProps)(MyComponent);
When we move the defaultProps
(and propTypes
) definitions inside of the class definition, it works. For now we're just passing in a mock tracking
prop ourselves in our tests which works however we're still getting this warning for some reason:
prop type 'tracking' is invalid; it must be a function, usually from the 'prop-types' package, but received 'undefined'.
EDIT: the prop-type warning was due to the mock using module.exports
and us importing with import from
.
Hmm it may be because of the connect()
wrapper? Could you try something like this?:
@track({ module: 'MyComponent' })
export class MyComponent extends Component {
render() {
...
}
}
const ConnectedMyComponent = connect(mapStateToProps)(MyComponent);
ConnectedMyComponent.propTypes = {
tracking: TrackingPropType,
};
ConnectedMyComponent.defaultProps = {
tracking: null,
};
export default ConnectedMyComponent;
If not, maybe you could create a repro in Codesandbox or something? I can try and take a closer look when I get a chance.
Hi team,
We've been integrating this wonderful package into our own application but have faced some issues with fixing broken unit tests as a result. We tried using the mock above to set the
tracking
default prop for our class components but it didn't work. I'm almost certain that the issue is that thedefaultProps
for our components are defined outside of the class definition, a common pattern for React developers.Here's an example:
@track({ module: 'MyComponent' }) export class MyComponent extends Component { render() { ... } } MyComponent.propTypes = { tracking: TrackingPropType, }; MyComponent.defaultProps = { tracking: null, }; export default connect(mapStateToProps)(MyComponent);
When we move the
defaultProps
(andpropTypes
) definitions inside of the class definition, it works. For now we're just passing in a mocktracking
prop ourselves in our tests which works however we're still getting this warning for some reason:prop type 'tracking' is invalid; it must be a function, usually from the 'prop-types' package, but received 'undefined'.
EDIT: the prop-type warning was due to the mock using
module.exports
and us importing withimport from
.
Hi, could you elaborate on the EDIT? What did you do to fix it? I'm newbie to react, just got a task to fix this problem. I also got a TypeError bug: TypeError: (0 , _tracking.track) is not a function
.
Thanks a lot in advance!
Hey @l225li are you still having this issue? Could you share more of your code or maybe create a Codesandbox example so I can take a closer look?
@tizmagik cc @l225li
With respect to the comment from @l225li, I also observed this issue recently when integrating react-tracking
. In my case, our project is a typescript project using stateless functional components and ES module imports, and using jest
for testing.
For tracking implemented at the component level, a lot of the code looks like this...
import track from 'react-tracking'
const MyComponent = () => { ... }
export default track({
event: 'my-component.presented'
})(MyComponent)
The key for mocking, then, is to mock the default exported function (track
).
By default, jest mocks do not support ES module semantics; when react-tracking
was not mocked for ES module syntax, I observed variants of the error described by @l225li.
FAIL src/components/pages/Foo/Bar/Baz/__tests__/Baz.test.tsx
● Test suite failed to run
TypeError: (0 , _reactTracking.default)(...) is not a function
120 | }
121 |
> 122 | export default track({
| ^
123 | event: 'foo-bar.baz.presented',
124 | })(Baz)
125 |
at Object.<anonymous> (src/components/pages/Foo/Bar/Baz/Baz.tsx:123:12)
at Object.<anonymous> (src/components/pages/Foo/Bar/Baz/__tests__/Baz.test.tsx:10:1)
This prevented me from mocking react-tracking
using a manual mock; however, I was able to get a satisfactory mocking solution using the following configuration.
jest.mock('react-tracking', () => {
const trackEvent = jest.fn()
return {
__esModule: true,
default: jest.fn(() => (id) => id),
useTracking: jest.fn(() => ({
trackEvent,
})),
}
})
Hope this helps.
Aside: really love the work NYT team has done with this library. In recent years I have spent a lot of time working on Android (where NYT team also shines), and was very pleasantly surprised to find this library, which shares a core philosophy and solves foundational problems I encountered in past projects in the mobile space. Great job.
Thank you @wokkaflokka , that's very helpful. And thank you for the kind words! 🤗
To disable react-tracking
in test, we've used something like this:
// lib/tracking/index.js
import tracking, { useTracking } from 'react-tracking';
let exportedTracking = tracking
let exportedUseTracking = useTracking
if (process.env.NODE_ENV == 'test') {
const Identity = (Component) => (Component)
exportedTracking = () => (Identity)
exportedUseTracking = () => {
trackEvent: () => {},
getTrackingData: () => ({})
}
}
export { exportedTracking as tracking, exportedUseTracking as useTracking }
import { tracking, useTracking } from 'lib/tracking'
It doesn't solve testability, just avoid dealing with renamed HOC classes and such in test.