separate validation logic to simplify testing and use same logic as backend

This commit is contained in:
Sebastian Sdorra
2018-07-27 10:14:55 +02:00
parent f5033290e2
commit 92d0fc6e69
3 changed files with 194 additions and 29 deletions

View File

@@ -1,9 +1,10 @@
// @flow // @flow
import React from "react"; import React from "react";
import {translate} from "react-i18next"; import { translate } from "react-i18next";
import type {User} from "../types/User"; import type { User } from "../types/User";
import {Checkbox, InputField} from "../../components/forms"; import { Checkbox, InputField } from "../../components/forms";
import {SubmitButton} from "../../components/buttons"; import { SubmitButton } from "../../components/buttons";
import * as validator from "./userValidation";
type Props = { type Props = {
submitForm: User => void, submitForm: User => void,
@@ -21,11 +22,10 @@ type State = {
validatePassword: string validatePassword: string
}; };
class UserForm extends React.Component<Props, State> { class UserForm extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.state = { this.state = {
user: { user: {
name: "", name: "",
@@ -46,7 +46,7 @@ class UserForm extends React.Component<Props, State> {
} }
componentDidMount() { componentDidMount() {
this.setState({ user: {...this.props.user} }); this.setState({ user: { ...this.props.user } });
} }
submit = (event: Event) => { submit = (event: Event) => {
@@ -57,8 +57,14 @@ class UserForm extends React.Component<Props, State> {
render() { render() {
const { t } = this.props; const { t } = this.props;
const user = this.state.user; const user = this.state.user;
const ButtonClickable = (this.state.validatePasswordError || this.state.nameValidationError || this.state.mailValidationError || this.state.validatePasswordError const ButtonClickable =
|| this.state.displayNameValidationError || user.name === undefined|| user.displayName === undefined); this.state.validatePasswordError ||
this.state.nameValidationError ||
this.state.mailValidationError ||
this.state.validatePasswordError ||
this.state.displayNameValidationError ||
user.name === undefined ||
user.displayName === undefined;
let nameField = null; let nameField = null;
if (!this.props.user) { if (!this.props.user) {
nameField = ( nameField = (
@@ -66,8 +72,8 @@ class UserForm extends React.Component<Props, State> {
label={t("user.name")} label={t("user.name")}
onChange={this.handleUsernameChange} onChange={this.handleUsernameChange}
value={user ? user.name : ""} value={user ? user.name : ""}
validationError= {this.state.nameValidationError} validationError={this.state.nameValidationError}
errorMessage= {t("validation.name-invalid")} errorMessage={t("validation.name-invalid")}
/> />
); );
} }
@@ -85,7 +91,7 @@ class UserForm extends React.Component<Props, State> {
label={t("user.mail")} label={t("user.mail")}
onChange={this.handleEmailChange} onChange={this.handleEmailChange}
value={user ? user.mail : ""} value={user ? user.mail : ""}
validationError= {this.state.mailValidationError} validationError={this.state.mailValidationError}
errorMessage={t("validation.mail-invalid")} errorMessage={t("validation.mail-invalid")}
/> />
<InputField <InputField
@@ -114,47 +120,68 @@ class UserForm extends React.Component<Props, State> {
onChange={this.handleActiveChange} onChange={this.handleActiveChange}
checked={user ? user.active : false} checked={user ? user.active : false}
/> />
<SubmitButton disabled={ButtonClickable} label={t("user-form.submit")} /> <SubmitButton
disabled={ButtonClickable}
label={t("user-form.submit")}
/>
</form> </form>
); );
} }
handleUsernameChange = (name: string) => { handleUsernameChange = (name: string) => {
const REGEX_NAME = /^[^ ][A-z0-9\\.\-_@ ]*[^ ]$/; this.setState({
this.setState( {nameValidationError: !REGEX_NAME.test(name), user : {...this.state.user, name} } ); nameValidationError: !validator.isNameValid(name),
user: { ...this.state.user, name }
});
}; };
handleDisplayNameChange = (displayName: string) => { handleDisplayNameChange = (displayName: string) => {
const REGEX_NAME = /^[^ ][A-z0-9\\.\-_@ ]*[^ ]$/; this.setState({
this.setState({displayNameValidationError: !REGEX_NAME.test(displayName), user : {...this.state.user, displayName} } ); displayNameValidationError: !validator.isDisplayNameValid(displayName),
user: { ...this.state.user, displayName }
});
}; };
handleEmailChange = (mail: string) => { handleEmailChange = (mail: string) => {
const REGEX_MAIL = /^[A-z0-9][\w.-]*@[A-z0-9][\w\-\\.]*\.[A-z0-9][A-z0-9-]+$/; this.setState({
this.setState( {mailValidationError: !REGEX_MAIL.test(mail), user : {...this.state.user, mail} } ); mailValidationError: !validator.isMailValid(mail),
user: { ...this.state.user, mail }
});
}; };
handlePasswordChange = (password: string) => { handlePasswordChange = (password: string) => {
const validatePasswordError = !this.checkPasswords(password, this.state.validatePassword); const validatePasswordError = !this.checkPasswords(
this.setState( {validatePasswordError: (password.length < 6) || (password.length > 32), passwordValidationError: validatePasswordError, user : {...this.state.user, password} } ); password,
this.state.validatePassword
);
this.setState({
validatePasswordError: !validator.isPasswordValid(password),
passwordValidationError: validatePasswordError,
user: { ...this.state.user, password }
});
}; };
handlePasswordValidationChange = (validatePassword: string) => { handlePasswordValidationChange = (validatePassword: string) => {
const validatePasswordError = this.checkPasswords(this.state.user.password, validatePassword) const validatePasswordError = this.checkPasswords(
this.setState({ validatePassword, passwordValidationError: !validatePasswordError }); this.state.user.password,
validatePassword
);
this.setState({
validatePassword,
passwordValidationError: !validatePasswordError
});
}; };
checkPasswords = (password1: string, password2: string) => { checkPasswords = (password1: string, password2: string) => {
return (password1 === password2); return password1 === password2;
} };
handleAdminChange = (admin: boolean) => { handleAdminChange = (admin: boolean) => {
this.setState({ user : {...this.state.user, admin} }); this.setState({ user: { ...this.state.user, admin } });
}; };
handleActiveChange = (active: boolean) => { handleActiveChange = (active: boolean) => {
this.setState({ user : {...this.state.user, active} }); this.setState({ user: { ...this.state.user, active } });
}; };
} }

View File

@@ -0,0 +1,24 @@
// @flow
const nameRegex = /^([A-z0-9\.\-_@]|[^ ]([A-z0-9\.\-_@ ]*[A-z0-9\.\-_@]|[^\s])?)$/;
export const isNameValid = (name: string) => {
return nameRegex.test(name);
};
export const isDisplayNameValid = (displayName: string) => {
if (displayName) {
return true;
}
return false;
};
const mailRegex = /^[A-z0-9][\w.-]*@[A-z0-9][\w\-\.]*\.[A-z0-9][A-z0-9-]+$/;
export const isMailValid = (mail: string) => {
return mailRegex.test(mail);
};
export const isPasswordValid = (password: string) => {
return password.length > 6 && password.length < 32;
};

View File

@@ -0,0 +1,114 @@
// @flow
import * as validator from "./userValidation";
describe("test name validation", () => {
it("should return false", () => {
// invalid names taken from ValidationUtilTest.java
const invalidNames = [
" test 123",
" test 123 ",
"test 123 ",
"test/123",
"test%123",
"test:123",
"t ",
" t",
" t ",
""
];
for (let name of invalidNames) {
expect(validator.isNameValid(name)).toBe(false);
}
});
it("should return true", () => {
// valid names taken from ValidationUtilTest.java
const validNames = [
"test",
"test.git",
"Test123.git",
"Test123-git",
"Test_user-123.git",
"test@scm-manager.de",
"test 123",
"tt",
"t"
];
for (let name of validNames) {
expect(validator.isNameValid(name)).toBe(true);
}
});
});
describe("test displayName validation", () => {
it("should return false", () => {
expect(validator.isDisplayNameValid("")).toBe(false);
});
it("should return true", () => {
// valid names taken from ValidationUtilTest.java
const validNames = [
"Arthur Dent",
"Tricia.McMillan@hitchhiker.com",
"Ford Prefect (ford.prefect@hitchhiker.com)",
"Zaphod Beeblebrox <zaphod.beeblebrox@hitchhiker.com>",
"Marvin, der depressive Roboter"
];
for (let name of validNames) {
expect(validator.isDisplayNameValid(name)).toBe(true);
}
});
});
describe("test mail validation", () => {
it("should return false", () => {
// invalid taken from ValidationUtilTest.java
const invalid = [
"ostfalia.de",
"@ostfalia.de",
"s.sdorra@",
"s.sdorra@ostfalia",
"s.sdorra@@ostfalia.de",
"s.sdorra@ ostfalia.de",
"s.sdorra @ostfalia.de"
];
for (let mail of invalid) {
expect(validator.isMailValid(mail)).toBe(false);
}
});
it("should return true", () => {
// valid taken from ValidationUtilTest.java
const valid = [
"s.sdorra@ostfalia.de",
"sdorra@ostfalia.de",
"s.sdorra@hbk-bs.de",
"s.sdorra@gmail.com",
"s.sdorra@t.co",
"s.sdorra@ucla.college",
"s.sdorra@example.xn--p1ai",
"s.sdorra@scm.solutions"
];
for (let mail of valid) {
expect(validator.isMailValid(mail)).toBe(true);
}
});
});
describe("test password validation", () => {
it("should return false", () => {
// invalid taken from ValidationUtilTest.java
const invalid = ["", "abc", "aaabbbcccdddeeefffggghhhiiijjjkkk"];
for (let password of invalid) {
expect(validator.isPasswordValid(password)).toBe(false);
}
});
it("should return true", () => {
// valid taken from ValidationUtilTest.java
const valid = ["secret123", "mySuperSecretPassword"];
for (let password of valid) {
expect(validator.isPasswordValid(password)).toBe(true);
}
});
});