How to verify method is not invoked on mock passed as prop - reactjs

I am developing a React application with jest and TypeMoq.
I can't test the negative path of a decision tree when the mocked call is a method on the object which needs to be undefined. Is there a method on TypeMoq that can help me verify that the provided method is not called?
type TopicComponentProps = {
topic: Topic
history?: History<any>
}
export const TopicComponent = ({topic, history} : TopicComponentProps) => {
const { Id, Name } = topic;
const filterTopic = () => {
if (history) { // <-- this is my problem
history.push(`/topic/overview/${Id}`);
}
}
return(
<Fragment>
<span
style={topicStyle}
onClick={() => filterTopic()}
className="topic">
{Name}
</span>
</Fragment>
)
}
The positive test case looks like this:
it('should trigger the navigation when clicked', () => {
const mockHistory = Mock.ofType<History<any>>();
const wrapper = mount(
<TopicComponent topic={testTopic} history={mockHistory.object} />
);
wrapper.simulate('click');
mockHistory.verify(x => x.push(It.isAnyString()), Times.once());
});
How do I setup the mock object, so i can test that no navigation happens when no history is provided?
it('should not trigger the navigation when history is undefined', () => {
let mockHistory = Mock.ofType<History<any>>();
???
const wrapper = mount(
<TopicComponent topic={testTopic} history={???} />
);
wrapper.simulate('click');
mockHistory.verify(x => x.push(It.isAnyString()), Times.never());
});

Related

Function component method spyOn failing unittest

I am using function component where is there is a arrow function.
const handleOnConfig = (cfg) => {
const layout = { ...config };
setConfig(layout);
};
Now, I want to write unit test for that function.
So, I did following in my test file. I used
beforeEach(() => {
let props = {user:user}
view = shallow(<Views {...props} />).instance();
});
test('should call config change call back', () => {
const handleOnConfig = jest.spyOn(view,'handleOnConfig').mockImplementation(() => config);
expect(handleOnConfig).toHaveBeenCalledTimes(1);
});
But, this test case gives error:
TypeError: Cannot read property 'handleOnConfig' of null
Any help would greatly appreciated
Edit:
Views component
const Views = forwardRef(({ user, id }, ref) => {
useEffect(() => {
handleOnConfig();
}, []);
return (
<div>
<Component
user={user}
id={id}
name='Component'
/>
</div>
);
})
export default Views;
Not a problem with spyOn() directly: your view variable is null.
Try using .dive() in the return from shadow():
beforeEach(() => {
let props = {user:user}
view = shallow(<Views {...props} />).dive().instance(); // <-- added .dive()
});

Why does my React Context runs twice, and returns `undefined` first before the expect output?

I'm trying to use React context to decide whether to have a button or not, and the problem is my context always runs twice and returns the first value as undefined -- the second time the output is correct.
Context:
const defaultMyContextValue = null;
export const myContext = createContext<GenericResponseFromEndpoint | null>(
defaultMyContextValue
);
export const fetcher = async (
endpoint: 'an_endpoint',
id: string
) => {
const client = new Client().ns('abcdef');
try {
return await client.rpc(
endpoint,
{
id
},
{}
);
} catch (err) {
// log error
return undefined;
}
};
export const MyContextProvider: React.FC = ({children}) => {
const context = useAnotherContext();
const {id} = useMatch();
const fetchMyContext = useCallback(
(endpoint: 'an_endppoint', id: string) =>
fetcher(endpoint, id),
[id]
);
const {data = null} = useSWR(
context?.name && ['an_endpoint', id],
fetchMyContext
);
return <myContext.Provider value={data}>{children}</myContext.Provider>;
};
export const useMyContext = () => {
const context = useContext(myContext);
if (context === undefined) {
throw new Error('------------------------');
}
return context;
};
Conditional render:
export const contextElement: React.FC = () => {
const info = useMYContext()?.info;
if (!info) {
return null;
// console.log('null');
}
console.log('not null');
// when i run it, it always returns two output scenarios:
// undefined - undefined
// undefine - expected value
// the front-end works as expected
return (
<div className="some-class-name">
<Button
variant="primary"
data-testid="button-123"
onClick={() => window.open('_blank')}
>'Do Something',
})}
</Button>
</div>
);
};
Test: my tests failed and the error is the system couldn't find the element. If I set the style={display:none} instead of returning null in the above conditional rendering -- it passes
describe('contextElement', () => {
const renderSomething = () => render(<contextElement />);
afterEach(() => {
myMock.mockClear();
});
it('renders button', () => {
myMock.mockResolvedValue({
info: 'some info'
});
const {getByTestId} = renderSomething();
expect(getByTestId('button-123')).toBeTruthy();
});
it('does not render button', () => {
myMock.mockResolvedValue(undefined);
const {getByTestId} = renderSomething();
expect(getByTestId('button-123')).not.toBeTruthy();
});
});
It's a really long post I know. Thanks for making it till the end. And yes, I check and there's no strictMode in my set-up. Thank you.

Testing React component that using hook

enter image description here
Find the attached image
I am getting this following error, while running Unit test for my react file.
I couldn't able to set value for a state method.
TestFile.tsx
const [attr, setAttributes] = useState<any>(initialState);
const getDetail = async () => {
if (Id) {
const form: IForm = await getResponse(Id);
console.log("||" + form.attributes.sourceName)
setFormResponseAttributes(form.attributes);
console.log("***" + JSON.stringify(attr));
};
useEffect(() => {
getDetail();
}, []);
return(
{attr.sourceName === 'ECR' ?
<div className='fe_u_padding--right-medium'>
<Button
id='saveDraftButtonId'
text='Save as Draft'
onClick={() => saveForm(true)}
variant='secondary'
className='hide-while-printing'
/>
</div>
: null
);
}
export
TestFile.test.tsx
it('load form response', () => {
const getResponseSpy = jest.spyOn(ResponseApi, 'getResponse');
getResponseSpy.mockImplementation(() => Promise.resolve(testUtils.Response));
const setAppContextSpy = jest.fn();
let setResponseAttributes;
const wrapper = mount(
<BrowserRouter>
<RegisteredApplicationContext.Provider
value={{ appContext: testUtils.registeredApplication, setAppContext: setAppContextSpy }}
>
<FormResponse match={{ params: { formResponseId: 'formResponseId1' } }} />
</RegisteredApplicationContext.Provider>
</BrowserRouter>
);
wrapper.find(Button).find('#saveDraftButtonId').first().simulate('click', {});
wrapper.update();
expect(getFormResponseSpy).toBeCalled();
TestUtils
export const Response: IForm = {
id: uuidv4(),
attributes: {"contextId": "111","sourceName" : "ECR"}
}
I am getting error while reading the SaveDraftButtonId,
Method “simulate” is meant to be run on 1 node. 0 found instead.,
it could able to find that button coz it couldn't set the value for attr state value
Any inputs would be helpful
TIA

Mock react hook and keep existing module

I am using Chakra UI and I have to mock just one hook, because I want to simulate various viewports.
My component is using the hook as following:
export const AuthenticationBase = (props: props) => {
const [isMobile] = useMediaQuery(['(max-width: 768px)']);
return (
<Box textAlign="center" fontSize={isMobile ? 'sm' : 'xl'}>
</Box>
);
}
I tried as following:
// runs before any tests start running
jest.mock("#chakra-ui/react", () => {
// --> Original module
const originalModule = jest.requireActual("#chakra-ui/react");
return {
__esModule: true,
...originalModule,
useMediaQuery: jest.fn().mockImplementation(() => [true]),
};
});
And then I execute my test:
describe('Authentication Component', () => {
it('should load with Login', () => {
const container = mount(<ChakraProvider theme={theme}><AuthenticationBase screen="login" /></ChakraProvider>);
const title = container.find('h1');
expect(title).toBeTruthy();
expect(title.text()).toBe('Login');
container.unmount();
});
}
But I get an error from JEST, somehow the hook is not mock correctly:

Testing State variable using Jest

I am learning to test React app using jest and Enzyme . I have created a component and using redux to maintain and update the state . The component code is below .
Now i want to write the test to check initial value of prodOverviewAccordion which we are setting as true in context file.
I have tried writing , but getting error . Sharing the test code also . Please help
const ProdOverview = () => {
const {
productState,
setProdOverviewAccordion
} = React.useContext(ProductContext);
const {prodOverviewAccordion } = productState;
const [completeStatusprod, setCompleteStatusprod] = useState(false);
return (
<div onClick={toggleTriggerProd}>
<s-box>
<Collapsible
trigger={
<Accordion
name={ProductConfig.accordionTriggerLabels.prodOverviewLabel}
completeStatusIcon={completeStatusprod ? 'check-circle' : 'alert-triangle'}
completeStatus={completeStatusprod}
/>
}
easing='ease-out'
handleTriggerClick={() => {
if (!prodOverviewAccordion) {
setProdOverviewAccordion(true);
} else {
setProdOverviewAccordion(false);
}
}}
open={prodOverviewAccordion}
data-test='prodOverViewCollapsible'
>
<p>Test</p>
</Collapsible>
</s-box>
</div>
);
};
export default ProdOverview;
const prodsetup = (props = {}) => {
return shallow(<ProdOverview />);
};
describe('Product Overview panel Test', () => {
const mockSetCurrentGuess = jest.fn();
beforeEach(() => {
mockSetCurrentGuess.mockClear();
});
test('should render Collapsible panel', () => {
const wrapper = prodsetup();
const component = findByTestAttr(wrapper, 'prodOverViewCollapsible');
expect(component.length).toBe(1);
});
test('Product Overview Panel should be in open state', () => {
const wrapper = prodsetup();
expect(wrapper.state().prodOverviewAccordion.to.equal(true));
});
});

Resources