-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Make blackbox testing easier #325
Comments
Within the polyfill, the If you can generate an I'd be cautious about using the |
@coopy, did this help resolve the issue for you? |
Thanks @hellendag. I spent a little bit of time trying to generate If I go back to this approach, I will definitely not use the |
This JavaScript is working with ChromeDriver in Selenium to add text at the current cursor position: function addTextToDraftJs(className, text) {
var components = document.getElementsByClassName(className);
if(components && components.length) {
var textarea = components[0].getElementsByClassName('public-DraftEditor-content')[0];
var textEvent = document.createEvent('TextEvent');
textEvent.initTextEvent ('textInput', true, true, null, text);
textarea.dispatchEvent(textEvent);
}
}
addTextToDraftJs('welcome-text-rte', 'Add this text at cursor position'); |
@skolmer |
@acikojevic - "Within the polyfill, the keypress event is used for browsers that do not have a native textInput event (Firefox, IE)" from hellendag on Apr 22 - what if you use keypress instead of the textInput event? |
Actually, Internet Explorer has native textInput event from version 9+. But still not working, tried with keypress. |
I'm tying to get this working in a test using enzyme, I've mounted the component if that matters. React test utils doesn't have a mapping for the // setting both data & target.value, because I'm not sure which is used
const event = new Event('textInput', { data: 'abc', target: { value: 'abc' } });
// finding the draft-js editor & dispatching the event
wrapper.find('div[role="textbox"]').get(0).dispatchEvent(event); Is there another way to go about this? Or a more manual way I can update |
Is anyone still looking into getting this working with Enzyme? I've had success with a few other custom React components by simulating a
|
@mikeislearning did you get anything to work? |
I agree that this is too hard today - it would be great if there was a library for testing contenteditable implementations. On var draftEditorContent = field.find('.public-DraftEditor-content')
draftEditorContent.simulate('beforeInput', { data: value }) But this stopped working when we upgraded to 0.10 (and upgraded React to 15.5) so now we do this instead: const editor = field.find(Editor)
let editorState = editor.props().editorState
var contentState = Modifier.insertText(editorState.getCurrentContent(),
editorState.getSelection(),
value, editorState.getCurrentInlineStyle(), null)
var newEditorState = EditorState.push(editorState, contentState, 'insert-characters')
editorState = EditorState.forceSelection(newEditorState, contentState.getSelectionAfter())
editor.props().onChange(editorState) It's not exactly black box but it simulates what we need to simulate :) |
Hello, your solution seems interesting. Would you tell us more, hopefully with working codes? |
Sorry for the late reply.
|
@mikeislearning Thank you very much :) @tarjei 's answer does work, only when what you want is text input. It sure things, but for the case we are encountering is to test For this case, manipulating EditorState manually fails to simulate the key event. import { shallow } from 'enzyme';
const wrapperComponent = shallow(EditorCore, props);
wrapperComponent.simulate('keyDown', {
keyCode: KeyCode.KEY_S,
altKey: true,
}); I am working on testing this |
@kenju: Actually my example can be modified to do anything, but it does not test draft-js. I.e. the test is responsible for the output. I agree that it is an inferior method, but it has the benefit of simpleness. I would love to see a draftjs-testing library :) |
I have found a better way for testing draft.js with enzyme in much more declarative way. tl;drIn order to test keyboard event with draft.js,
ExampleHere is a reproducible repository: https://github.com/kenju/enzyme-draftjs-sample/blob/master/src/Editor.jsx import { mount } from 'enzyme';
...
describe('Editor', function () {
it('dispatch COMMAND_SAVE when command+s key pressesd', function () {
const dispatchSpy = sinon.spy();
dispatchSpy.withArgs(COMMAND_SAVE);
// 1. use `mount` API for Full DOM Rendering
const wrapper = mount(<Editor dispatch={dispatchSpy} />);
// 2. find a DOM element with '.public-DraftEditor-content' classname
const ed = wrapper.find('.public-DraftEditor-content');
// 3. dispatch the 'keyDown' event with `simulate` API
ed.simulate('keyDown', {
keyCode: KeyCode.KEY_S,
metaKey: false, // is IS_OSX=true, this should be true
ctrlKey: true,
altKey: false,
});
assert.equal(dispatchSpy.calledOnce, true);
assert.equal(dispatchSpy.withArgs(COMMAND_SAVE).calledOnce, true);
});
}); DetailsWhy find a DOM element with '.public-DraftEditor-content' classname ?If you dive into the draft.js source code, you will find that the each events are attached to the inner div whose className is '.public-DraftEditor-content'. |
@kenju I've been picking apart your example, but can't figure out how it translates to my own code. I don't need a |
Um... what kind of changes do you want to watch, and what is supposed to trigger the change? |
@kenju What I'd like to have happen is that whenever a user makes a change in an Editor it triggers a callback to its parent component. For now that's just a keypress, but in the future that could could be richer content like inserting an image. That way I can change the parent's UI based on the Editor's content. I'm designing it so that I'm wrapping the draft-js component in a more generic component that will have some common functions throughout my app. This wrapper will then be used in different scenarios (a comment, a post, a search input, etc). This example is abbreviated, but this is my wrapper component. class DraftEditor extends React.Component {
static propTypes = {
onChangeDraft: PropTypes.func.isRequired,
};
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
this.onChange = (editorState) => {
this.setState({ editorState }, () => {
this.props.onChangeDraft(this.state);
});
};
}
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
/>
);
}
}
export default DraftEditor; In my Enzyme tests, I'm trying to verify that the |
The component looks fine.
How do you test " the content in the Editor component is changed" ? I'd be glad to see the test code. Here is some suggestions:
|
@kenju Thanks for taking a look. This is a whittled down version of my test. I've commented where I'm running into problems. describe('DraftEditor', () => {
let wrapper;
const defaultProps = {
className: 'test-class',
placeholder: 'Enter some text',
onChangeDraft: () => {},
};
const getMountComponent = (overrideProps) => {
const props = { ...defaultProps, ...overrideProps };
return mount(
<DraftEditor
className={props.className}
editingContent={props.editingContent}
placeholder={props.placeholder}
onChangeDraft={props.onChangeDraft}
/>
);
};
describe.only('onChangeDraft', () => {
it('calls props.onChange with JSON options', () => {
const onChangeSpy = sinon.spy();
wrapper = getMountComponent({ onChangeDraft: onChangeSpy });
// How to trigger the onChange event without calling it directly?
// None of these work:
// wrapper.find('.public-DraftEditor-content')...trigger keydown event
// wrapper.simulate('change')...
// wrapper.update();
expect(onChangeSpy.callCount).to.equal(1);
});
});
}); |
@nring However, I can tell you why your code does not work:
Therefore, we should find another way to test on the onChangeSpy. Here is my suggestion:
Btw, this is just a small advice on OSS activity :)
|
At this point I see many potential answers to the original question, and some great discussion. This is a pretty old issue now though, so I'm closing it. Feel free to open a new issue if questions remain. Thanks to everyone who added information here! |
I managed to get this working by creating fake paste events
where |
The code has changed since it was originally linked, so here's the line of code with |
For anyone still looking for an answer to this problem, here is what worked for me:
Obviously this abandons the notion of using |
@skolmer Thanks for the snippet 👍 . It working for adding new text. |
Problem with this , is that you'll get an warning saying : Warning: An update to KbSaveArticles inside a test was not wrapped in act(...).
|
I've been enjoying using
draft-js
; the approach to representing complex text editing states is great, and the API is pretty well documented.Where I'm getting stuck is performing integration-level blackbox testing of components that I build with Draft.
Example: I've got a
<RichTextEditor/>
component, largely based on the rich example. The editor lives in an ecosystem of HTML in, HTML out, so I want to assert that the conversion is happening as expected.I'd like to simulate a keypress with the end result of that character getting pushed onto the
editorState
, and theonChange
callback being called. I can't figure out how to accomplish this.I've tried grabbing the DOM node corresponding to the
[role="textbox"]
and simulating (with React TestUtils via Enzyme) akeyDown
event with a payload of{which: [someKeyCode]}
. I see this being handled ineditOnKeyDown
, but theonChange
handler is never called.I've tried generating a new editorState with something like this, but there's no obvious way to actually call
update()
on the<Editor/>
instance.Is there an existing approach that I'm missing? If not, I'd be happy to discuss how blackbox testing could be made easier.
Thanks!
The text was updated successfully, but these errors were encountered: