mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-01-27 22:59:51 -05:00
fix: login modal validation (#958)
This commit is contained in:
parent
431e7608d2
commit
9f78c31f66
4 changed files with 115 additions and 66 deletions
|
@ -64,7 +64,7 @@ export default class App extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Toogles the login modal
|
||||
* Toggles the login modal
|
||||
* Required by: <LoginModal /> <Header />
|
||||
*/
|
||||
toggleLoginModal() {
|
||||
|
@ -94,7 +94,7 @@ export default class App extends Component {
|
|||
storage.setItem('username', username);
|
||||
storage.setItem('token', token);
|
||||
// close login modal after successful login
|
||||
// set userLoggined to true
|
||||
// set isUserLoggedin to true
|
||||
this.setState({
|
||||
isUserLoggedIn: true,
|
||||
showLoginModal: false
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {Component} from 'react';
|
||||
import React, {Component, createRef} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Form, Button, Dialog, Input, Alert} from 'element-react';
|
||||
|
||||
|
@ -15,15 +15,34 @@ export default class LoginModal extends Component {
|
|||
error: {},
|
||||
onCancel: () => {},
|
||||
onSubmit: () => {}
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
username: '',
|
||||
password: ''
|
||||
}
|
||||
form: {
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input the username',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input the password',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.formRef = createRef();
|
||||
this.submitCredentials = this.submitCredentials.bind(this);
|
||||
this.setCredentials = this.setCredentials.bind(this);
|
||||
}
|
||||
|
@ -32,20 +51,34 @@ export default class LoginModal extends Component {
|
|||
* set login modal's username and password to current state
|
||||
* Required by: <LoginModal />
|
||||
*/
|
||||
setCredentials(name, e) {
|
||||
this.setState({
|
||||
[name]: e
|
||||
});
|
||||
setCredentials(key, value) {
|
||||
this.setState(
|
||||
(prevState) => ({
|
||||
form: {...prevState.form, [key]: value}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async submitCredentials(event) {
|
||||
// prevents default submit behaviour
|
||||
/**
|
||||
* Clears the username and password field.
|
||||
*/
|
||||
handleReset() {
|
||||
this.formRef.current.resetFields();
|
||||
}
|
||||
|
||||
submitCredentials(event) {
|
||||
// prevents default submit behavior
|
||||
event.preventDefault();
|
||||
const {username, password} = this.state;
|
||||
await this.props.onSubmit(username, password);
|
||||
// let's wait for API response and then set
|
||||
// username and password filed to empty state
|
||||
this.setState({username: '', password: ''});
|
||||
this.formRef.current.validate((valid) => {
|
||||
if (valid) {
|
||||
const {username, password} = this.state.form;
|
||||
this.props.onSubmit(username, password);
|
||||
this.setState({
|
||||
form: {username}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
renderLoginError({type, title, description} = {}) {
|
||||
|
@ -56,13 +89,16 @@ export default class LoginModal extends Component {
|
|||
description={description}
|
||||
showIcon={true}
|
||||
closable={false}
|
||||
style={{lineHeight: '10px'}}
|
||||
/>
|
||||
) : '';
|
||||
) : (
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {visibility, onCancel, error} = this.props;
|
||||
const {username, password} = this.state;
|
||||
const {username, password} = this.state.form;
|
||||
return (
|
||||
<div className="login-dialog">
|
||||
<Dialog
|
||||
|
@ -71,39 +107,47 @@ export default class LoginModal extends Component {
|
|||
visible={visibility}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<Form className="login-form">
|
||||
<Dialog.Body>
|
||||
{this.renderLoginError(error)}
|
||||
<br />
|
||||
<Input
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
onChange={this.setCredentials.bind(this, 'username')}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Input
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Type your password"
|
||||
value={password}
|
||||
onChange={this.setCredentials.bind(this, 'password')}
|
||||
/>
|
||||
</Dialog.Body>
|
||||
<Dialog.Footer className="dialog-footer">
|
||||
<Button onClick={onCancel} className="cancel-login-button">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
nativeType="submit"
|
||||
className="login-button"
|
||||
onClick={this.submitCredentials}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Form>
|
||||
<Dialog.Body>
|
||||
<Form
|
||||
className="login-form"
|
||||
ref={this.formRef}
|
||||
model={this.state.form}
|
||||
rules={this.state.rules}
|
||||
>
|
||||
<Form.Item>
|
||||
{this.renderLoginError(error)}
|
||||
</Form.Item>
|
||||
<Form.Item prop="username" labelPosition="top">
|
||||
<Input
|
||||
name="username"
|
||||
placeholder="Type your username"
|
||||
value={username}
|
||||
onChange={this.setCredentials.bind(this, 'username')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item prop="password">
|
||||
<Input
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Type your password"
|
||||
value={password}
|
||||
onChange={this.setCredentials.bind(this, 'password')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item style={{float: 'right'}}>
|
||||
<Button onClick={onCancel} className="cancel-login-button">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
nativeType="submit"
|
||||
className="login-button"
|
||||
onClick={this.submitCredentials}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Dialog.Body>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LoginModal /> should load the component in default state 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-dialog__body\\"><br><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div><br><br><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div><div class=\\"el-dialog__footer dialog-footer\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></form></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
exports[`<LoginModal /> should load the component in default state 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><div class=\\"el-dialog__body\\"><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Type your username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div style=\\"float: right;\\" class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></div></form></div></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
|
||||
exports[`<LoginModal /> should load the component with props 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-dialog__body\\"><div class=\\"el-alert el-alert--error\\"><i class=\\"el-alert__icon el-icon-circle-cross is-big\\"></i><div class=\\"el-alert__content\\"><span class=\\"el-alert__title is-bold\\">Error Title</span><p class=\\"el-alert__description\\">Error Description</p><i class=\\"el-alert__closebtn el-icon-close\\" style=\\"display: none;\\"></i></div></div><br><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div><br><br><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div><div class=\\"el-dialog__footer dialog-footer\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></form></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
exports[`<LoginModal /> should load the component with props 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><div class=\\"el-dialog__body\\"><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><div style=\\"line-height: 10px;\\" class=\\"el-alert el-alert--error\\"><i class=\\"el-alert__icon el-icon-circle-cross is-big\\"></i><div class=\\"el-alert__content\\"><span class=\\"el-alert__title is-bold\\">Error Title</span><p class=\\"el-alert__description\\">Error Description</p><i class=\\"el-alert__closebtn el-icon-close\\" style=\\"display: none;\\"></i></div></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Type your username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div style=\\"float: right;\\" class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></div></form></div></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('<LoginModal />', () => {
|
|||
onSubmit: () => {}
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
wrapper.find('.el-dialog__footer > .cancel-login-button').simulate('click');
|
||||
wrapper.find('button.cancel-login-button').simulate('click');
|
||||
expect(props.onCancel).toHaveBeenCalled();
|
||||
wrapper.find('.el-dialog__headerbtn > .el-dialog__close').simulate('click');
|
||||
expect(props.onCancel).toHaveBeenCalled();
|
||||
|
@ -45,35 +45,40 @@ describe('<LoginModal />', () => {
|
|||
const props = {
|
||||
visibility: true,
|
||||
error: {},
|
||||
onCancel: () => { },
|
||||
onSubmit: () => { }
|
||||
onCancel: () => {},
|
||||
onSubmit: () => {}
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
const { setCredentials } = wrapper.instance();
|
||||
|
||||
expect(setCredentials('username', 'xyz')).toBeUndefined();
|
||||
expect(wrapper.state('username')).toEqual('xyz');
|
||||
expect(wrapper.state('form').username).toEqual('xyz');
|
||||
|
||||
expect(setCredentials('password', '1234')).toBeUndefined();
|
||||
expect(wrapper.state('password')).toEqual('1234');
|
||||
expect(wrapper.state('form').password).toEqual('1234');
|
||||
});
|
||||
|
||||
it('submitCredential: should call the onSubmit', async () => {
|
||||
it('submitCredential: should call the onSubmit', () => {
|
||||
const props = {
|
||||
visibility: true,
|
||||
error: {},
|
||||
onCancel: () => { },
|
||||
onCancel: () => {},
|
||||
onSubmit: jest.fn()
|
||||
};
|
||||
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
}
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
const { submitCredentials } = wrapper.instance();
|
||||
wrapper.setState({username: 'sam', password: 1234})
|
||||
await submitCredentials(event);
|
||||
expect(props.onSubmit).toHaveBeenCalledWith('sam', 1234);
|
||||
wrapper
|
||||
.find('input[type="text"]')
|
||||
.simulate('change', { target: { value: 'sam' } });
|
||||
wrapper
|
||||
.find('input[type="password"]')
|
||||
.simulate('change', { target: { value: '1234' } });
|
||||
submitCredentials(event);
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(props.onSubmit).toHaveBeenCalledWith('sam', '1234');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue