Revision a671ecad
Added by Avi Sharvit about 6 years ago
package.json | ||
---|---|---|
"jest": {
|
||
"automock": true,
|
||
"verbose": true,
|
||
"testMatch": [
|
||
"**/*.test.js"
|
||
],
|
||
"collectCoverage": true,
|
||
"collectCoverageFrom": [
|
||
"webpack/**/*.js",
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrength.fixtures.js | ||
---|---|---|
export const passwords = {
|
||
username: { password: 'my-user-name', expected: __('Weak') },
|
||
email: { password: 'my-user@email.com', expected: __('Weak') },
|
||
tooShort: { password: '12345', expected: __('Too short') },
|
||
weak: { password: '123456', expected: __('Weak') },
|
||
medium: { password: 'qwedsa', expected: __('Medium') },
|
||
normal: { password: 'QwedsaZx', expected: __('Normal') },
|
||
strong: { password: 'StrongP@$w0rd', expected: __('Strong') },
|
||
veryStrong: { password: '|Kkh)Xeu#T8($"P;', expected: __('Very strong') },
|
||
};
|
||
|
||
export const passwordStrengthData = {
|
||
className: 'some-class-name',
|
||
id: 'some-id',
|
||
name: 'some-name',
|
||
error: 'some-password-error',
|
||
userInputIds: [],
|
||
};
|
||
|
||
export const passwordStrengthDataWithVerify = {
|
||
...passwordStrengthData,
|
||
verify: {
|
||
name: 'user[password_confirmation]',
|
||
error: 'some-password-confirmation-error',
|
||
},
|
||
};
|
||
|
||
export const passwordStrengthDataWithInputIds = {
|
||
...passwordStrengthData,
|
||
userInputIds: ['input1', 'input2'],
|
||
};
|
||
|
||
export const passwordStrengthDefaultProps = {
|
||
doesPasswordsMatch: true,
|
||
data: { ...passwordStrengthData },
|
||
};
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrength.js | ||
---|---|---|
import React from 'react';
|
||
import PropTypes from 'prop-types';
|
||
import ReactPasswordStrength from 'react-password-strength';
|
||
|
||
import CommonForm from '../common/forms/CommonForm';
|
||
|
||
import './PasswordStrength.scss';
|
||
|
||
export default class PasswordStrength extends React.Component {
|
||
render() {
|
||
const {
|
||
updatePassword,
|
||
updatePasswordConfirmation,
|
||
doesPasswordsMatch,
|
||
data: {
|
||
className, id, name, verify, error, userInputIds,
|
||
},
|
||
} = this.props;
|
||
|
||
const userInputs =
|
||
userInputIds && userInputIds.length > 0
|
||
? userInputIds.map(input => document.getElementById(input).value)
|
||
: [];
|
||
|
||
return (
|
||
<div>
|
||
<CommonForm label={__('Password')} touched={true} error={error}>
|
||
<ReactPasswordStrength
|
||
changeCallback={({ password }) => updatePassword(password)}
|
||
minLength={6}
|
||
minScore={2}
|
||
userInputs={userInputs}
|
||
tooShortWord={__('Too short')}
|
||
scoreWords={[__('Weak'), __('Medium'), __('Normal'), __('Strong'), __('Very strong')]}
|
||
inputProps={{ name, id, className }}
|
||
/>
|
||
</CommonForm>
|
||
{verify && (
|
||
<CommonForm
|
||
label={__('Verify')}
|
||
touched={true}
|
||
error={doesPasswordsMatch ? verify.error : __('Passwords do not match')}
|
||
>
|
||
<input
|
||
id="password_confirmation"
|
||
name={verify.name}
|
||
type="password"
|
||
onChange={({ target }) => updatePasswordConfirmation(target.value)}
|
||
className="form-control"
|
||
/>
|
||
</CommonForm>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
}
|
||
|
||
PasswordStrength.propTypes = {
|
||
updatePassword: PropTypes.func.isRequired,
|
||
updatePasswordConfirmation: PropTypes.func,
|
||
doesPasswordsMatch: PropTypes.bool,
|
||
data: PropTypes.shape({
|
||
className: PropTypes.string,
|
||
id: PropTypes.string,
|
||
name: PropTypes.string,
|
||
error: PropTypes.node,
|
||
userInputIds: PropTypes.arrayOf(PropTypes.string),
|
||
verify: PropTypes.shape({
|
||
name: PropTypes.string.isRequired,
|
||
error: PropTypes.node,
|
||
}),
|
||
}).isRequired,
|
||
};
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrength.scss | ||
---|---|---|
@import '~patternfly/dist/sass/patternfly/variables';
|
||
@import '../../common/colors.scss';
|
||
|
||
.ReactPasswordStrength {
|
||
.ReactPasswordStrength-input {
|
||
width: 100%;
|
||
font-size: 12px;
|
||
font-family: $font-family-base;
|
||
padding: 2px 30px 2px 6px;
|
||
font-style: normal;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-desc {
|
||
padding: 6px 10px;
|
||
right: -62.5%;
|
||
font-size: 12px;
|
||
width: 60%;
|
||
text-align: left;
|
||
font-style: normal;
|
||
font-family: $font-family-base;
|
||
}
|
||
}
|
||
|
||
#password_react {
|
||
.form-group.has-error .ReactPasswordStrength-input {
|
||
border: 1px solid $pf-red-100;
|
||
}
|
||
|
||
.is-strength-0 {
|
||
.ReactPasswordStrength-strength-desc {
|
||
color: $pf-red-200;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-bar {
|
||
background: $pf-red-200;
|
||
}
|
||
}
|
||
|
||
.is-strength-1 {
|
||
.ReactPasswordStrength-strength-desc {
|
||
color: $pf-orange-400;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-bar {
|
||
background: $pf-orange-400;
|
||
}
|
||
}
|
||
|
||
.is-strength-2 {
|
||
.ReactPasswordStrength-strength-desc {
|
||
color: $pf-gold-400;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-bar {
|
||
background: $pf-gold-400;
|
||
}
|
||
}
|
||
|
||
.is-strength-3 {
|
||
.ReactPasswordStrength-strength-desc {
|
||
color: $pf-green-400;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-bar {
|
||
background: $pf-green-400;
|
||
}
|
||
}
|
||
|
||
.is-strength-4 {
|
||
.ReactPasswordStrength-strength-desc {
|
||
color: $pf-green-600;
|
||
}
|
||
|
||
.ReactPasswordStrength-strength-bar {
|
||
background: $pf-green-600;
|
||
}
|
||
}
|
||
}
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrengthActions.js | ||
---|---|---|
import {
|
||
PASSWORD_STRENGTH_PASSWORD_CHANGED,
|
||
PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
|
||
} from './PasswordStrengthConstants';
|
||
|
||
export const updatePassword = password => ({
|
||
type: PASSWORD_STRENGTH_PASSWORD_CHANGED,
|
||
payload: password,
|
||
});
|
||
|
||
export const updatePasswordConfirmation = password => ({
|
||
type: PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
|
||
payload: password,
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrengthConstants.js | ||
---|---|---|
export const PASSWORD_STRENGTH_PASSWORD_CHANGED = 'PASSWORD_STRENGTH_PASSWORD_CHANGED';
|
||
export const PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED =
|
||
'PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED';
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrengthReducer.js | ||
---|---|---|
import Immutable from 'seamless-immutable';
|
||
|
||
import {
|
||
PASSWORD_STRENGTH_PASSWORD_CHANGED,
|
||
PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
|
||
} from './PasswordStrengthConstants';
|
||
|
||
const initialState = Immutable({
|
||
password: '',
|
||
passwordConfirmation: '',
|
||
});
|
||
|
||
export default (state = initialState, action) => {
|
||
const { payload } = action;
|
||
|
||
switch (action.type) {
|
||
case PASSWORD_STRENGTH_PASSWORD_CHANGED:
|
||
return state.set('password', payload);
|
||
|
||
case PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED:
|
||
return state.set('passwordConfirmation', payload);
|
||
|
||
default:
|
||
return state;
|
||
}
|
||
};
|
webpack/assets/javascripts/react_app/components/PasswordStrength/PasswordStrengthSelectors.js | ||
---|---|---|
export const doesPasswordsMatch = ({ password, passwordConfirmation }) =>
|
||
!passwordConfirmation || password === passwordConfirmation;
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/PasswordStrength.test.js | ||
---|---|---|
import React from 'react';
|
||
import { mount } from 'enzyme';
|
||
|
||
import { testComponentSnapshotsWithFixtures } from '../../../common/testHelpers';
|
||
|
||
import {
|
||
passwordStrengthDataWithVerify,
|
||
passwordStrengthDataWithInputIds,
|
||
passwordStrengthDefaultProps,
|
||
} from '../PasswordStrength.fixtures';
|
||
|
||
import PasswordStrength from '../PasswordStrength';
|
||
|
||
const createStubs = () => ({
|
||
updatePassword: jest.fn(),
|
||
updatePasswordConfirmation: jest.fn(),
|
||
});
|
||
|
||
const createProps = (props = {}) => ({
|
||
...createStubs(),
|
||
...passwordStrengthDefaultProps,
|
||
...props,
|
||
});
|
||
|
||
const fixtures = {
|
||
'renders password-strength': createProps(),
|
||
'renders password-strength with password-confirmation': createProps({
|
||
data: { ...passwordStrengthDataWithVerify },
|
||
}),
|
||
'renders password-strength with unmatched password-confirmation': createProps({
|
||
doesPasswordsMatch: false,
|
||
data: { ...passwordStrengthDataWithVerify },
|
||
}),
|
||
'renders password-strength with user-input-ids': createProps({
|
||
data: { ...passwordStrengthDataWithInputIds },
|
||
}),
|
||
};
|
||
|
||
describe('PasswordStrength component', () => {
|
||
jest.spyOn(document, 'getElementById').mockImplementation(id => ({ value: id }));
|
||
|
||
describe('rendering', () =>
|
||
testComponentSnapshotsWithFixtures(PasswordStrength, fixtures));
|
||
|
||
describe('triggering', () => {
|
||
const setInputValue = (input, value) => {
|
||
input.instance().value = value; // eslint-disable-line no-param-reassign
|
||
input.simulate('change', { target: { value } });
|
||
};
|
||
|
||
it('should trigger updatePassword', () => {
|
||
const props = createProps();
|
||
const component = mount(<PasswordStrength {...props} />);
|
||
|
||
const passwordInput = component.find(`input#${props.data.id}`);
|
||
setInputValue(passwordInput, 'some-value');
|
||
|
||
expect(props.updatePassword.mock.calls).toMatchSnapshot();
|
||
});
|
||
|
||
it('should trigger updatePasswordConfirmation', () => {
|
||
const props = createProps({ data: { ...passwordStrengthDataWithVerify } });
|
||
const component = mount(<PasswordStrength {...props} />);
|
||
|
||
const passwordConfirmationInput = component.find('input#password_confirmation');
|
||
setInputValue(passwordConfirmationInput, 'some-value');
|
||
|
||
expect(props.updatePasswordConfirmation.mock.calls).toMatchSnapshot();
|
||
});
|
||
});
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/PasswordStrengthActions.test.js | ||
---|---|---|
import { updatePassword, updatePasswordConfirmation } from '../PasswordStrengthActions';
|
||
|
||
describe('PasswordStrength actions', () => {
|
||
it('should update password', () =>
|
||
expect(updatePassword('some-password')).toMatchSnapshot());
|
||
|
||
it('should update password-confirmation', () =>
|
||
expect(updatePasswordConfirmation('some-password')).toMatchSnapshot());
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/PasswordStrengthReducer.test.js | ||
---|---|---|
import {
|
||
PASSWORD_STRENGTH_PASSWORD_CHANGED,
|
||
PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
|
||
} from '../PasswordStrengthConstants';
|
||
|
||
import reducer from '../PasswordStrengthReducer';
|
||
|
||
describe('PasswordStrength reducer', () => {
|
||
const reduce = ({ state, action = {} } = {}) => reducer(state, action);
|
||
|
||
it('should return the initial state', () => expect(reduce()).toMatchSnapshot());
|
||
|
||
it('should handle PASSWORD_STRENGTH_PASSWORD_CHANGED', () =>
|
||
expect(reduce({
|
||
action: {
|
||
type: PASSWORD_STRENGTH_PASSWORD_CHANGED,
|
||
payload: 'some-password',
|
||
},
|
||
})).toMatchSnapshot());
|
||
|
||
it('should handle PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED', () =>
|
||
expect(reduce({
|
||
action: {
|
||
type: PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
|
||
payload: 'some-password',
|
||
},
|
||
})).toMatchSnapshot());
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/PasswordStrengthSelectors.test.js | ||
---|---|---|
import { doesPasswordsMatch } from '../PasswordStrengthSelectors';
|
||
|
||
describe('PasswordStrength selectors', () => {
|
||
describe('doesPasswordsMatch', () => {
|
||
const expectPasswordsMatch = ({ password, passwordConfirmation }) =>
|
||
expect(doesPasswordsMatch({ password, passwordConfirmation }));
|
||
|
||
it('should not match different passwords', () =>
|
||
expectPasswordsMatch({
|
||
password: 'password',
|
||
passwordConfirmation: 'different-password',
|
||
}).toBe(false));
|
||
|
||
it('should match empty state', () => expectPasswordsMatch({}).toBe(true));
|
||
|
||
it('should match empty password-confirmation', () =>
|
||
expectPasswordsMatch({ password: 'some-password' }).toBe(true));
|
||
|
||
it('should match same password', () =>
|
||
expectPasswordsMatch({ password: 'password', passwordConfirmation: 'password' }).toBe(true));
|
||
});
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/__snapshots__/PasswordStrength.test.js.snap | ||
---|---|---|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||
|
||
exports[`PasswordStrength component rendering renders password-strength 1`] = `
|
||
<div>
|
||
<CommonForm
|
||
error="some-password-error"
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "some-class-name",
|
||
"id": "some-id",
|
||
"name": "some-name",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
/>
|
||
</CommonForm>
|
||
</div>
|
||
`;
|
||
|
||
exports[`PasswordStrength component rendering renders password-strength with password-confirmation 1`] = `
|
||
<div>
|
||
<CommonForm
|
||
error="some-password-error"
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "some-class-name",
|
||
"id": "some-id",
|
||
"name": "some-name",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
/>
|
||
</CommonForm>
|
||
<CommonForm
|
||
error="some-password-confirmation-error"
|
||
label="Verify"
|
||
touched={true}
|
||
>
|
||
<input
|
||
className="form-control"
|
||
id="password_confirmation"
|
||
name="user[password_confirmation]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
/>
|
||
</CommonForm>
|
||
</div>
|
||
`;
|
||
|
||
exports[`PasswordStrength component rendering renders password-strength with unmatched password-confirmation 1`] = `
|
||
<div>
|
||
<CommonForm
|
||
error="some-password-error"
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "some-class-name",
|
||
"id": "some-id",
|
||
"name": "some-name",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
/>
|
||
</CommonForm>
|
||
<CommonForm
|
||
error="Passwords do not match"
|
||
label="Verify"
|
||
touched={true}
|
||
>
|
||
<input
|
||
className="form-control"
|
||
id="password_confirmation"
|
||
name="user[password_confirmation]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
/>
|
||
</CommonForm>
|
||
</div>
|
||
`;
|
||
|
||
exports[`PasswordStrength component rendering renders password-strength with user-input-ids 1`] = `
|
||
<div>
|
||
<CommonForm
|
||
error="some-password-error"
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "some-class-name",
|
||
"id": "some-id",
|
||
"name": "some-name",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={
|
||
Array [
|
||
"input1",
|
||
"input2",
|
||
]
|
||
}
|
||
/>
|
||
</CommonForm>
|
||
</div>
|
||
`;
|
||
|
||
exports[`PasswordStrength component triggering should trigger updatePassword 1`] = `
|
||
Array [
|
||
Array [
|
||
"some-value",
|
||
],
|
||
]
|
||
`;
|
||
|
||
exports[`PasswordStrength component triggering should trigger updatePasswordConfirmation 1`] = `
|
||
Array [
|
||
Array [
|
||
"some-value",
|
||
],
|
||
]
|
||
`;
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/__snapshots__/PasswordStrengthActions.test.js.snap | ||
---|---|---|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||
|
||
exports[`PasswordStrength actions should update password 1`] = `
|
||
Object {
|
||
"payload": "some-password",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
}
|
||
`;
|
||
|
||
exports[`PasswordStrength actions should update password-confirmation 1`] = `
|
||
Object {
|
||
"payload": "some-password",
|
||
"type": "PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED",
|
||
}
|
||
`;
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/__snapshots__/PasswordStrengthReducer.test.js.snap | ||
---|---|---|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||
|
||
exports[`PasswordStrength reducer should handle PASSWORD_STRENGTH_PASSWORD_CHANGED 1`] = `
|
||
Object {
|
||
"password": "some-password",
|
||
"passwordConfirmation": "",
|
||
}
|
||
`;
|
||
|
||
exports[`PasswordStrength reducer should handle PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED 1`] = `
|
||
Object {
|
||
"password": "",
|
||
"passwordConfirmation": "some-password",
|
||
}
|
||
`;
|
||
|
||
exports[`PasswordStrength reducer should return the initial state 1`] = `
|
||
Object {
|
||
"password": "",
|
||
"passwordConfirmation": "",
|
||
}
|
||
`;
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/__snapshots__/integration.test.js.snap | ||
---|---|---|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||
|
||
exports[`email fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "my-user@email.com",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "my-user@email.com",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`initial state 1`] = `
|
||
Object {
|
||
"passwordStrength": Object {
|
||
"password": "",
|
||
"passwordConfirmation": "",
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`mached password confirmation 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "|Kkh)Xeu#T8($\\"P;",
|
||
"type": "PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "|Kkh)Xeu#T8($\\"P;",
|
||
"passwordConfirmation": "|Kkh)Xeu#T8($\\"P;",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`medium fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "qwedsa",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "qwedsa",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`normal fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "QwedsaZx",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "QwedsaZx",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`strong fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "StrongP@$w0rd",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "StrongP@$w0rd",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`tooShort fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "12345",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "12345",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`unmached password confirmation 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "StrongP@$w0rd",
|
||
"type": "PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "|Kkh)Xeu#T8($\\"P;",
|
||
"passwordConfirmation": "StrongP@$w0rd",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`username fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "my-user-name",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "my-user-name",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`veryStrong fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "|Kkh)Xeu#T8($\\"P;",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "|Kkh)Xeu#T8($\\"P;",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
||
|
||
exports[`weak fixture 1`] = `
|
||
Object {
|
||
"action": Array [
|
||
Array [
|
||
Object {
|
||
"payload": "123456",
|
||
"type": "PASSWORD_STRENGTH_PASSWORD_CHANGED",
|
||
},
|
||
],
|
||
],
|
||
"state": Object {
|
||
"passwordStrength": Object {
|
||
"password": "123456",
|
||
"passwordConfirmation": "",
|
||
},
|
||
},
|
||
}
|
||
`;
|
webpack/assets/javascripts/react_app/components/PasswordStrength/__tests__/integration.test.js | ||
---|---|---|
import React from 'react';
|
||
|
||
import IntegrationTestHelper from '../../../common/IntegrationTestHelper';
|
||
|
||
import { passwords } from '../PasswordStrength.fixtures';
|
||
import PasswordStrength, { reducers } from '../index';
|
||
|
||
// mock the document.getElementById
|
||
document.getElementById = jest.fn(id => ({ value: passwords[id].password }));
|
||
|
||
describe('PasswordStrength integration test', () => {
|
||
// the password-strength 3rd-party reading the input.value instead the event.value
|
||
// therefore, it is not enough to simulate a change-event
|
||
const setInputValue = (input, value) => {
|
||
input.instance().value = value; // eslint-disable-line no-param-reassign
|
||
input.simulate('change', { target: { value } });
|
||
};
|
||
|
||
it('should flow', () => {
|
||
const integrationTestHelper = new IntegrationTestHelper(reducers);
|
||
|
||
const component = integrationTestHelper.mount(<div>
|
||
<input id="username" value={passwords.username.password} readOnly />
|
||
<input id="email" value={passwords.email.password} readOnly />
|
||
<PasswordStrength
|
||
data={{
|
||
className: 'form-control',
|
||
id: 'user_password',
|
||
name: 'user[password]',
|
||
verify: { name: 'user[password_confirmation]' },
|
||
userInputIds: ['username', 'email'],
|
||
}}
|
||
/>
|
||
</div>);
|
||
|
||
const passwordInput = component.find('input#user_password');
|
||
const passwordConfirmationInput = component.find('input#password_confirmation');
|
||
const passwordWarning = component.find('.ReactPasswordStrength-strength-desc');
|
||
|
||
integrationTestHelper.takeStoreSnapshot('initial state');
|
||
|
||
Object.keys(passwords).forEach((key) => {
|
||
const { password, expected } = passwords[key];
|
||
|
||
setInputValue(passwordInput, password);
|
||
|
||
expect(passwordWarning.text()).toBe(expected);
|
||
integrationTestHelper.takeStoreAndLastActionSnapshot(`${key} fixture`);
|
||
});
|
||
|
||
setInputValue(passwordConfirmationInput, passwords.strong.password);
|
||
expect(component.find(`CommonForm[label="${__('Verify')}"] .help-block`).length).toBe(1);
|
||
integrationTestHelper.takeStoreAndLastActionSnapshot('unmached password confirmation');
|
||
|
||
setInputValue(passwordConfirmationInput, passwords.veryStrong.password);
|
||
expect(component.find(`CommonForm[label="${__('Verify')}"] .help-block`).length).toBe(0);
|
||
integrationTestHelper.takeStoreAndLastActionSnapshot('mached password confirmation');
|
||
});
|
||
});
|
webpack/assets/javascripts/react_app/components/PasswordStrength/index.js | ||
---|---|---|
import { bindActionCreators } from 'redux';
|
||
import { connect } from 'react-redux';
|
||
|
||
import * as actions from './PasswordStrengthActions';
|
||
import { doesPasswordsMatch } from './PasswordStrengthSelectors';
|
||
import reducer from './PasswordStrengthReducer';
|
||
|
||
import PasswordStrength from './PasswordStrength';
|
||
|
||
// map state to props
|
||
const mapStateToProps = ({ passwordStrength }) => ({
|
||
doesPasswordsMatch: doesPasswordsMatch(passwordStrength),
|
||
});
|
||
|
||
// map action dispatchers to props
|
||
const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
|
||
|
||
// export reducers
|
||
export const reducers = { passwordStrength: reducer };
|
||
|
||
// export connected component
|
||
export default connect(mapStateToProps, mapDispatchToProps)(PasswordStrength);
|
webpack/assets/javascripts/react_app/components/componentRegistry.js | ||
---|---|---|
import ToastsList from './toastNotifications/';
|
||
import StorageContainer from './hosts/storage/vmware/';
|
||
import BookmarkContainer from './bookmarks';
|
||
import PasswordStrength from './user/passwordStrength/';
|
||
import PasswordStrength from './PasswordStrength';
|
||
import BreadcrumbBar from './BreadcrumbBar';
|
||
import FactChart from './factCharts';
|
||
|
webpack/assets/javascripts/react_app/components/user/passwordStrength/__snapshots__/passwordStrength.test.js.snap | ||
---|---|---|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||
|
||
exports[`Verify field display verify password field with error 1`] = `
|
||
<Connect(PasswordStrength)
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": Object {
|
||
"error": "Error",
|
||
"name": "user[password_confirmation]",
|
||
},
|
||
}
|
||
}
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
>
|
||
<PasswordStrength
|
||
checkPasswordsMatch={[Function]}
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": Object {
|
||
"error": "Error",
|
||
"name": "user[password_confirmation]",
|
||
},
|
||
}
|
||
}
|
||
matchMessage={false}
|
||
password="password"
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
storeSubscription={
|
||
Subscription {
|
||
"listeners": Object {
|
||
"clear": [Function],
|
||
"get": [Function],
|
||
"notify": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"onStateChange": [Function],
|
||
"parentSub": undefined,
|
||
"store": Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"unsubscribe": [Function],
|
||
}
|
||
}
|
||
updatePassword={[Function]}
|
||
>
|
||
<div>
|
||
<CommonForm
|
||
error={false}
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<div
|
||
className="form-group "
|
||
>
|
||
<label
|
||
className="col-md-2 control-label"
|
||
>
|
||
Password
|
||
</label>
|
||
<div
|
||
className="col-md-4"
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "form-control",
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
>
|
||
<div
|
||
className="ReactPasswordStrength "
|
||
>
|
||
<input
|
||
className="ReactPasswordStrength-input form-control"
|
||
id="user_password"
|
||
name="user[password]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
value=""
|
||
/>
|
||
<div
|
||
className="ReactPasswordStrength-strength-bar"
|
||
/>
|
||
<span
|
||
className="ReactPasswordStrength-strength-desc"
|
||
>
|
||
Too short
|
||
</span>
|
||
</div>
|
||
</ReactPasswordStrength>
|
||
</div>
|
||
</div>
|
||
</CommonForm>
|
||
<CommonForm
|
||
error="Password do not match"
|
||
label="Verify"
|
||
touched={true}
|
||
>
|
||
<div
|
||
className="form-group has-error"
|
||
>
|
||
<label
|
||
className="col-md-2 control-label"
|
||
>
|
||
Verify
|
||
</label>
|
||
<div
|
||
className="col-md-4"
|
||
>
|
||
<input
|
||
className="form-control"
|
||
id="password_confirmation"
|
||
name="user[password_confirmation]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
/>
|
||
</div>
|
||
<span
|
||
className="help-block help-inline"
|
||
>
|
||
<span
|
||
className="error-message"
|
||
>
|
||
Password do not match
|
||
</span>
|
||
</span>
|
||
</div>
|
||
</CommonForm>
|
||
</div>
|
||
</PasswordStrength>
|
||
</Connect(PasswordStrength)>
|
||
`;
|
||
|
||
exports[`Verify field display verify password field with no error 1`] = `
|
||
<Connect(PasswordStrength)
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": Object {
|
||
"error": false,
|
||
"name": "user[password_confirmation]",
|
||
},
|
||
}
|
||
}
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
>
|
||
<PasswordStrength
|
||
checkPasswordsMatch={[Function]}
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": Object {
|
||
"error": false,
|
||
"name": "user[password_confirmation]",
|
||
},
|
||
}
|
||
}
|
||
matchMessage={true}
|
||
password="password"
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
storeSubscription={
|
||
Subscription {
|
||
"listeners": Object {
|
||
"clear": [Function],
|
||
"get": [Function],
|
||
"notify": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"onStateChange": [Function],
|
||
"parentSub": undefined,
|
||
"store": Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"unsubscribe": [Function],
|
||
}
|
||
}
|
||
updatePassword={[Function]}
|
||
>
|
||
<div>
|
||
<CommonForm
|
||
error={false}
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<div
|
||
className="form-group "
|
||
>
|
||
<label
|
||
className="col-md-2 control-label"
|
||
>
|
||
Password
|
||
</label>
|
||
<div
|
||
className="col-md-4"
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "form-control",
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
>
|
||
<div
|
||
className="ReactPasswordStrength "
|
||
>
|
||
<input
|
||
className="ReactPasswordStrength-input form-control"
|
||
id="user_password"
|
||
name="user[password]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
value=""
|
||
/>
|
||
<div
|
||
className="ReactPasswordStrength-strength-bar"
|
||
/>
|
||
<span
|
||
className="ReactPasswordStrength-strength-desc"
|
||
>
|
||
Too short
|
||
</span>
|
||
</div>
|
||
</ReactPasswordStrength>
|
||
</div>
|
||
</div>
|
||
</CommonForm>
|
||
<CommonForm
|
||
error={false}
|
||
label="Verify"
|
||
touched={true}
|
||
>
|
||
<div
|
||
className="form-group "
|
||
>
|
||
<label
|
||
className="col-md-2 control-label"
|
||
>
|
||
Verify
|
||
</label>
|
||
<div
|
||
className="col-md-4"
|
||
>
|
||
<input
|
||
className="form-control"
|
||
id="password_confirmation"
|
||
name="user[password_confirmation]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</CommonForm>
|
||
</div>
|
||
</PasswordStrength>
|
||
</Connect(PasswordStrength)>
|
||
`;
|
||
|
||
exports[`Verify field verify password field should not rendered 1`] = `
|
||
<Connect(PasswordStrength)
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": false,
|
||
}
|
||
}
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
>
|
||
<PasswordStrength
|
||
checkPasswordsMatch={[Function]}
|
||
data={
|
||
Object {
|
||
"className": "form-control",
|
||
"error": false,
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
"userInputIds": Array [],
|
||
"verify": false,
|
||
}
|
||
}
|
||
matchMessage={true}
|
||
password=""
|
||
store={
|
||
Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
}
|
||
}
|
||
storeSubscription={
|
||
Subscription {
|
||
"listeners": Object {
|
||
"clear": [Function],
|
||
"get": [Function],
|
||
"notify": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"onStateChange": [Function],
|
||
"parentSub": undefined,
|
||
"store": Object {
|
||
"clearActions": [Function],
|
||
"dispatch": [Function],
|
||
"getActions": [Function],
|
||
"getState": [Function],
|
||
"replaceReducer": [Function],
|
||
"subscribe": [Function],
|
||
},
|
||
"unsubscribe": [Function],
|
||
}
|
||
}
|
||
updatePassword={[Function]}
|
||
>
|
||
<div>
|
||
<CommonForm
|
||
error={false}
|
||
label="Password"
|
||
touched={true}
|
||
>
|
||
<div
|
||
className="form-group "
|
||
>
|
||
<label
|
||
className="col-md-2 control-label"
|
||
>
|
||
Password
|
||
</label>
|
||
<div
|
||
className="col-md-4"
|
||
>
|
||
<ReactPasswordStrength
|
||
changeCallback={[Function]}
|
||
className=""
|
||
defaultValue=""
|
||
inputProps={
|
||
Object {
|
||
"className": "form-control",
|
||
"id": "user_password",
|
||
"name": "user[password]",
|
||
}
|
||
}
|
||
minLength={6}
|
||
minScore={2}
|
||
scoreWords={
|
||
Array [
|
||
"Weak",
|
||
"Medium",
|
||
"Normal",
|
||
"Strong",
|
||
"Very strong",
|
||
]
|
||
}
|
||
tooShortWord="Too short"
|
||
userInputs={Array []}
|
||
>
|
||
<div
|
||
className="ReactPasswordStrength "
|
||
>
|
||
<input
|
||
className="ReactPasswordStrength-input form-control"
|
||
id="user_password"
|
||
name="user[password]"
|
||
onChange={[Function]}
|
||
type="password"
|
||
value=""
|
||
/>
|
||
<div
|
||
className="ReactPasswordStrength-strength-bar"
|
||
/>
|
||
<span
|
Also available in: Unified diff
Fixes #22683 - Domain level PasswordStrength entry
ref #22473