Unable to find an element with React testing library testing a ternary operator - reactjs

In my React component <MyBlock /> I have the following conditional rendering:
So when variant="one" prop is passed it will return <Container /> component, when variant="two" is passed it will render <Scroller />.
{variant === 'one' ? (
<Container items={items} testId="container" />
) : (
<Scroller items={items} testId="scroller" />
)}
With React testing library I am testing this component:
it('should render the container correctly', () => {
const { getByTestId } = mount(<MyBlock data={MockData} variant="one" />);
expect(getByTestId('container')).toBeDefined();
});
This test pass and works fine.
Now I want to test the other variant:
it('should render the container correctly', () => {
const { getByTestId } = mount(<MyBlock data={MockData} variant="two" />);
expect(getByTestId('scroller')).toBeDefined();
});
But then I get:
Unable to find an element by: [data-testid="scroller"]
What's the issue here?

I figured out. I have to use queryByTestId instead of getByTestId:
it('should render the container correctly', () => {
const { queryByTestId } = mount();
expect(queryByTestId('scroller')).toBeDefined();
});
Now it's working fine for both.

Related

How to properly mock named export children components with jest

So, here is a simplified version of both my component and my test.
export const VerifyPositionsDialog = () => {
return (
<BaseVerifyPositionsDialog>
<PositionsArea />
</BaseVerifyPositionsDialog>
);
};
I've omitted props and components logic for better readability.
What I've been trying to do is to mock PositionsArea component, so I can unit test VerifyPositionsDialog isolatedly.
This is my test so far.
jest.mock("../VerifyPositionsDialog/PositionsArea", () => ({
__esModule: true,
PositionsArea: () => <div />,
}));
render(<VerifyPositionsDialog />);
I've already tried a lot of different ways based on other answer from SO, but none seems to work.
Any help would be awesome.
You should mock the component using jest.fn returning the mocked div:
jest.mock('../VerifyPositionsDialog/PositionsArea', () =>
jest.fn(() => <div>Mocked</div>),
);
describe('Test', () => {
it('Mock Component Test', () => {
const { debug } = render(<VerifyPositionsDialog />);
// You will check with debug() that mocked div was rendered
debug();
});
});

Why does a react component, tested with React Testing Library has issue with react-intersection-observer?

I wrote a component built with react 17.0.2 that uses react-intersection-observer 9.1.0
import { useInView } from 'react-intersection-observer'
...
const [ref, inView] = useInView({
threshold: 0.99,
root: scrollRef.current,
delay: 250,
trackVisibility: true,
onChange: (inView: boolean) => {
onChildInView(index, inView)
}
})
to detect sliding behaviours inside or outside the viewport. And the component works fine.
I wrote some unit tests to make the component safer, using #testing-library/react 12.1.4 and #testing-library/jest-dom 5.16.3.
As soon as I test just the existence or visibility of the above component with the following code
describe('method render', () => {
test('renders correctly', () => {
render(
<MyComponent
props={...}
data-testid="component-id"
>
<div />
<div />
</MyComponent>
)
const componentNode = screen.getByTestId('component-id')
expect(componentNode).toBeInTheDocument()
expect(componentNode).toBeVisible()
})
})
the testing library complains with the message error.
ReferenceError: IntersectionObserver is not defined
I tried to fix it with this suggestion of mocking the library (as linked here) written at the top of the test
const intersectionObserverMock = () => ({
observe: () => null
})
declare global {
interface Window {
IntersectionObserver: typeof IntersectionObserver
}
}
window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock);
but it did not work due to
TypeError: observer.unobserve is not a function
Suggestions? Missing something?
To fix this issue I'd recommend using mockAllIsIntersecting from test-utils.js in react-intersection-observer. This function mocks the IntersectionObserver.
e.g.
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
describe('method render', () => {
test('renders correctly', () => {
render(
<MyComponent
props={...}
data-testid="component-id"
>
<div />
<div />
</MyComponent>
)
mockAllIsIntersecting(true)
const componentNode = screen.getByTestId('component-id')
expect(componentNode).toBeInTheDocument()
expect(componentNode).toBeVisible()
})
})

How to add test cases for Link using jest /enzyme

