How can Enzyme check for component visibility? - javascript

I've attached a cut down version of an issue I am having. I have a simple Checkbox which I hide using opacity : 0 depending on what is passed into the component containing the Checkbox (in this case MyCheckbox)
MyCheckBox.js
import React from "react";
import "./styles.css";
import { Checkbox, makeStyles } from "#material-ui/core";
const useStyles = makeStyles({
checkboxHiddenStyle: {
opacity: 0
}
});
export default function MyCheckbox(props) {
const styles = useStyles(props);
return (
<div>
<Checkbox
{...props}
className={props.data.length === 0 && styles.checkboxHiddenStyle}
/>
</div>
);
}
I have a component which uses MyCheckbox called MyCheckboxesInUse which results in one checkbox showing and the other being hidden.
How do I check the visibility of each of these in a Jest/Enzyme test ? I've looked at lots of posts but can't find something that works!
Code and test running here on CodeSandbox
MyCheckBoxesInUse.js
import React from "react";
import MyCheckbox from "./MyCheckbox";
import "./styles.css";
export default function MyCheckboxesInUse() {
const arrayWithNothing = [];
const arrayWithSomething = [1];
return (
<div className="App">
<h1>Hidden Checkbox</h1>
<MyCheckbox data={arrayWithNothing} />
<h1>Visible Checkbox</h1>
<MyCheckbox data={arrayWithSomething} />
</div>
);
}
MyCheckbox.test.js
import React from "react";
import Enzyme, { mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import MyCheckboxesInUse from "./MyCheckboxesInUse";
import MyCheckbox from "./MyCheckbox";
Enzyme.configure({ adapter: new Adapter() });
test("Check that one checkbox is hidden and the other is visible", () => {
const wrapper = mount(<MyCheckboxesInUse />);
const checkboxes = wrapper.find(MyCheckbox);
expect(checkboxes).toHaveLength(2);
//HOW DO I CHECK THAT ONE IS VISIBLE AND THE OTHER IS NOT ?
});

You can tryout jest-dom from testing-library, but if you want to see how they implement what you want, check out their code: https://github.com/testing-library/jest-dom/blob/master/src/to-be-visible.js

Related

I can't see why my context api does not work in reactjs

i have been trying to implement a context api solution since i want to use children states(data) in my app.js without lifting up the states. anyways i have tried to implement it a context api soloution to by doing the following :
i created a folder names context and then created Context.js
the code is as follows:
mport { createContext,useState } from "react";
export const Mycontext = createContext()
const Context = ({children}) =>{
const [post, setPost] = useState([])
return(
<Mycontext.Provider value={[post,setPost]}>
{children}
</Mycontext.Provider>
)
}
export default Context
i wrapped the index.js file with the Provider wrapper as follows:
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import Context from './context/Context';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Context>
<App />
</Context>
);
my main goal for now is to use useState hook data or states so i can use them in higher up comonents , in this case i want my post.js file to change usestate data in context so i can then use that data to post something in App.js using a container component that takes value as a props
i will post the both post.js and container.js and app.js below
import React,{useContext,useState,useEffect,useRef} from 'react'
import '../HomeMainStyling/HomeStyling.css'
import Tweets from './Tweets'
import Context from '../../context/Context'
function Tweet() {
const tw = useRef('')
const {post,setPost} = useContext(Context);
useEffect(() => {
if (post.length) console.log(post);
}, [post]);
function PostNow(event){
event.preventDefault();
setPost((oldpost) => [tw.current.value,...oldpost]);
}
return (
<div className="tweetcontainer">
<textarea ref={tw} className="tweetinfo"></textarea>
<button className="postIt" onClick={PostNow}>tweet</button>
</div>
)
}
export default Tweet
//
the container is the following:
import React from 'react'
import '../HomeMainStyling/HomeStyling.css'
function Tweets({value}) {
return (
<h2>{value}</h2>
)
}
export default Tweets
App.js:
import Tweet from './Center/HomeMain/Tweet';
import Tweets from './Center/HomeMain/Tweets';
import { useContext,useState } from 'react';
import Context from './context/Context';
function App() {
const {post,setPost} = useContext(Context);
return (
<div className="App">
<Tweet/>
<Tweets value={post}/>
</div>
);
}
export default App;
the app should in principle post 1 h1 element for every click in Tweet components
The useContext hook takes the context you created using createContext() as a parameter, but you are passing a custom component to it, so try:
import { Mycontext } from './context/Context';
const [post, setPost] = useContext(Mycontext)
<Mycontext.Provider value={[post,setPost]}>
this is wrong you ahve to write
<Mycontext.Provider value={{post,setPost}}>

render props doesn't display

