Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
jest-mock-action-creators
Advanced tools
Readme
You're cool. You're going to test your React smart components (aka containers in redux) and make assumptions what they call necessary redux action creators. Well, you can have few ways to achieve this:
class Comp extends Component {
render() {
// some render... not important
}
onSomeButtonClick() {
this.props.sendMyAction();
}
}
function mapDispatchToProps(dispatch) {
return { sendMyAction: bindActionCreators(dispatch, sendMyAction) }
};
then in test
const spy = jest.fn();
shallow(<Comp sendMyAction={spy} />);
It works well in plain Javascript, but quickly becomes headache in Typescript:
interface Actions {
sendMyAction: typeof sendMyAction; // What??
sendMyOtherAction: typeof sendMyOtherAction;
actions: typeof actionBundle;
}
class Comp extends Component<Actions> {
// ....
}
You must to declare your actions here to not lose the function types, which is the boring task. Also, you may have some middleware which converts your action to promises/observables (very common case) and you'll probably be ended in declaring separate function types with promisified results.
dispatch()
and call action creators directlyimport { sendMyAction } from "./actions";
class Comp extends Component {
onSomeButtonClick() {
this.props.dispatch(sendMyAction());
}
}
This is also neat in Typescript (since you don't need to declare your actions in component props again) and you can do some tricks with generics and redux's dispatch()
to automatically obtain correct result type from request action type. Nice!
Unfortunately this way has very big disadvantages when it comes to testing:
For example:
function myAction(a, b) {
return {
type: "MY_ACTION",
payload: {
a: a === true ? "truthy": "falsy",
b
}
}
}
class C extends Component {
someButtonClick() {
this.props.dispatch(myAction(true, 5));
}
}
test:
const dispatch = jest.fn();
const w = shallow(<Component dispatch={dispatch} />);
w.find("button").simulate("click");
expect(dispatch).toBeCalledWith(myAction(true, 5));
// or
expect(dispatch).toBeCalledWith({ type: "MY_ACTION", payload: { a: "truthy", b: 5 }});
Variant 1 looks OK, but is not always achievable. For example if you have some param validation in your creator and throw error - it won't be possible to test it without mocking AC.
function myAction(a, b) {
return dispatch => {
dispatch(someOtherAction());
}
}
expect(dispatch).toBeCalledWith(myAction(true, 5));
Will always fail
class C extends Component {
async someButtonClick() {
const res = await this.props.dispatch(myAction(true, 5));
// do something with res
res.someval;
}
}
//test
import { myAction } from "../actions";
jest.mock("../actions");
myAction.mockReturnValue({ someval: 1 });
Again, this will quickly become very boring if you have many actions creators and even much boring when using Typescript
class C extends React.Component {
render() {
// some render
}
buttonClick() {
this.props.dispatch(anotherAction("test"));
}
async anotherButtonClick() {
const res = await this.props.dispatch(myAction(true, 5, "prop"));
await this.props.dispatch(anotherAction(res.val));
}
}
test:
import { mockActionCreators, createDispatchMockImplementation } from "jest-mock-action-creators";
import { myAction } from "../myAction";
import { anotherAction } from "../anotherAction";
// Automatically mock your action creator modules. When using babel transformer it will insert jest.mock() for their module paths
mockActionCreators(myAction, anotherAction);
// or replaceActionCreators(myAction, anotherAction); // Doesn't insert jest.mock() for their module paths, expects myAction and anotherAction be already mocked (i.e. jest.fn())
const dispatch = jest.fn();
const wrapper = shallow(<C dispatch={dispatch} />);
wrapper.find("button").simulate("click");
// Pretty easy, isn't it?
expect(dispatch).toBeCalledWithActionCreator(anotherAction, "test");
expect(dispatch).not.toBeCalledWithActionCreator(myAction);
// Return { val: "test2" } when calling myAction();
createDispatchMockImplementation(dispatch, {
[myAction.name]: { val: "test2" }
});
wrapper.find("anotherButton").simulate("click");
expect(dispatch).toBeCalledWithActionCreator(myAction, true, 5, "prop");
expect(dispatch).toBeCalledWithActionCreator(anotherAction, "test2");
npm install jest-mock-action-creators --save-dev
Add jest-mock-action-creators/babel
to your plugins in .babelrc or .babelrc.js
When using typescript and ts-jest
, enable babel processing in ts-jest
(enabled by default) and tell it to use .babelrc:
{
"jest": {
"globals": {
"ts-jest": {
"useBabelrc": true
}
}
}
}
Note: Specifying plugins: []
in ts-jest babel configuration won't work
and finally import in your test:
import { mockActionCreators, createDispatchMockImplementation } from "jest-mock-action-creators";
It's possible with using jest-easy-mock, use this configuration:
["jest-easy-mock", {
requireActual: true,
identifiers: [
{
name: "jest.mockObj",
remove: true,
type: "name",
},
{
name: "jest.mockFn",
remove: true,
type: "mock",
},
{
name: "replaceActionCreators",
remove: false,
type: "mock"
}
]
}],
["jest-mock-action-creators/babel", { mockIgnoreExpressions: ["mock", "doMock", "mockObj", "mockFn"] }],
and in the test:
import { myAction, myAction2 } from "../actions";
import { ActionModule } from "../../module";
beforeEach(() => {
replaceActionCreators(
myAction,
ActionModule.action1,
);
});
it("test", () => {
myAction(); // mocked
myAction2(); // non-mocked
ActionModule.action1(); // mocked
ActionModule.action2(); // non-mocked
});
FAQs
Easy mock & test redux action creators with dispatch() in your components
The npm package jest-mock-action-creators receives a total of 648 weekly downloads. As such, jest-mock-action-creators popularity was classified as not popular.
We found that jest-mock-action-creators demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.