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

[RichTextInput] add tests and fix bugs #3223

Merged
merged 26 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cd43418
add failing test
cherniavskii May 14, 2019
f24ce0c
do not show error message, if input isn't touched
cherniavskii May 9, 2019
433136e
add test
cherniavskii May 14, 2019
0ab0ff4
remove .only
cherniavskii May 14, 2019
b817a66
add failing test
cherniavskii May 14, 2019
69693e6
do not block rerendering
cherniavskii May 14, 2019
ccca089
remove .only
cherniavskii May 14, 2019
928980a
add failing test
cherniavskii May 14, 2019
04df688
fix debouncing handling
cherniavskii May 14, 2019
16365ba
use bodyInput variable
cherniavskii May 14, 2019
aad3382
add bodyInput to EditPage
cherniavskii May 14, 2019
c9a2432
move new tests to create suite
cherniavskii May 14, 2019
d7642a0
fix typos
cherniavskii May 14, 2019
6e9efca
remove unnecessary navigation, which broke tests
cherniavskii May 14, 2019
acd6bb7
add rich-text-input support to create page helper
cherniavskii May 14, 2019
7139c4b
fix broken test
cherniavskii May 14, 2019
a5b3892
use setValues helper
cherniavskii May 14, 2019
5072175
use submit method
cherniavskii May 14, 2019
ecbd4bb
remove createPage bodyInput helper
cherniavskii May 14, 2019
ae9d1d4
remove bodyInput
cherniavskii May 14, 2019
39b5d7e
fix test regression
cherniavskii May 14, 2019
116b703
fix EditPage.setInputValue to have same signature as CreatePage
cherniavskii May 14, 2019
7c30b13
make error selectors more specific
cherniavskii May 14, 2019
8aebf9b
remove .only
cherniavskii May 16, 2019
24352d6
add className to rich-text-input error
cherniavskii Jun 5, 2019
647759f
add richTextInputError element to CreatePage helper
cherniavskii Jun 5, 2019
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
61 changes: 61 additions & 0 deletions cypress/integration/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ describe('Create Page', () => {
name: 'teaser',
value: 'Test teaser',
},
{
type: 'rich-text-input',
name: 'body',
value: 'Test body',
},
];

CreatePage.setValues(values);
Expand Down Expand Up @@ -103,6 +108,11 @@ describe('Create Page', () => {
name: 'teaser',
value: 'Test teaser',
},
{
type: 'rich-text-input',
name: 'body',
value: 'Test body',
},
];

CreatePage.setValues(values);
Expand All @@ -124,6 +134,11 @@ describe('Create Page', () => {
name: 'teaser',
value: 'Test teaser',
},
{
type: 'rich-text-input',
name: 'body',
value: 'Test body',
},
];
CreatePage.setValues(values);
CreatePage.submitAndAdd();
Expand Down Expand Up @@ -153,6 +168,11 @@ describe('Create Page', () => {
name: 'commentable',
value: false,
},
{
type: 'rich-text-input',
name: 'body',
value: 'Test body',
},
];

CreatePage.setValues(values);
Expand Down Expand Up @@ -212,4 +232,45 @@ describe('Create Page', () => {
expect(el).to.have.value('The real Slim Shady!')
);
});

it('should not show rich text input error message when field is untouched', () => {
cy.get(CreatePage.elements.richTextInputError).should('not.exist');
});

it('should show rich text input error message when form is submitted', () => {
CreatePage.submit();
cy.get(CreatePage.elements.richTextInputError).should('exist').contains('Required');
});

it('should not show rich text input error message when form is submitted and input is filled with text', () => {
CreatePage.submit();
cy.get(CreatePage.elements.richTextInputError).should('exist').contains('Required');
cy.get(CreatePage.elements.input('body', 'rich-text-input')).type('text');
cy.get(CreatePage.elements.richTextInputError).should('not.exist');
});

it('should show body in edit view after creating new post', () => {
const values = [
{
type: 'input',
name: 'title',
value: 'Test title',
},
{
type: 'textarea',
name: 'teaser',
value: 'Test teaser',
},
{
type: 'rich-text-input',
name: 'body',
value: 'Test body',
},
];

CreatePage.setValues(values);
CreatePage.submit();
EditPage.gotoTab(2);
cy.get(EditPage.elements.input('body', 'rich-text-input')).contains('Test body');
});
});
10 changes: 5 additions & 5 deletions cypress/integration/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Edit Page', () => {
});

it('should allow to update elements', () => {
EditPostPage.setInputValue('title', 'Lorem Ipsum');
EditPostPage.setInputValue('input', 'title', 'Lorem Ipsum');
EditPostPage.submit();
EditPostPage.navigate();
cy.get(EditPostPage.elements.input('title')).should(el =>
Expand All @@ -34,7 +34,7 @@ describe('Edit Page', () => {
});

it('should redirect to list page after edit success', () => {
EditPostPage.setInputValue('title', 'Lorem Ipsum +');
EditPostPage.setInputValue('input', 'title', 'Lorem Ipsum +');
EditPostPage.submit();
cy.url().then(url => expect(url).to.contain('/#/posts'));
});
Expand Down Expand Up @@ -68,11 +68,11 @@ describe('Edit Page', () => {
);

// This validate that the current redux form values are not kept after we navigate
EditCommentPage.setInputValue('body', 'Test');
EditCommentPage.setInputValue('input', 'body', 'Test');

CreatePostPage.navigate();

cy.get(CreatePostPage.elements.bodyInput).should(el =>
cy.get(CreatePostPage.elements.input('body', 'rich-text-input')).should(el =>
// When the Quill editor is empty, it add the "ql-blank" CSS class
expect(el).to.have.class('ql-blank')
);
Expand Down Expand Up @@ -108,7 +108,7 @@ describe('Edit Page', () => {
);

// This validate that the current redux form values are not kept after we navigate
EditPostPage.setInputValue('title', 'Another title');
EditPostPage.setInputValue('input', 'title', 'Another title');

CreatePostPage.navigate();
cy.get(CreatePostPage.elements.input('title')).should(el =>
Expand Down
12 changes: 10 additions & 2 deletions cypress/support/CreatePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ export default url => ({
elements: {
addAuthor: '.button-add-authors',
body: 'body',
bodyInput: '.ra-input-body .ql-editor',
input: (name, type = 'input') => `.create-page ${type}[name='${name}']`,
input: (name, type = 'input') => {
if (type === 'rich-text-input') {
return `.ra-input-${name} .ql-editor`;
}
return `.create-page ${type}[name='${name}']`
},
inputs: `.ra-input`,
richTextInputError: '.create-page .ra-rich-text-input-error',
snackbar: 'div[role="alertdialog"]',
submitButton: ".create-page div[role='toolbar'] button[type='submit']",
submitAndShowButton:
Expand Down Expand Up @@ -37,6 +42,9 @@ export default url => ({
cy.get(this.elements.input(name, type)).clear();
}
cy.get(this.elements.input(name, type)).type(value);
if (type === 'rich-text-input') {
cy.wait(500);
}
},

setValues(values, clearPreviousValue = true) {
Expand Down
14 changes: 11 additions & 3 deletions cypress/support/EditPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ export default url => ({
elements: {
body: 'body',
deleteButton: '.ra-delete-button',
input: name => `.edit-page [name='${name}']`,
input: (name, type = 'input') => {
if (type === 'rich-text-input') {
return `.ra-input-${name} .ql-editor`;
}
return `.edit-page [name='${name}']`
},
inputs: `.ra-input`,
tabs: `.form-tab`,
snackbar: 'div[role="alertdialog"]',
Expand All @@ -20,11 +25,14 @@ export default url => ({
return cy.get(this.elements.title);
},

setInputValue(name, value, clearPreviousValue = true) {
setInputValue(type, name, value, clearPreviousValue = true) {
if (clearPreviousValue) {
cy.get(this.elements.input(name)).clear();
}
return cy.get(this.elements.input(name)).type(value);
cy.get(this.elements.input(name)).type(value);
if (type === 'rich-text-input') {
cy.wait(500);
}
},

clickInput(name) {
Expand Down
3 changes: 2 additions & 1 deletion examples/simple/src/posts/PostCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
TextInput,
Toolbar,
crudCreate,
required,
} from 'react-admin'; // eslint-disable-line import/no-unresolved

const saveWithNote = (values, basePath, redirectTo) =>
Expand Down Expand Up @@ -102,7 +103,7 @@ const PostCreate = ({ permissions, ...props }) => (
>
<TextInput autoFocus source="title" />
<LongTextInput source="teaser" />
<RichTextInput source="body" />
<RichTextInput source="body" validate={[required()]} />
<FormDataConsumer>
{({ formData, ...rest }) =>
formData.title && (
Expand Down
21 changes: 9 additions & 12 deletions packages/ra-input-rich-text/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,11 @@ export class RichTextInput extends Component {
this.quill.setContents(this.quill.clipboard.convert(value));

this.editor = this.divRef.querySelector('.ql-editor');
this.quill.on('text-change', debounce(this.onTextChange, 500));
this.quill.on('text-change', this.onTextChange);
}

shouldComponentUpdate(nextProps) {
return nextProps.input.value !== this.lastValueChange;
}

componentDidUpdate(prevProps) {
if (prevProps.input.value !== this.props.input.value) {
componentDidUpdate() {
if (this.lastValueChange !== this.props.input.value) {
const selection = this.quill.getSelection();
this.quill.setContents(
this.quill.clipboard.convert(this.props.input.value)
Expand All @@ -76,30 +72,31 @@ export class RichTextInput extends Component {

componentWillUnmount() {
this.quill.off('text-change', this.onTextChange);
this.onTextChange.cancel();
this.quill = null;
}

onTextChange = () => {
onTextChange = debounce(() => {
const value =
this.editor.innerHTML == '<p><br></p>' ? '' : this.editor.innerHTML;
this.lastValueChange = value;
this.props.input.onChange(value);
};
}, 500);

updateDivRef = ref => {
this.divRef = ref;
};

render() {
const { error, helperText = false } = this.props.meta;
const { touched, error, helperText = false } = this.props.meta;
return (
<FormControl
error={error !== null && error != undefined}
error={!!(touched && error)}
fullWidth={this.props.fullWidth}
className="ra-rich-text-input"
>
<div data-testid="quill" ref={this.updateDivRef} />
{error && <FormHelperText error>{error}</FormHelperText>}
{touched && error && <FormHelperText error className="ra-rich-text-input-error">{error}</FormHelperText>}
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
Expand Down