I have this very simple stateless component
const Text = () => 'text'
Text.displayName = 'MyText'
export default Text
My test case
import Text from './Components/Text'
import { shallow } from 'enzyme'
it('render Text', () => {
const wrapper = shallow(<Text />)
expect(wrapper.find('Text').length).toBe(1)
})
What's wrong? I also tried exists(), seems like this is not working wrapper.find('Text')
You are rendering <Text /> so wrapper will contain result of Text's rendering without that tag itself.
If you check wrapper.debug() you will see just "text".
Related
So basically when I'm trying to make use of the "fireEvent" method from React Testing Library it just gives me an error telling me the following:
MainSection.test.js:
test('Check SearchBar functionality', async () => {
render(<SearchBar />);
const textInput = screen.getByTestId('text-input');
fireEvent.change(textInput, { target: { value: 'mens cotton jacket' } });
});
SearchBar.js
import React from 'react';
import './SearchBar.css';
function SearchBar({ setSearch }) {
return (
<div className='search_bar'>
<input
type='text'
placeholder='Search here!'
className='search_bar-text'
data-testid='text-input'
onChange={e => setSearch(e.target.value)}></input>
</div>
);
}
export default SearchBar;
Also, when I delete the "onChange" event from the input text, the test just pass (aka green).
:/
The issue to me appears to be that you're not providing the setSearch prop. I think an appropriate test for this component would look like this:
it("sets search text", () => {
// mock out the work the parent component would
// ordinarily do to provide a `setSearch` prop
// by settting up a noop jest stub
const setSearch = jest.fn();
// note that we render w/ the setSearch prop
// provided here, so it's not `undefined` later
render(<SearchBar setSearch={setSearch} />);
// fire the event we want to test behaviours for
const textInput = screen.getByTestId('text-input');
fireEvent.change(textInput, { target: { value: 'mens cotton jacket' } });
// assert that `setSearch` was called how we expected
// as this is part of the component's public interface
expect(setSearch).toHaveBeenCalledTimes(1);
expect(setSearch).toHaveBeenCalledWith("mens cotton jacket");
});
I'm trying to test a TextInput by checking its value after entering a string, but it's not working. Any help would be appreciated.
Here's the code:
import React from 'react'
import { TextInput } from 'react-native'
import { fireEvent, render } from "#testing-library/react-native"
test('<TextInput/>, () => {
const { getByTestId } = render( <TextInput testID="input" /> );
const input = getByTestId("input");
fireEvent.changeText(input, "123");
expect(input.value).toBe("123");
})
The test fails with the message:
Expected: "123"
Received: undefined
I think your example is not working because you are not controlling the input. Try adding a value and an onChangeText function. Something like:
function Example() {
const [value, setValue] = useState('')
return <TextInput value={value} onChangeText={setValue} testID="input" />
}
test('Should apply the value when changing text', () => {
const { getByTestId } = render(<Exampler />);
const input = getByTestId('input');
fireEvent.changeText(input, '123');
expect(input.props.value).toBe('123');
});
Also, you need to check input.props.value instead of input.value
Hope it helps.
I'm going to suggest a few things to assist you to get to the solution,
Are you sure TextInput has a prop called testID? You use getByTestId subsequently, which needs a data-testid value on the element. So please make sure of this first.
You can try finding the element in another way. Probably use getByPlaceholderText or similar.
Once you can get the element properly, and after the fireEvent, the value should certainly be updated, and assertion would succeed.
I want to create a slate.js-based editor component that keeps it's state in markdown. Slate.js docs keep repeating how simple serializing and deserializing state into md should be, but they don't provide an actual way to do it.
I tried achieving such editor with remark-slate-transformer in a very straight-forward way , based on these two examples: remark-slate-transformer, slate:
import React, { useMemo, useState } from "react";
import { createEditor } from "slate";
import { Slate, Editable, withReact } from "slate-react";
import stringify from "remark-stringify";
import unified from "unified";
import markdownParser from "remark-parse";
import { remarkToSlate, slateToRemark } from "remark-slate-transformer";
import { withHistory } from "slate-history";
function markdown2slate(markdown) {
const processor = unified().use(markdownParser).use(remarkToSlate);
return processor.processSync(markdown).result;
}
function slate2markdown(slate) {
const processor = unified().use(slateToRemark).use(stringify);
const ast = processor.runSync({ type: "root", children: slate });
return processor.stringify(ast);
}
export const App = () => {
const editor = useMemo(() => withHistory(withReact(createEditor())), []);
const [value, setValue] = useState("**initialText**");
const onChange = (newVal) => {
setValue(slate2markdown(newVal));
};
const editorValue = markdown2slate(value);
return (
<div className="wrapper">
<Slate editor={editor} value={editorValue} onChange={onChange}>
<Editable />
</Slate>
</div>
);
};
export default App;
sandbox here
But this doesn't work very well. I expect the initial text to appear in bold, but it doesn't. The cursor keeps jumping back to position 0 on every keystroke. Also, when I delete the string (value becomes ''), the editor breaks.
What is the correct, hassle-free way of making an editor component with state stored as markdown?
I'm not sure why you would absolutely want to store the editor state as Markdown, but this just cannot and will not work: you can't simply swap Slate internal state to something different than what it expects, its own object model, and expect it to work.
What you can do is to deserialize Markdown content into a Slate state object, feed that to the editor, let Slate do its thing while you edit and then serialize back to Markdown to do whatever you need to do with it, store it, send it, etc.
I've built a custom Input component which is simply a wrapper for the HTML input element. Here's the critical code, which I've simplified for posting here:
// #flow
import React, { useState } from 'react';
type Props = {
value?: string,
onChange: Function
};
const Input = ((props: Props) => {
const [ currentValue, setCurrentValue ] = useState(!!props.value ? props.value : '');
const handleChange = (event: SyntheticInputEvent<EventTarget>) => {
setCurrentValue(event.target.value);
props.onChange(event);
};
return <input type='text'
value={currentValue}
onChange={handleChange} />;
});
I wrote a bunch of React Testing Library tests for this and they all pass fine. But when I implemented this component in a web page, the initial value failed to appear. I solved the problem by dropping the currentValue code and just using props.value instead. That solves it. But I'm most curious why this approach above fails to display the initial value.
Look at this code, I did use prop-types
I'm trying to test a simple component that take some props (it have no state, or redux connection) with Enzyme, it works for the plain elements like <div /> and so on, but when i try to test if the element rendered by the child component exists, it fails.
I'm trying to use mount but it spit me a lot of errors, i'm new in this so, here is my code:
import React, { Component } from 'react';
import WordCloud from 'react-d3-cloud';
class PredictWordCloud extends Component {
render() {
const fontSizeMapper = word => Math.log2(word.value) * 3.3;
const { size, data, show } = this.props;
if (!show)
return <h3 className='text-muted text-center'>No data</h3>
return (
<section id='predict-word-cloud'>
<div className='text-center'>
<WordCloud
data={data}
fontSizeMapper={fontSizeMapper}
width={size}
height={300} />
</div>
</section>
)
}
}
export default PredictWordCloud;
It's just a wrapper for <WordCloud />, and it just recieves 3 props directly from his parent: <PredictWordCloud data={wordcloud} size={cloudSize} show={wordcloud ? true : false} />, anything else.
The tests is very very simple for now:
import React from 'react';
import { shallow } from 'enzyme';
import PredictWordCloud from '../../components/PredictWordCloud.component';
import cloudData from '../../helpers/cloudData.json';
describe('<PredictWordCloud />', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<PredictWordCloud data={cloudData} size={600} show={true} />)
});
it('Render without problems', () => {
const selector = wrapper.find('#predict-word-cloud');
expect(selector.exists()).toBeTruthy();
});
});
For now it pass but if we change the selector to: const selector = wrapper.find('#predict-word-cloud svg'); where the svg tag is the return of <Wordcloud /> component, the tests fails because the assertion returns false.
I tried to use mount instead of shallow, exactly the same test, but i get a big error fomr react-d3-cloud:
PredictWordCloud Render without problems TypeError: Cannot read property 'getImageData' of null.
This is specially weird because it just happens in the test environment, the UI and all behaviors works perfectly in the browser.
You can find your component directly by Component name.
Then you can use find inside your sub-component as well.
e.g
it('Render without problems', () => {
const selector = wrapper.find('WordCloud').first();
expect(selector.find('svg')).to.have.length(1);
});
or
You can compare generated html structure as well via
it('Render without problems', () => {
const selector = wrapper.find('WordCloud').first();
expect(selector.html()).to.equal('<svg> Just an example </svg>');
});