fix(client): add validation to profile image URL (#41927)
* fix: fix broken image url after validation * feat: add tests for a broken image url submission * fix: reduce event related calls * Update cypress/integration/settings/image-picture-check.js Co-authored-by: Sem Bauke <46919888+Sembauke@users.noreply.github.com> * Update cypress/integration/settings/image-picture-check.js Co-authored-by: Ahmad Abdolsaheb <ahmad.abdolsaheb@gmail.com> Co-authored-by: Sem Bauke <46919888+Sembauke@users.noreply.github.com>
This commit is contained in:
@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
|
||||
import {
|
||||
FormGroup,
|
||||
ControlLabel,
|
||||
FormControl
|
||||
FormControl,
|
||||
HelpBlock,
|
||||
Alert
|
||||
} from '@freecodecamp/react-bootstrap';
|
||||
|
||||
import { FullWidthRow, Spacer } from '../helpers';
|
||||
@ -28,7 +30,7 @@ const propTypes = {
|
||||
class AboutSettings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.validationImage = new Image();
|
||||
const { name = '', location = '', picture = '', about = '' } = props;
|
||||
const values = {
|
||||
name,
|
||||
@ -39,7 +41,8 @@ class AboutSettings extends Component {
|
||||
this.state = {
|
||||
formValues: { ...values },
|
||||
originalValues: { ...values },
|
||||
formClicked: false
|
||||
formClicked: false,
|
||||
isPictureUrlValid: true
|
||||
};
|
||||
}
|
||||
|
||||
@ -69,18 +72,25 @@ class AboutSettings extends Component {
|
||||
|
||||
isFormPristine = () => {
|
||||
const { formValues, originalValues } = this.state;
|
||||
return Object.keys(originalValues)
|
||||
.map(key => originalValues[key] === formValues[key])
|
||||
.every(bool => bool);
|
||||
return (
|
||||
this.state.isPictureUrlValid === false ||
|
||||
Object.keys(originalValues)
|
||||
.map(key => originalValues[key] === formValues[key])
|
||||
.every(bool => bool)
|
||||
);
|
||||
};
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
const { formValues } = this.state;
|
||||
const { submitNewAbout } = this.props;
|
||||
return this.setState({ formClicked: true }, () =>
|
||||
submitNewAbout(formValues)
|
||||
);
|
||||
if (this.state.isPictureUrlValid === true) {
|
||||
return this.setState({ formClicked: true }, () =>
|
||||
submitNewAbout(formValues)
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
handleNameChange = e => {
|
||||
@ -103,8 +113,22 @@ class AboutSettings extends Component {
|
||||
}));
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.validationImage.addEventListener('error', this.errorEvent);
|
||||
this.validationImage.addEventListener('load', this.loadEvent);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.validationImage.removeEventListener('load', this.loadEvent);
|
||||
this.validationImage.removeEventListener('error', this.errorEvent);
|
||||
}
|
||||
|
||||
loadEvent = () => this.setState({ isPictureUrlValid: true });
|
||||
errorEvent = () => this.setState({ isPictureUrlValid: false });
|
||||
|
||||
handlePictureChange = e => {
|
||||
const value = e.target.value.slice(0);
|
||||
this.validationImage.src = value;
|
||||
return this.setState(state => ({
|
||||
formValues: {
|
||||
...state.formValues,
|
||||
@ -113,6 +137,19 @@ class AboutSettings extends Component {
|
||||
}));
|
||||
};
|
||||
|
||||
showImageValidationWarning = () => {
|
||||
const { t } = this.props;
|
||||
if (this.state.isPictureUrlValid === false) {
|
||||
return (
|
||||
<HelpBlock>
|
||||
<Alert bsStyle='info'>{t('validation.url-not-image')}</Alert>
|
||||
</HelpBlock>
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
handleAboutChange = e => {
|
||||
const value = e.target.value.slice(0);
|
||||
return this.setState(state => ({
|
||||
@ -164,6 +201,7 @@ class AboutSettings extends Component {
|
||||
type='url'
|
||||
value={picture}
|
||||
/>
|
||||
{this.showImageValidationWarning()}
|
||||
</FormGroup>
|
||||
<FormGroup controlId='about-about'>
|
||||
<ControlLabel>
|
||||
|
39
cypress/integration/settings/image-picture-check.js
Normal file
39
cypress/integration/settings/image-picture-check.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* global cy */
|
||||
|
||||
describe('Picture input field', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit('/settings');
|
||||
// Setting aliases here
|
||||
cy.get('input#about-picture').as('pictureInput');
|
||||
});
|
||||
|
||||
it('Should be possible to type', () => {
|
||||
cy.get('@pictureInput')
|
||||
.clear({ force: true })
|
||||
.type('twaha', { force: true })
|
||||
.should('have.attr', 'value', 'twaha');
|
||||
});
|
||||
it('Show an error message if an incorrect url was submitted', () => {
|
||||
cy.get('@pictureInput')
|
||||
.clear({ force: true })
|
||||
.type('https://s3.amazonaws.com/freecodecamp/camper-image', {
|
||||
force: true
|
||||
})
|
||||
.then(() => {
|
||||
cy.contains('URL must link directly to an image file');
|
||||
});
|
||||
});
|
||||
it('Can submit a correct URL', () => {
|
||||
cy.get('@pictureInput')
|
||||
.clear({ force: true })
|
||||
.type(
|
||||
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png',
|
||||
{
|
||||
force: true
|
||||
}
|
||||
);
|
||||
cy.wait(500);
|
||||
cy.get('#camper-identity > .btn').should('not.be.disabled');
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user