Test a function inside another function - reactjs

Hello I was trying to test a function inside another function that needs a parameter from outside the second function.
export const DetailsView = ({ intl, object, onClose }) => {
// some code
const getIsLogbookAllowed = () => {
return object && object.driver;
};
// more code
};
Trying to test this function onLogbookReportModalClose, but I think when I do instance the variable object is not read it and it converted as null.
Testing
test('should return \'false\' when there is no driver', () => {
const wrapper = shallow(<DetailsView {...props} />)
const instance = wrapper.instance()
expect(instance.getIsLogbookAllowed()).toBe(true)
}
Error:
TypeError: instance.getIsLogbookAllowed is not a function
Any suggestion?

That's because getIsLogBookAllowed isn't a property of the component's instance, it's undefined, thus not a function.
What you should do is something like this:
export class DetailsView extends Component {
getIsLogBookAllowed = () => this.props.object && this.props.object.driver;
render() {
return <JSX />
}
}
This way the function becomes part of the instance of the component, you could replace classes with functions, that'd work too.

Related

How can I test method from component that has been called from child component with React Testing Library and Jest

I'm trying to test a Parent component which has a method that has been called from Child component. An example:
Parent.js
export default function Parent() {
const methodToTest = () => {
//method code
}
return (
<div>
<Child onChange={methodToTest} />
</div>
)
}
Child.js
export default function Child({ onChange }) {
const handleChange = () => {
onChange()
}
//InaccesibleElement is a component from a library that not render the element in test instance.
return (
<div>
....
<InaccesibleElement onClick={() => handleChange()} />
</div>
)
}
I would thinking to mock Child and inject into Parent component but doesn't work or I don't know how to do it correctly. My test example:
Parent.test.js
function ChildMock({ onChange }) {
const handleChange = () => {
onChange("mockedValue");
}
return(
<button onClick={() => handleChange()}>click me</button>
)
}
jest.mock('../components/Child', () => {
return { Child: ChildMock}
})
test("test parent method", () => {
const component = render(<Parent />);
const button = component.getByText("click me");
//rest of the test...
})
jest.mock() throws an exception:
"Reference error: The module factory of jest.mock() is not allowed to reference any out-of-scope variables.
Invalid variable access: BarGraphContainerMock
Allowed objects: Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Boolean, Buffer, DataView, Date, ....
Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with mock (case insensitive) are permitted."
Thanks.

Trigger Child component method when prop changes

I'm trying to make a child functional component to update when a Parent component changes a value in its state that I'm passing to a this child component as a prop.
The child component "receives" the value correctly and displays the prop value, but the method does not run again.
Child component
import React from 'react'
const MyCustomTable = props => {
const {
data = [],
} = props
const finalData = getSalesData() //This is the method i want to run when the selectedMonth prop updates
const getSalesData = () => {
//It does some calculations with the prop called data
}
return (
<Box>
{JSON.stringify(props.selectedMonth.value)}
<Table
data={finalData}
/>
</Box>
)
}
SalesByFamilyBU.propTypes = {}
export default MyCustomTable
The JSON.stringify line displays the changes correctly but I guess the getSalesData() is not automatically executed.
While you could use some lifecycle method or the useEffect hook to achieve what you want to do, I would rather use a functional approach.
In your example, finalData is a derived value of props.data and props.selectedMonth. You could then compute finalData directly from these props:
const MyCustomTable = props => {
const {
data = [],
} = props;
const filterData = (data, selectedMonth) => data.map(dataPoint => ({
...dataPoint,
selected: dataPoint.month === selectedMonth,
}); // or whatever, use your function logic here
const finalData = filterData(data, props.selectedMonth.value);
return (...);
};
If you really needed to call a function each time data is changing (ex. to fetch data elsewhere) you could use something like that:
const MyComponent = ({ data }) => {
const [finalData, setFinalData] = useState([]);
const myFunction = () => {
const newData = ... // whatever you need to do
setFinalData(newData);
};
useEffect(myFunction, [data]);
return ...;
};

How do I mock a function being used by my React Component in Jest testing?

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.

How to mock dependency being used in my React component?

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.

Should one use const when declaring an arrow function in React class

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.

Resources