I am trying to write some test cases using jest and enzyme,I am unable to add test cases for Link and Please suggest if any more test cases needs to be added
these is styled component, and when should we spy /mock function
displayErr.tsx
export const DisplayErr = React.memo<Props>(({ text, SearchLink }) => (
<Section>
<h1>{text}</h1>
{!SearchLink && <Link to={getPath('SEARCH')}>some text</Link>}
</Section>
));
displayErr.test.tsx
describe('Error Msg', () => {
it('styled component', () => {
const output = mount(<DisplayErr text="hello world" SearchLink={true} />);
const link = output.find(Link).find({ to: '/Search' });
expect(output.find(Section).text()).toEqual('hello world');
//expect(link).toBe('<div class="link">Login</div>');//error
});
});
Here Link will render based on the SearchLink props. As you are passing it as true, it wont be available in the DOM. Pass SearchLink=false and execute the unit tests.
describe('Error Msg', () => {
it('styled component', () => {
const output = mount(<DisplayErr text="hello world" SearchLink=false/>)
expect(output.find(Link).props().to).toEqual('/search');
});
Let me know if you are facing the same issue.

How to test React components inside react-responsive tags

Inside a <MyComponent> component I am using react-responsive <MediaQuery> components to distinguish between rendering mobile and desktop content.
export class MyComponent extends React.Component {
//...
render() {
<MediaQuery query="(max-width: 600)">
<div className="inside-mobile">mobile view</div>
</MediaQuery>
}
}
I want to test the HTML inside <MyComponent>'s render() using enzyme, but can't seem to dive into the child elements of <MediaQuery>:
it('should dive into <MediaQuery>', () => {
const wrapper = mount(<Provider store={mockedStore}><MyComponent/></Provider>)
const actual = wrapper.getDOMNode().querySelectorAll(".inside-mobile")
expect(actual).to.have.length(1)
}
A console.log(wrapper.debug())shows that nothing inside <MediaQuery> is being rendered, though.
I'm guessing in a test (with no actual browser) window.width is not set which leads to the <MediaQuery> component not rendering anything.
What I want to do:
I want to be able to test <MyComponent>'s content using enzyme with react-responsive (or something similar such as react-media) to deal with mobile vs desktop viewports.
Things I've tried:
circumventing this by using enzyme's shallow with dive() instead of mount, to no avail.
using react-media's <Media> instead of react-responsive's <MediaQuery>, which seems to set window.matchMedia() to true by default. However, that's not working either.
console.log(wrapper.debug()) shows:
<MyComponent content={{...}}>
<Media query="(min-width: 600px)" defaultMatches={true} />
</MyComponent>
I found a working solution, using react-media instead of react-responsive, by mocking window.matchMedia so that matches is set to true during the test:
Create specific media components for different viewports:
const Mobile = ({ children, content }) => <Media query="(max-width: 600px)" children={children}>{matches => matches ? content : "" }</Media>;
const Desktop = ...
Use specific media component:
<MyComponent>
<Mobile content={
<div className="mobile">I'm mobile</div>
}/>
<Desktop content={...}/>
</MyComponent>
Test content per viewport:
const createMockMediaMatcher = matches => () => ({
matches,
addListener: () => {},
removeListener: () => {}
});
describe('MyComponent', () => {
beforeEach(() => {
window.matchMedia = createMockMediaMatcher(true);
});
it('should display the correct text on mobile', () => {
const wrapper = shallow(<MyComponent/>);
const mobileView = wrapper.find(Mobile).shallow().dive();
const actual = mobileView.find(".mobile").text();
expect(actual).to.equal("I'm mobile");
});
});

How to assert a React component with multiple <a> tags has an <a> tag with a given href

I'm trying to write a mocha test for a React component. Basically the component needs to render an <a> tag with its href set to a value in a property that is passed in. The issue is that the component can render multiple <a> tags in an unpredictable order and only one of them has to have the correct href.
I'm using enzyme, chai and chai-enzyme
The following is a cut down version of my real code, but neither of the tests are passing:
const TestComponent = function TestComponent(props) {
const { myHref } = props;
return (
<div>
Link 1<br />
<a href={myHref}>Link 2</a><br />
Link 3
</div>
);
};
TestComponent.propTypes = {
myHref: React.PropTypes.string.isRequired
};
describe('<TestComonent />', () => {
it('renders link with correct href', () => {
const myHref = 'http://example.com/test.htm';
const wrapper = Enzyme.render(
<TestComponent myHref={myHref} />
);
expect(wrapper).to.have.attr('href', myHref);
});
it('renders link with correct href 2', () => {
const myHref = 'http://example.com/test.htm';
const wrapper = Enzyme.render(
<TestComponent myHref={myHref} />
);
expect(wrapper.find('a')).to.have.attr('href', myHref);
});
});
It turns out that I was approaching this wrong. Rather than try to get the assertion part of the expression to work with multiple results from the query, it is better to change the find query to be more specific. It is possible to use attribute filters in a similar way to jQuery. As such my test becomes like this:
const TestComponent = function TestComponent(props) {
const { myHref } = props;
return (
<div>
Link 1<br />
<a href={myHref}>Link 2</a><br />
Link 3
</div>
);
};
TestComponent.propTypes = {
myHref: React.PropTypes.string.isRequired
};
describe('<TestComonent />', () => {
it('renders link with correct href', () => {
const myHref = 'http://example.com/test.htm';
const wrapper = Enzyme.render(
<TestComponent myHref={myHref} />
);
expect(wrapper.find(`a[href="${myHref}"]`)).be.present();
});
});

Resources