I have something akin to the following case:
import { someFunction } from "./utils/function"
class ExampleComponent extends React.Component {
buildPages = () => {
return someFunction();
}
render() {
const pages = this.buildPages();
return <div className="container">{pages}</div>;
}
}
My code is a lot more complicated than the above, but the above is what it boils down to.
I have the following test:
describe("ExampleComponent", () => {
it("should match snapshot", () => {
// Somehow mock someFunction being used in the component.
expect(mount(getExampleComponent())).toMatchSnapshot();
};
});
someFunction is an expensive computation, and I basically want it to just be a jest.fn().mockReturnValue(true) when testing. Is there a way to do this? I read up on mocking with jest, but none of them seem to go over this use case. I'm not interested in passing someFunction in as a prop.
Turns out it is as simple as this:
import * as Functions from "./utils/function";
describe("ExampleComponent", () => {
it("should match snapshot", () => {
jest.spyOn(Functions, "someFunction").mockImplementation(() => {
return true
})
expect(mount(getExampleComponent())).toMatchSnapshot();
};
});
The import * as Functions from "./utils/function"; is pretty important stylistically, as the jest.spyOn takes two parameters, and you need the function you're spying on as the second parameter string.
Related
I have below code in my render method
render() {
let isNew = Boolean(domService.getQueryParamByName("isNew"));
if(isNew) {
return(
// soemthing
)} else {
return(// return anything)
Now how to mock the getQueryParamByName unit function in the jestUnit testcase such that it should cover if block.
If you are importing the domService from another file to your component, inside the test you can add a spy like this:
//component.test.js
import domService from "relative-path";
const mockFunction = jest.fn((obj) => {});
beforeEach(() => {
mockFunction.mockClear();
jest.spyOn(domService,"getQueryParamByName").mockReturnValue(mockFunction);
});
So I have something like the following:
function calculate = (value) => { return value + somecalculations }
class MyComponent extends React.Component {
...
render() {
if (calcuate(this.props.value) === 1) {
return(<MyComponentVersion1 />)
} else {
return <MyComponentVersion2 />
}
}
}
My question is, when doing jest unit testing, I want to be able to mock the function calculate(). But the function is global to that file, and is not part of my react component. Is there a way to mock this function so it always returns say 1? Thanks
If you want to do this without any extra dependencies (like a mocking library), you should be able to use dependency injection by telling MyComponent which function to use by setting it in a prop on your component to achieve this, like so:
calculate = (value) => { return value + somecalculations }
class MyComponent extends React.Component {
constructor(props) {
this.calculate = this.props.calculate || calculate
}
render() {
if (this.calculate(this.props.value) === 1 {
return (<MyComponentVersion1 />)
} else {
return (<MyComponentVersion2 />)
}
}
}
...and then, in your test, you can use a mock-calculate function:
test('put a really good test description here', () => {
const mockCalculate = () => 1
const myTestSubject = (<MyComponent calculate={mockCalculate} value={whatever}/>)
// the rest of your test
})
If you want to use an actual mocking library instead, maybe try sinon.js Mocks.
You need a way to access the calculate function from outside of the file. The easiest way to do this would be to export the function separately:
export function calculate () {
// ...
}
This option is also minimally invasive to your source code.
Let me define my use case, it'll be easier to explain.
I'm using the package localforage-observable, which basically creates an Observable via localForage.newObservable() that fires every time an item has changed in localforage.
I then have a recompose HOC, mapPropsStream, which takes this Observable and passes the value into the wrapped component.
const withLocalForage = mapPropsStream((props$) => {
return props$.pipe(
combineLatest(localForage.newObservable(), (props, lf) => {
return { ...props, lf };
})
);
});
export default withLocalForage
So that in my React component, I do
import './withLocalForage';
#withLocalForage
class MyComp extends React.Component {
render() {
return <div>{JSON.stringify(this.props.lf)}</div>
}
}
This would work, except for one issue: Currently localForage Observables should only be created after localforage.ready() (localforage-observable's doc).
The only thing is that, on app load, localForage.newObservable() is not defined; it is only defined if I do localForage.ready().then(() => { /* do something with localForage.newObservable() */})
I hope the post's title is clearer now: How can I define in my case the withLocalForage HOC asyncly, so that it's only defined after localForage.ready()?
It would be reasonable for newObservable to chain localforage.ready() internally. Since this is not so, this likely should be done manually:
const localforage$ = from(localForage.ready()).pipe(
switchMap(() => localForage.newObservable())
);
const withLocalForage = mapPropsStream((props$) => {
return props$.pipe(
combineLatest(localforage$, (props, lf) => {
return { ...props, lf };
})
);
});
Inside a react class component, should one use a const/let to declare an arrow function, or they should be emmited:
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
In this example, is sayBye declared correctly? (Without a const)
In addition, why outside the class, such a declaration does not work?
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
This will return an exception: Uncaught ReferenceError: sayBye is not defined
Thanks a lot!
The answer is "it depends"... your two examples do very different things. Let's take a look at both before I give you a more detailed answer.
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
The code above probably throws a syntax error as const (in this context) is not a valid decorator. Even if it was valid (or you simply omit it), sayHello() becomes a method on the ReactComp class (i.e. an instance method). Every time you create a new instance of this component, it will have an internal method called sayHello.
const example = <ReactComp />;
example.sayHello(); // oversimplified example
Make sense? On to your next example:
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
Ignoring for a moment the syntax error you mentioned earlier, this code creates two global(ish) functions: sayHello() and sayBye() which (depending on your other code) could be accessed globally by any other component or script.
sayHello(); // I can run this line of code anywhere!
// no need for "const example = <ReactComp /> because sayHello() was defined outside of that class
My point: instance methods on a class are different than functions declared outside of a component.
Should one use const when declaring an arrow function in React class?
If you're creating an instance method, then no you don't need const. If you're creating a generic (i.e. utility) function outside of a component, then yes you probably should use const.
You can't define a variable using any declarative statement inside a class.
It expects property names to be attached to the this context of your class.
Defining the following class:
class C extends Component {
sayGoodBye = () => console.log("Bye!")
sayHello = who => console.log("Hello " + who)
render() {
this.sayGoodBye()
this.sayHello('world')
// ...
}
}
can be translated as:
const C = {
sayGoodBye : () => console.log('bye!'),
sayHello : who => console.log('Hello ' + who),
render : () => {
C.sayGoodBye()
C.sayHello('world')
}
}
if you try to define a variable inside a class using const/let/var it will result in an error.
If I simply have:
const App = function() {
return (
<div>{this.renderList()}</div>
)
}
How do I define the renderList method?
I can't do const renderList = function() {} (nor with var or let). I can't do renderList() {}.
What's the right syntax?
I am hesitant to give a solution to this because inline Stateless Functions are not supposed to have methods. if you want a method you should use a Class and theres nothing wrong with using a class. Its all based on what you need to do. Stateless Functions are designed to be a super light weight way to render something that doesn't need methods, or a state or even a this context (in terms of a class).
you should be doing it like this.
class App extends Component {
constructor(){
super();
// note this is a Stateless Component because its a react class without a state defined.
}
renderList = () => {
return <span>Something Here</span>;
}
render() {
return <div>{this.renderList()}</div>
}
}
a HACK way that I wouldn't recommend (but does solve your question in the way you want it to) would be like this.
const App = () => {
let renderList = () => {
return <span>Something Here</span>
}
return <div>{renderList()}</div>
}
The reason why its generally a bad practice is because you are creating a function and all the memory allocation needed every render cycle. Subsequently, the internal diffing optimizations that react provides is generally useless if you do this because a new function gives a different signature than the prior render cycle. If this had a lot of children, they would all be forced to re-render!
Edit - React Version 16.8.0 +
You can use Hooks to do this. I would recommend using memo to memoize the function, this way you aren't creating it in memory each render cycle.
const RenderList = React.memo(props => (
<span>Something Here</span>
))
const App = function() {
const renderList = ()=> {
return "this variables"
}
return (
<div>{renderList()}</div>
)
}
You would want to do something like this
const App = function() {
return (
<div>{renderList()}</div>
)
}
function renderList(){
return "this variables"
}
Naturally this is a bad approach you its recommended that you pass in functions as props and stateless component are always dumb componets. Say if you are using redux for example you can have your component render like this
import {connect} from 'react-redux';
const App = (props) => {
return (
<div> {props.renderList} </div>
)
}
function renderList (){
return "your render logic"
}
export default connect(null, {renderList})(App)
Can you try something like
const App = () => {
return (
<div>{this.renderList()}</div>
)
}
App.renderList = () => {
return 'This is my list'
}
You can create render list function as standalone and use function parameter to pass props into function.