Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use callback for refs and use enzyme #54

Merged
merged 9 commits into from
May 18, 2017
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ root = true
indent_style = space

[*.{js,jsx}]
indent_size = 4
indent_size = 2
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ module.exports = {
"react",
"jsx-a11y",
"import"
]
],
"env": {
"browser": true,
"mocha": true
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"babel-register": "~6.16.0",
"chai": "~3.5.0",
"chai-spies": "~0.7.1",
"enzyme": "~2.8.1",
"eslint": "~3.7.1",
"eslint-config-airbnb": "~12.0.0",
"eslint-plugin-import": "~1.16.0",
Expand Down
10 changes: 5 additions & 5 deletions src/components/markdown-editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class MarkdownEditor extends React.Component {
}

get value() {
return this.refs.textarea.value;
return this.textarea.value;
}

onInsertImageClick() {
Expand Down Expand Up @@ -81,7 +81,7 @@ export default class MarkdownEditor extends React.Component {
if (e && e.target && e.target.value) {
value = e.target.value;
} else {
value = this.refs.textarea.value;
value = this.textarea.value;
}

this.props.onChange({
Expand All @@ -107,7 +107,7 @@ export default class MarkdownEditor extends React.Component {
// helper to call markdown-insert functions on the textarea
// wrapFn takes / returns a string (from ./lib/markdown-insert.js)

const textarea = this.refs.textarea;
const textarea = this.textarea;
const selection = md.getSelection(textarea);
const { text, cursor } = wrapFn(selection);

Expand All @@ -116,7 +116,7 @@ export default class MarkdownEditor extends React.Component {
}

wrapLinesIn(wrapFn, opts = {}) {
const textarea = this.refs.textarea;
const textarea = this.textarea;
const lines = md.getSelection(textarea).split('\n');
let formattedText = lines.map((line) => wrapFn(line).text).join('\n');

Expand Down Expand Up @@ -261,7 +261,7 @@ export default class MarkdownEditor extends React.Component {

<div className="editor-area">
<textarea
ref="textarea"
ref={(textarea) => { this.textarea = textarea; }}
className="markdown-editor-input"
name={this.props.name}
placeholder={this.props.placeholder}
Expand Down
12 changes: 12 additions & 0 deletions test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"rules": {
"func-names": 0,
"prefer-arrow-callback": 0,
"import/prefer-default-export": 0,
"max-len": 0,
"react/prop-types": 0,
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-unused-expressions": 0,
"space-before-function-paren": 0,
}
}
4 changes: 2 additions & 2 deletions test/helper.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import chai from 'chai';
import spy from 'chai-spies';
import MarkdownIt from 'markdown-it'
const jsdom = require('jsdom').jsdom;
import MarkdownIt from 'markdown-it';
import { jsdom } from 'jsdom';

chai.use(spy);

Expand Down
117 changes: 55 additions & 62 deletions test/markdown-editor-test.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import TestUtils from 'react-addons-test-utils';
import React from 'react';
import { mount, shallow } from 'enzyme';
import { MarkdownEditor } from '../src/index';

function mockTextarea() {
const mockTextarea = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why this is assigning an anonymous function to a variable, rather than just declaring mockTextArea as a function.

return {
textarea: {
focus: () => {},
value: "A long\nboring string that doesn't mean anything",
selectionStart: 2,
selectionEnd: 10
}
focus: () => {},
value: "A long\nboring string that doesn't mean anything",
selectionStart: 2,
selectionEnd: 10
};
}
};

describe('MarkdownEditor', () => {
let editor;

beforeEach(() => {
editor = new MarkdownEditor({ name: 'test', onChange: Function.prototype });
editor = shallow(<MarkdownEditor name="test" onChange={() => {}} />);
});

it('exists', () => {
Expand All @@ -25,7 +24,7 @@ describe('MarkdownEditor', () => {

describe('initial state', () => {
it('should set previewing to false', () => {
expect(editor.state).to.deep.equal({ previewing: false });
expect(editor.state('previewing')).to.deep.equal(false);
});
});

Expand All @@ -34,17 +33,17 @@ describe('MarkdownEditor', () => {

beforeEach(() => {
wrapFnSpy = spy((text) => { return { text: `*${text}*`, cursor: { start: 0, end: 5 }}; });
editor.refs = mockTextarea();
editor.instance().textarea = mockTextarea();
});

it('should apply a function to the selected text', () => {
editor.wrapSelectionIn(wrapFnSpy);
editor.instance().wrapSelectionIn(wrapFnSpy);
expect(wrapFnSpy).to.have.been.called.with('long\nbor');
});

it('should trigger the onChange handler', () => {
const onChangeSpy = spy.on(editor, 'onInputChange');
editor.wrapSelectionIn(wrapFnSpy);
const onChangeSpy = spy.on(editor.instance(), 'onInputChange');
editor.instance().wrapSelectionIn(wrapFnSpy);
expect(onChangeSpy).to.have.been.called();
});
});
Expand All @@ -54,25 +53,26 @@ describe('MarkdownEditor', () => {

beforeEach(() => {
wrapFnSpy = spy((text) => { return { text: `*${text}*`, cursor: { start: 0, end: 5 }}; });
editor.refs = mockTextarea();
editor.instance().textarea = mockTextarea();
});

it('should apply a function to the selected text', () => {
editor.wrapLinesIn(wrapFnSpy);
editor.instance().wrapLinesIn(wrapFnSpy);
expect(wrapFnSpy).to.have.been.called.twice.with('long');
});

it('should trigger the onChange handler', () => {
const onChangeSpy = spy.on(editor, 'onInputChange');
editor.wrapLinesIn(wrapFnSpy);
const onChangeSpy = spy.on(editor.instance(), 'onInputChange');
editor.instance().wrapLinesIn(wrapFnSpy);
expect(onChangeSpy).to.have.been.called();
});
});

describe('#onInputChange', () => {
it('calls the props.onChange callback', () => {
const changeSpy = spy.on(editor.props, 'onChange');
editor.onInputChange({ target: { value: 'testVal' }});
const changeSpy = spy.on(editor.instance(), 'onChange');
editor = shallow(<MarkdownEditor name="test" onChange={changeSpy} />);
editor.instance().onInputChange({ target: { value: 'testVal' }});
expect(changeSpy).to.have.been.called();
});
});
Expand All @@ -81,47 +81,40 @@ describe('MarkdownEditor', () => {
let helpSpy;
beforeEach(() => {
helpSpy = spy();
editor = new MarkdownEditor({ onHelp: helpSpy });
editor = mount(<MarkdownEditor onHelp={helpSpy} />);
});

it('should call the onHelp property', () => {
editor.handleHelpRequest({ });
editor.instance().handleHelpRequest({ });
expect(helpSpy).to.have.been.called.with({ });
});
});

describe('#handlePreviewToggle', () => {
it('should toggle the preview State', () => {
editor = TestUtils.renderIntoDocument(<MarkdownEditor value="##blah blash" />);
editor.handlePreviewToggle();
expect(editor.state.previewing).to.be.true;
editor = shallow(<MarkdownEditor />);
editor.setProps({ value: '##blah blash' });
editor.instance().handlePreviewToggle();
expect(editor.state('previewing')).to.be.true;
});
});

describe('#componentWillMount', () => {
it('should set state.previewing to the value of the previewing prop', () => {
editor = TestUtils.renderIntoDocument(
<MarkdownEditor previewing value="##blah blash" />
);
expect(editor.state.previewing).to.be.true;
editor = mount(<MarkdownEditor previewing={true} value='##blah blash' />);
editor.setProps({ previewing: true, value: '##blah blash' });
expect(editor.state('previewing')).to.be.true;
});
});

describe('#componentWillReceiveProps', () => {
it('should set state.previewing to the value of the previewing prop (after mount)', () => {
// We can't manipulate props of editor directly, so create a parent component to do it via render
const testParent = React.createFactory(React.createClass({
getInitialState() {
return { previewing: true };
},
render() {
return <MarkdownEditor ref="editor" previewing={this.state.previewing} value="##blah blash" />;
}
}));

const parent = TestUtils.renderIntoDocument(testParent());
parent.setState({ previewing: false });
expect(parent.refs.editor.state.previewing).to.be.false;
const cwrpSpy = spy.on(MarkdownEditor.prototype, 'componentWillReceiveProps');
editor = mount(<MarkdownEditor value="##blah blash" />);
expect(editor.state('previewing')).to.be.false;
editor.setProps({ previewing: true });
expect(cwrpSpy).to.have.been.called();
expect(editor.state('previewing')).to.be.true;
});
});

Expand All @@ -140,50 +133,50 @@ describe('MarkdownEditor', () => {
it(`should setup a click listener for ${name} button`, () => {
cbName = cbName || name.charAt(0).toUpperCase() + name.slice(1);
const cbSpy = spy.on(MarkdownEditor.prototype, `on${cbName}Click`);
editor = TestUtils.renderIntoDocument(<MarkdownEditor value="##blah blash" />);
editor.refs = mockTextarea();
const button = TestUtils.findRenderedDOMComponentWithClass(editor, `talk-comment-${name}-button`);
TestUtils.Simulate.click(button);
editor = mount(<MarkdownEditor value="##blah blash" />);
editor.textarea = mockTextarea();
const button = editor.find(`.talk-comment-${name}-button`);
button.simulate('click');
expect(cbSpy).to.have.been.called();
});
});

context('when previewing is true', () => {
beforeEach(() => {
editor = TestUtils.renderIntoDocument(<MarkdownEditor previewing />);
editor = shallow(<MarkdownEditor previewing />);
});

it('should set the preview icon to pencil', () => {
const icon = TestUtils.findRenderedDOMComponentWithClass(editor, 'fa-pencil');
const icon = editor.find('.fa-pencil');
expect(icon).to.be.ok;
});

it('should set data-previewing to true', () => {
const md = TestUtils.findRenderedDOMComponentWithClass(editor, 'markdown-editor');
expect(md.hasAttribute('data-previewing')).to.be.true;
const md = editor.render().find('.markdown-editor');
expect(md.attr('data-previewing')).to.exist;
});
});

context('when previewing is false', () => {
beforeEach(() => {
editor = TestUtils.renderIntoDocument(<MarkdownEditor previewing={false} />);
editor = shallow(<MarkdownEditor previewing={false} />);
});

it('should set the preview icon to eye', () => {
const icon = TestUtils.findRenderedDOMComponentWithClass(editor, 'fa-eye');
const icon = editor.find('.fa-eye');
expect(icon).to.be.ok;
});

it('should not set data-previewing', () => {
const md = TestUtils.findRenderedDOMComponentWithClass(editor, 'markdown-editor');
expect(md.hasAttribute('data-previewing')).to.be.false;
const md = editor.render().find('.markdown-editor');
expect(md.attr('data-previewing')).to.not.exist;
});
});

it('should render a markdown preview from the value property', () => {
editor = TestUtils.renderIntoDocument(<MarkdownEditor value="## blah blah" />);
const markdown = TestUtils.findRenderedDOMComponentWithClass(editor, 'markdown-editor-preview');
expect(markdown.innerHTML).to.match(/blah blah/);
editor = shallow(<MarkdownEditor value="## blah blah" />);
const markdown = editor.find('.markdown-editor-preview');
expect(markdown.html()).to.match(/blah blah/);
});

it('should pass properties to the textarea', () => {
Expand All @@ -194,13 +187,13 @@ describe('MarkdownEditor', () => {
name: 'hey there'
};
const value = 'oh there';
editor = TestUtils.renderIntoDocument(<MarkdownEditor {...properties} value={value} />);
const textarea = TestUtils.findRenderedDOMComponentWithTag(editor, 'textarea');
editor = shallow(<MarkdownEditor {...properties} value={value} />);
const textarea = editor.render().find('textarea');
Object.keys(properties).forEach((key) => {
const val = properties[key];
expect(textarea.getAttribute(key)).to.be.equal(val);
expect(textarea.attr(key)).to.equal(val);
});
expect(textarea.value).to.equal(value);
expect(editor.find('textarea').props().value).to.equal(value);
});
});
});