I am new to React and I am learning about the props.
My prop doesn't display color on Events.js
I got "I am a car" and red didn't display.
This is my component Welcome.js :
import React from 'react'
import ReactDOM from "react-dom";
function Welcome(props) {
return <h2>I am a {props.color} Car!</h2>;
}
ReactDOM.render(<Welcome color="red"/>, document.getElementById('root'));
export default Welcome;
my page Events.js:
import React, { useState } from "react";
import Calendar from "react-calendar";
import { render } from "react-dom";
import Form from "./Form";
import Welcome from "./Welcome"
function Events() {
const [date, setDate] = useState(new Date());
return (
<div className='app'>
<Form/>
<Welcome/>
</div>
);
}
export default Events;
You are not setting the prop in Events.js. This means the value of props.color is undefined when the render function is called. undefined within curly braces will be ignored by React.
You can add a guard to ensure that you see an error if the prop is not defined:
function Welcome(props) {
if (props.color == null) {
throw 'color should be defined';
}
return <h2>I am a {props.color} Car!</h2>;
}

How to do an integration test for a material UI <Slider /> component with userEvent or fireEvent?

I have been struggling trying to do an integration test on a material UI component. I can target the slider, but have not successfully been able to move the slider and find the new value. Do you have any guidance on how to interact with this component and test that interaction?
import React from "react";
import { fireEvent, render, screen } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
import "#testing-library/jest-dom";
import { MemoryRouter } from "react-router-dom";
import { Slider } from "#material-ui/core";
import SearchForm from "./SearchForm";
describe("SearchForm interaction", () => {
it("should change value if slider is moved", () => {
const minValue = 1;
const maxValue = 8;
const currentValue = 4;
render(
<Slider
className="slider"
min={minValue}
max={maxValue}
value={currentValue}
onChange={jest.fn()}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
data-testid="numPlayer-slider"
/>
);
const slider = screen.getByTestId("numPlayer-slider");
//userEvent.click(slider, )
});
});
I have no experience with this, but something you could try is:
Inspect element on a slider and check how values are stored in the html tag.
If property value is being used perhaps you can try:
slider.value = INSERT VALUE;

Testing prop drilling with Enzyme

I want to write an integration test to assert that a when a parent component drills certain values or properties to a child component, that component receives said values and renders them properly. Below I have two component examples and an example test. Of course, the test is not accurate, but I'm wondering how I can use enzyme to accomplish this? Thanks!
sampleComponent.js:
import React from 'react';
const SampleComponent = () => (
<div test-attr="div">
<SampleChildComponent title="Sample title" />
</div>
);
export default SampleComponent;
sampleChildComponent.js:
import React from 'react';
const SampleChildComponent = ({ title }) => <h3 test-attr="h">{title}</h3>;
export default SampleChildComponent;
sampleComponent.test.js:
import React from 'react';
import { shallow } from 'enzyme';
import SampleComponent from './sampleComponent';
import SampleChildComponent from './sampleChildComponent';
test('renders component without errors', () => {
const wrapper = shallow(<SampleComponent />);
const childWrapper = shallow(<SampleChildComponent />);
expect(childWrapper.text()).toEqual('sample title');
});
To render child components you should use mount instead of shallow:
import { mount } from 'enzyme'
import React from 'react'
import SampleChildComponent from './sampleChildComponent'
import SampleComponent from './sampleComponent'
test('renders component without errors', () => {
const wrapper = mount(<SampleComponent />)
expect(wrapper.find(SampleChildComponent).text()).toEqual('sample title')
})

React Css Themr not working

My target is to have one main theme for the app and load custom vendor styles if one is set.
I have been following the tutorial of react-css-themr and I can't get it to work. The minimalistic example I could come up with is this:
my module:
import {render} from 'react-dom'
import React from 'react';
import {Item} from './components/presentational/Item';
import {ThemeProvider} from 'react-css-themr';
import style from './theme/ItemDefault.scss';
const contextTheme = {
Item: require('./theme/ItemVendor.scss'),
};
const About = () => {
return (
<ThemeProvider theme={contextTheme}>
<Item theme={style} className={style.red}/>
</ThemeProvider>
)
};
ItemDefault.scss:
.button{
color:deeppink;
}
ItemVendor.scss:
.button{
color:orangered;
}
That doesn't seem to give my any classes or any styling. Any ideas please?
The way I was wiring components was incorrect. The way to do this is as follows:
In the root component you need to have your theme provider and theme attached to it. This theme will override any child component theming.
import {render} from 'react-dom'
import React from 'react';
import {ThemeProvider} from 'react-css-themr';
import inlineCss from './page.scss';
import {Item} from './components/Item';
const contextTheme = {
Item: require('./theme/ItemVendor.scss'),
};
render((
<ThemeProvider theme={contextTheme}>
<Item />
</ThemeProvider>
), document.getElementById('app'));
The component itself will have it's default theming and then will be wrapped with themr API to overwrite the it's default settings.
import {render} from 'react-dom'
import React from 'react';
import { themr } from 'react-css-themr';
import defaultTheme from './Item.scss';
const DefaultItem = ({theme}) => {
return (
<div className={theme.button} >
Example item
</div>
)
};
export const Item = themr('Item', defaultTheme)(DefaultItem);
I put together a github repo showing how to use this:
https://github.com/adamgajzlerowicz/react-css-themr

Categories