Skip to content

Commit

Permalink
Merge 007987f into f7a762e
Browse files Browse the repository at this point in the history
  • Loading branch information
sharvit committed Feb 7, 2018
2 parents f7a762e + 007987f commit 9c673ec
Show file tree
Hide file tree
Showing 24 changed files with 724 additions and 724 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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 : __('Password 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,
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import '../../../common/colors.scss';
@import '../../common/colors.scss';

.ReactPasswordStrength {
.ReactPasswordStrength-input {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
PASSWORD_STRENGTH_PASSWROD_CHANGED,
PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
} from './PasswordStrengthConstants';

export const updatePassword = password => ({
type: PASSWORD_STRENGTH_PASSWROD_CHANGED,
payload: password,
});

export const updatePasswordConfirmation = password => ({
type: PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED,
payload: password,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const PASSWORD_STRENGTH_PASSWROD_CHANGED = 'PASSWORD_STRENGTH_PASSWROD_CHANGED';
export const PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED =
'PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Immutable from 'seamless-immutable';

import {
PASSWORD_STRENGTH_PASSWROD_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_PASSWROD_CHANGED:
return state.set('password', payload);

case PASSWORD_STRENGTH_PASSWROD_CONFIRMATION_CHANGED:
return state.set('passwordConfirmation', payload);

default:
return state;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const doesPasswordsMatch = ({ password, passwordConfirmation }) =>
!passwordConfirmation || password === passwordConfirmation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import toJson from 'enzyme-to-json';

import PasswordStrength from '../PasswordStrength';

describe('PasswordStrength component', () => {
const getBasePrpops = () => ({
updatePassword: jest.fn(),
updatePasswordConfirmation: jest.fn(),
doesPasswordsMatch: true,
data: {
className: 'some-class-name',
id: 'some-id',
name: 'some-name',
error: 'some-password-error',
userInputIds: [],
},
});

beforeEach(() => {
document.__originalGetElementById = document.getElementById;
document.getElementById = jest.fn(id => ({ value: id }));
});

afterEach(() => {
document.getElementById = document.__originalGetElementById;
delete document.__originalGetElementById;
});

describe('rendering', () => {
test('it should get rendered correctly', () => {
const component = shallow(<PasswordStrength {...getBasePrpops()} />);

expect(toJson(component)).toMatchSnapshot();
});

test('it should get rendered correctly with password-confirmation', () => {
const props = getBasePrpops();
props.data.verify = {
name: 'user[password_confirmation]',
error: 'some-password-confirmation-error',
};

const component = shallow(<PasswordStrength {...props} />);

expect(toJson(component)).toMatchSnapshot();
});

test('it should get rendered correctly with unmatched password-confirmation', () => {
const props = { ...getBasePrpops(), doesPasswordsMatch: false };
props.data.verify = {
name: 'user[password_confirmation]',
error: 'some-password-confirmation-error',
};

const component = shallow(<PasswordStrength {...props} />);

expect(toJson(component)).toMatchSnapshot();
});

test('it should get rendered correctly with user-input-ids', () => {
const props = getBasePrpops();
props.data.userInputIds = ['input1', 'input2'];

const component = shallow(<PasswordStrength {...props} />);

expect(toJson(component)).toMatchSnapshot();
expect(document.getElementById.mock.calls).toMatchSnapshot('getElementById calls');
});
});

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 = getBasePrpops();
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 = getBasePrpops();
props.data.verify = {
name: 'user[password_confirmation]',
error: 'some-password-confirmation-error',
};

const component = mount(<PasswordStrength {...props} />);

const passwordConfirmationInput = component.find('input#password_confirmation');
setInputValue(passwordConfirmationInput, 'some-value');

expect(props.updatePasswordConfirmation.mock.calls).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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());
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
PASSWORD_STRENGTH_PASSWROD_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_PASSWROD_CHANGED', () =>
expect(reduce({
action: {
type: PASSWORD_STRENGTH_PASSWROD_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());
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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));
});
});

0 comments on commit 9c673ec

Please sign in to comment.